Fires: everyone keeps their own pile
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a02a81dffd
commit
b4ecacf96c
4 changed files with 91 additions and 54 deletions
56
game.py
56
game.py
|
|
@ -2053,9 +2053,11 @@ def _use_charge(player: dict, skill: str, summary: dict) -> None:
|
|||
|
||||
|
||||
# --- fires -----------------------------------------------------------------
|
||||
# Each fire is a list of fuel: {tier, left (game seconds), by (who fed it)}. It burns on
|
||||
# game time, hottest fuel first and the oldest of that first, so the flame's colour is
|
||||
# the best fuel still in it.
|
||||
# Each fire is a list of fuel: {tier, left (game seconds), by (who fed it)}. Everyone who
|
||||
# feeds a fire keeps their own pile in it, up to their own bank, so a full fire never
|
||||
# shuts a beginner out. The fire burns a game minute a minute, shared evenly between the
|
||||
# piles, so every log adds to how long it lasts; each pile burns its hottest fuel first,
|
||||
# and the fire is as hot as its hottest pile.
|
||||
|
||||
def new_fire(now: float) -> dict:
|
||||
return {"fuel": [], "at": now, "saved": 0}
|
||||
|
|
@ -2069,39 +2071,44 @@ def burn_fires(world: dict, now: float) -> None:
|
|||
seconds = (now - fire["at"]) * speed(world)
|
||||
fire["at"] = now
|
||||
fuel = fire["fuel"]
|
||||
while seconds > 0 and fuel:
|
||||
chunk = burning(fire)
|
||||
used = min(seconds, chunk["left"])
|
||||
chunk["left"] -= used
|
||||
seconds -= used
|
||||
if chunk["left"] <= 1e-6:
|
||||
fuel.remove(chunk)
|
||||
while seconds > 1e-9 and fuel:
|
||||
# Each pile burns its best fuel at 1/n of the pace, until the first of those runs out.
|
||||
heads = [burning(fuel, by) for by in {chunk["by"] for chunk in fuel}]
|
||||
step = min(seconds, min(chunk["left"] for chunk in heads) * len(heads))
|
||||
for chunk in heads:
|
||||
chunk["left"] -= step / len(heads)
|
||||
if chunk["left"] <= 1e-6:
|
||||
fuel.remove(chunk)
|
||||
seconds -= step
|
||||
|
||||
|
||||
def burning(fire: dict) -> dict | None:
|
||||
"""The fuel burning right now: the hottest, and the oldest of those."""
|
||||
return max(fire["fuel"], key=lambda chunk: chunk["tier"], default=None)
|
||||
def burning(fuel: list, by: str | None = None) -> dict | None:
|
||||
"""The fuel burning hottest (in one pile, with `by`): the hottest, and the oldest of those."""
|
||||
return max((chunk for chunk in fuel if by is None or chunk["by"] == by), key=lambda chunk: chunk["tier"], default=None)
|
||||
|
||||
|
||||
def heat(world: dict, fire: str) -> int:
|
||||
"""The tier of a fire's flame, or -1 when it's out."""
|
||||
chunk = burning(world["city"]["fires"][fire])
|
||||
chunk = burning(world["city"]["fires"][fire]["fuel"])
|
||||
return chunk["tier"] if chunk else -1
|
||||
|
||||
|
||||
def _room(fire: dict, tier: int, level: int) -> float:
|
||||
"""Game seconds of cheaper fuel a log of `tier` would push out, or -1 if it won't fit."""
|
||||
short = sum(chunk["left"] for chunk in fire["fuel"]) + fire_minutes(level) * 60 - fire_bank(level) * 60
|
||||
cheaper = sum(chunk["left"] for chunk in fire["fuel"] if chunk["tier"] < tier)
|
||||
def _room(fire: dict, player: dict, tier: int) -> float:
|
||||
"""Game seconds of the player's own cheaper fuel a log of `tier` would push out, or -1 if it won't fit."""
|
||||
level = skill_level(player, "firekeeping")
|
||||
mine = [chunk for chunk in fire["fuel"] if chunk["by"] == player["id"]]
|
||||
short = sum(chunk["left"] for chunk in mine) + fire_minutes(level) * 60 - fire_bank(level) * 60
|
||||
cheaper = sum(chunk["left"] for chunk in mine if chunk["tier"] < tier)
|
||||
return -1 if short > cheaper + 1e-6 else max(0.0, short)
|
||||
|
||||
|
||||
def feed_fire(world: dict, player: dict, fire_id: str, tier: int) -> float:
|
||||
"""Put one log in a fire, pushing out the cheapest fuel if it's full. Returns the minutes added."""
|
||||
"""Put one log on your pile in a fire, pushing out your cheapest fuel if it's full. Returns the minutes added."""
|
||||
fire, level = world["city"]["fires"][fire_id], skill_level(player, "firekeeping")
|
||||
short = _room(fire, tier, level)
|
||||
short = _room(fire, player, tier)
|
||||
while short > 1e-6:
|
||||
cheapest = min((chunk for chunk in fire["fuel"] if chunk["tier"] < tier), key=lambda chunk: chunk["tier"])
|
||||
cheapest = min((chunk for chunk in fire["fuel"] if chunk["by"] == player["id"] and chunk["tier"] < tier),
|
||||
key=lambda chunk: chunk["tier"])
|
||||
out = min(short, cheapest["left"])
|
||||
cheapest["left"] -= out
|
||||
short -= out
|
||||
|
|
@ -2135,7 +2142,7 @@ def _warm(world: dict, crafter: dict, action: dict, xp: float, now: float) -> No
|
|||
"""A fire paid for a craft: count it, and give its feeder a share of the XP."""
|
||||
fire = world["city"]["fires"][action["fire"]]
|
||||
fire["saved"] = fire.get("saved", 0) + 1
|
||||
keeper = world["players"].get(burning(fire)["by"])
|
||||
keeper = world["players"].get(burning(fire["fuel"])["by"])
|
||||
if keeper and keeper is not crafter:
|
||||
gain_xp(world, keeper, "firekeeping", xp * WARMTH, now, keeper.setdefault("away", empty_summary()))
|
||||
|
||||
|
|
@ -2184,9 +2191,8 @@ def can_start(world: dict, player: dict, action: dict) -> str | None:
|
|||
return f"Out of {ITEMS[item]['name'].lower()}"
|
||||
elif player["bank"].get(item, 0) < qty:
|
||||
return f"Out of {ITEMS[item]['name'].lower()}"
|
||||
if action.get("special") == "tend" and _room(world["city"]["fires"][action["tend"]], action["tier"],
|
||||
skill_level(player, "firekeeping")) < 0:
|
||||
return f"The {FIRES[action['tend']]['name'].lower()} is full"
|
||||
if action.get("special") == "tend" and _room(world["city"]["fires"][action["tend"]], player, action["tier"]) < 0:
|
||||
return f"Your pile in the {FIRES[action['tend']]['name'].lower()} is full"
|
||||
if action.get("special") == "sabotage":
|
||||
raid = upcoming_raid(world)
|
||||
if not raid or intel_level(world, raid) < 3:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue