Commit Graph
1685 Commits
Author SHA1 Message Date
Sam SungandClaude Opus 5.5 863998aa54 Right-clicking a bag or worn item puts a held item back first, as 1.12.1 clears the cursor before any use (#431)
- Right-clicking a bag or worn item puts a held item back first, as 1.12.1 clears the cursor before any use
- The bag frame's end-to-end test: a right-click with a held item puts it back, then uses the slot

Fixes #413
Fixes #421

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:25:41 +07:00
Sam SungandClaude Opus 5.5 12bba15345 Repair All greys out after a repair: its total is swept before the inventory event that refreshes the button (#426)
Fixes #417

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:09:32 +07:00
Sam SungandClaude Opus 5.5 cf969431a3 Repair All greys out after a repair: its total is swept before the inventory event that refreshes the button (#426)
Fixes #417

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 15:09:32 +07:00
ab897f76d6 /dnd clears a standing AFK first, as every chat type but AFK does (#186)
- fix: clear a standing AFK when /dnd is sent
- The AFK clear runs once, ahead of the type arms, and a test drives /afk then /dnd through the real drain

Fixes #185

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 14:51:49 +07:00
4ebc2a9f23 /dnd clears a standing AFK first, as every chat type but AFK does (#186)
- fix: clear a standing AFK when /dnd is sent
- The AFK clear runs once, ahead of the type arms, and a test drives /afk then /dnd through the real drain

Fixes #185

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 14:51:49 +07:00
f8e0e6c702 The trainer's ability icon shows its spell tooltip on the first hover (#158)
- Fix trainer tooltip on first hover
- The spell-tooltip feed keeps its in-game gate, and a test holds it after the trainer feed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 14:41:33 +07:00
2f35f63274 The trainer's ability icon shows its spell tooltip on the first hover (#158)
- Fix trainer tooltip on first hover
- The spell-tooltip feed keeps its in-game gate, and a test holds it after the trainer feed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 14:41:33 +07:00
36b1c93fcd Repair mode: bag and worn-item clicks in 1.12.1's order, right-clicks clearing the cursor first (#378)
- fix: repair mode
- repair mode: a right-click puts a held payload back, then repairs the item
- repair clicks sound ITEM_REPAIR as they are sent, under the kit's no-duplicates gate
- the repair-all button is no longer driven from Rust
- repair mode: the click bindings' order, for every cursor payload
- worn-item repair clicks drain beside the bag's, in no system of their own

Fixes #147
Fixes #148

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 13:42:44 +07:00
263ea062ab Repair mode: bag and worn-item clicks in 1.12.1's order, right-clicks clearing the cursor first (#378)
- fix: repair mode
- repair mode: a right-click puts a held payload back, then repairs the item
- repair clicks sound ITEM_REPAIR as they are sent, under the kit's no-duplicates gate
- the repair-all button is no longer driven from Rust
- repair mode: the click bindings' order, for every cursor payload
- worn-item repair clicks drain beside the bag's, in no system of their own

Fixes #147
Fixes #148

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-09-26 13:42:44 +07:00
pkuzic 4bf3e51c3c Merge graphics-programme (visual fixes: ocean fog wedge, cloud ring, whitecaps, skybox allocs, fog clock) into main 2026-09-26 06:02:01 +01:00
pkuzic 942c0e47a0 Merge graphics-programme (visual fixes: ocean fog wedge, cloud ring, whitecaps, skybox allocs, fog clock) into main 2026-09-26 06:02:01 +01:00
pkuzicandClaude Opus 5.5 5f78d55794 MONKEY (visualfix): volumetric fog density follows the rendered clock
The dawn/weather density curve read WorldTime, the server clock, which stays at its noon default
offline, so a manual or capture time never got the dawn mist. It now reads the rendered minute
through grading's rendered_minute (the same rule as ac9a1ef3). Baselines move: volfog-dawn is
mistier (MAE 8.5), volfog-night is unchanged (0.07).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 f5c58c81a2 MONKEY (visualfix): volumetric fog density follows the rendered clock
The dawn/weather density curve read WorldTime, the server clock, which stays at its noon default
offline, so a manual or capture time never got the dawn mist. It now reads the rendered minute
through grading's rendered_minute (the same rule as ac9a1ef3). Baselines move: volfog-dawn is
mistier (MAE 8.5), volfog-night is unchanged (0.07).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 2193f9d33e MONKEY (visualfix): skybox animation stops allocating and re-uploading per frame
Review leftover #17. animate_skyboxes keeps its per-model clocks across frames (a path String is
cloned only when a model first shows), poses into reused buffers (SkyRig::pose_into), and
re-skins and re-uploads a skinned batch only when its model's pose changed (a generation
counter). resolve_camera_skybox compares paths with an allocation-free norm_eq and owns only the
winning WMO skybox name. Test: norm_eq agrees with norm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 2e384482b8 MONKEY (visualfix): skybox animation stops allocating and re-uploading per frame
Review leftover #17. animate_skyboxes keeps its per-model clocks across frames (a path String is
cloned only when a model first shows), poses into reused buffers (SkyRig::pose_into), and
re-skins and re-uploads a skinned batch only when its model's pose changed (a generation
counter). resolve_camera_skybox compares paths with an allocation-free norm_eq and owns only the
winning WMO skybox name. Test: norm_eq agrees with norm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 d26898a3e8 MONKEY (visualfix): whitecaps break in scattered short runs, not a lattice
The fold mask came from the two long wave bands only, which cross in a regular diamond lattice:
every crest broke into the same elongated patch. The mask adds the next two bands' compression,
a slow domain-warped gust field moves the break threshold and calms patches, and ~6 yd warped
segments break each crest into short runs. Geometry is unchanged; crest foam stays on steep waves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 d78948d5c5 MONKEY (visualfix): whitecaps break in scattered short runs, not a lattice
The fold mask came from the two long wave bands only, which cross in a regular diamond lattice:
every crest broke into the same elongated patch. The mask adds the next two bands' compression,
a slow domain-warped gust field moves the break threshold and calms patches, and ~6 yd warped
segments break each crest into short runs. Geometry is unchanged; crest foam stays on steep waves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 9c2eadd98d MONKEY (visualfix): High cloud detail no longer punches a ring round the glow
The erosion weight 4a(1-a) was 0.84 in dense cloud (a = 0.7), so one low base-octave detail cell
(~5 degrees) cut a round hole in the mass, and the detail's mean (0.573, not 0.5) lifted the
plateau around it: a hard ring near the sun, rimmed by the silver lining. Erosion is now centred
on the detail's mean and weighted 6.75a(1-a)^2 (thin edges keep the cauliflower, dense cores
keep their shape); thin cloud is not self-shadowed, and the silver lining reads a wider
footprint ahead and is capped. Cloud behind the glow is a diffuse brightening again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
pkuzicandClaude Opus 5.5 5ddad6ef35 MONKEY (visualfix): High cloud detail no longer punches a ring round the glow
The erosion weight 4a(1-a) was 0.84 in dense cloud (a = 0.7), so one low base-octave detail cell
(~5 degrees) cut a round hole in the mass, and the detail's mean (0.573, not 0.5) lifted the
plateau around it: a hard ring near the sun, rimmed by the silver lining. Erosion is now centred
on the detail's mean and weighted 6.75a(1-a)^2 (thin edges keep the cauliflower, dense cores
keep their shape); thin cloud is not self-shadowed, and the silver lining reads a wider
footprint ahead and is capped. Cloud behind the glow is a diffuse brightening again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 06:00:26 +01:00
Sam SungandClaude Opus 5.5 98b0733013 contributing: what happens to a pull request after it is opened (#404)
A maintainer reviews it against the reference and usually finishes it on the contributor's branch
(a rebase, a fix, a test, a comment) rather than sending it back, so "Allow edits by maintainers"
stays ticked; it lands as one squash-merged commit with the contributor as its author, or, when
what lands would be mostly ours, as our own commit crediting them as co-author.

Docs only; no gate reads it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 11:59:13 +07:00
Sam SungandClaude Opus 5.5 11e185fc09 contributing: what happens to a pull request after it is opened (#404)
A maintainer reviews it against the reference and usually finishes it on the contributor's branch
(a rebase, a fix, a test, a comment) rather than sending it back, so "Allow edits by maintainers"
stays ticked; it lands as one squash-merged commit with the contributor as its author, or, when
what lands would be mostly ours, as our own commit crediting them as co-author.

Docs only; no gate reads it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 11:59:13 +07:00
pkuzicandClaude Opus 5.5 1895461d5c MONKEY (visualfix): volumetric haze meets the ocean at its surface, not the seabed
Water writes no depth, so the haze pass measured the seabed behind it, and water with no seabed
behind it (depth 0 below the horizon) read as sky and took no haze. The underwater slope of an
island drew a hard-edged wedge across the sea (water-ocean at High). With an ocean footprint in
reach and the eye above sea level, a point below sea level is now hazed at the ocean plane.
Samples past the cascade's far bound take the ray's mean covered visibility instead of 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 05:05:55 +01:00
pkuzicandClaude Opus 5.5 1a892794ce MONKEY (visualfix): volumetric haze meets the ocean at its surface, not the seabed
Water writes no depth, so the haze pass measured the seabed behind it, and water with no seabed
behind it (depth 0 below the horizon) read as sky and took no haze. The underwater slope of an
island drew a hard-edged wedge across the sea (water-ocean at High). With an ocean footprint in
reach and the eye above sea level, a point below sea level is now hazed at the ocean plane.
Samples past the cascade's far bound take the ray's mean covered visibility instead of 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 05:05:55 +01:00
pkuzic 6ea2291fc6 Merge graphics-programme (review fixes, polish, perf) into main 2026-09-26 04:17:14 +01:00
pkuzic 7759391890 Merge graphics-programme (review fixes, polish, perf) into main 2026-09-26 04:17:14 +01:00
Sam SungandClaude Opus 5.5 2306892ce9 ci: a pull request from a fork runs the no-install gates on Linux (#403)
The gates of scripts/gates.sh that need neither the install nor a display (fmt, clippy, the
workspace tests without an install, the doc-link and render-pass lints, the player build and its
tests), on ubuntu-latest, so a red pull request is seen before anyone builds it. A branch of this
repository skips the job: it runs the full chain before it lands. The job reads the repository
only, keeps no credentials in the checkout, pins its two actions by commit, drops debuginfo for
the runner's disk and caches dependencies. gates.sh and CONTRIBUTING say what runs where.

actionlint passes; the system packages are the ones CONTRIBUTING names for Linux. The workflow's
first run is a manual one on main once it lands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 10:09:29 +07:00
Sam SungandClaude Opus 5.5 8d5e43c33f ci: a pull request from a fork runs the no-install gates on Linux (#403)
The gates of scripts/gates.sh that need neither the install nor a display (fmt, clippy, the
workspace tests without an install, the doc-link and render-pass lints, the player build and its
tests), on ubuntu-latest, so a red pull request is seen before anyone builds it. A branch of this
repository skips the job: it runs the full chain before it lands. The job reads the repository
only, keeps no credentials in the checkout, pins its two actions by commit, drops debuginfo for
the runner's disk and caches dependencies. gates.sh and CONTRIBUTING say what runs where.

actionlint passes; the system packages are the ones CONTRIBUTING names for Linux. The workflow's
first run is a manual one on main once it lands.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 10:09:29 +07:00
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