Spend favour on the city: builders, informants, militia

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-18 19:48:22 +01:00
parent 34dc85284d
commit 67a5db86ff
5 changed files with 142 additions and 3 deletions

60
game.py
View file

@ -903,6 +903,7 @@ def defence(world: dict) -> dict:
"weapons": round(3 * iron + 1.5 * (swords - iron), 1),
"shields": 2 * min(armed, stock.get("iron_shield", 0)),
"arrows": min(100, stock.get("arrows", 0) // 10),
"rallied": city.get("rally", 0),
"garrison": 0,
}
garrison = []
@ -1192,6 +1193,7 @@ def _resolve_raid(world: dict, event: dict, now: float, rng: random.Random) -> N
event["report"] = report
for player in world["players"].values():
player["garrison"] = False
city["rally"] = city["rallies"] = 0
def _use_up(stock: dict, item: str, share: float) -> None:
@ -1203,6 +1205,64 @@ def _use_up(stock: dict, item: str, share: float) -> None:
# --- favour --------------------------------------------------------------
BUILDER_FAVOUR_PER_HOUR = 40
INFORMANT_FAVOUR = 250
RALLY_FAVOUR = 150
RALLY_DEFENCE = 10
def favours(world: dict, now: float) -> dict:
"""What favour can buy for the city right now: cost, and why not if it can't."""
city = world["city"]
work = city["construction"]
hours = (work["done_at"] - now) * speed(world) / HOUR if work else 0
event = upcoming_event(world)
raid = upcoming_raid(world)
return {
"builders": {
"cost": max(25, math.ceil(hours * BUILDER_FAVOUR_PER_HOUR)),
"why": None if work and hours > 0.05 else "Nothing is being built",
"saves": hours / 2,
},
"informant": {
"cost": INFORMANT_FAVOUR,
"why": "No news to dig into" if not event else
"Nothing more to learn" if intel_level(world, event) >= 3 else None,
},
"militia": {
"cost": RALLY_FAVOUR * (city.get("rallies", 0) + 1),
"why": None if raid else "No raid to prepare for",
"rallied": city.get("rally", 0),
},
}
def spend_favour(world: dict, player: dict, kind: str, now: float) -> str | None:
"""Turn a player's favour into help for the whole city."""
option = favours(world, now).get(kind)
if not option:
return "No such favour"
if option["why"]:
return option["why"]
if player["favour"] < option["cost"]:
return f"Needs {option['cost']:,} favour"
player["favour"] -= option["cost"]
city = world["city"]
if kind == "builders":
work = city["construction"]
work["done_at"] = now + (work["done_at"] - now) / 2
name = BUILDINGS[work["building"]]["name"].lower()
log(world, now, "favour", f"{player['name']} hired extra builders for the {name}", player["id"])
elif kind == "informant":
upcoming_event(world)["recon"] += RECON_PER_INTEL
log(world, now, "favour", f"{player['name']} paid an informant for news from the roads", player["id"])
else:
city["rally"] = city.get("rally", 0) + RALLY_DEFENCE
city["rallies"] = city.get("rallies", 0) + 1
log(world, now, "favour", f"{player['name']} rallied the militia (+{RALLY_DEFENCE} defence for the coming raid)", player["id"])
return None
def perk_cost(player: dict, perk: str) -> int:
if perk == "bank_slot":
return 500 * 2 ** player["perks"]["bank_slot"]