From 084354c2311ecd4bb8e0e3541119e3ec9274ba6b Mon Sep 17 00:00:00 2001 From: Sam Sung <51686767+samwhosung@users.noreply.github.com> Date: Tue, 29 Sep 2026 13:56:56 +0700 Subject: [PATCH] Spell text keeps "every 1 second": the $l plural keying on every token is recorded as a deviation (#595) The reference's $a, $d, $t, $e, $c, $p, $f, $F and $z arms never write the plural count [0xbe0b84], so 1.12.1's Blizzard and Consecration read "every 1 seconds". benilla keys on the nearest token and prints the grammar the text means; a test pins it. Built and tested on macOS. Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/benilla-formats/src/spells/tokens.rs | 29 +++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/crates/benilla-formats/src/spells/tokens.rs b/crates/benilla-formats/src/spells/tokens.rs index d20999fa..baf51c38 100644 --- a/crates/benilla-formats/src/spells/tokens.rs +++ b/crates/benilla-formats/src/spells/tokens.rs @@ -458,6 +458,11 @@ pub fn substitute(text: &str, spell: &SpellDisplay, ctx: &TokenContext) -> Strin }; match token_value(letter, slot, target, ctx, scale) { Some((sub, val)) => { + // Deviation: every token keys the `$l` plural. The reference's `$a`, `$d`, `$t`, + // `$e`, `$c`, `$p`, `$f`, `$F` and `$z` arms never write `[0xbe0b84]`, so its `$l` + // keys on the number before them, and Blizzard's "$s1 … every $t1 + // $lsecond:seconds;" reads "every 1 seconds" in 1.12.1. We print the grammar the + // text means. last_value = val; out.push_str(&sub); } @@ -1084,6 +1089,30 @@ mod tests { assert_eq!(substitute("$t1", &tick(3000, 1), &c), "5"); } + /// The `$l` deviation in [`substitute`]: Blizzard's wording keys its plural on the `$t` just + /// before it, "every 1 second", where 1.12.1 keys on the damage and reads "every 1 seconds". + #[test] + fn the_plural_keys_on_the_nearest_token_a_deviation() { + let durations = SpellDurationCatalog::default(); + let radii = SpellRadiusCatalog::default(); + let c = ctx(&durations, &radii, &none_lookup); + let blizzard = SpellDisplay { + effect_base_points: [24, 0, 0], + effect_base_dice: [1, 0, 0], + effect_die_sides: [1, 0, 0], + effect_amplitude: [1000, 0, 0], + ..Default::default() + }; + assert_eq!( + substitute( + "$s1 Frost damage every $t1 $lsecond:seconds;", + &blizzard, + &c + ), + "25 Frost damage every 1 second" + ); + } + /// `$r` (`507d5b`) reads row 1 for an index at or below 1 and prints one decimal through /// op 5; `$e` (`507f83`) prints one decimal through op 27; `$a` (`507c74`) truncates the /// radius, applies op 6 and prints an integer, 0 without a row.