Skip to content

Pricing Shared ​

Pricing is a shared module to normalize and manipulate prices in your scripts.

TIP

You can use the Price Generator to build price tables and paste the generated Lua code into your config files.

Quick usage ​

lua
-- Create a price with $5 and 1 acid item.
local price = jo.pricing.new({
  money = 5,
  item = "acid"
})

-- Add 1 gold to the existing price.
price:add({ gold = 1 })

-- Create a group where the player can pay either $10 or 1 gold.
local group = jo.pricing.newGroup({
  { money = 10 },
  { gold = 1 }
})

Prices are normalized into canonical cost tables:

lua
log(price:getCosts())
-- Expected output:
-- {
--   { money = 5 },
--   { gold = 1 },
--   { item = "acid", quantity = 1, keep = false }
-- }

print(group.operator)
-- Expected output: "or"

Mathematical Operations ​

Addition ​

Use the + operator to combine two prices into a new PriceClass.

lua
local priceA = jo.pricing.new({ money = 10 })
local priceB = jo.pricing.new({ money = 5, item = "water" })

local total = priceA + priceB

log(total:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { item = "water", quantity = 1, keep = false }
-- }

log(priceA:getCosts())
-- Expected output: { { money = 10 } }

Multiplication ​

Use the * operator to multiply a price into a new PriceClass. Currencies keep their multiplied value, while item quantities are rounded to the nearest integer.

lua
local price = jo.pricing.new({
  money = 10,
  item = "water",
  quantity = 3
})

local multiplied = price * 1.5

log(multiplied:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { item = "water", quantity = 5, keep = false }
-- }

log(price:getCosts())
-- Expected output:
-- {
--   { money = 10 },
--   { item = "water", quantity = 3, keep = false }
-- }

The reversed order also works:

lua
local multiplied = 2 * jo.pricing.new({ money = 5 })

log(multiplied:getCosts())
-- Expected output: { { money = 10 } }

PriceGroupClass ​

The * operator can also multiply every price in a PriceGroupClass. It returns a new group, preserves the original operator and does not modify the source group.

lua
local group = jo.pricing.newGroup({
  { money = 10 },
  { gold = 2 }
})

local multipliedGroup = group * 3

print(multipliedGroup.operator)
-- Expected output: "or"

log(multipliedGroup:get(1):getCosts())
-- Expected output: { { money = 30 } }

log(multipliedGroup:get(2):getCosts())
-- Expected output: { { gold = 6 } }

log(group:get(1):getCosts())
-- Expected output: { { money = 10 } }

The reversed order is supported too:

lua
local multipliedGroup = 3 * group

Division ​

Use the / operator to divide a price by a number into a new PriceClass. It reuses the multiplication behavior internally, so currencies keep their divided value and item quantities are rounded to the nearest integer.

lua
local price = jo.pricing.new({
  money = 15,
  item = "water",
  quantity = 5
})

local divided = price / 2

log(divided:getCosts())
-- Expected output:
-- {
--   { money = 7.5 },
--   { item = "water", quantity = 3, keep = false }
-- }

log(price:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { item = "water", quantity = 5, keep = false }
-- }

Only price / number is supported. Division by zero raises an error.

Length ​

Use the # operator to count canonical entries. For a PriceClass, it returns the number of costs. For a PriceGroupClass, it returns the number of prices in the group.

lua
local price = jo.pricing.new({ money = 10, item = "water" })
local group = jo.pricing.newGroup({
  { money = 10 },
  { gold = 2 }
})

print(#price)
-- Expected output: 2

print(#group)
-- Expected output: 2

Equality ​

Use the == operator to compare two prices by value. Cost order does not matter.

lua
local priceA = jo.pricing.new({ money = 10, item = "water" })
local priceB = jo.pricing.new({
  { item = "water", quantity = 1, keep = false },
  { money = 10 }
})

print(priceA == priceB)
-- Expected output: true

Constructor ​

jo.pricing.new() ​

Creates a canonical PriceClass.

Syntax ​

lua
jo.pricing.new(data, reuseExisting)

Parameters ​

data : PriceInput|PriceClass Optional

Price input to normalize
default:nil

reuseExisting : boolean Optional

Reuse existing PriceClass if already created
default:false

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({
  money = 5,
  { money = 10 },
  { item = "water", quantity = 2 }
})

log(price:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { item = "water", quantity = 2, keep = false }
-- }

jo.pricing.newGroup() ​

Creates a canonical PriceGroupClass.

Syntax ​

lua
jo.pricing.newGroup(data, reuseExisting)

Parameters ​

data : PriceGroupInput Optional

Price group input to normalize
default:nil

reuseExisting : boolean Optional

Reuse existing PriceGroupClass if already created
default:false

Return Value ​

Type : PriceGroupClass

Example ​

lua
local group = jo.pricing.newGroup({
  operator = "and",
  money = 10,
  gold = 2
})

print(group.operator)
-- Expected output: "and"

print(group:count())
-- Expected output: 2

log(group:compact():getCosts())
-- Expected output:
-- {
--   { money = 10 },
--   { gold = 2 }
-- }

JO Functions ​

jo.pricing.getCosts() ​

Returns the canonical costs list for a price input.

Syntax ​

lua
jo.pricing.getCosts(price)

Parameters ​

price : PriceInput

Price input

Return Value ​

Type : Cost[]


jo.pricing.isPrice() ​

Returns true when a value is a PriceClass instance.

Syntax ​

lua
jo.pricing.isPrice(value)

Parameters ​

value : any

Value to test

Return Value ​

Type : boolean

Example ​

lua
local price = jo.pricing.new({ money = 10 })
local plainTable = { costs = { { money = 10 } } }

print(jo.pricing.isPrice(price))
-- Expected output: true

print(jo.pricing.isPrice(plainTable))
-- Expected output: false

jo.pricing.isPriceGroup() ​

Returns true when a value is a PriceGroupClass instance.

Syntax ​

lua
jo.pricing.isPriceGroup(value)

Parameters ​

value : any

Value to test

Return Value ​

Type : boolean

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
local plainTable = { operator = "or", prices = {} }

print(jo.pricing.isPriceGroup(group))
-- Expected output: true

print(jo.pricing.isPriceGroup(plainTable))
-- Expected output: false

jo.pricing.tax() ​

Returns the canonical costs list for a price input.
Splits a price into tax and remaining prices.

Syntax ​

lua
jo.pricing.tax(price, percentage, roundUpItems)

Parameters ​

price : PriceInput

Price input to split

percentage : number Optional

Tax multiplier applied to the input price
default:0

roundUpItems : boolean Optional

Round item quantities up instead of down
default:false

Return Value ​

Type : PriceClass,PriceClass

Example ​

lua
local price = jo.pricing.new({ money = 10, item = "water", quantity = 3 })

-- With roundUpItems = false, item quantities in the tax are rounded down.
local taxPrice, remainingPrice = jo.pricing.tax(price, 0.5, false)

log(taxPrice:getCosts()) -- Tax PriceClass
-- Expected output:
-- {
--   { money = 5 },
--   { item = "water", quantity = 1, keep = false }
-- }

log(remainingPrice:getCosts()) -- Remaining PriceClass
-- Expected output:
-- {
--   { money = 5 },
--   { item = "water", quantity = 2, keep = false }
-- }

-- With roundUpItems = true, item quantities in the tax are rounded up.
local roundedTaxPrice, roundedRemainingPrice = jo.pricing.tax(price, 0.5, true)

log(roundedTaxPrice:getCosts()) -- Tax PriceClass
-- Expected output:
-- {
--   { money = 5 },
--   { item = "water", quantity = 2, keep = false }
-- }

log(roundedRemainingPrice:getCosts()) -- Remaining PriceClass
-- Expected output:
-- {
--   { money = 5 },
--   { item = "water", quantity = 1, keep = false }
-- }

The first returned PriceClass contains the tax amount. The second returned PriceClass contains the remaining price after the tax was removed from the input.

PriceClass Methods ​

PriceClass:add() ​

Adds a price to the current PriceClass.

Syntax ​

lua
PriceClass:add(price)

Parameters ​

price : PriceInput

Price input to add to the current price

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({ money = 10 })
price:add({ money = 5, gold = 2 })

log(price:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { gold = 2 }
-- }

PriceClass:clear() ​

Removes every cost from the current PriceClass.

Syntax ​

lua
PriceClass:clear()

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({ money = 10, item = "water" })
price:clear()

log(price:getCosts())
-- Expected output: {}

print(price:isFree())
-- Expected output: true

PriceClass:copy() ​

Creates a new independent copy of the current PriceClass.

Syntax ​

lua
PriceClass:copy()

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({ money = 10 })
local copy = price:copy()

copy:add({ gold = 2 })

log(price:getCosts())
-- Expected output: { { money = 10 } }

log(copy:getCosts())
-- Expected output: { { money = 10 }, { gold = 2 } }

PriceClass:equals() ​

Returns true when another price has the same costs.

Syntax ​

lua
PriceClass:equals(other)

Parameters ​

other : PriceInput

Price input to compare with the current price

Return Value ​

Type : boolean

Example ​

lua
local price = jo.pricing.new({ money = 10, item = "water" })

print(price:equals({ item = "water", money = 10 }))
-- Expected output: true

print(price:equals("invalid"))
-- Expected output: false

PriceClass:getCosts() ​

Returns the canonical costs list.

Syntax ​

lua
PriceClass:getCosts()

Return Value ​

Type : Cost[]


PriceClass:getGold() ​

Returns the gold amount.

Syntax ​

lua
PriceClass:getGold()

Return Value ​

Type : number|nil

Example ​

lua
local price = jo.pricing.new({ money = 10, gold = 2 })
local gold = price:getGold()

log(gold)
-- Expected output: 2

PriceClass:getItem() ​

Returns an ItemCost by item name and keep flag.

Syntax ​

lua
PriceClass:getItem(item, keep)

Parameters ​

item : string

Item name

keep : boolean

Item keep flag - false: consumed cost, true: required but kept

Return Value ​

Type : ItemCost|nil

Example ​

lua
local price = jo.pricing.new({
  { item = "water", quantity = 2, keep = false },
  { item = "permit", quantity = 1, keep = true }
})

local consumedWater = price:getItem("water", false)
local keptPermit = price:getItem("permit", true)

log(consumedWater)
-- Expected output: { item = "water", quantity = 2, keep = false }

log(keptPermit)
-- Expected output: { item = "permit", quantity = 1, keep = true }

PriceClass:getItems() ​

Returns all ItemCost entries.

Syntax ​

lua
PriceClass:getItems()

Return Value ​

Type : ItemCost[]

Example ​

lua
local price = jo.pricing.new({ money = 10, item = "water" })
local items = price:getItems()

log(items)
-- Expected output:
-- {
--   { item = "water", quantity = 1, keep = false }
-- }

PriceClass:getMoney() ​

Returns the money amount.

Syntax ​

lua
PriceClass:getMoney()

Return Value ​

Type : number|nil

Example ​

lua
local price = jo.pricing.new({ money = 10, gold = 2 })
local money = price:getMoney()

log(money)
-- Expected output: 10

PriceClass:getRol() ​

Returns the rol amount.

Syntax ​

lua
PriceClass:getRol()

Return Value ​

Type : number|nil

Example ​

lua
local price = jo.pricing.new({ rol = 3 })
local rol = price:getRol()

log(rol)
-- Expected output: 3

PriceClass:hasCurrency() ​

Returns true when a currency cost exists.

Syntax ​

lua
PriceClass:hasCurrency(key)

Parameters ​

key : "money"|"gold"|"rol"

Currency cost key

Return Value ​

Type : boolean

Example ​

lua
local price = jo.pricing.new({ money = 10, item = "water" })

print(price:hasCurrency("money"))
-- Expected output: true

print(price:hasCurrency("gold"))
-- Expected output: false

PriceClass:hasItem() ​

Returns true when an ItemCost exists for an item name and keep flag.

Syntax ​

lua
PriceClass:hasItem(item, keep)

Parameters ​

item : string

Item name

keep : boolean

Item keep flag - false: consumed cost, true: required but kept

Return Value ​

Type : boolean

Example ​

lua
local price = jo.pricing.new({ item = "water", quantity = 2 })

print(price:hasItem("water", false))
-- Expected output: true

print(price:hasItem("water", true))
-- Expected output: false

PriceClass:isCurrencyOnly() ​

Returns true when the PriceClass contains only currency costs.

Syntax ​

lua
PriceClass:isCurrencyOnly()

Return Value ​

Type : boolean

Example ​

lua
print(jo.pricing.new({ money = 10, gold = 2 }):isCurrencyOnly())
-- Expected output: true

print(jo.pricing.new({ money = 10, item = "water" }):isCurrencyOnly())
-- Expected output: false

PriceClass:isFree() ​

Returns true when the PriceClass has no payable costs.

Syntax ​

lua
PriceClass:isFree()

Return Value ​

Type : boolean

Example ​

lua
print(jo.pricing.new():isFree())
-- Expected output: true

print(jo.pricing.new({ money = 0 }):isFree())
-- Expected output: true

print(jo.pricing.new({ item = "water" }):isFree())
-- Expected output: false

PriceClass:isItemOnly() ​

Returns true when the PriceClass contains only item costs.

Syntax ​

lua
PriceClass:isItemOnly()

Return Value ​

Type : boolean

Example ​

lua
print(jo.pricing.new({ item = "water" }):isItemOnly())
-- Expected output: true

print(jo.pricing.new({ money = 10, item = "water" }):isItemOnly())
-- Expected output: false

PriceClass:removeCurrency() ​

Removes a currency cost from the current PriceClass.

Syntax ​

lua
PriceClass:removeCurrency(key)

Parameters ​

key : "money"|"gold"|"rol"

Currency cost key to remove

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({ money = 10, gold = 2 })
price:removeCurrency("money")

log(price:getCosts())
-- Expected output: { { gold = 2 } }

PriceClass:removeItem() ​

Removes an ItemCost from the current PriceClass.

Syntax ​

lua
PriceClass:removeItem(item, keep)

Parameters ​

item : string

Item name

keep : boolean

Item keep flag - false: consumed cost, true: required but kept

Return Value ​

Type : PriceClass

Example ​

lua
local price = jo.pricing.new({
  { item = "water", quantity = 2, keep = false },
  { item = "permit", keep = true }
})

price:removeItem("water", false)

log(price:getCosts())
-- Expected output:
-- {
--   { item = "permit", quantity = 1, keep = true }
-- }

PriceGroupClass Methods ​

PriceGroupClass:clear() ​

Removes every price from the group.

Syntax ​

lua
PriceGroupClass:clear()

Return Value ​

Type : PriceGroupClass

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
group:clear()

print(group:count())
-- Expected output: 0

print(group:isEmpty())
-- Expected output: true

PriceGroupClass:compact() ​

Compacts an "and" PriceGroupClass into a new PriceClass.

Syntax ​

lua
PriceGroupClass:compact()

Return Value ​

Type : PriceClass

Example ​

lua
local group = jo.pricing.newGroup({
  operator = "and",
  prices = {
    { money = 10 },
    { money = 5 },
    { item = "water", quantity = 2, keep = false  },
    { item = "water", quantity = 5 },
    { item = "water", quantity = 2, keep = true }
  }
})

local price = group:compact()
log(price:getCosts())
-- Expected output:
-- {
--   { money = 15 },
--   { item = "water", quantity = 7, keep = false },
--   { item = "water", quantity = 2, keep = true }
-- }

PriceGroupClass:copy() ​

Creates a new independent copy of the current PriceGroupClass.

Syntax ​

lua
PriceGroupClass:copy()

Return Value ​

Type : PriceGroupClass

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
local copy = group:copy()

copy:insert({ rol = 1 })

print(group:count())
-- Expected output: 2

print(copy:count())
-- Expected output: 3

PriceGroupClass:count() ​

Returns the number of prices in the group.

Syntax ​

lua
PriceGroupClass:count()

Return Value ​

Type : number

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })

print(group:count())
-- Expected output: 2

PriceGroupClass:get() ​

Returns a PriceClass by index.

Syntax ​

lua
PriceGroupClass:get(index)

Parameters ​

index : number

Price index

Return Value ​

Type : PriceClass|nil

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
local firstPrice = group:get(1)

log(firstPrice:getCosts())
-- Expected output: { { money = 10 } }

PriceGroupClass:getCosts() ​

Returns the costs of a price by index.

Syntax ​

lua
PriceGroupClass:getCosts(index)

Parameters ​

index : number

Price index

Return Value ​

Type : Cost[]|nil


PriceGroupClass:insert() ​

Inserts a PriceClass into the group.

Syntax ​

lua
PriceGroupClass:insert(price, index)

Parameters ​

price : PriceInput

Price input to insert

index : number Optional

Insertion index
default: append at the end

Return Value ​

Type : PriceGroupClass

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 } })
group:insert({ gold = 2 })
group:insert({ rol = 1 }, 1)

print(group:count())
-- Expected output: 3

log(group:get(1):getCosts())
-- Expected output: { { rol = 1 } }

PriceGroupClass:isEmpty() ​

Returns true when the group contains no prices.

Syntax ​

lua
PriceGroupClass:isEmpty()

Return Value ​

Type : boolean

Example ​

lua
local group = jo.pricing.newGroup()

print(group:isEmpty())
-- Expected output: true

group:insert({ money = 10 })

print(group:isEmpty())
-- Expected output: false

PriceGroupClass:remove() ​

Removes a PriceClass from the group by index.

Syntax ​

lua
PriceGroupClass:remove(index)

Parameters ​

index : number

Price index to remove

Return Value ​

Type : PriceClass|nil

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
local removed = group:remove(1)

log(removed:getCosts())
-- Expected output: { { money = 10 } }

print(group:count())
-- Expected output: 1

PriceGroupClass:set() ​

Replaces an existing PriceClass by index.

Syntax ​

lua
PriceGroupClass:set(index, price)

Parameters ​

index : number

Existing price index to replace

price : PriceInput

Replacement price input

Return Value ​

Type : PriceGroupClass

Example ​

lua
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
group:set(2, { item = "water", quantity = 2 })

log(group:get(2):getCosts())
-- Expected output:
-- {
--   { item = "water", quantity = 2, keep = false }
-- }

Last updated: