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
-- 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:
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.
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.
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:
local multiplied = 2 * jo.pricing.new({ money = 5 })
log(multiplied:getCosts())
-- Expected output: { { money = 10 } }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.
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.
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: 2Equality
Use the == operator to compare two prices by value. Cost order does not matter.
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: trueConstructor
jo.pricing.new()
Creates a canonical PriceClass.
Syntax
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
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
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
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
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
jo.pricing.isPrice(value)Parameters
value : any
Value to test
Return Value
Type : boolean
Example
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: falsejo.pricing.isPriceGroup()
Returns true when a value is a PriceGroupClass instance.
Syntax
jo.pricing.isPriceGroup(value)Parameters
value : any
Value to test
Return Value
Type : boolean
Example
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: falsejo.pricing.tax()
Returns the canonical costs list for a price input.
Splits a price into tax and remaining prices.
Syntax
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
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
PriceClass:add(price)Parameters
price : PriceInput
Price input to add to the current price
Return Value
Type : PriceClass
Example
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
PriceClass:clear()Return Value
Type : PriceClass
Example
local price = jo.pricing.new({ money = 10, item = "water" })
price:clear()
log(price:getCosts())
-- Expected output: {}
print(price:isFree())
-- Expected output: truePriceClass:copy()
Creates a new independent copy of the current PriceClass.
Syntax
PriceClass:copy()Return Value
Type : PriceClass
Example
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
PriceClass:equals(other)Parameters
other : PriceInput
Price input to compare with the current price
Return Value
Type : boolean
Example
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: falsePriceClass:getCosts()
Returns the canonical costs list.
Syntax
PriceClass:getCosts()Return Value
Type : Cost[]
PriceClass:getGold()
Returns the gold amount.
Syntax
PriceClass:getGold()Return Value
Type : number|nil
Example
local price = jo.pricing.new({ money = 10, gold = 2 })
local gold = price:getGold()
log(gold)
-- Expected output: 2PriceClass:getItem()
Returns an ItemCost by item name and keep flag.
Syntax
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
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
PriceClass:getItems()Return Value
Type : ItemCost[]
Example
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
PriceClass:getMoney()Return Value
Type : number|nil
Example
local price = jo.pricing.new({ money = 10, gold = 2 })
local money = price:getMoney()
log(money)
-- Expected output: 10PriceClass:getRol()
Returns the rol amount.
Syntax
PriceClass:getRol()Return Value
Type : number|nil
Example
local price = jo.pricing.new({ rol = 3 })
local rol = price:getRol()
log(rol)
-- Expected output: 3PriceClass:hasCurrency()
Returns true when a currency cost exists.
Syntax
PriceClass:hasCurrency(key)Parameters
key : "money"|"gold"|"rol"
Currency cost key
Return Value
Type : boolean
Example
local price = jo.pricing.new({ money = 10, item = "water" })
print(price:hasCurrency("money"))
-- Expected output: true
print(price:hasCurrency("gold"))
-- Expected output: falsePriceClass:hasItem()
Returns true when an ItemCost exists for an item name and keep flag.
Syntax
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
local price = jo.pricing.new({ item = "water", quantity = 2 })
print(price:hasItem("water", false))
-- Expected output: true
print(price:hasItem("water", true))
-- Expected output: falsePriceClass:isCurrencyOnly()
Returns true when the PriceClass contains only currency costs.
Syntax
PriceClass:isCurrencyOnly()Return Value
Type : boolean
Example
print(jo.pricing.new({ money = 10, gold = 2 }):isCurrencyOnly())
-- Expected output: true
print(jo.pricing.new({ money = 10, item = "water" }):isCurrencyOnly())
-- Expected output: falsePriceClass:isFree()
Returns true when the PriceClass has no payable costs.
Syntax
PriceClass:isFree()Return Value
Type : boolean
Example
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: falsePriceClass:isItemOnly()
Returns true when the PriceClass contains only item costs.
Syntax
PriceClass:isItemOnly()Return Value
Type : boolean
Example
print(jo.pricing.new({ item = "water" }):isItemOnly())
-- Expected output: true
print(jo.pricing.new({ money = 10, item = "water" }):isItemOnly())
-- Expected output: falsePriceClass:removeCurrency()
Removes a currency cost from the current PriceClass.
Syntax
PriceClass:removeCurrency(key)Parameters
key : "money"|"gold"|"rol"
Currency cost key to remove
Return Value
Type : PriceClass
Example
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
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
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
PriceGroupClass:clear()Return Value
Type : PriceGroupClass
Example
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
group:clear()
print(group:count())
-- Expected output: 0
print(group:isEmpty())
-- Expected output: truePriceGroupClass:compact()
Compacts an "and" PriceGroupClass into a new PriceClass.
Syntax
PriceGroupClass:compact()Return Value
Type : PriceClass
Example
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
PriceGroupClass:copy()Return Value
Type : PriceGroupClass
Example
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: 3PriceGroupClass:count()
Returns the number of prices in the group.
Syntax
PriceGroupClass:count()Return Value
Type : number
Example
local group = jo.pricing.newGroup({ { money = 10 }, { gold = 2 } })
print(group:count())
-- Expected output: 2PriceGroupClass:get()
Returns a PriceClass by index.
Syntax
PriceGroupClass:get(index)Parameters
index : number
Price index
Return Value
Type : PriceClass|nil
Example
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
PriceGroupClass:getCosts(index)Parameters
index : number
Price index
Return Value
Type : Cost[]|nil
PriceGroupClass:insert()
Inserts a PriceClass into the group.
Syntax
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
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
PriceGroupClass:isEmpty()Return Value
Type : boolean
Example
local group = jo.pricing.newGroup()
print(group:isEmpty())
-- Expected output: true
group:insert({ money = 10 })
print(group:isEmpty())
-- Expected output: falsePriceGroupClass:remove()
Removes a PriceClass from the group by index.
Syntax
PriceGroupClass:remove(index)Parameters
index : number
Price index to remove
Return Value
Type : PriceClass|nil
Example
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: 1PriceGroupClass:set()
Replaces an existing PriceClass by index.
Syntax
PriceGroupClass:set(index, price)Parameters
index : number
Existing price index to replace
price : PriceInput
Replacement price input
Return Value
Type : PriceGroupClass
Example
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 }
-- }