diff --git a/app.py b/app.py index 7911d7e..f42e559 100644 --- a/app.py +++ b/app.py @@ -113,6 +113,8 @@ def player_view(world: dict, player: dict, now: float) -> dict: action, fight = game.growing(player), player["action"].get("fight") duration = fight["duration"] if fight else game.action_time(world, player, action) view["action"] = {**player["action"], "growing": action["id"], "duration": duration} + if fight: + view["action"]["respawn"] = game.RESPAWN / game.speed(world) # A fight takes as long as it takes: show the average time to a kill. view["times"] = {action["id"]: (view["fight_odds"][action["id"]]["kill_time"] + game.RESPAWN) / game.speed(world) if "enemy" in action else game.action_time(world, player, action) for action in game.ACTIONS} @@ -289,6 +291,7 @@ class Handler(BaseHTTPRequestHandler): player["last_active"] = now error = self.player_route(path, player, body, now) if error is None: + game.process_player(world, player, now, self.store.rng) # a new fight is drawn up at once game.tick(world, now, self.store.rng) self.store.save() if error: diff --git a/static/app.js b/static/app.js index 0477786..0d13dac 100644 --- a/static/app.js +++ b/static/app.js @@ -14,7 +14,8 @@ let selected = null; // bank item let pickedClass = null; // registration const tabs = {}; // skill -> selected recipe tab let refreshing = false; -let refreshedFor = null; // action start a completion refresh was sent for +let refreshedFor = null; // action (start and length) a completion refresh was sent for +let retriedAt = 0; // last time a fight past its kill asked again for the next one let version = null; // server build this page was loaded from let failures = 0; // polls in a row that didn't reach the server @@ -481,20 +482,19 @@ function animateFight(now) { const a = S.me?.action, f = a?.fight; if (!f) return; const t = now - a.start; - { - let i = -1; - while (i + 1 < f.events.length && f.events[i + 1][0] <= t) i++; - const left = i >= 0 ? f.events[i][5] : f.enemy_hp; - for (const el of document.querySelectorAll("[data-progress]")) el.style.width = `${left / f.enemy_hp * 100}%`; - } - 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); + const over = t >= f.end; + // From the kill until the next enemy turns up (the next fight's start, once the server sends it), + // the panel is the same quiet countdown: no enemy, both swing timers empty. + const waiting = t < 0 || (over && f.result === "won"); + const respawnIn = t < 0 ? -t : f.end + (a.respawn || 1) - t; let shown = -1; while (shown + 1 < f.events.length && f.events[shown + 1][0] <= t) shown++; const last = f.events[shown]; - const hp = last ? last[4] : f.start_hp, foeHp = last ? last[5] : f.enemy_hp; + const hp = last ? last[4] : f.start_hp, foeHp = waiting ? 0 : last ? last[5] : f.enemy_hp; + for (const el of document.querySelectorAll("[data-progress]")) el.style.width = `${foeHp / f.enemy_hp * 100}%`; + const panel = $("[data-fight]"); + if (!panel) return; + panel.classList.toggle("waiting", waiting); // Your HP everywhere follows the fight as it plays out. for (const el of document.querySelectorAll("[data-live-hp]")) el.textContent = fmt(hp); for (const el of document.querySelectorAll("[data-live-hpbar]")) el.style.width = `${Math.max(0, hp / f.top * 100)}%`; @@ -502,21 +502,19 @@ function animateFight(now) { set("you-bar", (el) => { el.style.width = `${Math.max(0, hp / f.top * 100)}%`; }); set("foe-bar", (el) => { el.style.width = `${Math.max(0, foeHp / f.enemy_hp * 100)}%`; }); set("you-hp", (el) => { el.textContent = `${fmt(hp)} / ${fmt(f.top)}`; }); - set("foe-hp", (el) => { el.textContent = `${fmt(foeHp)} / ${fmt(f.enemy_hp)}`; }); - const over = t >= f.end; + set("foe-hp", (el) => { el.textContent = waiting ? "" : `${fmt(foeHp)} / ${fmt(f.enemy_hp)}`; }); 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 || t < 0 ? "0%" : `${Math.min(100, (t - swung) / every * 100)}%`; }); + set(`${who}-swing`, (el) => { el.style.width = over || waiting ? "0%" : `${Math.min(100, (t - swung) / every * 100)}%`; }); } set("log", (el) => { - const key = `${a.start}:${shown}:${over}:${t < 0 ? Math.ceil(-t * 10) : ""}`; + const key = `${a.start}:${shown}:${over}:${waiting ? Math.ceil(respawnIn * 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" ? `