Track donations per item
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
45a51476a9
commit
fa960e1d6c
2 changed files with 48 additions and 19 deletions
47
game.py
47
game.py
|
|
@ -1542,7 +1542,7 @@ RAID_TRAITS = ["lightly armoured, heavy on archers", "mounted and fast, few bows
|
|||
|
||||
# --- world ---------------------------------------------------------------
|
||||
|
||||
WORLD_VERSION = 33
|
||||
WORLD_VERSION = 34
|
||||
|
||||
|
||||
def new_world(now: float, speed: float = 1.0) -> dict:
|
||||
|
|
@ -1798,6 +1798,11 @@ def migrate(world: dict, now: float | None = None) -> dict:
|
|||
for player in world["players"].values():
|
||||
player.setdefault("bury", True)
|
||||
world["version"] = 33
|
||||
if world["version"] < 34:
|
||||
# Donation history per item, from here on.
|
||||
for player in world["players"].values():
|
||||
player.setdefault("gave", {})
|
||||
world["version"] = 34
|
||||
return world
|
||||
|
||||
|
||||
|
|
@ -2058,6 +2063,7 @@ def new_player(uid: str, name: str, cls: str, now: float) -> dict:
|
|||
"rented": 0, "boosts": [], "bought": None, "deeds": {}, "owned": [], "look": dict(DEFAULT_LOOK),
|
||||
"garrison": False,
|
||||
"donated": 0,
|
||||
"gave": {}, # item (or "gold"): {qty, worth, favour} given to the city, see credit()
|
||||
"pinned": [], # skills pinned to the top of the sidebar
|
||||
"tracked": None, # recipe shown under the top bar
|
||||
}
|
||||
|
|
@ -2131,13 +2137,26 @@ def bank_add(world: dict, player: dict, item: str, qty: int, now: float, summary
|
|||
overflow = summary["overflow"]
|
||||
stockpile = world["city"]["stockpile"]
|
||||
stockpile[item] = stockpile.get(item, 0) + spill
|
||||
gain = spill * ITEMS[item]["value"]
|
||||
player["favour"] += gain * OVERFLOW_FAVOUR
|
||||
player["donated"] += gain
|
||||
credit(player, item, spill, OVERFLOW_FAVOUR)
|
||||
overflow[item] = overflow.get(item, 0) + spill
|
||||
return keep
|
||||
|
||||
|
||||
def credit(player: dict, item: str, qty: int, rate: float) -> None:
|
||||
"""Favour for giving `qty` of an item (or gold) to the city, at `rate` per point of worth.
|
||||
|
||||
Every gift is tallied per item in `gave`: how many, their worth at the time, and the
|
||||
favour paid for them, so a later revalue can recompute favour exactly.
|
||||
"""
|
||||
worth = qty * (1 if item == "gold" else ITEMS[item]["value"])
|
||||
player["favour"] += worth * rate
|
||||
player["donated"] += worth
|
||||
tally = player["gave"].setdefault(item, {"qty": 0, "worth": 0, "favour": 0})
|
||||
tally["qty"] += qty
|
||||
tally["worth"] += worth
|
||||
tally["favour"] += worth * rate
|
||||
|
||||
|
||||
def bank_take(player: dict, item: str, qty: int) -> None:
|
||||
left = player["bank"][item] - qty
|
||||
if left > 0:
|
||||
|
|
@ -4036,7 +4055,6 @@ def donate(world: dict, player: dict, item: str, qty: int, now: float) -> str |
|
|||
return "Not enough gold"
|
||||
player["gold"] -= qty
|
||||
city["treasury"] += qty
|
||||
gain = qty
|
||||
label = f"{qty:,} gold"
|
||||
else:
|
||||
if not city_uses(item):
|
||||
|
|
@ -4045,10 +4063,8 @@ def donate(world: dict, player: dict, item: str, qty: int, now: float) -> str |
|
|||
return "You don't have that many"
|
||||
bank_take(player, item, qty)
|
||||
city["stockpile"][item] = city["stockpile"].get(item, 0) + qty
|
||||
gain = qty * ITEMS[item]["value"]
|
||||
label = amount(item, qty)
|
||||
player["favour"] += gain * city_rate(world, "favour")
|
||||
player["donated"] += gain
|
||||
credit(player, item, qty, city_rate(world, "favour"))
|
||||
log(world, now, "donation", f"{player['name']} donated {label}", player["id"])
|
||||
return None
|
||||
|
||||
|
|
@ -4115,9 +4131,7 @@ def fund(world: dict, player: dict, key: str, item: str, qty: int | str, source:
|
|||
player["gold"] -= qty
|
||||
else:
|
||||
bank_take(player, item, qty)
|
||||
gain = qty * (1 if item == "gold" else ITEMS[item]["value"])
|
||||
player["favour"] += gain * city_rate(world, "favour")
|
||||
player["donated"] += gain
|
||||
credit(player, item, qty, city_rate(world, "favour"))
|
||||
elif item == "gold":
|
||||
city["treasury"] -= qty
|
||||
else:
|
||||
|
|
@ -4148,9 +4162,7 @@ def install(world: dict, player: dict, fitting: str, source: str, now: float) ->
|
|||
if not player["bank"].get(fitting):
|
||||
return "You don't have one"
|
||||
bank_take(player, fitting, 1)
|
||||
gain = ITEMS[fitting]["value"]
|
||||
player["favour"] += gain * city_rate(world, "favour")
|
||||
player["donated"] += gain
|
||||
credit(player, fitting, 1, city_rate(world, "favour"))
|
||||
elif source == "city":
|
||||
if not city["stockpile"].get(fitting):
|
||||
return "There isn't one in the stockpile"
|
||||
|
|
@ -4379,8 +4391,7 @@ def pay_wages(world: dict, player: dict, qty, source: str, now: float) -> str |
|
|||
qty = min(qty, room)
|
||||
if source == "bank":
|
||||
player["gold"] -= qty
|
||||
player["favour"] += qty * city_rate(world, "favour")
|
||||
player["donated"] += qty
|
||||
credit(player, "gold", qty, city_rate(world, "favour"))
|
||||
log(world, now, "donation", f"{player['name']} paid {qty:,} gold of guard wages", player["id"])
|
||||
else:
|
||||
city["treasury"] -= qty
|
||||
|
|
@ -5417,9 +5428,7 @@ def aid_problem(world: dict, player: dict, kind: str, item: str, source: str, no
|
|||
return "Nothing to give"
|
||||
if source == "bank":
|
||||
bank_take(player, item, qty)
|
||||
gain = qty * ITEMS[item]["value"] * city_rate(world, "favour")
|
||||
player["favour"] += gain
|
||||
player["donated"] += qty * ITEMS[item]["value"]
|
||||
credit(player, item, qty, city_rate(world, "favour"))
|
||||
else:
|
||||
take_stock_qty(stock, item, qty)
|
||||
problem["progress"][item] = problem["progress"].get(item, 0) + qty
|
||||
|
|
|
|||
|
|
@ -261,6 +261,26 @@ class ActionTest(unittest.TestCase):
|
|||
self.assertEqual(world["city"]["stockpile"]["stone"], 3)
|
||||
self.assertEqual(p["favour"], 1.5) # half favour for overflow
|
||||
self.assertEqual(p["donated"], 3)
|
||||
self.assertEqual(p["gave"], {"stone": {"qty": 3, "worth": 3, "favour": 1.5}})
|
||||
|
||||
def test_every_gift_is_tallied_by_item(self):
|
||||
world = world_with(("fred", "commoner"))
|
||||
p = world["players"]["fred"]
|
||||
p["bank"], p["gold"] = {"bricks": 20}, 100
|
||||
brick = game.ITEMS["bricks"]["value"]
|
||||
self.assertIsNone(game.donate(world, p, "bricks", 5, T0))
|
||||
self.assertIsNone(game.donate(world, p, "gold", 40, T0))
|
||||
self.assertIsNone(game.fund(world, p, "walls", "bricks", 3, "bank", T0))
|
||||
self.assertEqual(p["gave"]["bricks"], {"qty": 8, "worth": 8 * brick, "favour": 8 * brick})
|
||||
self.assertEqual(p["gave"]["gold"], {"qty": 40, "worth": 40, "favour": 40})
|
||||
self.assertEqual(sum(t["favour"] for t in p["gave"].values()), p["favour"])
|
||||
|
||||
def test_migrate_starts_an_empty_donation_tally(self):
|
||||
world = world_with(("fred", "commoner"))
|
||||
del world["players"]["fred"]["gave"]
|
||||
world["version"] = 33
|
||||
game.migrate(world, T0)
|
||||
self.assertEqual(world["players"]["fred"]["gave"], {})
|
||||
|
||||
def test_full_bank_sells_what_the_city_cannot_use(self):
|
||||
world = world_with(("fred", "commoner"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue