From ea1bae9b53566cc9972b889e82f861b9f429a9b1 Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 20 Oct 2026 14:21:34 +0100 Subject: [PATCH] Encounter cards: gold range as a reward chip, drop the odds lines Co-Authored-By: Claude Opus 5.5 --- game.py | 9 ++++++--- static/app.js | 8 +++----- tests/test_game.py | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/game.py b/game.py index 7c86ea7..23adb15 100644 --- a/game.py +++ b/game.py @@ -564,7 +564,9 @@ def _encounter(id: str, name: str, group: str, level: int, roster: list, gold: i total = sum(v["weight"] for v in variants) xp = round(sum(v["xp"] * v["weight"] for v in variants) / total) enemy = {"name": name, "level": level, "boss": boss, "variants": variants} - return _action(id, "combat", extra.pop("label", None) or name, level, RESPAWN, xp, gold=gold, + # Gold per kill is a range around the encounter's worth. + purse = [max(1, round(gold * 0.7)), max(2, round(gold * 1.3))] if gold else None + return _action(id, "combat", extra.pop("label", None) or name, level, RESPAWN, xp, gold=purse, drops=[list(drop) for drop in drops], enemy=enemy, group=group, **extra) @@ -1865,8 +1867,9 @@ def _complete(world: dict, player: dict, action: dict, now: float, rng: random.R gain_xp(world, player, "combat", xp // 3, now, summary) return summary["wins"] += 1 - player["gold"] += action.get("gold", 0) - summary["gold"] += action.get("gold", 0) + gold = rng.randint(*action["gold"]) if action.get("gold") else 0 + player["gold"] += gold + summary["gold"] += gold for item, qty, odds in action.get("drops", []): if rng.random() < odds: outputs[item] = outputs.get(item, 0) + qty diff --git a/static/app.js b/static/app.js index cbbf0a0..6f2e9f9 100644 --- a/static/app.js +++ b/static/app.js @@ -708,11 +708,9 @@ function actionCard(a) { io += Object.entries(a.outputs).map(([id, q]) => itemChip(id, q)).join(""); let extra = ""; if (a.enemy) { - const o = me.fight_odds[a.id], e = a.enemy, pct = (x) => `${Math.round(x * 100)}%`; - extra = `${variantRows(e, o)} -
Hits up to ${o.their_max}${e.boss ? ` · Boss` : ""}
-
You hit ${pct(o.hit)} (max ${o.max_hit}) · it hits ${pct(o.their_hit)}
-
~${dur(o.kill_time)} a kill · ${Math.round(o.damage)} damage taken${a.gold ? ` · ${a.gold} gold` : ""}
`; + const o = me.fight_odds[a.id], e = a.enemy; + extra = `${e.boss ? `
Boss
` : ""}${variantRows(e, o)}`; + if (a.gold) io += `${COIN} ${a.gold[0]}–${a.gold[1]}`; if (a.drops) io += a.drops.map(([id, q, odds]) => `${item(id).icon} ${Math.round(odds * 100)}%`).join(""); if (a.special === "sabotage") extra += `
-3% raid strength per win (max 30%)
`; } diff --git a/tests/test_game.py b/tests/test_game.py index f9c14ae..f3565f1 100644 --- a/tests/test_game.py +++ b/tests/test_game.py @@ -163,7 +163,8 @@ class ActionTest(unittest.TestCase): summary = game.process_player(world, p, T0 + 3600, random.Random(5)) self.assertGreater(summary["done"], 50) # a fight lasts as long as it takes self.assertEqual(summary["wins"] + summary["losses"], summary["done"]) - self.assertEqual(p["gold"], summary["wins"] * 2) + low, high = game.ACTION_BY_ID["fight_wolves"]["gold"] + self.assertTrue(summary["wins"] * low <= p["gold"] <= summary["wins"] * high) class GiftTest(unittest.TestCase):