DPS meter under the combat log
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1bf3f3b62f
commit
4f2d113abd
3 changed files with 48 additions and 1 deletions
|
|
@ -943,7 +943,8 @@ function combatFrame() {
|
|||
foe = `<div class="foe-head"><span class="foe-ico">${encounter?.icon || ""}</span><b>${esc(f.enemy)}</b></div>
|
||||
<div class="pack">${f.pack.map((v, i) => unit(`e${i}`, `${esc(v.name)}${v.archetype === "elite" && !v.boss ? ` <span class="muted">· rare</span>` : ""}`, true,
|
||||
` <span class="traits-inline">${traits(v)}</span>`)).join("")}</div>
|
||||
<ul class="fight-log" data-f="log"></ul>`;
|
||||
<ul class="fight-log" data-f="log"></ul>
|
||||
<div class="dps" data-f="dps"></div>`;
|
||||
}
|
||||
return `<div class="panel fight combat-frame" ${f ? `data-fight="${a.start}"` : ""}>
|
||||
<div class="you-side">${you}${abilityBar(me)}${prayerBar(me)}${paperDoll(me, true)}</div>
|
||||
|
|
@ -1071,6 +1072,28 @@ function fightState(f, t) {
|
|||
return { st, shown };
|
||||
}
|
||||
|
||||
// The damage meter: what each fighter has dealt so far, and per second since they joined (game seconds,
|
||||
// so dev speed doesn't inflate it). Best first, bars scaled to the top DPS.
|
||||
const DAMAGE = new Set(["hit", "crit", "tick"]);
|
||||
let lastMeter = null; // the fight just finished, shown dimmed while resting for the next one
|
||||
function dpsMeter(f, t) {
|
||||
const rows = f.members.map((m) => {
|
||||
let dmg = 0, heal = 0;
|
||||
for (const e of f.events) {
|
||||
if (e[0] > t) break;
|
||||
if (e[1] !== m.id) continue;
|
||||
if (DAMAGE.has(e[3])) dmg += e[4] || 0;
|
||||
else if (e[3] === "heal" && e[6] !== "potion") heal += e[4] || 0;
|
||||
}
|
||||
const secs = Math.max(1, Math.min(t, f.end) - (m.at + f.rest) / f.pace) * f.pace;
|
||||
return { m, dmg, heal, dps: dmg / secs };
|
||||
}).sort((x, y) => y.dmg - x.dmg);
|
||||
const top = Math.max(...rows.map((r) => r.dps)) || 1;
|
||||
return rows.map(({ m, dmg, heal, dps }) => `<li class="${m.id === S.uid ? "mine" : ""}"
|
||||
title="${esc(`${fmt(dmg)} damage${heal ? ` · ${fmt(heal)} healing` : ""}`)}"><span class="dps-fill" style="width:${dps / top * 100}%"></span>
|
||||
<b>${esc(playerName(m.id))}</b><span>${dps < 10 ? dps.toFixed(1) : fmt(Math.round(dps))} <span class="muted">· ${fmt(dmg)}</span></span></li>`).join("");
|
||||
}
|
||||
|
||||
function animateFight(now) {
|
||||
const a = S.me?.action, f = a?.fight;
|
||||
if (!f) return;
|
||||
|
|
@ -1166,6 +1189,20 @@ function animateFight(now) {
|
|||
: lines.join("") || `<li class="muted">Squaring up…</li>`;
|
||||
}
|
||||
}
|
||||
// Refreshed on every swing and once a second, since DPS falls between hits.
|
||||
const meter = panel.querySelector('[data-f="dps"]');
|
||||
if (meter) {
|
||||
const stale = resting && lastMeter?.start !== a.start ? lastMeter : null;
|
||||
const key = resting ? `rest:${stale?.start}` : `${a.start}:${shown}:${Math.floor(Math.min(t, f.end))}`;
|
||||
if (meter.dataset.key !== key) {
|
||||
meter.dataset.key = key;
|
||||
if (!resting) lastMeter = { start: a.start, rows: dpsMeter(f, t) };
|
||||
const rows = resting ? stale?.rows : lastMeter.rows;
|
||||
meter.classList.toggle("stale", resting);
|
||||
meter.innerHTML = rows ? `<div class="dps-head small muted"><span>${resting ? "Last fight" : "Damage"}</span><span title="Damage per second · total">DPS · total</span></div>
|
||||
<ul>${rows}</ul>` : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A piece of jewellery's bonus, e.g. "+8% accuracy".
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue