diff --git a/game.py b/game.py index a9b7dd7..eaacd3b 100644 --- a/game.py +++ b/game.py @@ -1195,12 +1195,9 @@ def fight_odds(player: dict, action: dict) -> dict: "kill_time": round(kill, 1), "damage": round(hurt, 1)} -def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random, carry: float = 0) -> dict: - """Play out one fight swing by swing. Nothing changes until it's over: the result is applied then. - - `carry` is how long ago (in game seconds) you last swung: your swing timer runs on from one - enemy to the next, so outclassing an enemy means killing as fast as you can swing. - """ +def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random) -> dict: + """Play out one fight swing by swing, both swing timers starting empty. Nothing changes + until it's over: the result is applied then.""" foe, blessed, brew = action["enemy"], blessing(player), potion_effect(player, "combat") me = fighter(player, blessed, brew, foe) shrug = 0 if me["pierce"] else foe["reduction"] @@ -1211,16 +1208,13 @@ def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random, wind = blessed["wind"] and not (player["action"] or {}).get("wind_used") pace = speed(world) # A bow looses its first arrow before the enemy closes in. - ready = max(0.0, me["interval"] - carry) - mine, theirs, result, t = (min(ready, 0.5) if me["first"] else ready), foe["interval"], None, 0.0 - swung = -carry + mine, theirs, result, t = (0.5 if me["first"] else me["interval"]), foe["interval"], None, 0.0 while result is None: t = min(mine, theirs) if t > MAX_FIGHT: result = "fled" break if mine <= theirs: - swung = mine mine += me["interval"] crit = rng.random() < me["crit"] landed = rng.random() < hit @@ -1258,7 +1252,7 @@ def simulate_fight(world: dict, player: dict, action: dict, rng: random.Random, elif starving: result = "fled" return {"enemy": foe["name"], "enemy_hp": foe["hp"], "top": top, "start_hp": round(player["hp"]), - "hp": hp, "result": result, "end": round(t / pace, 2), "duration": t / pace, "carry": t - swung, + "hp": hp, "result": result, "end": round(t / pace, 2), "duration": t / pace, "interval": me["interval"] / pace, "enemy_interval": foe["interval"] / pace, "events": events, "style": me["style"], "eaten": eaten, "damage": hurt, "pp": blessed["cost"], "wind_used": blessed["wind"] and not wind and not (player["action"] or {}).get("wind_used")} @@ -1519,8 +1513,8 @@ def _complete(world: dict, player: dict, action: dict, now: float, rng: random.R if "enemy" in action: outing = player["action"] - fight = outing.pop("fight", None) or simulate_fight(world, player, action, rng, outing.get("carry", 0)) - outing["carry"] = fight.get("carry", 0) + RESPAWN # fights from before the carry-over have none + fight = outing.pop("fight", None) or simulate_fight(world, player, action, rng) + outing.pop("carry", None) # from a short-lived version that ran the swing timer on if player["prayers"] and not fight["pp"]: summary["prayer_out"] = True paid = min(player["pp"], fight["pp"]) @@ -1647,7 +1641,7 @@ def process_player(world: dict, player: dict, now: float, rng: random.Random | N if "enemy" in action and not can_start(world, player, action): if not current.get("fight"): regen(world, player, current["start"], blessing(player)["regen"]) - current["fight"] = simulate_fight(world, player, action, rng, current.get("carry", 0)) + current["fight"] = simulate_fight(world, player, action, rng) duration = current["fight"]["duration"] else: duration = action_time(world, player, action) diff --git a/static/app.js b/static/app.js index 0267adb..efe6c37 100644 --- a/static/app.js +++ b/static/app.js @@ -489,6 +489,8 @@ function animateFight(now) { } const panel = $("[data-fight]"); if (!panel) return; + // Between kills: the next enemy is on its way, both swing timers empty. + panel.classList.toggle("waiting", t < 0); let shown = -1; while (shown + 1 < f.events.length && f.events[shown + 1][0] <= t) shown++; const last = f.events[shown]; @@ -505,16 +507,17 @@ function animateFight(now) { for (const [who, every] of [["you", f.interval], ["foe", f.enemy_interval]]) { let swung = 0; for (let i = shown; i >= 0; i--) if (f.events[i][1] === who && f.events[i][2] !== "eat" && f.events[i][2] !== "wind") { swung = f.events[i][0]; break; } - set(`${who}-swing`, (el) => { el.style.width = over ? "0%" : `${Math.min(100, (t - swung) / every * 100)}%`; }); + set(`${who}-swing`, (el) => { el.style.width = over || t < 0 ? "0%" : `${Math.min(100, (t - swung) / every * 100)}%`; }); } set("log", (el) => { - const key = `${a.start}:${shown}:${over}`; + const key = `${a.start}:${shown}:${over}:${t < 0 ? Math.ceil(-t * 10) : ""}`; if (el.dataset.key === key) return; el.dataset.key = key; const lines = f.events.slice(Math.max(0, shown - 5), shown + 1).reverse().map((e) => fightLine(e, f.enemy)); if (over) lines.unshift(f.result === "won" ? `