feat(packages): ludic.shop - prices by standing with the fountain guard, a weekly demand on its own dice, stock, buying and selling through purse and pack ports, a trade fact
Items (base price, sell fraction) and vendors (stock, buys, refuses) are the game's data handed over at boot; standing, the day, a shortage and "buys beyond its list" are the ShopWorld port; money is ShopPurse and the pack ShopPack. The week's wanted and glutted items come from an Rng seeded by the week, never the world's. The balance invariants - a shop is not a fountain, friction falls and never inverts, raw keeps its order - are the package's tests (nine). ludic.crafting: its private names carry the package's prefix too (a private name is still one global namespace with the game's - ludic.shop's `sp_seed` met the game's). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
cc9cec922a
commit
12cfcb10ac
12 changed files with 663 additions and 28 deletions
43
packages/ludic.shop/prices.ludic
Normal file
43
packages/ludic.shop/prices.ludic
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# prices.ludic - what a thing costs and what it fetches. One standing moves both, toward each
|
||||
# other and never past: a newcomer pays a little over and sells a little under.
|
||||
function shop_rep01() -> float { return Math.clamp(float(ShopWorld.rep()), 0.0, 100.0) / 100.0 }
|
||||
|
||||
# the fraction of base a buyer pays, and a seller is paid before the item's own fraction
|
||||
export function shop_buy_factor() -> float { return shop_buy_new + (shop_buy_best - shop_buy_new) * shop_rep01() }
|
||||
export function shop_sell_factor() -> float { return shop_sell_new + (shop_sell_best - shop_sell_new) * shop_rep01() }
|
||||
|
||||
export function shop_price_buy(it: int) -> int {
|
||||
if not shop_item_ok(it) { return 0 }
|
||||
let p = int(float(shop_base[it]) * shop_buy_factor() * ShopWorld.buy_mult() + 0.5)
|
||||
return Math.max(p, 1)
|
||||
}
|
||||
|
||||
# what vendor `v` pays (-1: no vendor, no demand). ROUNDED, so cheap raw material keeps its
|
||||
# order; and a vendor that stocks the thing never pays what it charges, not even a floor of $1
|
||||
export function shop_price_sell_at(v: int, it: int) -> int {
|
||||
if not shop_item_ok(it) { return 0 }
|
||||
let f = shop_sell_factor() * shop_sell_frac[it] * shop_demand_mult(v, it)
|
||||
var p = Math.max(int(float(shop_base[it]) * f + 0.5), 1)
|
||||
if shop_stocks(v, it) { p = Math.max(Math.min(p, shop_price_buy(it) - 1), 0) }
|
||||
return p
|
||||
}
|
||||
|
||||
# what the vendor at the counter pays
|
||||
export function shop_price_sell(it: int) -> int { return shop_price_sell_at(shop_at, it) }
|
||||
|
||||
export function shop_stocks(v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(v) or shop_vendor_list[v].stock == null { return false }
|
||||
let st = shop_vendor_list[v].stock
|
||||
for k in 0 .. len(st) { if st[k] == it { return true } }
|
||||
return false
|
||||
}
|
||||
|
||||
# what `v` takes: its list and whatever the world says, and never the one thing it refuses
|
||||
export function shop_buys(v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(v) or it == shop_vendor_list[v].refuses { return false }
|
||||
if ShopWorld.also_buys(v, it) { return true }
|
||||
let b = shop_vendor_list[v].buys
|
||||
if b == null { return false }
|
||||
for k in 0 .. len(b) { if b[k] == it { return true } }
|
||||
return false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue