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 } }

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: