Firekeeping: shared guild fires

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-10-21 12:16:22 +01:00
parent c64e28fc38
commit 54ae3ae641
6 changed files with 657 additions and 34 deletions

19
app.py
View file

@ -87,13 +87,17 @@ class Store:
def tick(self) -> None:
with self.lock:
if game.tick(self.world, self.now(), self.rng):
now = self.now()
changed = game.tick(self.world, now, self.rng)
# Everyone's actions run as time passes: the fires are shared, so a craft
# has to meet the fire as it was, not as it is when its player next looks.
if game.catch_up(self.world, now, self.rng) or changed:
self.save()
def player_view(world: dict, player: dict, now: float) -> dict:
game.regen(world, player, now)
view = {key: value for key, value in player.items() if key not in ("last_active", "hp_at")}
view = {key: value for key, value in player.items() if key not in ("last_active", "hp_at", "away")}
view["hp"] = int(player["hp"])
view["max_hp"] = game.max_hp(player)
view["armour"] = game.armour(player)
@ -127,6 +131,10 @@ def player_view(world: dict, player: dict, now: float) -> dict:
view["drill_per_action"] = game.drill_per_action(player)
view["recon_gain"] = {action["id"]: game.recon_gain(world, player, action) for action in game.ACTIONS
if action.get("special") == "recon"}
level = game.skill_level(player, "firekeeping")
view["firekeeping"] = {"minutes": game.fire_minutes(level), "bank": game.fire_bank(level)}
# Inputs as the fires leave them: a lit fire pays the log.
view["fuelled"] = {action["id"]: game.fire_inputs(world, action) for action in game.ACTIONS if action.get("fire")}
return view
@ -162,6 +170,7 @@ def city_view(world: dict, now: float) -> dict:
"repelled": city["repelled"],
"defence": game.defence(world),
"day": game.calendar_day(world, now) + 1,
"fires": game.fires_view(world, now),
}
@ -263,8 +272,9 @@ class Handler(BaseHTTPRequestHandler):
game.tick(world, now, self.store.rng)
player = world["players"].get(uid)
summary = None
game.catch_up(world, now, self.store.rng)
if player:
summary = game.process_player(world, player, now, self.store.rng)
summary = game.take_summary(player, game.empty_summary())
game.regen(world, player, now)
player["last_active"] = now
self.store.save()
@ -294,7 +304,8 @@ class Handler(BaseHTTPRequestHandler):
elif not player:
return self.fail("Create your adventurer first", HTTPStatus.CONFLICT)
else:
summary = game.process_player(world, player, now, self.store.rng)
game.catch_up(world, now, self.store.rng) # everyone, so the fires are as they really are
summary = game.take_summary(player, game.empty_summary())
game.regen(world, player, now)
player["last_active"] = now
error = self.player_route(path, player, body, now)