Part of #92, for `benilla-ui`, `benilla-world` and `benilla-formats`. - 88 string literals drop private record and bug numbers, the dates of private incidents, and the workspace's name for the maintainer. They are assert and panic texts, log and printout lines, the `--` comments of the Lua prelude and of test fixtures, and one Lua assert. Each keeps its fact in its own words. - Two test names lose their numbers: `burning_steppes_lava_builds_a_magma_surface_at_the_reported_pin` and `join_channel_by_name_answers_the_row_custom_and_nil_legs`. - A test-only event, `B271_PROBE`, is now `ERROR_PROBE` in the two crates that register and fire it. A fixture's error text in `benilla-app`'s `ui_script` tests drops its bug number, together with the assertion that reads it. - Doc comments that named a client function by a disassembler's label (`FUN_0068a830`) now give its address, in `benilla-formats`, `benilla-assets` and one `benilla-app` file. - Every literal change keeps each literal's line count, proven with comments stripped and every literal masked. The two renamed tests differ only in their names. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
77 lines
2.8 KiB
Rust
77 lines
2.8 KiB
Rust
//! The Blackrock lava bubble keys all its animation in file sequence slot 1, a 50% variation of
|
|
//! animation id 0: both sequences are id 0 at frequencies 16384 and 16383, re-rolled every play
|
|
//! window (`0x6951b0`). Slot 0 holds still; slot 1 swells the bubbles to 2.785 and flips the V
|
|
//! offset by 0.605.
|
|
|
|
use benilla_formats::{open_chain, parse_m2_animations, parse_m2_render_submeshes};
|
|
|
|
const BUBBLE: &str =
|
|
"World\\KhazModan\\Blackrock\\PassiveDoodads\\BlackrockLavaBubbles\\BlackrockStatueLavaBubble.m2";
|
|
|
|
#[test]
|
|
fn the_lava_bubble_keys_its_whole_uv_flipbook_in_variation_one() {
|
|
let data = benilla_formats::wow_data_or_skip!();
|
|
let mut chain = open_chain(&data).expect("open vanilla patch chain");
|
|
let bytes = chain
|
|
.read_file(BUBBLE)
|
|
.expect("the bubble M2 is in the chain");
|
|
|
|
let anims = parse_m2_animations(&bytes);
|
|
assert_eq!(anims.len(), 2, "two sequences");
|
|
assert!(
|
|
anims.iter().all(|a| a.anim_id == 0),
|
|
"both are animation id 0 — one variation chain"
|
|
);
|
|
assert!(
|
|
anims.iter().all(|a| a.frequency > 15_000),
|
|
"…and both are genuinely rollable (≈50/50), so placements DIVERGE: {:?}",
|
|
anims.iter().map(|a| a.frequency).collect::<Vec<_>>()
|
|
);
|
|
|
|
let peak = |slot: usize| {
|
|
anims[slot]
|
|
.bones
|
|
.iter()
|
|
.flat_map(|b| b.scale.iter().map(|&(_, s)| s[0]))
|
|
.fold(0.0f32, f32::max)
|
|
};
|
|
assert!((peak(0) - 1.0).abs() < 1e-3, "slot 0 is a rest hold");
|
|
assert!(peak(1) > 2.5, "slot 1 is the swell (peak {})", peak(1));
|
|
|
|
let subs = parse_m2_render_submeshes(&bytes, "", &[]).expect("parse");
|
|
assert_eq!(subs.len(), 5, "five bubbles, five batches");
|
|
for (i, sub) in subs.iter().enumerate() {
|
|
let set = sub
|
|
.uv_seq
|
|
.as_ref()
|
|
.unwrap_or_else(|| panic!("batch {i} carries a per-sequence UV set"));
|
|
assert!(
|
|
set.uniform().is_none(),
|
|
"batch {i}: the slots disagree — that IS the verdict"
|
|
);
|
|
assert!(
|
|
set.slots()[0].is_none(),
|
|
"batch {i}: slot 0's window never moves the UVs — the dead bake"
|
|
);
|
|
let live = set.slots()[1]
|
|
.as_ref()
|
|
.unwrap_or_else(|| panic!("batch {i}: slot 1 carries the flipbook"));
|
|
let v_span = live
|
|
.keys
|
|
.iter()
|
|
.fold((f32::MAX, f32::MIN), |(lo, hi), &(_, v)| {
|
|
(lo.min(v[1]), hi.max(v[1]))
|
|
});
|
|
assert!(
|
|
v_span.1 - v_span.0 > 0.5,
|
|
"batch {i}: the V offset flips a whole sprite row (span {:?})",
|
|
v_span
|
|
);
|
|
}
|
|
|
|
assert!(
|
|
subs.iter().all(|s| s.uv_anim.is_none()),
|
|
"the slot-0 bake yields nothing on any batch — read alone, the sprite freezes"
|
|
);
|
|
}
|