Skip to content

Cost curves ​

Cost curves price one or more resources from an owned count.

ts
import { costCurve, flat, geometric } from "@idlekitjs/economy/cost-curves";

Lines ​

flat(resourceId, amount, options?) creates a fixed per-unit price.

ts
flat("currency:coins", 10);

geometric(resourceId, { baseAmount, growth, round? }) creates a per-unit price that grows with the owned count.

ts
geometric("currency:coins", {
  baseAmount: 100,
  growth: 1.15,
  round: "ceil",
});

growth === 1 is linear. Invalid growth and negative amounts throw when the line or curve is created.

Curve ​

ts
const labCost = costCurve<State>({
  getOwned: (state) => state.labsOwned,
  lines: [
    flat("currency:gems", 1),
    geometric("currency:coins", { baseAmount: 100, growth: 1.15, round: "ceil" }),
  ],
});

The curve exposes three methods:

MethodBehavior
costFor(state, quantity)Total cost for quantity consecutive units
next(state)Cost for the next single unit
maxAffordable(state, economy)Largest whole quantity affordable right now

costFor floors quantity. Non-finite or non-positive quantities return an empty cost.

maxAffordable reads spendable balances through the economy. Spendable means the resource balance minus its min.

Rounding ​

round is optional and belongs to each curve line:

ts
type Rounding = "none" | "floor" | "ceil" | "round";

Rounding applies to each unit price before summing. This keeps the displayed unit price and the total for a bulk purchase consistent.

Rounded decreasing geometric curves (growth < 1 with per-unit rounding) throw when the curve is created.

Transaction usage ​

ts
const quantity = labCost.maxAffordable(state, economy);

const result = economy.execute(state, {
  id: "buy:labs",
  cost: labCost.costFor(state, quantity),
  apply: (state) => {
    state.labsOwned += quantity;
  },
});

The curve prices the action. The transaction settles it.