From a7e6fc230128e647959825923bdf8917c3d98bf9 Mon Sep 17 00:00:00 2001 From: Sam Sung <51686767+samwhosung@users.noreply.github.com> Date: Sat, 26 Sep 2026 08:57:47 +0700 Subject: [PATCH] Comments and strings: the passes' leftovers, and a region's template matched as one name (#391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- crates/benilla-app/src/capture/fixtures.rs | 4 ++- crates/benilla-app/src/cinematic.rs | 3 +- .../src/creature_anim/spell_visual.rs | 2 +- crates/benilla-app/src/death/mod.rs | 5 ++-- crates/benilla-app/src/debug_panel/mod.rs | 11 ++++--- .../src/entities/attach/preview.rs | 4 +-- crates/benilla-app/src/names.rs | 6 ++-- crates/benilla-app/src/net/motion/spline.rs | 6 ++-- crates/benilla-app/src/net/objects.rs | 5 ++-- crates/benilla-app/src/player/ride.rs | 3 +- crates/benilla-app/src/query_cache.rs | 5 ++-- crates/benilla-app/src/sound/interior.rs | 13 ++++---- crates/benilla-app/src/sound/mixer.rs | 4 ++- crates/benilla-app/src/spell/net.rs | 13 ++++---- crates/benilla-app/src/target/cursor_mode.rs | 2 +- crates/benilla-app/src/ui_chat/combat.rs | 11 +++---- crates/benilla-app/src/ui_chat/feed.rs | 4 +-- crates/benilla-app/src/ui_pet_doll.rs | 2 +- .../benilla-app/src/ui_script/quest_tests.rs | 30 ------------------- .../src/ui_script/reputation_frame_tests.rs | 2 +- crates/benilla-app/tests/trade_frame.rs | 2 +- .../src/bin/benilla-extract/scan/material.rs | 17 +++++------ .../src/bin/benilla-extract/scan/sequence.rs | 11 ++++--- crates/benilla-formats/src/creatures.rs | 3 +- crates/benilla-formats/src/models/anim.rs | 11 +++---- .../benilla-formats/src/spell_visual/mod.rs | 2 +- .../src/bin/benilla-world/probes/speed.rs | 6 ++-- crates/benilla-ui/src/framexml.rs | 11 +++---- crates/benilla-ui/src/loader/mod.rs | 10 +++---- crates/benilla-ui/src/loader/tests.rs | 25 ++++++++++++++++ .../src/script/object/events_regions.rs | 4 ++- crates/benilla-ui/src/script/reputation.rs | 2 +- crates/benilla-ui/src/script/tests/anchors.rs | 6 ++-- .../src/script/tests/tooltip_item/bindings.rs | 3 +- crates/benilla-ui/src/script/unit/bindings.rs | 6 ++-- crates/benilla-ui/src/script/unit/tests.rs | 2 +- .../src/terrain_stream/spawn/mod.rs | 3 +- scripts/smoke.sh | 4 +-- 38 files changed, 140 insertions(+), 123 deletions(-) diff --git a/crates/benilla-app/src/capture/fixtures.rs b/crates/benilla-app/src/capture/fixtures.rs index 110b6047..88ef42a1 100644 --- a/crates/benilla-app/src/capture/fixtures.rs +++ b/crates/benilla-app/src/capture/fixtures.rs @@ -69,7 +69,9 @@ pub(super) fn seed_ui_fixture( // exits non-zero, as the window-size refusal does. if script.is_none() { error!( - "capture: REFUSING this capture โ€” scenario {:?} declares a UI fixture but no script VM exists, so its window cannot be opened and the shot would be a UI-less world wearing the scenario's name.", + "capture: REFUSING this capture โ€” scenario {:?} declares a UI fixture but no script \ + VM exists, so its window cannot be opened and the shot would be a UI-less world \ + wearing the scenario's name.", scenario.name ); exit.write(AppExit::error()); diff --git a/crates/benilla-app/src/cinematic.rs b/crates/benilla-app/src/cinematic.rs index bfa3519a..c4f45e08 100644 --- a/crates/benilla-app/src/cinematic.rs +++ b/crates/benilla-app/src/cinematic.rs @@ -419,7 +419,8 @@ fn drive( if home || left <= 0.0 { if !home { warn!( - "cinematic: the world did not come back inside the settle budget โ€” revealing anyway" + "cinematic: the world did not come back inside the settle budget โ€” \ + revealing anyway" ); } cine.settling = None; diff --git a/crates/benilla-app/src/creature_anim/spell_visual.rs b/crates/benilla-app/src/creature_anim/spell_visual.rs index 4874ffd4..c977ee9b 100644 --- a/crates/benilla-app/src/creature_anim/spell_visual.rs +++ b/crates/benilla-app/src/creature_anim/spell_visual.rs @@ -191,7 +191,7 @@ pub(crate) struct MissileSpawn { pub(crate) ground_aim: Option, /// The caster's ranged fallback visual, carried to arrival when the caster may be gone. pub(crate) weapon_visual: Option, - /// `SpellVisual` field 10: the sound the projectile loops in flight (`CMissile+0x44`). + /// `SpellVisual` field 10: the sound the projectile loops in flight (`CMissile+0x40`). pub(crate) missile_sound: Option, /// Launch at the cast animation's release event (`0x5ffbd0` โ†’ `0x60c940`), not at GO; the /// reference launches at GO only when the cast kit plays no body animation (`0x6e7a70`). diff --git a/crates/benilla-app/src/death/mod.rs b/crates/benilla-app/src/death/mod.rs index 11e94c55..98304162 100644 --- a/crates/benilla-app/src/death/mod.rs +++ b/crates/benilla-app/src/death/mod.rs @@ -221,8 +221,9 @@ fn feed_death( // Ghost to alive: reclaim, spirit healer or an accepted res. (Some((_, _, true)), false, false) => { feed.died_at = None; - // The 1.12 client re-queries on the ghost-bit edge (`0x5ee990`), and the not-found - // answer drops the map markers; the server's own push is sent only with a looter + // The not-found answer drops the map markers. The reference sends nothing on this + // edge: its ghost-bit watcher (`0x5ee990`) clears the corpse cache, and `0x491f50` + // queries only while a ghost. The server's own push needs a looter // (`Map.cpp:3617-3629`). let _ = net.0.send(ClientCommand::CorpseQuery); } diff --git a/crates/benilla-app/src/debug_panel/mod.rs b/crates/benilla-app/src/debug_panel/mod.rs index c318360b..56ec4980 100644 --- a/crates/benilla-app/src/debug_panel/mod.rs +++ b/crates/benilla-app/src/debug_panel/mod.rs @@ -360,7 +360,8 @@ fn debug_panel_ui( } } ui.label(format!( - "animated doodads ยท {} ({} ticking) ยท {} material ({hidden} culled, {dim} dimmed) ยท {} uv", + "animated doodads ยท {} ({} ticking) ยท {} material \ + ({hidden} culled, {dim} dimmed) ยท {} uv", anim_hosts.iter().count(), ticking, mat_anims.iter().count(), @@ -595,9 +596,7 @@ fn debug_panel_ui( .id_salt("stepup_report") .show(ui, |ui| { for line in report { - ui.label( - egui::RichText::new(line).small().monospace(), - ); + ui.label(egui::RichText::new(line).small().monospace()); } }); }); @@ -609,8 +608,8 @@ fn debug_panel_ui( egui::RichText::new(format!( "{DEV_CHORD}: D panel ยท P perf ยท I inspect ยท M mute ยท F free-fly" )) - .small() - .color(OVERLAY_TEXT_DIM), + .small() + .color(OVERLAY_TEXT_DIM), ); // The build; a click copies the full sha. let build = ui.add( diff --git a/crates/benilla-app/src/entities/attach/preview.rs b/crates/benilla-app/src/entities/attach/preview.rs index ca45002c..3e518664 100644 --- a/crates/benilla-app/src/entities/attach/preview.rs +++ b/crates/benilla-app/src/entities/attach/preview.rs @@ -327,8 +327,8 @@ pub(in crate::entities) fn build_dressup_preview( equipment: look.equipment, emblem: look.emblem, // No hide flags: `crate::ui_dressup` already left out a hidden worn helm or cloak, as - // `SetUnit` (`0x476cb0`) clones the live display pointers, and a mask here would hide a - // tried-on one. + // `SetUnit` (`0x505d70`) clones the live display pointers (`0x476cb0`), and a mask here + // would hide a tried-on one. flags: 0, // The ranged slot here only holds a try-on: `SetUnit` clones the live model, which shows // a ranged weapon only while ranged-drawn, so `crate::ui_dressup` leaves a worn one out. diff --git a/crates/benilla-app/src/names.rs b/crates/benilla-app/src/names.rs index c404a7dd..1edd7345 100644 --- a/crates/benilla-app/src/names.rs +++ b/crates/benilla-app/src/names.rs @@ -2,7 +2,8 @@ //! guid), a creature's `CMSG_CREATURE_QUERY` (by template entry), a pet's or charm's //! `CMSG_PET_NAME_QUERY` (by pet number), and which one applies is read off the descriptor as the //! reference's `GetUnitName` (`0x609210`) reads it. Each key is asked once while in flight, and a -//! negative answer is cached so a bad id never loops. +//! negative answer is cached so a bad id never loops; for a player that is an empty name, which the +//! reference evicts instead (`0x55f6f0`), so its next read asks again. //! //! Creature templates persist, as the reference's `creaturecache.wdb` does; player and pet names //! are never written to disk and are cleared at world-session start, as the reference does. @@ -509,7 +510,8 @@ pub(crate) mod net { } /// `SMSG_INVALIDATE_PLAYER`, which vmangos sends after a rename (`CharacterHandler.cpp:839`): - /// the only per-player eviction, as in the reference, whose name cache has no TTL (`0x555600`). + /// the reference's eviction (`0x555600`) in a name cache with no TTL; its other, an empty-name + /// answer (`0x55f6f0`), is a cached negative here. fn invalidate_player(guid: u64, names: &mut NameCache) { debug!("net: invalidating cached name for player {guid:#x}"); names.invalidate_player(guid); diff --git a/crates/benilla-app/src/net/motion/spline.rs b/crates/benilla-app/src/net/motion/spline.rs index d44d23b1..37aeaf23 100644 --- a/crates/benilla-app/src/net/motion/spline.rs +++ b/crates/benilla-app/src/net/motion/spline.rs @@ -68,8 +68,10 @@ impl Spline { } /// Raw-WoW position, facing (`None` when vertical) and pitch `asin(dz/len)` at `now`, at - /// constant speed. Segments are located by chord length (`0x4532e0`); the evaluator `0x4541b0` - /// lerps a ground path and runs a uniform Catmull-Rom (`0x453580`) on a flying one. + /// constant speed. Segments are located by chord length here in both modes; the reference + /// uses the chord on a ground path only and a flying segment's Catmull-Rom length in 20 steps + /// (`0x454320`, `0x453760`). The evaluator `0x4541b0` lerps a ground path and runs a uniform + /// Catmull-Rom (`0x453580`) on a flying one. pub(crate) fn sample(&self, now: Instant) -> ([f32; 3], Option, f32) { let pts = self.points.as_slice(); if pts.len() < 2 { diff --git a/crates/benilla-app/src/net/objects.rs b/crates/benilla-app/src/net/objects.rs index d7e3062a..e9f4bd06 100644 --- a/crates/benilla-app/src/net/objects.rs +++ b/crates/benilla-app/src/net/objects.rs @@ -935,8 +935,9 @@ fn monster_move( } } } - // Every spline move un-nocks and drops the weapon hold: the handler `0x6018f0` (opcodes - // 0xDD, 0x2AE) always ends through `0x60d040` (clear `0x400`) and `0x60f530` (un-nock). + // Every spline move un-nocks and drops the weapon hold here. The handler `0x6018f0` + // (opcodes 0xDD, 0x2AE) ends through `0x60d040` (clear `0x400`) and `0x60f530` (un-nock) on + // every path but one: a stop within 3 yd of the stop point jumps past both (`0x6019e4`). commands.entity(e).remove::<( crate::creature_anim::NockLatch, crate::creature_anim::RangedHold, diff --git a/crates/benilla-app/src/player/ride.rs b/crates/benilla-app/src/player/ride.rs index 9eeaca7a..94027aaa 100644 --- a/crates/benilla-app/src/player/ride.rs +++ b/crates/benilla-app/src/player/ride.rs @@ -115,7 +115,8 @@ pub(super) fn update_attachment( benilla_assets::trace::line( "ride", &format!( - "on {:#x} deck({:8.2},{:7.2},{:8.2}) yaw{:+.3} | feet({:8.2},{:7.2},{:8.2}) local({:7.2},{:6.2},{:7.2}) | grounded={} support={} vy={:+6.2}{}", + "on {:#x} deck({:8.2},{:7.2},{:8.2}) yaw{:+.3} | feet({:8.2},{:7.2},{:8.2}) \ + local({:7.2},{:6.2},{:7.2}) | grounded={} support={} vy={:+6.2}{}", ride.guid, bpos.x, bpos.y, diff --git a/crates/benilla-app/src/query_cache.rs b/crates/benilla-app/src/query_cache.rs index 3b5a333e..a4462664 100644 --- a/crates/benilla-app/src/query_cache.rs +++ b/crates/benilla-app/src/query_cache.rs @@ -5,7 +5,8 @@ //! The read that asks takes `&self` (the in-flight set is behind a lock), so read-only systems //! share the owning resource and its change detection means an answer landed. //! -//! A negative answer (the server's high-bit miss) is cached as `None` and never re-asked. +//! A negative answer is cached as `None` and never re-asked: an integer-keyed store's high-bit miss +//! (`0x556e67`), or a player's empty name. use std::collections::{HashMap, HashSet}; use std::hash::Hash; @@ -86,7 +87,7 @@ impl QueryCache { self.generation = self.generation.wrapping_add(1); } - /// The reference's explicit eviction (a high-bit key, `SMSG_INVALIDATE_PLAYER`): the next + /// The reference's explicit eviction (`SMSG_INVALIDATE_PLAYER` for a player's name): the next /// read re-asks. Returns whether there was anything to evict. pub(crate) fn evict(&mut self, key: K) -> bool { self.pending diff --git a/crates/benilla-app/src/sound/interior.rs b/crates/benilla-app/src/sound/interior.rs index 50e79ebc..eac45309 100644 --- a/crates/benilla-app/src/sound/interior.rs +++ b/crates/benilla-app/src/sound/interior.rs @@ -1,13 +1,14 @@ -//! WMO interior audio: the `WMOAreaTable` row for the group the camera eye is in (exact group -//! row, then whole-WMO default, then name-set 0), published as an override layer. Zone music, -//! ambience, intro and reverb take its nonzero fields over the terrain `AreaTable` chain; zero -//! fields fall through to it (the reference's rule for a zero interior field is untraced). +//! WMO interior audio: the `WMOAreaTable` row for the group the character is in, where the +//! listener sits (the camera before login), by exact group row, then whole-WMO default, then +//! name-set 0, published as an override layer. Zone music, ambience, intro and reverb take its +//! nonzero fields over the terrain `AreaTable` chain; zero fields fall through to it (the +//! reference's rule for a zero interior field is untraced). use bevy::prelude::*; use benilla_world::schedule::WorldStage; -/// The audio FKs of the interior the eye is in; `None` is the open world. +/// The audio FKs of the interior the listener is in; `None` is the open world. #[derive(Resource, Default, Clone, Copy, PartialEq, Eq)] pub(crate) struct CurrentInterior(pub(crate) Option); @@ -23,7 +24,7 @@ pub(crate) struct InteriorAudio { pub(crate) intro_sound: u32, } -/// Resolve the eye's interior keys to the audio row; log transitions by interior name. +/// Resolve the listener's interior keys to the audio row; log transitions by interior name. fn resolve_interior( world: benilla_world::world_point::WorldPoint, mut current: ResMut, diff --git a/crates/benilla-app/src/sound/mixer.rs b/crates/benilla-app/src/sound/mixer.rs index 143fa6e3..18ebb502 100644 --- a/crates/benilla-app/src/sound/mixer.rs +++ b/crates/benilla-app/src/sound/mixer.rs @@ -942,7 +942,9 @@ mod tests { ); assert!( shut_asked > 0.9, - "gate shut: the METER plane must still read the mix the game produced โ€” asked {shut_asked:.3}. A tap that goes silent with the speakers is the false negative this ordering exists to prevent" + "gate shut: the METER plane must still read the mix the game produced โ€” asked \ + {shut_asked:.3}. A tap that goes silent with the speakers is the false negative \ + this ordering exists to prevent" ); } diff --git a/crates/benilla-app/src/spell/net.rs b/crates/benilla-app/src/spell/net.rs index eccdf8db..098a0b7e 100644 --- a/crates/benilla-app/src/spell/net.rs +++ b/crates/benilla-app/src/spell/net.rs @@ -598,12 +598,13 @@ fn cast_result( // arm clears the guard: both clears are the reference's one `0x6e741a call 0x6e4940(0x1c)`. let in_flight = pending.committed(Instant::now()) == Some(spell_id); if !success { - // `HandleCastFailed 0x6e1a00`: a failure clears only the GCD armed at send (`0x6e1d83 โ†’ - // 0x6e1630`); the spell's own recovery starts at SPELL_GO, which a failed cast never - // reaches. A failing cached auto-repeat spell with reason โ‰  0x17 runs the full local - // cancel (`0x6e1cd9`โ€“`0x6e1cea` โ†’ `0x6ea080`, the `SMSG_CANCEL_AUTO_REPEAT` routine). A - // deselect arrives as this failure (vmangos `HandleSetSelectionOpcode` โ†’ `Spell::cancel` โ†’ - // `SendCastResult(INTERRUPTED)`); target death arrives as [`cancel_auto_repeat`]. + // `HandleCastFailed 0x6e1a00` clears the GCD armed at send (`0x6e1d83 โ†’ 0x6e1630`), and the + // bit-25 revert below drops a parked record; the spell's own recovery starts at SPELL_GO, + // which a failed cast never reaches. A failing cached auto-repeat spell with reason โ‰  0x17 + // runs the full local cancel (`0x6e1cd9`โ€“`0x6e1cea` โ†’ `0x6ea080`, the + // `SMSG_CANCEL_AUTO_REPEAT` routine). A deselect arrives as this failure (vmangos + // `HandleSetSelectionOpcode` โ†’ `Spell::cancel` โ†’ `SendCastResult(INTERRUPTED)`); target + // death arrives as [`cancel_auto_repeat`]. let now = Instant::now(); // Reason 0x17 DONT_REPORT exits before the GCD clear and the display (`6e1ce1`/`6e1cf7` โ†’ // `0x6e224f`). The in-flight clear below still runs, as the reference's `0x6e741a` does diff --git a/crates/benilla-app/src/target/cursor_mode.rs b/crates/benilla-app/src/target/cursor_mode.rs index 37f41648..57167d01 100644 --- a/crates/benilla-app/src/target/cursor_mode.rs +++ b/crates/benilla-app/src/target/cursor_mode.rs @@ -1190,7 +1190,7 @@ mod tests { assert_eq!(go_interact_range_sq(GO_TYPE_CHAIR), 9.0); assert!( go_interact_range_sq(GO_TYPE_CHAIR) < GO_INTERACT_RANGE_SQ, - "the chair reaches SHORTER than the interim โ€” a longer one would restore the bug" + "a chair's reach is shorter than the default GameObject reach" ); assert!(!fishing_channel_owned(None, Some(7))); assert!(!fishing_channel_owned(None, None)); diff --git a/crates/benilla-app/src/ui_chat/combat.rs b/crates/benilla-app/src/ui_chat/combat.rs index 1507c648..169ec109 100644 --- a/crates/benilla-app/src/ui_chat/combat.rs +++ b/crates/benilla-app/src/ui_chat/combat.rs @@ -795,8 +795,9 @@ pub(crate) fn power_word(script: &benilla_ui::script::UiScript, power: u32) -> O } /// One endpoint's display name, the reference's `GetObjectName` (`0x6264e0`); `None` until the -/// name cache answers, and the caller retries as the deferred queue at `0xc4e208` does. A streamed -/// unit names through its descriptor (`GetUnitName`, `0x609210`), which is how a pet is named. +/// name cache answers, and the caller retries, where the reference never waits and prints +/// `UNKNOWNOBJECT`. A streamed unit names through its descriptor (`GetUnitName`, `0x609210`), which +/// is how a pet is named. pub(crate) fn object_name( guid: u64, unit: Option<&ObjectStore>, @@ -1552,9 +1553,9 @@ pub(crate) fn melee_family( // โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ the queued line, awaiting its names โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -/// A combat-log line classified at the packet, with only its names outstanding: the reference's -/// `0x629b60` decides while both units are streamed and parks the message on the deferred queue -/// at `0xc4e208` until the name-ready callback `0x6294b0`, so a despawned creature still logs. +/// A combat-log line classified at the packet while both units are streamed, so a despawned +/// creature still logs, with only its names outstanding. The reference's deferred queue +/// (`0xc4e208`, replayed by `0x6294b0`) holds only a line waiting on an item name (`0x55ba30`). #[derive(Clone, Debug)] pub(crate) struct PendingCombat { pub kind: ChatEventKind, diff --git a/crates/benilla-app/src/ui_chat/feed.rs b/crates/benilla-app/src/ui_chat/feed.rs index 406b5365..19a2172d 100644 --- a/crates/benilla-app/src/ui_chat/feed.rs +++ b/crates/benilla-app/src/ui_chat/feed.rs @@ -98,8 +98,8 @@ enum Pending { }, /// An area discovery (`SMSG_EXPLORATION_EXPERIENCE`), fired at the drain, which holds the VM. Discovery { area: String, xp: u32 }, - /// One combat-log line, classified at the packet, waiting on its two endpoint names: the - /// reference's deferred queue (`0xc4e208`), replayed by the name-ready callback `0x6294b0`. + /// One combat-log line, classified at the packet, waiting on its two endpoint names; the + /// reference's deferred queue (`0xc4e208`) waits only on an item name. Combat(Box), /// A ready event (client-composed lines; name-carrying notices). Event(ChatEvent), diff --git a/crates/benilla-app/src/ui_pet_doll.rs b/crates/benilla-app/src/ui_pet_doll.rs index 29a3e6f2..e76e62ac 100644 --- a/crates/benilla-app/src/ui_pet_doll.rs +++ b/crates/benilla-app/src/ui_pet_doll.rs @@ -132,7 +132,7 @@ mod tests { assert_eq!( s.defense_skill, (0, 0), - "INTERIM โ€” unconfirmed in the reference" + "no pet defense here; the reference answers UnitLevel ร— 5 and 0 (`0x613680`)" ); } diff --git a/crates/benilla-app/src/ui_script/quest_tests.rs b/crates/benilla-app/src/ui_script/quest_tests.rs index 2b4cd7fb..bcf828e3 100644 --- a/crates/benilla-app/src/ui_script/quest_tests.rs +++ b/crates/benilla-app/src/ui_script/quest_tests.rs @@ -22,9 +22,6 @@ fn questgiver_show_hide_plays_open_and_close_kits() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -85,9 +82,6 @@ fn panel_events_show_exactly_one_child_panel_and_hide_the_others() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -179,9 +173,6 @@ fn detail_panel_reward_grid_follows_the_refs_two_per_row_layout() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -278,9 +269,6 @@ fn reward_panel_choice_click_selects_and_completes_with_zero_based_index() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -358,9 +346,6 @@ fn greeting_goodbye_button_closes_the_window() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -409,9 +394,6 @@ fn detail_panel_action_buttons_resolve_to_real_onscreen_rects() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -535,9 +517,6 @@ fn write_on_still_fades_when_instant_text_is_off() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -612,9 +591,6 @@ fn npc_name_reaches_the_title_bar_on_open_and_on_refresh() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -692,9 +668,6 @@ fn greeting_panel_title_rows_grow_to_their_wrapped_titles() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); @@ -787,9 +760,6 @@ fn reward_rows_preview_and_post_without_selecting_the_choice() { load_xml(&s, r"Interface\FrameXML\BasicControls.xml"); load_xml(&s, r"Interface\FrameXML\LocaleProperties.lua"); load_xml(&s, r"Interface\FrameXML\StaticPopup.xml"); - load_xml(&s, "ScrollTemplates.xml"); // our scroll kits - load_xml(&s, "Interface\\FrameXML\\CharacterFrameTemplates.xml"); - load_xml(&s, "Interface\\FrameXML\\MerchantFrame.xml"); load_xml(&s, "Interface\\FrameXML\\BasicControls.xml"); load_xml(&s, "Interface\\FrameXML\\ItemButtonTemplate.xml"); load_xml(&s, "Interface\\FrameXML\\QuestFrame.xml"); diff --git a/crates/benilla-app/src/ui_script/reputation_frame_tests.rs b/crates/benilla-app/src/ui_script/reputation_frame_tests.rs index 3b9764dc..9800e053 100644 --- a/crates/benilla-app/src/ui_script/reputation_frame_tests.rs +++ b/crates/benilla-app/src/ui_script/reputation_frame_tests.rs @@ -530,7 +530,7 @@ fn the_watch_bar_shows_the_watched_factions_progress_and_swaps_at_max_level() { s.set_unit("player", Some(player(40))); assert!( !shown(&mut s, "ReputationWatchBar"), - "nothing watched: the bar stays down, as it has since it was a stub" + "nothing watched: the bar stays down" ); // Ironforge is rep slot 20; watching it is a server field, so it rides the push. diff --git a/crates/benilla-app/tests/trade_frame.rs b/crates/benilla-app/tests/trade_frame.rs index 8e4292c5..89daa910 100644 --- a/crates/benilla-app/tests/trade_frame.rs +++ b/crates/benilla-app/tests/trade_frame.rs @@ -299,7 +299,7 @@ fn player_money_input_reflects_then_offers() { ) .unwrap(), ("1".into(), "23".into(), "45".into()), - "the echo reflects 1g 23s 45c into the boxes" + "the event fills 1g 23s 45c into the boxes" ); assert_eq!( s.take_trade_money(), diff --git a/crates/benilla-formats/src/bin/benilla-extract/scan/material.rs b/crates/benilla-formats/src/bin/benilla-extract/scan/material.rs index f12269a5..5ffa46a4 100644 --- a/crates/benilla-formats/src/bin/benilla-extract/scan/material.rs +++ b/crates/benilla-formats/src/bin/benilla-extract/scan/material.rs @@ -1513,7 +1513,7 @@ pub fn fxuvscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { for c in [FxClass::Invisible, FxClass::Never, FxClass::Unknown] { listing( c.label(), - " (frozen@identity โ€” what the effect lane renders today)", + " (frozen@identity โ€” what the effect lane renders)", |h| h.class, c, ); @@ -2442,7 +2442,7 @@ pub fn entityuvscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { ] { listing( c.label(), - " (frozen@identity โ€” what the entity lane renders today)", + " (frozen@identity โ€” what the entity lane renders)", |h| h.class, c, ); @@ -2521,12 +2521,11 @@ pub fn entityuvscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { println!(); println!( "============================== M2COLOR TINT ==============================\n\ - The same corpus asked about the OTHER channel `entity_variants` leaves unserved.\n\ - `build` passes `sub.rgb_anim.as_ref()` unconditionally, so a tint-animating entity\n\ - batch is SEEDED at the loop's first key (`model_material`'s `tint.xyz`) โ€” and then\n\ - nothing re-samples it, because `doodad_anim::register_tint`'s only call sites are in\n\ - `terrain_stream/spawn/assemble.rs`. There is no `play_rgb` flag to flip: the hole is\n\ - the missing registration, not a missing argument." + The same corpus asked about the OTHER channel, the keyed M2Color tint. A batch is\n\ + seeded at the loop's first key (`model_material`'s `tint.xyz`) and re-sampled only\n\ + where `doodad_anim::register_tint` registers it: placed doodads\n\ + (`terrain_stream/spawn/assemble.rs`), dressed entity parts (`entities/attach/dress.rs`)\n\ + and the glue booth (`portrait/glue_booth.rs`)." ); for (path, block) in &tint_blocks { println!( @@ -2554,7 +2553,7 @@ pub fn entityuvscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { ); } println!(); - println!(" --- the CLOCK the tint fix has to serve ---"); + println!(" --- the CLOCK each tint rides ---"); for c in UvClock::ALL { println!( " {:<6} {:>5} batch(es) โ€” {}", diff --git a/crates/benilla-formats/src/bin/benilla-extract/scan/sequence.rs b/crates/benilla-formats/src/bin/benilla-extract/scan/sequence.rs index 2d0ee551..c84ff8b3 100644 --- a/crates/benilla-formats/src/bin/benilla-extract/scan/sequence.rs +++ b/crates/benilla-formats/src/bin/benilla-extract/scan/sequence.rs @@ -514,9 +514,8 @@ pub fn seqclockscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { eprintln!( "{scanned} models scanned, {with_seqs} with sequences: {frozen} CLOCKLESS \ ({frozen_emitters} emitters) โ€” sequences + per-sequence consumers, not one keyed bone; \ - {frozen_go} of them GameObject display models (the hosted lane, frozen at slot 0 t=0). \ - {partial} PARTIAL models have unkeyed sequences a clip lookup can never reach; \ - {inert} more are boneless with nothing to sample (a clock there is inert)." + {frozen_go} of them GameObject display models. {partial} PARTIAL models key a bone in \ + some sequences only; {inert} more key no bone and have nothing to sample." ); Ok(()) } @@ -643,9 +642,9 @@ pub fn soundeventscan(chain: &mut Chain, prefix: Option<&str>) -> Result<()> { } eprintln!( "{scanned} models with sequences scanned; {carriers} carry a $DSL/$DSO/$SND marker, \ - {hostless} of them on the Static tier (no anim-root entity exists to hang an emitter \ - on today); {rest_gated} carry the marker on a REST-posed sequence โ€” the class \ - benilla's rig gate never arms, so the marker is unreachable through an AnimationPlayer." + {hostless} of them on the Static tier (the marker alone arms their clock); \ + {rest_gated} carry the marker on a REST-posed sequence, which gets no rig, so only the \ + rig-free sequence clock reaches it." ); Ok(()) } diff --git a/crates/benilla-formats/src/creatures.rs b/crates/benilla-formats/src/creatures.rs index 2b54c166..5f242e5c 100644 --- a/crates/benilla-formats/src/creatures.rs +++ b/crates/benilla-formats/src/creatures.rs @@ -940,7 +940,8 @@ mod tests { let swim_delta = 0.75 * (ours_before - reference); assert!( swim_delta.abs() > 0.05, - "{label}: the two readings must actually differ, else this test asserts nothing (reference {reference}, form-derived {ours_before})" + "{label}: the two readings must actually differ, else this test asserts nothing \ + (reference {reference}, form-derived {ours_before})" ); worst = worst.max(swim_delta.abs()); } diff --git a/crates/benilla-formats/src/models/anim.rs b/crates/benilla-formats/src/models/anim.rs index c0a5e574..0bd63c6e 100644 --- a/crates/benilla-formats/src/models/anim.rs +++ b/crates/benilla-formats/src/models/anim.rs @@ -922,16 +922,17 @@ mod tests { { let first = rot.keys[0].1; assert!( - rot.keys.iter().all(|(_, q)| q + rot.keys .iter() - .zip(first) - .all(|(a, b)| (a - b).abs() < 1e-6)), - "UI_{token}'s stage rotation is a PARKED key, not an animation โ€” a moving stage would have to be read off the live joint instead" + .all(|(_, q)| q.iter().zip(first).all(|(a, b)| (a - b).abs() < 1e-6)), + "UI_{token}'s stage rotation is a PARKED key, not an animation โ€” a \ + moving stage would have to be read off the live joint instead" ); let [x, y, z, w] = first; assert!( x.abs() < 1e-3 && y.abs() < 1e-3, - "UI_{token}'s stage rotation is a pure YAW about +Z โ€” a stage tipped in pitch or roll would need composing, not summing (got {first:?})" + "UI_{token}'s stage rotation is a pure YAW about +Z โ€” a stage tipped in \ + pitch or roll would need composing, not summing (got {first:?})" ); yaw += 2.0 * f32::atan2(z, w).to_degrees(); } diff --git a/crates/benilla-formats/src/spell_visual/mod.rs b/crates/benilla-formats/src/spell_visual/mod.rs index 85fff58d..cd6c0ee4 100644 --- a/crates/benilla-formats/src/spell_visual/mod.rs +++ b/crates/benilla-formats/src/spell_visual/mod.rs @@ -183,7 +183,7 @@ pub struct VisualStages { pub missile_model: u32, /// Field 9: the index into [`MISSILE_ATTACH_TABLE`]. pub missile_attach: u32, - /// Field 10: the `SoundEntries.dbc` loop the missile plays in flight (`CMissile+0x44`, its + /// Field 10: the `SoundEntries.dbc` loop the missile plays in flight (`CMissile+0x40`, its /// volume shaped by distance at `0x61d790`), stopped when it arrives. pub missile_sound: Option, /// Field 14: the `SoundEntries.dbc` id the `$TRD` anim event plays at a craft's strike frame diff --git a/crates/benilla-protocol/src/bin/benilla-world/probes/speed.rs b/crates/benilla-protocol/src/bin/benilla-world/probes/speed.rs index 8281cca1..8b5fbc76 100644 --- a/crates/benilla-protocol/src/bin/benilla-world/probes/speed.rs +++ b/crates/benilla-protocol/src/bin/benilla-world/probes/speed.rs @@ -39,7 +39,8 @@ impl Probe for Speed { let speed_changes_seen = &cx.world.speed_changes_seen; ensure!( speed_changes_seen.len() >= 2, - "--speed: expected 2 force-speed changes (got {}) โ€” did the first ack drop the session, or is the account not GM?", + "--speed: expected 2 force-speed changes (got {}) โ€” did the first ack drop the \ + session, or is the account not GM?", speed_changes_seen.len() ); let (k1, c1, s1) = speed_changes_seen[0]; @@ -57,7 +58,8 @@ impl Probe for Speed { "--speed: movement counter must increment across changes (got {c1} then {c2})" ); println!( - "\n--speed PASS: {k1:?} 7.0->10.5->7.0 yd/s, counters {c1}->{c2}, both acks accepted (stream survived)" + "\n--speed PASS: {k1:?} 7.0->10.5->7.0 yd/s, counters {c1}->{c2}, both acks accepted \ + (stream survived)" ); Ok(()) } diff --git a/crates/benilla-ui/src/framexml.rs b/crates/benilla-ui/src/framexml.rs index 957e8e3a..0e1cdfe1 100644 --- a/crates/benilla-ui/src/framexml.rs +++ b/crates/benilla-ui/src/framexml.rs @@ -311,11 +311,12 @@ fn element_from_node(node: roxmltree::Node) -> Element { } /// Resolve `inherits` into a materialized [`Element`]: the named template, itself expanded first, -/// then the element on top, as the reference splices a template's nodes before the instance's -/// own (`LoadChildFrames 0x76a060` keeps that order for ``). Children are the template's -/// then the element's; the element's attributes override or extend the template's -/// (case-insensitively). `name` and `virtual` splice like any attribute; whether the reference -/// exempts them is untraced. A cycle is skipped with a warning. +/// then the element on top. Children are the template's then the element's; the element's +/// attributes override or extend the template's (case-insensitively). The reference merges +/// nothing: `LoadXML` re-enters itself on the one object against each template, the most distant +/// first, then the instance (`0x76985c`; `` repeat the walk, `0x76a060`), and reads `name` +/// and `id` from the instance alone (`PreLoadXML 0x769770`). Here `name` and `virtual` merge like +/// any attribute. A cycle is skipped with a warning. pub fn expand( element: &Element, templates: &HashMap<&str, &Element>, diff --git a/crates/benilla-ui/src/loader/mod.rs b/crates/benilla-ui/src/loader/mod.rs index 890e68e2..d576c165 100644 --- a/crates/benilla-ui/src/loader/mod.rs +++ b/crates/benilla-ui/src/loader/mod.rs @@ -428,13 +428,13 @@ impl Loader<'_> { /// [`Loader::expand`] for a region, only when `inherits=` names a registered element template: /// a FontString's `inherits=` usually names a font object, which passes through unwarned. pub(super) fn expand_region(&mut self, el: &Element) -> Element { - let hit = el.attr("inherits").is_some_and(|names| { + // One verbatim name, matched case-insensitively, as `framexml::expand` looks it up. + let hit = el.attr("inherits").is_some_and(|name| { let model = self.model(); let templates = model.framexml_templates.borrow(); - names - .split(',') - .map(str::trim) - .any(|n| templates.contains_key(n)) + !name.is_empty() + && (templates.contains_key(name) + || templates.keys().any(|k| k.eq_ignore_ascii_case(name))) }); if hit { self.expand(el) diff --git a/crates/benilla-ui/src/loader/tests.rs b/crates/benilla-ui/src/loader/tests.rs index a2ba089b..dd5bcd1c 100644 --- a/crates/benilla-ui/src/loader/tests.rs +++ b/crates/benilla-ui/src/loader/tests.rs @@ -384,6 +384,31 @@ mod loader_tests { ); } + /// A region's `inherits=` is one name matched case-insensitively (`0x6ee747`), as a frame's + /// is, so a mis-cased template name still reaches the template. + #[test] + fn a_region_takes_a_mis_cased_template() { + let s = UiScript::new().unwrap(); + let doc = parse( + r#" + + + + + + + + + "#, + ); + let report = load(&s, &doc, &no_files); + assert!(report.errors.is_empty(), "errors: {:?}", report.errors); + assert_eq!( + s.eval::("return MarkHostMark:GetWidth()").unwrap(), + 32.0 + ); + } + #[test] fn frame_set_all_points_pins_to_parent() { let mut s = UiScript::new().unwrap(); diff --git a/crates/benilla-ui/src/script/object/events_regions.rs b/crates/benilla-ui/src/script/object/events_regions.rs index 750d880f..333d21a0 100644 --- a/crates/benilla-ui/src/script/object/events_regions.rs +++ b/crates/benilla-ui/src/script/object/events_regions.rs @@ -301,7 +301,9 @@ fn apply_region_inherits(lua: &Lua, wrapper: &Table, from: &str) -> mlua::Result if is_template { let mut model = lua.app_data_mut::().expect("model"); model.record_warning(format!( - "CreateTexture/CreateFontString: '{from}' is a registered TEMPLATE, not a font object; the region is created but the template's content is not applied (no corpus caller does this)" + "CreateTexture/CreateFontString: '{from}' is a registered TEMPLATE, not a font object; \ + the region is created but the template's content is not applied (no corpus caller \ + does this)" )); return Ok(()); } diff --git a/crates/benilla-ui/src/script/reputation.rs b/crates/benilla-ui/src/script/reputation.rs index 414e3d20..0dae6603 100644 --- a/crates/benilla-ui/src/script/reputation.rs +++ b/crates/benilla-ui/src/script/reputation.rs @@ -789,7 +789,7 @@ mod tests { s.eval::("return GetWatchedFactionInfo()") .unwrap() .is_nil(), - "nothing watched โ†’ one nil, which is the ref's own `if ( name )` gate" + "nothing watched โ†’ a nil name, which stock `if ( name )` gates on" ); s.run("SetWatchedFactionIndex(3)").unwrap(); // Stormwind diff --git a/crates/benilla-ui/src/script/tests/anchors.rs b/crates/benilla-ui/src/script/tests/anchors.rs index 63394d14..6139bcd6 100644 --- a/crates/benilla-ui/src/script/tests/anchors.rs +++ b/crates/benilla-ui/src/script/tests/anchors.rs @@ -216,7 +216,7 @@ fn a_region_resolves_even_when_its_owner_frame_has_no_rect() { host:SetWidth(400) host:SetHeight(200) host:SetPoint("BOTTOMLEFT", 100, 50) - -- the shape that was invisible: owner with NO size and NO SetPoint + -- an owner with NO size and NO SetPoint bare = CreateFrame("Frame", "BareOwner") mark = bare:CreateTexture("BareMark", "ARTWORK") mark:SetWidth(20) mark:SetHeight(10) @@ -236,7 +236,7 @@ fn a_region_resolves_even_when_its_owner_frame_has_no_rect() { assert_eq!( s.eval::>("return BareOwner:GetLeft()").unwrap(), None, - "an unpositioned frame has no rect; the fix must not invent one for it" + "an unpositioned frame has no rect" ); // Host's BOTTOMLEFT (100,50) plus the (5,7) offset. @@ -253,7 +253,7 @@ fn a_region_resolves_even_when_its_owner_frame_has_no_rect() { assert_eq!( s.eval::>("return SizedMark:GetLeft()").unwrap(), Some(105.0), - "a sized owner's region must be unaffected by the fix" + "a sized owner's region resolves the same" ); } diff --git a/crates/benilla-ui/src/script/tests/tooltip_item/bindings.rs b/crates/benilla-ui/src/script/tests/tooltip_item/bindings.rs index e1737762..122cf20e 100644 --- a/crates/benilla-ui/src/script/tests/tooltip_item/bindings.rs +++ b/crates/benilla-ui/src/script/tests/tooltip_item/bindings.rs @@ -348,7 +348,8 @@ fn set_inventory_item_renders_full_outside_compare() { assert(count(tt:SetInventoryItem("player", 16)) == 3, "occupied: three returns, got " .. count(tt:SetInventoryItem("player", 16))) local _, _, repairCost = tt:SetInventoryItem("player", 16) - assert(repairCost == 0, "repairCost is a NUMBER โ€” the reference always pushes one; 0 INTERIM") + assert(repairCost == 0, + "repairCost is a NUMBER โ€” the reference always pushes one; 0 as the cost is not fed") assert(count(tt:SetInventoryItem("player", 5)) == 3, "empty: three returns too, got " .. count(tt:SetInventoryItem("player", 5))) local hasItem, _, emptyCost = tt:SetInventoryItem("player", 5) diff --git a/crates/benilla-ui/src/script/unit/bindings.rs b/crates/benilla-ui/src/script/unit/bindings.rs index 5423f78e..91247561 100644 --- a/crates/benilla-ui/src/script/unit/bindings.rs +++ b/crates/benilla-ui/src/script/unit/bindings.rs @@ -994,8 +994,8 @@ pub(in crate::script) fn install(lua: &Lua) -> mlua::Result<()> { // AssistUnit(unit) (`0x489b80`): select the unit's `UNIT_FIELD_TARGET`. The shared tail // (`0x489bb2`-`0x489c07`) returns silently on 0 and selects through `0x489a40`, which leaves // the selection alone when nothing resolves; no `CanAssist` gate (`0x6066f0`), any unit, and a - // swing only with `assistAttack` set (default "0", `0x48fc50`). Deviation: a nil token is - // silent, because the reference's game message `0xb8` for it has no recoverable text. + // swing only with `assistAttack` set (default "0", `0x48fc50`). A token that resolves nothing + // is silent here, where the reference shows `0xb8` ERR_GENERIC_NO_TARGET (`0x489c0e`). g.set( "AssistUnit", lua.create_function(|lua, token: Option| { @@ -1046,7 +1046,7 @@ pub(in crate::script) fn install(lua: &Lua) -> mlua::Result<()> { // number is taken as its string. Deviation: among whole-name matches ours picks the nearest, // because the reference's first-walked pick is order-dependent and reads as a bug. A miss is // silent here, where the reference shows `0x127` ERR_UNIT_NOT_FOUND, or `0xb8` - // ERR_GENERIC_NO_TARGET for an empty name (#52). + // ERR_GENERIC_NO_TARGET for an empty name. g.set( "TargetByName", lua.create_function(|lua, (name, exact): (Value, Option)| { diff --git a/crates/benilla-ui/src/script/unit/tests.rs b/crates/benilla-ui/src/script/unit/tests.rs index 81df4187..3b482b0c 100644 --- a/crates/benilla-ui/src/script/unit/tests.rs +++ b/crates/benilla-ui/src/script/unit/tests.rs @@ -469,7 +469,7 @@ fn power_bindings_read_the_active_type() { assert!( s.eval::("return UnitPower == nil and UnitPowerMax == nil") .unwrap(), - "the Era spellings must not linger beside the 1.12 ones" + "UnitPower and UnitPowerMax are not 1.12 globals" ); // An absent unit is the number 0, never nil: `UnitFrame.lua:122` indexes `ManaBarColor` by it. assert_eq!( diff --git a/crates/benilla-world/src/terrain_stream/spawn/mod.rs b/crates/benilla-world/src/terrain_stream/spawn/mod.rs index bb929246..ca141660 100644 --- a/crates/benilla-world/src/terrain_stream/spawn/mod.rs +++ b/crates/benilla-world/src/terrain_stream/spawn/mod.rs @@ -565,7 +565,8 @@ pub(super) fn spawn_loaded_placements( // Once per burst, not per prop: a city WMO can flood thousands in a frame. let (live, peak) = probes.occupancy(); warn_once!( - "interior-prop probe table full (live {live}, peak {peak}); overflowing props fall back to exterior light" + "interior-prop probe table full (live {live}, peak {peak}); \ + overflowing props fall back to exterior light" ); } slot diff --git a/scripts/smoke.sh b/scripts/smoke.sh index 737adb88..bda7cab7 100755 --- a/scripts/smoke.sh +++ b/scripts/smoke.sh @@ -108,7 +108,7 @@ sup="$(printf '%s\n' "$plain" | sed -n 's/.*logout-smoke: re-entered.*suppressor printf ' %-24s %s\n' "re-entry suppressors" "${sup:-}" [ "$sup" = "none" ] || fail "the re-entered character could not be driven โ€” suppressors: ${sup:-} \ -(1542: everything the ended session granted its mover dies with it)" +(everything the ended session granted its mover dies with it)" # vmangos skips the logout root when resting, on a taxi or at account security >= `InstantLogout` # (`MiscHandler.cpp`, `CMSG_LOGOUT_REQUEST`); probe accounts are GM, so report whether the check @@ -152,7 +152,7 @@ writes="$(printf '%s\n' "$plain" | grep -cF "saved variables: wrote")" printf ' %-24s %s\n' "shutdown writes" "$writes" [ "$writes" -eq "$sessions" ] || fail "the shutdown tail wrote $writes time(s), expected $sessions โ€” a session ended without \ -saving (1528: the quit root must be observed in \`Last\`, after PostUpdate's exit_on_all_closed)" +saving (the quit root must be observed in \`Last\`, after PostUpdate's exit_on_all_closed)" # The read-only verdict names each changed file, the whole lead to whatever wrote it. if [ -n "$install_root" ]; then