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
local price = jo.pricing.formatPrice({
money = 5,
item = "acid"
})
price:add({ gold = 1 })
local prices = jo.pricing.formatPrices({
operator = "or",
{ money = 10 },
{ gold = 1 }
})Price and Prices remain classic Lua numeric tables, so existing table access is still valid:
print(price[1].item)
print(prices[1][1].money)JO Functions
jo.pricing.formatPrice()
A function to format a single price
Formats one payment expression and returns a Price object.
A Price is still a numeric Lua table. Each entry inside it is paid together.
Accepted formats include:
10for a money price.{ money = 10 },{ gold = 1 }or{ rol = 5 }.{ money = 2.75, gold = 2 }for an AND price.{ item = "water" }for one item.{ money = 5, item = "acid" }for money plus one item.{ money = 2, { item = "acid", quantity = 3 } }for money plus multiple items.
If quantity is missing on an item, it defaults to 1. If keep is missing on an item, it defaults to false.
Syntax
jo.pricing.formatPrice(price)Parameters
price : table|integer|number
The price to format
Return Value
Type : Price
The formatted price
Example
local moneyPrice = jo.pricing.formatPrice(10)
print(moneyPrice[1].money) -- 10
local currencyPrice = jo.pricing.formatPrice({
money = 2.75,
gold = 2
})
-- $2.75 AND 2 gold
local itemPrice = jo.pricing.formatPrice({
item = "water",
quantity = 2
})
-- 2 water items
local mixedPrice = jo.pricing.formatPrice({
money = 5,
item = "acid"
})
-- $5 AND 1 acid item
local mixedWithQuantity = jo.pricing.formatPrice({
money = 2,
{ item = "acid", quantity = 3 }
})
-- $2 AND 3 acid itemsjo.pricing.formatPrices()
A function to format price variations.
Only a root operator = "or" creates alternatives; every other shape is a single AND price.
Formats a list of payment expressions and returns a Prices object.
Prices is a numeric table containing one or more Price objects. Its operator property is either "and" or "or".
Without a root operator = "or", the input is formatted as a single AND option. This means { money = 2, gold = 1 } and { { money = 2 }, { gold = 1 } } both become one option.
Only a root operator = "or" creates alternatives. Nested operators are ignored.
Syntax
jo.pricing.formatPrices(prices)Parameters
prices : table|integer|number
The prices to format
Return Value
Type : Prices
The formatted prices
Example
local andPrices = jo.pricing.formatPrices({
money = 2,
gold = 1
})
-- One option: $2 AND 1 gold
local alsoAndPrices = jo.pricing.formatPrices({
{ money = 2 },
{ gold = 1 }
})
-- One option: $2 AND 1 gold
local orPrices = jo.pricing.formatPrices({
operator = "or",
{ money = 2 },
{ gold = 1 }
})
-- Option 1: $2
-- Option 2: 1 gold
local complexOrPrices = jo.pricing.formatPrices({
operator = "or",
{ money = 5, item = "acid" },
{ gold = 5 },
{ money = 2, { item = "acid", quantity = 3 } }
})
-- Option 1: $5 AND 1 acid
-- Option 2: 5 gold
-- Option 3: $2 AND 3 acid
print(orPrices.operator) -- "or"
print(orPrices[1][1].money) -- 2jo.pricing.isPriceFree()
Checks if a price is free
Returns true only when the formatted price is free.
For a Prices object, it returns true only when the set contains one free option.
Syntax
jo.pricing.isPriceFree(price)Parameters
price : table|integer|number
The price to check
Return Value
Type : boolean
Return
trueif the price is free
Example
print(jo.pricing.isPriceFree(0)) -- true
print(jo.pricing.isPriceFree({ money = 1 })) -- false
local prices = jo.pricing.formatPrices({ money = 0 })
print(jo.pricing.isPriceFree(prices)) -- truejo.pricing.mergePrices()
Merge prices
Merges multiple prices into one AND Price.
This is useful when you need to add several price fragments and keep the result as a single payment expression.
Syntax
jo.pricing.mergePrices(...)Parameters
... : table
The prices to merge
Return Value
Type : Price
The merged prices
Example
local price = jo.pricing.mergePrices(
{ money = 10 },
{ gold = 1 },
{ item = "water", quantity = 2 }
)
-- $10 AND 1 gold AND 2 waterjo.pricing.tax()
Gets the tax price from a price and a percentage
Returns a new taxed Price based on the provided value.
percentage is a multiplier. For example, 0.2 returns 20% of the price and 1.2 returns 120% of the price. Item quantities are rounded down by default, or rounded up when roundUpItems is true.
Syntax
jo.pricing.tax(price, percentage, roundUpItems)Parameters
price : table|integer|number
The price to tax
percentage : number
The percentage to apply. Example:
0.2returns 20% of the price
roundUpItems : boolean Optional
Whether item quantities should be rounded up. Defaults to
false
Return Value
Type : Price
The taxed price
Example
local price = jo.pricing.tax({
money = 10,
item = "water",
quantity = 3
}, 0.5)
-- $5 AND 1 water, because item quantities are rounded down by default
local roundedUpPrice = jo.pricing.tax({
item = "water",
quantity = 3
}, 0.5, true)
-- 2 water, because roundUpItems is truePriceClass Methods
PriceClass:add()
Adds a price to the current price.
Mutates the current Price by adding another price to it.
Currencies and compatible items are normalized after the addition. Items are merged only when they use the same item name, keep value and metadata.
Syntax
PriceClass:add(price)Parameters
price : table|integer|number
The price to add
Return Value
Type : Price
The mutated price
Example
local price = jo.pricing.formatPrice({ money = 10 })
price:add({ gold = 1 })
price:add({ item = "water", quantity = 2 })
-- price is now: $10 AND 1 gold AND 2 waterPriceClass:copy()
Copies the price.
Creates an independent Price copy.
Mutating the copy does not mutate the original price.
Syntax
PriceClass:copy()Return Value
Type : Price
The copied price
Example
local original = jo.pricing.formatPrice({ money = 10 })
local copy = original:copy()
copy:add({ gold = 1 })
print(original[1].money) -- 10PriceClass:isFree()
Checks if the price is free.
Checks whether this Price is free.
Syntax
PriceClass:isFree()Return Value
Type : boolean
Return
trueif the price is free
Example
local freePrice = jo.pricing.formatPrice(0)
local paidPrice = jo.pricing.formatPrice(10)
print(freePrice:isFree()) -- true
print(paidPrice:isFree()) -- falsePriceClass:remove()
Removes a price from the current price.
Strictly removes another price from the current Price.
If one currency amount or item quantity is missing, the method returns false, reason and the original Price is not mutated.
Syntax
PriceClass:remove(price)Parameters
price : table|integer|number
The price to remove
Return Value
Type : Price|boolean,string?
The mutated price, or false and the reason
Example
local price = jo.pricing.formatPrice({
money = 10,
item = "water",
quantity = 2
})
price:remove({ money = 5 })
-- price is now: $5 AND 2 water
local success, reason = price:remove({ money = 15 })
if not success then
print(reason) -- "not_enough_money"
endPriceClass:tax()
Applies a percentage to the current price.
Mutates the current Price by applying a multiplier.
Currencies are multiplied directly. Item quantities are rounded down by default, or rounded up when roundUpItems is true.
Syntax
PriceClass:tax(percentage, roundUpItems)Parameters
percentage : number
The percentage to apply
roundUpItems : boolean Optional
Whether item quantities should be rounded up
Return Value
Type : Price
The mutated price
Example
local price = jo.pricing.formatPrice({
money = 10,
item = "water",
quantity = 3
})
price:tax(0.5)
-- price is now: $5 AND 1 waterPriceClass:toTable()
Converts the price to a plain table.
Returns a deep plain table copy without object methods.
Use it when you explicitly need to serialize or pass a price without its metatable.
Syntax
PriceClass:toTable()Return Value
Type : table
The plain table
Example
local price = jo.pricing.formatPrice({
money = 10,
item = "water"
})
local plainPrice = price:toTable()
print(plainPrice[1].money or plainPrice[2].money)PricesClass Methods
PricesClass:addPrice()
Adds a price option to the prices set.
Adds a price option to this Prices object.
When operator is "or", this adds a new option. When operator is "and", this merges the price into the single AND option.
Syntax
PricesClass:addPrice(price)Parameters
price : table|integer|number
The price to add
Return Value
Type : Prices
The mutated prices set
Example
local prices = jo.pricing.formatPrices({
operator = "or",
{ money = 10 }
})
prices:addPrice({ gold = 1 })
-- prices now has two options
local andPrices = jo.pricing.formatPrices({ money = 10 })
andPrices:addPrice({ gold = 1 })
-- andPrices still has one option: $10 AND 1 goldPricesClass:copy()
Copies the prices set.
Creates an independent copy of the Prices object and all its nested Price objects.
Syntax
PricesClass:copy()Return Value
Type : Prices
The copied prices set
Example
local prices = jo.pricing.formatPrices({
operator = "or",
{ money = 10 },
{ gold = 1 }
})
local copy = prices:copy()
copy:addPrice({ rol = 5 })
print(#prices) -- 2
print(#copy) -- 3PricesClass:removePrice()
Removes a price option from the prices set.
Removes one option from this Prices object by numeric index.
Syntax
PricesClass:removePrice(index)Parameters
index : integer
The price option index
Return Value
Type : Prices
The mutated prices set
Example
local prices = jo.pricing.formatPrices({
operator = "or",
{ money = 10 },
{ gold = 1 }
})
prices:removePrice(1)
-- only the gold option remainsPricesClass:toTable()
Converts the prices set to a plain table.
Returns a deep plain table copy without object methods.
The returned table keeps the operator field.
Syntax
PricesClass:toTable()Return Value
Type : table
The plain table
Example
local prices = jo.pricing.formatPrices({
operator = "or",
{ money = 10 },
{ gold = 1 }
})
local plainPrices = prices:toTable()
print(plainPrices.operator) -- "or"