From 11c01d07adfda5683d51d9ecacb5d59b8d4136e1 Mon Sep 17 00:00:00 2001 From: grom Date: Fri, 30 Oct 2026 09:02:47 -0600 Subject: [PATCH] The slam macro was never ours, and a fixture I invented is why I said otherwise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grom reports `/cast [noslamclip] Slam; [slamclip] Heroic Strike` never picking Slam. Yesterday I drove the whole chain in the harness, measured a 44% no-clip window and called it healthy. The 44% came from a cast time I supplied: s.set_spell_tooltip(1464, … cast_time: Some("1.5 sec cast") …) **OctoWoW's Slam is a 2.5 s cast.** `Spell.dbc` ids 1464/8820/11604/11605 all carry `CastingTimeIndex` 20 and `SpellCastTimes.dbc` row 20 is 2500 ms, where vanilla's Slam is 1500. SuperCleveRoidMacros' own `DEFAULT_SLAM_CAST = 2.5 -- Turtle WoW` agrees independently. Against his 2.70 s weapon the window is `(2.70 - 2.50) / 2.70` = 7.4%, 0.2 s wide — not something a hand can hit, which is the whole report. The same DBC gives every Slam rank `spellLevel` 54, and he is level 14. The field alignment is checked against spells whose levels are known (Heroic Strike rank 1/2/3 = 1/8/16, Charge 4, Shield Bash 12, Overpower 12, Thunder Clap 6), so that reading is safe to act on: 477 Heroic Strikes in his combat log and zero Slams, in any session since 10/12. The fixtures now carry the realm's numbers and `WINDOW_PCT` carries where they come from, including this mistake — a number I supply cannot test anything, and a green test then argues against the player's own report. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- .../src/addon_harness/tick_bench_tests.rs | 59 ++++++++++++------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/crates/benilla-app/src/addon_harness/tick_bench_tests.rs b/crates/benilla-app/src/addon_harness/tick_bench_tests.rs index 7d27e9e7..a4d1286d 100644 --- a/crates/benilla-app/src/addon_harness/tick_bench_tests.rs +++ b/crates/benilla-app/src/addon_harness/tick_bench_tests.rs @@ -24,6 +24,22 @@ use super::{ }; /// Plates a crowded pull shows; the nameplate CVar cap and `pfValidUnits`' own range. +/// `CleveRoids.GetSlamWindowPercent()` for grom's own numbers, as Lua prints it. +/// +/// `(mainhand - slamCast) / mainhand * 100` = `(2.70 - 2.50) / 2.70 * 100`. **Both numbers are +/// the realm's, not vanilla's.** Slam on OctoWoW is a 2.5 s cast — `Spell.dbc` id 1464 (and 8820, +/// 11604, 11605) carries `CastingTimeIndex` 20, and `SpellCastTimes.dbc` row 20 is 2500 ms, where +/// vanilla's Slam is 1.5 s. SuperCleveRoidMacros' own `DEFAULT_SLAM_CAST = 2.5 -- Turtle WoW` +/// agrees independently. +/// +/// So the no-clip window on a 2.70 s weapon is **0.2 s wide, 7.4% of the swing**, and a player +/// pressing the macro by hand will almost never land in it. That is the macro's arithmetic, not +/// a fault of this client — and it is worth a constant with this comment on it, because an +/// earlier revision of these tests invented a `1.5 sec cast` fixture, measured a 44% window off +/// it, and concluded the chain was healthy while the player's own sessions cast Heroic Strike 477 +/// times and Slam never once. +const WINDOW_PCT: &str = "7.4074074074074"; + const PLATES: u32 = 40; /// Frames per timed window. @@ -1587,7 +1603,7 @@ fn the_whole_slam_macro_line_picks_slam_early_and_heroic_strike_late() { ); assert_eq!( ask(&mut s, "CleveRoids.GetSlamCastTime()"), - "1.5", + "2.5", "the cast time came off the scanning tooltip, not the addon's 2.5 s fallback — against a \ 2.70 s swing the fallback leaves a 7% window instead of 44%, which in play reads as \ `[noslamclip]` never being true at all" @@ -1599,14 +1615,15 @@ fn the_whole_slam_macro_line_picks_slam_early_and_heroic_strike_late() { // `VANILLA_SWING_MS` stand-in — and `st_timer` is still 0, so the whole swing reads as // elapsed: // - // window = (2.0 - 1.5) / 2.0 = 25%, elapsed = 100% -> `[noslamclip]` false -> Heroic Strike. + // maxSlamStart = 2.0 - 2.50 <= 0 -> window 0%, elapsed 100% -> `[noslamclip]` false -> + // Heroic Strike. // // That is correct of the numbers it has and wrong about the weapon, and it heals on the first // auto-attack that lands (below). It is also why the latch is worth a log line // (`char_stats::with_unit_stats`): if the sheet never arrives, this *is* the session. assert_eq!(ask(&mut s, "st_timerMax"), "2"); assert_eq!(ask(&mut s, "CleveRoids.GetSwingPercentElapsed()"), "100"); - assert_eq!(ask(&mut s, "CleveRoids.GetSlamWindowPercent()"), "25"); + assert_eq!(ask(&mut s, "CleveRoids.GetSlamWindowPercent()"), "0"); assert_eq!( ask(&mut s, "CleveRoids.ValidateNoSlamClip()"), "false", @@ -1635,8 +1652,8 @@ fn the_whole_slam_macro_line_picks_slam_early_and_heroic_strike_late() { assert_eq!(ask(&mut s, "CleveRoids.GetSwingPercentElapsed()"), "0"); assert_eq!( ask(&mut s, "CleveRoids.GetSlamWindowPercent()"), - "44.444444444444", - "(2.70 - 1.50) / 2.70, off the real weapon this time" + WINDOW_PCT, + "(2.70 - 2.50) / 2.70, off the real weapon this time — 0.2 s of a 2.7 s swing" ); let _ = s.take_spell_casts(); s.fire_event( @@ -1650,12 +1667,12 @@ fn the_whole_slam_macro_line_picks_slam_early_and_heroic_strike_late() { `GetSwingPercentElapsed` and `GetSlamWindowPercent` above before anything else" ); - // 1.6 s later the swing is 59% elapsed, past the window: the second clause takes it. + // 1.6 s later the swing is 59% elapsed, far past the window: the second clause takes it. s.tick(1.6); assert_eq!( ask(&mut s, "CleveRoids.ValidateNoSlamClip()"), "false", - "59% elapsed is past the 44% window, so casting Slam now would clip the auto-attack" + "59% elapsed is past the 7.4% window, so casting Slam now would clip the auto-attack" ); let _ = s.take_spell_casts(); s.fire_event( @@ -1745,7 +1762,7 @@ fn seat_a_warrior_mid_fight(s: &mut UiScript, offhand: bool) { ..Default::default() })); for (id, name, cast) in [ - (1464u32, "Slam", Some("1.5 sec cast".to_string())), + (1464u32, "Slam", Some("2.5 sec cast".to_string())), (78, "Heroic Strike", None), (23922, "Shield Slam", None), ] { @@ -1823,14 +1840,12 @@ fn seat_a_warrior_mid_fight(s: &mut UiScript, offhand: bool) { /// * The spellbook walk `GetSpellName(i, BOOKTYPE_SPELL)` finding Slam. /// * `GameTooltip:SetSpell` on a **nil-parent scanning tooltip built from /// `GameTooltipTemplate`**, whose `TextLeft` the addon reads with `getglobal` looking -/// for `"%d+%.?%d* sec cast"`. This is the one that decides the size of the window: without it -/// the addon falls back to a 2.5 s constant, which against a 2.70 s swing leaves a 7% window -/// instead of 44% and would read in play as "Slam never fires". +/// for `"%d+%.?%d* sec cast"`. This is the one that decides the size of the window. /// * The `` delta reaching `SP_ST_OnUpdate(arg1)` as seconds. /// -/// **All five answer correctly** once the sheet is pushed, with a 44.4% window off a 1.5 s -/// scanned cast time — and the asymmetry this test originally only *documented* turned out to be -/// the whole defect. It is the first bullet's edge: before the stats feed has pushed, +/// **All five answer correctly** once the sheet is pushed — see [`WINDOW_PCT`] for the window +/// they produce and for the fixture mistake that made an earlier revision of this test read as a +/// clean bill of health while the macro was still picking Heroic Strike every time. It is the first bullet's edge: before the stats feed has pushed, /// `UnitAttackSpeed("player")` answered `0`, and SP_SwingTimer's `ADDON_LOADED` arm latches that /// into `st_timerMax` behind `if not st_timerMax` — where `0` is truthy, so the guard never /// re-fires. The first write to that global in a session is therefore always the pre-push answer. @@ -1878,7 +1893,7 @@ fn the_slam_clip_conditional_answers_on_the_players_own_interface() { rank: Some("Rank 1".into()), cost: Some("15 Rage".into()), range: Some("Melee Range".into()), - cast_time: Some("1.5 sec cast".into()), + cast_time: Some("2.5 sec cast".into()), description: "Slams the opponent.".into(), ..Default::default() }, @@ -1934,10 +1949,11 @@ fn the_slam_clip_conditional_answers_on_the_players_own_interface() { // The scanning tooltip: a nil parent, the shipped template, and `getglobal` down the lines. assert_eq!( ask(&mut s, "CleveRoids.GetSlamCastTime()"), - "1.5", - "the cast time came off the scanning tooltip, not the addon's 2.5 s fallback — the \ - fallback leaves a 7% window against a 2.70 s swing and reads as `[noslamclip]` never \ - being true" + "2.5", + "the cast time came off the scanning tooltip. On this realm it happens to equal the \ + addon's own 2.5 s fallback, so a scan that silently failed would read identically — what \ + this pins is that the `sec cast` line is reachable at all through a nil-parent \ + `GameTooltipTemplate`. [`WINDOW_PCT`] carries where the 2.5 comes from" ); // The latch, before any swing. This loader runs the addon walk before the `set_*` calls // above, exactly as `load_ingame_ui_on_world_entry` runs it before any feed system — so this @@ -1984,8 +2000,9 @@ fn the_slam_clip_conditional_answers_on_the_players_own_interface() { ); assert_eq!( ask(&mut s, "CleveRoids.GetSlamWindowPercent()"), - "44.444444444444", - "(2.70 - 1.50) / 2.70 — the share of the swing in which Slam still beats the auto-attack" + WINDOW_PCT, + "(2.70 - 2.50) / 2.70 — the share of the swing in which Slam still beats the \ + auto-attack: 0.2 s of 2.7, which is the whole story of this macro on this weapon" ); assert_eq!( ask(&mut s, "CleveRoids.ValidateNoSlamClip()"),