Commit Graph
1608 Commits
Author SHA1 Message Date
pkuzicandClaude Opus 5.5 86e1d6c43d MONKEY (perf): WOW_PERF_CROWD probe crowd; perf measurement notes in LIGHTING.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:34 +01:00
pkuzicandClaude Opus 5.5 891a4da5a3 MONKEY (perf): WOW_PERF_CROWD probe crowd; perf measurement notes in LIGHTING.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:34 +01:00
pkuzicandClaude Opus 5.5 68100e1120 MONKEY (perf): bleed fixtures bucket sources per placement and run at 10 Hz
update_bleed_fixtures walked every interior source in the world four times per
doorway every frame (~1.0 ms/frame main thread, traced, Northshire at High).
Sources are now bucketed per placement once (same rows, same order, same sums:
another placement's claimant weighs 0), the evaluation runs at 10 Hz with
arrivals and dial changes bypassing the cadence, and the light is written only
on a real change. Captures inn-noon and perf-abbey-night are pixel-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:33 +01:00
pkuzicandClaude Opus 5.5 18effa6e78 MONKEY (perf): bleed fixtures bucket sources per placement and run at 10 Hz
update_bleed_fixtures walked every interior source in the world four times per
doorway every frame (~1.0 ms/frame main thread, traced, Northshire at High).
Sources are now bucketed per placement once (same rows, same order, same sums:
another placement's claimant weighs 0), the evaluation runs at 10 Hz with
arrivals and dial changes bypassing the cadence, and the light is written only
on a real change. Captures inn-noon and perf-abbey-night are pixel-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:33 +01:00
pkuzicandClaude Opus 5.5 d6f1cbe355 MONKEY (perf): FPS probe runs unfocused windows continuous; night probe scenarios
A probe window opens unfocused and WinitSettings::game() drives an unfocused
window at reactive 1/60 s, so every FPS_PROBE read ~16.7 ms whatever the scene
cost (Classic at 720p with 0.4 ms of GPU read 57 fps). Probes now run
Continuous in both modes. Adds perf-northshire-night / perf-abbey-night.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:33 +01:00
pkuzicandClaude Opus 5.5 fff74b21e8 MONKEY (perf): FPS probe runs unfocused windows continuous; night probe scenarios
A probe window opens unfocused and WinitSettings::game() drives an unfocused
window at reactive 1/60 s, so every FPS_PROBE read ~16.7 ms whatever the scene
cost (Classic at 720p with 0.4 ms of GPU read 57 fps). Probes now run
Continuous in both modes. Adds perf-northshire-night / perf-abbey-night.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 04:01:33 +01:00
pkuzicandClaude Opus 5.5 8624de9550 MONKEY (integration): water-ocean-lodring capture scenario for the water LOD ring
Frames the Westfall sea from 30 yd up so the 64-80 yd fine/coarse ring crosses the frame
centre; used to verify the stitched LOD edges at WOW_WATER=2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:56:02 +01:00
pkuzicandClaude Opus 5.5 1ba4876a11 MONKEY (integration): water-ocean-lodring capture scenario for the water LOD ring
Frames the Westfall sea from 30 yd up so the 64-80 yd fine/coarse ring crosses the frame
centre; used to verify the stitched LOD edges at WOW_WATER=2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:56:02 +01:00
Sam SungandClaude Opus 5.5 a7e0bba958 HasFullControl's comment names the menu entries it greys: Trade and Duel (#402)
One comment corrected: the stock unit menu greys Trade and Duel on `HasFullControl()` (`UnitPopup.lua:474-477`, `:502-505`), not follow and trade.

Comment only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 09:34:23 +07:00
Sam SungandClaude Opus 5.5 bf2e1d551d HasFullControl's comment names the menu entries it greys: Trade and Duel (#402)
One comment corrected: the stock unit menu greys Trade and Duel on `HasFullControl()` (`UnitPopup.lua:474-477`, `:502-505`), not follow and trade.

Comment only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 09:34:23 +07:00
Sam SungandClaude Opus 5.5 d8bafacc42 The pet sheet test says where a pet's defense comes from (#396)
One test message corrected. A pet's combat-stats snapshot carries no defense pair, because `UnitDefense("pet")` computes the pet's level × 5 itself (`CGUnit_C` `0x613680`). The message added in #391 said benilla had no pet defense, which is wrong.

Verified: the `ui_pet_doll` tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 09:29:17 +07:00
Sam SungandClaude Opus 5.5 bbfa601bda The pet sheet test says where a pet's defense comes from (#396)
One test message corrected. A pet's combat-stats snapshot carries no defense pair, because `UnitDefense("pet")` computes the pet's level × 5 itself (`CGUnit_C` `0x613680`). The message added in #391 said benilla had no pet defense, which is wrong.

Verified: the `ui_pet_doll` tests pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 09:29:17 +07:00
pkuzic ff520aa1ff Merge gfx/reviewfix-b (water/skybox/formats review fixes) into integration 2026-09-26 03:01:47 +01:00
pkuzic 5828dc7406 Merge gfx/reviewfix-b (water/skybox/formats review fixes) into integration 2026-09-26 03:01:47 +01:00
pkuzicandClaude Opus 5.5 5b1de75cf7 MONKEY (reviewfix-a): capture camera area folded into update_current_area
A separate system added 10 unordered pairs to Update (schedule ambiguity
ceiling test). Same behaviour; the recapture is identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:01:01 +01:00
pkuzicandClaude Opus 5.5 18d0a287d3 MONKEY (reviewfix-a): capture camera area folded into update_current_area
A separate system added 10 unordered pairs to Update (schedule ambiguity
ceiling test). Same behaviour; the recapture is identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 03:01:01 +01:00
Sam SungandClaude Opus 5.5 7a1d799cf7 Comments and strings: the passes' leftovers, and a region's template matched as one name (#391)
The comment and string passes' last leftovers, and one lookup made to match the reference.

**Comments that stated a wrong reference fact**, now stating the right one:
- A cast failure clears the GCD, and a failed cooldown-on-event spell also drops its parked record (`0x6e73cc`).
- `SetUnit` is `0x505d70`; `0x476cb0` is the component clone it reaches.
- Interior sound follows the character, where the listener sits, not the camera.
- Template inheritance re-runs `LoadXML` on the one object against each template (`0x76985c`), and reads `name` and `id` from the instance alone (`0x769770`).
- On the ghost-to-alive edge the reference clears its corpse cache and sends nothing (`0x5ee990`, `0x491f50`).
- The name cache has no high-bit miss. An empty-name answer evicts the record in the reference (`0x55f6f0`).
- The combat-log deferred queue (`0xc4e208`) waits only on an item name. A unit name never waits.
- A flying spline's segments are paced by curve length (`0x454320`, `0x453760`), not by chord length.
- A stop within 3 yd of its stop point keeps the arrow nocked (`0x6019e4`).
- A missile's sound id is at `CMissile+0x40`.
- A nil or unresolved `AssistUnit` token is a gap against `0xb8` ERR_GENERIC_NO_TARGET, not a deviation.

**Strings:**
- Test, log and tool messages lose leftover history wording and placeholder labels.
- The extractor's scan summaries describe the current tint and sequence-clock paths.
- The smoke script's failure text carries no private numbers.

**Line continuations:** twelve log, panic and assert strings get back the `\` continuations they had lost. Each printed a run of spaces mid-message. Fixes #106.

**One lookup:** a region's `inherits=` is looked up as one verbatim name, matched case-insensitively (`0x6ee6f0`, `_strnicmp` at `0x6ee747`), as `framexml::expand` already did for frames. The gate before it split on commas and matched case-sensitively, so a texture or font string whose `inherits=` spelled its template in another case never received the template. `a_region_takes_a_mis_cased_template` fails before this change and passes after.

**Tests:** the quest tests stop loading three FrameXML files that no quest file uses.

**In game:** nothing changes for the stock UI. Log lines read as one sentence, and an addon texture that names its template in another case now gets it.

Verified with `scripts/check.sh` on the changed crates, plus the loader and quest tests with the install present.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:57:47 +07:00
Sam SungandClaude Opus 5.5 a7e6fc2301 Comments and strings: the passes' leftovers, and a region's template matched as one name (#391)
The comment and string passes' last leftovers, and one lookup made to match the reference.

**Comments that stated a wrong reference fact**, now stating the right one:
- A cast failure clears the GCD, and a failed cooldown-on-event spell also drops its parked record (`0x6e73cc`).
- `SetUnit` is `0x505d70`; `0x476cb0` is the component clone it reaches.
- Interior sound follows the character, where the listener sits, not the camera.
- Template inheritance re-runs `LoadXML` on the one object against each template (`0x76985c`), and reads `name` and `id` from the instance alone (`0x769770`).
- On the ghost-to-alive edge the reference clears its corpse cache and sends nothing (`0x5ee990`, `0x491f50`).
- The name cache has no high-bit miss. An empty-name answer evicts the record in the reference (`0x55f6f0`).
- The combat-log deferred queue (`0xc4e208`) waits only on an item name. A unit name never waits.
- A flying spline's segments are paced by curve length (`0x454320`, `0x453760`), not by chord length.
- A stop within 3 yd of its stop point keeps the arrow nocked (`0x6019e4`).
- A missile's sound id is at `CMissile+0x40`.
- A nil or unresolved `AssistUnit` token is a gap against `0xb8` ERR_GENERIC_NO_TARGET, not a deviation.

**Strings:**
- Test, log and tool messages lose leftover history wording and placeholder labels.
- The extractor's scan summaries describe the current tint and sequence-clock paths.
- The smoke script's failure text carries no private numbers.

**Line continuations:** twelve log, panic and assert strings get back the `\` continuations they had lost. Each printed a run of spaces mid-message. Fixes #106.

**One lookup:** a region's `inherits=` is looked up as one verbatim name, matched case-insensitively (`0x6ee6f0`, `_strnicmp` at `0x6ee747`), as `framexml::expand` already did for frames. The gate before it split on commas and matched case-sensitively, so a texture or font string whose `inherits=` spelled its template in another case never received the template. `a_region_takes_a_mis_cased_template` fails before this change and passes after.

**Tests:** the quest tests stop loading three FrameXML files that no quest file uses.

**In game:** nothing changes for the stock UI. Log lines read as one sentence, and an addon texture that names its template in another case now gets it.

Verified with `scripts/check.sh` on the changed crates, plus the loader and quest tests with the install present.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 08:57:47 +07:00
pkuzicandClaude Opus 5.5 ac9a1ef390 MONKEY (reviewfix-a): zone grading visible in captures; follows the rendered clock
Found by the first runtime capture of the grade: a capture has no avatar, so
CurrentArea stayed None and no zone was ever graded; and the day/night weight
read WorldTime (the server clock, noon offline), so a manual/capture night
graded with the day LUT. Adds CaptureCameraArea (area under the camera, only
under WOW_CAPTURE, never read by the area authority) and grades by the
rendered GameClock minute. LIGHTING.md notes the preset/capture changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 02:25:15 +01:00
pkuzicandClaude Opus 5.5 7661b7d372 MONKEY (reviewfix-a): zone grading visible in captures; follows the rendered clock
Found by the first runtime capture of the grade: a capture has no avatar, so
CurrentArea stayed None and no zone was ever graded; and the day/night weight
read WorldTime (the server clock, noon offline), so a manual/capture night
graded with the day LUT. Adds CaptureCameraArea (area under the camera, only
under WOW_CAPTURE, never read by the area authority) and grades by the
rendered GameClock minute. LIGHTING.md notes the preset/capture changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 02:25:15 +01:00
Sam SungandClaude Opus 5.5 4510a9b284 Quests print their chat lines: accepted, completed, experience, money and items (#390)
Quests printed no chat lines: no "Quest accepted: …", "… completed.", "Experience gained: …" or "Received …". Nothing raised the reference's quest messages.

Fixes #69.

- **Accept** (`0x5ddd80`): a quest-log slot watcher raises "Quest accepted: <title>" when a slot gains a quest, or keeps its quest and loses the fail bit (`0x5dde17`-`0x5dde34`); a slot that swaps quests says nothing. An uncached quest prints when its record arrives. The QUESTADDED sound now comes from that message row.
- **Turn-in** (`0x5dc400`), in order: "<title> completed." only when the quest has no follow-up in its chain; "Experience gained: N." when the XP is non-zero; "Received …" with the paid coins from the COPPER/SILVER/GOLD globals; then one "Received item: [link]." per fixed reward, and one for the chosen reward, which the client remembers from `GetQuestReward` (`0x50161a`) because the packet does not carry it (vmangos `Player.cpp:14500`).
- Every line comes from the install's strings. A line whose quest or item record is still in flight waits for it; an unknown record is dropped.
- The money line joins only the paid coins ("1 Gold, 5 Copper"). The reference's separator test prints "1 Gold, , 5 Copper" when the middle coin is zero, a quirk not copied.

Tests: six new tests across the quest log, the turn-in handler and the line queue; `scripts/check.sh` is green.

To see it: accept a quest from any giver and read "Quest accepted: <title>"; turn it in and read the completed, experience, money and item lines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:42:53 +07:00
Sam SungandClaude Opus 5.5 3e4792f886 Quests print their chat lines: accepted, completed, experience, money and items (#390)
Quests printed no chat lines: no "Quest accepted: …", "… completed.", "Experience gained: …" or "Received …". Nothing raised the reference's quest messages.

Fixes #69.

- **Accept** (`0x5ddd80`): a quest-log slot watcher raises "Quest accepted: <title>" when a slot gains a quest, or keeps its quest and loses the fail bit (`0x5dde17`-`0x5dde34`); a slot that swaps quests says nothing. An uncached quest prints when its record arrives. The QUESTADDED sound now comes from that message row.
- **Turn-in** (`0x5dc400`), in order: "<title> completed." only when the quest has no follow-up in its chain; "Experience gained: N." when the XP is non-zero; "Received …" with the paid coins from the COPPER/SILVER/GOLD globals; then one "Received item: [link]." per fixed reward, and one for the chosen reward, which the client remembers from `GetQuestReward` (`0x50161a`) because the packet does not carry it (vmangos `Player.cpp:14500`).
- Every line comes from the install's strings. A line whose quest or item record is still in flight waits for it; an unknown record is dropped.
- The money line joins only the paid coins ("1 Gold, 5 Copper"). The reference's separator test prints "1 Gold, , 5 Copper" when the middle coin is zero, a quirk not copied.

Tests: six new tests across the quest log, the turn-in handler and the line queue; `scripts/check.sh` is green.

To see it: accept a quest from any giver and read "Quest accepted: <title>"; turn it in and read the completed, experience, money and item lines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:42:53 +07:00
Sam SungandClaude Opus 5.5 622f8ce525 A ghost is dead to the attack check, the action bar, the cast ladder and the cursor (#389)
A ghost could swing, got a lit action bar, a sword cursor over enemies, and an Attack button that did not refuse. benilla tested death as health 0 only, and a released ghost has health 1.

Fixes #246. Fixes #248. Fixes #250. Fixes #251.

- **One predicate** (`0x605f30`): dead or ghost is health 0 or below, or a player with the `PLAYER_FLAGS` ghost bit `0x10`. It lives on the object fields and every site uses it: the attack check (`0x612e10`), the usable walk's first check (`0x6e3dad`), summon, trade and the death screen.
- **#248:** the cast ladder refuses a dead or ghost caster with `SPELL_FAILED_CASTER_DEAD` and sends nothing, unless the spell's `Attributes` has `0x800000` (`0x6e4c49`-`0x6e4c68`); the Attack action button takes it first ("You are dead").
- **#251:** the sword cursor also needs a live, unmounted, unpacified player in control (`0x482648`-`0x4826cb`). A right-click now decides attack from the reference's CanInteract/CanAttack fork (`0x60c18c`-`0x60c247`), not from the cursor kind, so a ghost right-clicking a hostile NPC with a service flag selects it and does nothing else, instead of opening its window.

Tests: seven tests, each with a ghost at health 1; `scripts/check.sh` is green.

To see it: release spirit. The action bar stays grey; Attack Target reads "Can't attack while dead."; hovering a hostile mob shows the pointer; right-clicking a hostile vendor selects it and opens nothing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:23:28 +07:00
Sam SungandClaude Opus 5.5 b8a32a06e7 A ghost is dead to the attack check, the action bar, the cast ladder and the cursor (#389)
A ghost could swing, got a lit action bar, a sword cursor over enemies, and an Attack button that did not refuse. benilla tested death as health 0 only, and a released ghost has health 1.

Fixes #246. Fixes #248. Fixes #250. Fixes #251.

- **One predicate** (`0x605f30`): dead or ghost is health 0 or below, or a player with the `PLAYER_FLAGS` ghost bit `0x10`. It lives on the object fields and every site uses it: the attack check (`0x612e10`), the usable walk's first check (`0x6e3dad`), summon, trade and the death screen.
- **#248:** the cast ladder refuses a dead or ghost caster with `SPELL_FAILED_CASTER_DEAD` and sends nothing, unless the spell's `Attributes` has `0x800000` (`0x6e4c49`-`0x6e4c68`); the Attack action button takes it first ("You are dead").
- **#251:** the sword cursor also needs a live, unmounted, unpacified player in control (`0x482648`-`0x4826cb`). A right-click now decides attack from the reference's CanInteract/CanAttack fork (`0x60c18c`-`0x60c247`), not from the cursor kind, so a ghost right-clicking a hostile NPC with a service flag selects it and does nothing else, instead of opening its window.

Tests: seven tests, each with a ghost at health 1; `scripts/check.sh` is green.

To see it: release spirit. The action bar stays grey; Attack Target reads "Can't attack while dead."; hovering a hostile mob shows the pointer; right-clicking a hostile vendor selects it and opens nothing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:23:28 +07:00
Sam SungandClaude Opus 5.5 632ab88572 Party and raid roster lines and the join chime follow the reference's two stores (#388)
Party and raid join and leave lines, and the join chime, follow the reference: it composes them from two stores, the party slots and the raid roster, where benilla ran one ungated diff over the whole member list.

Fixes #264. Fixes #268. Fixes #269. Fixes #270.

- **Party lines** (`0x5e6a40`): join lines print only onto a group already held (an occupied slot, `0x5e6afb`, or a raid roster, `0x5e6b29`); forming a group as leader prints one line, for the member the list names last (`0x5e6c94`-`0x5e6cc1`); a raid list prints no party member lines (`0x5e6c01`, `0x5e6cd1`).
- **Raid lines** (`0x4ba5f0`, `0x4ba550`): arrivals print only onto a held roster (`0x4ba725`), departures from `0x4ba7a0`; "You have joined a raid group" when none was held (`0x4ba83a`), and "You have left the raid group" when a non-raid list ends a held raid (`0x4ba55f`).
- **Ending the group**: the leave acknowledgement, `SMSG_GROUP_UNINVITE` and `SMSG_GROUP_DESTROYED` empty the party slots first (`0x4e84a0`), so the empty list that follows names nobody.
- **The chime** (`igPlayerInviteAccept`): queued when a member is seated into no held group (`0x5e6dc6`) or joins a held party (`0x5e6c24`); a raid arrival plays nothing.

Tests: eight new tests fail on the old composition and pass now; `scripts/check.sh` is green.

To see it (two or more characters): accept a party invite and hear the chime, with no "joins the party." lines for members already there; `/leave` prints only "You leave the group."; convert a party of four to a raid and party members see only "You have joined a raid group".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:56:26 +07:00
Sam SungandClaude Opus 5.5 459a9a5697 Party and raid roster lines and the join chime follow the reference's two stores (#388)
Party and raid join and leave lines, and the join chime, follow the reference: it composes them from two stores, the party slots and the raid roster, where benilla ran one ungated diff over the whole member list.

Fixes #264. Fixes #268. Fixes #269. Fixes #270.

- **Party lines** (`0x5e6a40`): join lines print only onto a group already held (an occupied slot, `0x5e6afb`, or a raid roster, `0x5e6b29`); forming a group as leader prints one line, for the member the list names last (`0x5e6c94`-`0x5e6cc1`); a raid list prints no party member lines (`0x5e6c01`, `0x5e6cd1`).
- **Raid lines** (`0x4ba5f0`, `0x4ba550`): arrivals print only onto a held roster (`0x4ba725`), departures from `0x4ba7a0`; "You have joined a raid group" when none was held (`0x4ba83a`), and "You have left the raid group" when a non-raid list ends a held raid (`0x4ba55f`).
- **Ending the group**: the leave acknowledgement, `SMSG_GROUP_UNINVITE` and `SMSG_GROUP_DESTROYED` empty the party slots first (`0x4e84a0`), so the empty list that follows names nobody.
- **The chime** (`igPlayerInviteAccept`): queued when a member is seated into no held group (`0x5e6dc6`) or joins a held party (`0x5e6c24`); a raid arrival plays nothing.

Tests: eight new tests fail on the old composition and pass now; `scripts/check.sh` is green.

To see it (two or more characters): accept a party invite and hear the chime, with no "joins the party." lines for members already there; `/leave` prints only "You leave the group."; convert a party of four to a raid and party members see only "You have joined a raid group".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:56:26 +07:00
Sam SungandClaude Opus 5.5 1f77007977 Floating combat text words each outcome as the reference's emitter does (#387)
Floating combat text picks the wrong outcome word for mitigated hits, partly mitigated spell hits, damage-over-time ticks and one spell-miss code. Each now follows the reference's own emitter.

Fixes #42. Fixes #43. Fixes #89. Fixes #349.

- **Melee partials (#42):** tested resist (`0x629efd`), then block (`0x629f15`), then absorb (`0x629f30`); benilla tested absorb first.
- **Direct spell hits (#43):** a landed hit words its first partial as `0x62cd80` does: `SPELL_RESISTED`, else `SPELL_BLOCKED` (carrying the blocked amount), else `SPELL_ABSORBED`, else `SPELL_DAMAGE`; a zero-damage hit tests absorbed, blocked, resisted. The wider cause: benilla applied the direct words to every `SMSG_SPELLNONMELEEDAMAGELOG`. The reference's handler (`0x5e85e0`) sends split damage to `SPLIT_DAMAGE` (`0x62de60`) and a periodic log, gated on `CombatLogPeriodicSpells` (`0x62d9ae`), to the periodic emitter; the text now routes the same three ways.
- **Damage ticks (#89):** a landed tick words `RESIST`, else `ABSORB`, else `DAMAGE` (`0x628100`: `0x628354`, `0x62836c`, `0x62837f`); a zero-damage tick words `SPELL_ABSORBED`, else `SPELL_RESISTED`.
- **Spell-miss codes (#349):** the jump table at `0x62be10` sends code 10, 1 and 12 and up to `SPELL_MISSED` (`0x62bdc3`), and code 0 fires nothing.

Tests: six tests in `combat_log/text.rs`; the two over existing functions fail on the old code, and the new routing is covered by three more. `scripts/check.sh` is green.

To see it (Floating Combat Text on, "Show Damage Reduction" on): a damage-over-time tick now scrolls as damage, "-N", and a partly resisted tick as "N (M resisted)"; a partly resisted spell hit reads "300 (100 resisted)" instead of "-300".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:45:22 +07:00
Sam SungandClaude Opus 5.5 7a795659d9 Floating combat text words each outcome as the reference's emitter does (#387)
Floating combat text picks the wrong outcome word for mitigated hits, partly mitigated spell hits, damage-over-time ticks and one spell-miss code. Each now follows the reference's own emitter.

Fixes #42. Fixes #43. Fixes #89. Fixes #349.

- **Melee partials (#42):** tested resist (`0x629efd`), then block (`0x629f15`), then absorb (`0x629f30`); benilla tested absorb first.
- **Direct spell hits (#43):** a landed hit words its first partial as `0x62cd80` does: `SPELL_RESISTED`, else `SPELL_BLOCKED` (carrying the blocked amount), else `SPELL_ABSORBED`, else `SPELL_DAMAGE`; a zero-damage hit tests absorbed, blocked, resisted. The wider cause: benilla applied the direct words to every `SMSG_SPELLNONMELEEDAMAGELOG`. The reference's handler (`0x5e85e0`) sends split damage to `SPLIT_DAMAGE` (`0x62de60`) and a periodic log, gated on `CombatLogPeriodicSpells` (`0x62d9ae`), to the periodic emitter; the text now routes the same three ways.
- **Damage ticks (#89):** a landed tick words `RESIST`, else `ABSORB`, else `DAMAGE` (`0x628100`: `0x628354`, `0x62836c`, `0x62837f`); a zero-damage tick words `SPELL_ABSORBED`, else `SPELL_RESISTED`.
- **Spell-miss codes (#349):** the jump table at `0x62be10` sends code 10, 1 and 12 and up to `SPELL_MISSED` (`0x62bdc3`), and code 0 fires nothing.

Tests: six tests in `combat_log/text.rs`; the two over existing functions fail on the old code, and the new routing is covered by three more. `scripts/check.sh` is green.

To see it (Floating Combat Text on, "Show Damage Reduction" on): a damage-over-time tick now scrolls as damage, "-N", and a partly resisted tick as "N (M resisted)"; a partly resisted spell hit reads "300 (100 resisted)" instead of "-300".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:45:22 +07:00
pkuzicandClaude Opus 5.5 ddc001c849 MONKEY (reviewfix-a): cloud-review fixes — cvars, capture fixture, wind pin, post perf
- farclip High seed 777 declared in SEEDED_DEVIATIONS (owner: High is the
  default); test walks the seeded column against every reference row (#6)
- WOW_CAPTURE_CVARS=<file> replaces BENILLA_HOME as the capture cvar fixture (#13)
- label derivation skips session-owned rows, so an env lever no longer
  persists graphicsQuality/lightingQuality = Custom (#14)
- /console help strings: restored line continuations + a test (#15)
- WOW_FOLIAGE_WIND read only in a dev build under WOW_CAPTURE (#16)
- fog node skipped at volumetricFog 0 with no lamp; fog and SSAO uniforms
  persistent per view, written in prepare (#17)
- tests: every governed graphics row through its observer; OptionsFrame
  farclip slider tied to view::FARCLIP_RANGE

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 00:42:27 +01:00
pkuzicandClaude Opus 5.5 b2b5ef7539 MONKEY (reviewfix-a): cloud-review fixes — cvars, capture fixture, wind pin, post perf
- farclip High seed 777 declared in SEEDED_DEVIATIONS (owner: High is the
  default); test walks the seeded column against every reference row (#6)
- WOW_CAPTURE_CVARS=<file> replaces BENILLA_HOME as the capture cvar fixture (#13)
- label derivation skips session-owned rows, so an env lever no longer
  persists graphicsQuality/lightingQuality = Custom (#14)
- /console help strings: restored line continuations + a test (#15)
- WOW_FOLIAGE_WIND read only in a dev build under WOW_CAPTURE (#16)
- fog node skipped at volumetricFog 0 with no lamp; fog and SSAO uniforms
  persistent per view, written in prepare (#17)
- tests: every governed graphics row through its observer; OptionsFrame
  farclip slider tied to view::FARCLIP_RANGE

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 00:42:27 +01:00
Sam SungandClaude Opus 5.5 3df3303d0e Every loot close deselects a dead unit, and a selection change closes the loot on the old target (#379)
Closing a loot window left the looted corpse targeted, and changing target left the old corpse's loot window open.

Fixes #238. Fixes #71.

- **One close routine** (`0x48f200`): every close (CloseLoot, the last row or the coins taken, the server's release response, stepping away) runs the same routine, then deselects the source when it is a unit or player with health 0 or below (`0x48f34f`-`0x48f369`). Before, only the movement close asked, and it keyed on the loot type rather than health. A skinned corpse now loses the selection; a live pick-pocket target keeps it.
- **A selection change closes the old target's loot** (`0x4936cc` → `0x493910` → `0x493974`): Tab, Esc, a click-off or the target's death sends the release before the new selection. A chest window survives a Tab.
- Declaring the loot drain's order against the target update also clears about ninety older undeclared schedule pairs, so the ceiling follows down.

Tests: four new or extended tests fail with the behaviours stubbed out and pass now; `scripts/check.sh` is green.

To see it: kill a mob, loot it and close the window: the target frame clears. Loot a corpse and press Tab with the window open: the window closes and the next mob is targeted.

One wire difference stays and is documented at the seam: when Tab closes a window on a dead target, the reference also sends a `CMSG_SET_SELECTION` of 0 before the new selection (`0x493a2a`). The server ends in the same state.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:15:14 +07:00
Sam SungandClaude Opus 5.5 43a2acda1d Every loot close deselects a dead unit, and a selection change closes the loot on the old target (#379)
Closing a loot window left the looted corpse targeted, and changing target left the old corpse's loot window open.

Fixes #238. Fixes #71.

- **One close routine** (`0x48f200`): every close (CloseLoot, the last row or the coins taken, the server's release response, stepping away) runs the same routine, then deselects the source when it is a unit or player with health 0 or below (`0x48f34f`-`0x48f369`). Before, only the movement close asked, and it keyed on the loot type rather than health. A skinned corpse now loses the selection; a live pick-pocket target keeps it.
- **A selection change closes the old target's loot** (`0x4936cc` → `0x493910` → `0x493974`): Tab, Esc, a click-off or the target's death sends the release before the new selection. A chest window survives a Tab.
- Declaring the loot drain's order against the target update also clears about ninety older undeclared schedule pairs, so the ceiling follows down.

Tests: four new or extended tests fail with the behaviours stubbed out and pass now; `scripts/check.sh` is green.

To see it: kill a mob, loot it and close the window: the target frame clears. Loot a corpse and press Tab with the window open: the window closes and the next mob is targeted.

One wire difference stays and is documented at the seam: when Tab closes a window on a dead target, the reference also sends a `CMSG_SET_SELECTION` of 0 before the new selection (`0x493a2a`). The server ends in the same state.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 06:15:14 +07:00
pkuzic 675a78e0d8 Merge graphics-programme (Everwood graphics programme) into main 2026-09-25 23:46:18 +01:00
pkuzic 3a564d0cc8 Merge graphics-programme (Everwood graphics programme) into main 2026-09-25 23:46:18 +01:00
pkuzicandGPT-5.6 Sol (Codex) 62f1476e4f MONKEY (reviewfix): pin shared shader buffer literals
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:43:56 +01:00
pkuzicandGPT-5.6 Sol (Codex) 8c894bf9f7 MONKEY (reviewfix): pin shared shader buffer literals
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:43:56 +01:00
pkuzicandGPT-5.6 Sol (Codex) 554d3a5eb9 MONKEY (reviewfix): shade water in its source wave domain
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:37:11 +01:00
pkuzicandGPT-5.6 Sol (Codex) 405e9b534f MONKEY (reviewfix): shade water in its source wave domain
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:37:11 +01:00
pkuzicandGPT-5.6 Sol (Codex) c59d42e708 MONKEY (reviewfix): stitch displaced water LOD edges
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:36:16 +01:00
pkuzicandGPT-5.6 Sol (Codex) cc42b2f9fb MONKEY (reviewfix): stitch displaced water LOD edges
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:36:16 +01:00
pkuzicandGPT-5.6 Sol (Codex) 32b3880cc1 MONKEY (reviewfix): separate skybox sort bands
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:32:00 +01:00
pkuzicandGPT-5.6 Sol (Codex) 6107bdc7a4 MONKEY (reviewfix): separate skybox sort bands
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:32:00 +01:00
pkuzicandGPT-5.6 Sol (Codex) 82240e8e76 MONKEY (reviewfix): isolate animated sky materials
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:28:28 +01:00
pkuzicandGPT-5.6 Sol (Codex) 9a88ea2de5 MONKEY (reviewfix): isolate animated sky materials
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:28:28 +01:00
pkuzicandClaude Opus 5.5 4db69f6b53 MONKEY (reviewfix-a): SSAO normal cannot go NaN on isolated pixels against the sky
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 23:27:18 +01:00
pkuzicandClaude Opus 5.5 40238ad3e8 MONKEY (reviewfix-a): SSAO normal cannot go NaN on isolated pixels against the sky
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 23:27:18 +01:00
pkuzicandClaude Opus 5.5 b50a66fefb MONKEY (reviewfix-a): WarcraftXL credits — standard header on grading, sky_fx row, layer.rs module credit
The grading port carries the same attribution header as the other WarcraftXL
ports (used with the author's permission, attribution required).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 23:27:02 +01:00
pkuzicandClaude Opus 5.5 c5711fce22 MONKEY (reviewfix-a): WarcraftXL credits — standard header on grading, sky_fx row, layer.rs module credit
The grading port carries the same attribution header as the other WarcraftXL
ports (used with the author's permission, attribution required).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 23:27:02 +01:00
pkuzicandGPT-5.6 Sol (Codex) 488d451500 MONKEY (reviewfix): make skybox path lookup deterministic
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:26:09 +01:00
pkuzicandGPT-5.6 Sol (Codex) 4b692177ae MONKEY (reviewfix): make skybox path lookup deterministic
Co-Authored-By: GPT-5.6 Sol (Codex)
2026-09-25 23:26:09 +01:00