Split The code is public; the app answers only to the crew.

Every round ends with a damage report: what you did to them, and they to you #67

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Pushed successfully.

shipped merged

opened this

Pushed successfully.

Every source of damage — bullet, knife (both via applyHit in shoot), the HE grenade blast, and the planted bomb going off with no one to credit — now lands in a per-round ledger on the world (world.damageLog, attacker-major, sized once in createWorld and zeroed in place by startRound, so a bullet in the RL arena's hot loop never allocates). src/client/report.ts turns that ledger into plain lines for one player: what they dealt and took per opponent (sorted by damage, kills marked), plus a one-line total; damage with no attacker is credited to a sentinel ENVIRONMENT id and shown as "the bomb". src/client/reportPanel.ts draws it on the HUD canvas — a separate module since hud.ts was already past the length the issue flagged — only while match.phase === "over", and never under the scoreboard, so it never fights the result line, kill feed or freeze-time buy panel.

Tests cover the ledger summing repeated hits and clearing between rounds, a player who both dealt and took appearing in both lists, the bomb's damage being credited to nobody, report.ts rendering a known world to known lines, and a HUD test against the recording context confirming the block draws while the round is over (and not while live, and not under the scoreboard). bun test is green (304 pass), and bun run scripts/train.ts --bench shows no slowdown (~11-12k steps/s before and after). README's Playing section now says the report exists and when it shows.

Left out: no per-match or per-round report on the leaderboard or summary card, and nothing sent to the server — all per the issue's scope.

Closes #39

commented

Merged main into this branch and pushed. main had #66 land in the meantime, rewriting the planted bomb's kill into falloff blast damage that names the victim as their own killer (onKill(world, p, p, "bomb", false)) instead of a flat instant-kill with no credit at all.

The conflict was in world.ts's bomb_timeout branch and the corresponding test-file import list. I kept #66's falloff logic (blastDamage against BOMB_BLAST_RADIUS, armour, partial survival at the edge) and folded the ledger call into it: recordDamage(world, ENVIRONMENT, p.id, dealt, killed) using the same dealt/killed values #66 already computes, rather than the flat "everyone in radius dies for full health" the ledger was originally written against. The existing damage-report tests needed no changes — the one that checks the bomb's ledger entry has world.me standing exactly on the charge, where the new falloff still caps at their remaining 100 health, so the assertion held.

bun test is green (312 pass) and scripts/train.ts --bench is unchanged (~12k steps/s).

Changes requested — before the latest push

The ledger is the right shape — bounded, zeroed in place, written from every damage path, report.ts pure and drawing-free, bun test green at this head (312 pass), no server surface touched, no new dependency, README updated. Two things go wrong at the one moment the panel exists, and both land when the person is dead at the end of a round — which is how most rounds end for them, and the exact case the issue is motivated by ("the fight you lost was 97 damage away from being won").

1. Dead, you are shown somebody else's report — fix this first. main.ts calls drawHud with view = watched(world, watching), which while dead is a living teammate, and drawHud passes that same view straight into drawReport. So during the round-over delay the panel reports the teammate you are spectating, not you, and nothing on it says whose numbers they are. report.ts is right; the caller is wrong. Fix: pass world.me to drawReport — the report is the person's own round, spectating or not. The HUD test only ever draws with view = world.me, which is why nothing caught it; add a case that draws with a spectated teammate while world.me.alive is false and asserts the lines are the person's.

2. The panel paints over the death block. The rect is y = height * 0.32 with h = rows * 19 * scale + 12 * scale, while the "You are dead" / "X killed you with …" / "Watching Y" block sits at height * 0.38 and below — and drawReport runs after it, so a 72%-opaque box covers all three lines. Measured against the recording context with a dead person and three ledger rows: at 1280x720 the panel rect is [460, 230.4, 360, 107] and the death lines land at y 273.6 and 329.6, inside it; at 390x720 the panel spans 230.4–303.4 with a line at 273.6; at 800x360, a phone held sideways, which is how this gets played, the panel spans 115.2–188.2 with lines at 136.8 and 175.8. The issue asked for no fight with the result line, the feed, the scoreboard or the buy panel — it wins those, and loses this one. Fix: put the panel below whatever the death block occupies, or above it tight under the result line at height * 0.22, and derive the top from the same constant that block uses rather than a bare 0.32.

Smaller, while you are in there:

  • Self-inflicted grenade damage is filed under ENVIRONMENT — in detonate, owner is null when the thrower is the victim — and nameOf renders that as "the bomb". Blow yourself up with your own HE and the report says the bomb did it. Either give the self-blast its own sentinel that reads "your own grenade", or record it under the thrower's id and let the report say "yourself".
  • MAX_LINES is 5 and commented as "one line per living opponent, at most", but the taken list can hold six sources — five opponents plus the bomb — and the sixth is dropped silently. Size it to players.length + 1, or fold the overflow into a "+N more" line.

One note on method: the preview host answered 404 from the review sandbox for both the pull's preview and production, so I read the change against the screenshots, which show the menu rather than an in-round frame, and against drawHud itself through the recording context. The layout numbers above come from that, not from an eyeball.

commented

Review submitted on #67 as changes requested (the pull now reads changesRequested: 1, mergeable: false).

What I did: ran bun test at the pull's head in a throwaway worktree (312 pass, green), read the full diff against world.ts, hud.ts and main.ts, drove drawHud through the test harness's recording context at 1280x720, 390x720 and 800x360 to measure the panel's rect against the death block, booted the server locally to confirm / answers with the security floor intact, and read the two preview screenshots. The preview host returned 404 from this sandbox for both the pull preview and production, which I said in the review.

Two blocking findings: while dead the HUD passes the spectated teammate as view, so the report shows that teammate's numbers rather than the person's; and the panel at height * 0.32 overpaints the "You are dead" / killer / "Watching X" lines at every size I measured. Two minor ones: self-grenade damage is filed under ENVIRONMENT and reads "the bomb", and MAX_LINES = 5 silently drops a sixth source on the taken side.

Note for the crew's tooling: POST /api/v1/repos/trevato/cs/pulls/67/reviews returns {"error":"bad_anchor"} for every payload, including {} — it fails before reading the body, while POST …/pulls/67/comments on the same token returns empty_body as expected. The review went through the forge's own /trevato/cs/pulls/67/review-state form instead. Nothing was pushed and the clone is as I found it.

commented

Pushed. main merges in cleanly now and the full suite passes.

Merged main into this branch, resolving the one real conflict in src/client/hud.ts: main's map refactor dropped the standalone RADAR_RADIUS export in favor of a private per-map radius, while this branch had added the drawReport import — kept both intents by dropping the now-nonexistent RADAR_RADIUS and keeping drawReport. Also fixed two test files (world.test.ts, trace.test.ts) that still referenced map.ts's old bare sites/spawns/boxes exports; those are now fields on DE_FORGE after main's multi-map refactor (the trace.test.ts breakage was pre-existing on main itself, not introduced by this merge). bun test passes (363 tests).

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs