fix(ui): render armed record 148 item region

Record 148 publishes player item 20 and refreshes word-quad 20 through overlay
A. Its recovered bounds are (9,14)-(25,30). Rust tracked the armed special hole
but never rendered this visible 17x17 table state.

Expose the armed/active special-hole state and composite the exact DAT997 region
until the special respawn consumes record 148's contact. Make the deterministic
effect-seven scenario internally valid by seeding the required contact, so its
framebuffer now covers both the DAT407 effect and item 20.

Test Plan:
- `cargo test --workspace --all-targets --all-features` -- 120 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed
- `rumdl check --flavor commonmark RECONSTRUCTION.md CHANGELOG.md` -- passed
- `cargo run -- --simulate effect-7 --step 0 --screenshot /tmp/tdkpin-effect7-special.png` -- passed; visually inspected at 640x460
- launcher/effect screenshot comparison -- 136 RGB pixels differ inside only the expected 17x17 item region
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-23 20:09:55 +02:00
parent 8d436b8a4b
commit ac254f9e45
4 changed files with 19 additions and 2 deletions
+13
View File
@@ -446,6 +446,10 @@ impl Game {
pub(crate) fn begin_effect_scenario(&mut self, effect: u8) {
self.target_effect = effect.min(7);
self.object_active[usize::from(EFFECT_SENSOR.id)] = self.target_effect != 0;
if self.target_effect == 7 {
self.multiball_state = MultiballState::Ready;
self.record_contacts[148] = 2;
}
}
fn fire_launcher(&mut self) {
@@ -1937,6 +1941,13 @@ impl Game {
self.object_active[usize::from(EFFECT_SENSOR.id)]
}
pub fn special_hole_active(&self) -> bool {
matches!(
self.multiball_state,
MultiballState::Ready | MultiballState::Active
)
}
pub fn player_effect(&self) -> u8 {
self.target_effect.min(7)
}
@@ -2794,6 +2805,7 @@ mod tests {
.secondary_ball
.expect("effect seven should spawn a second ball");
assert_eq!(game.multiball_state, MultiballState::Active);
assert!(game.special_hole_active());
assert_eq!(spawned.position, vec2(17.0, 23.0));
assert_eq!(
MilliVec::from_velocity_per_second(spawned.velocity),
@@ -2822,6 +2834,7 @@ mod tests {
MilliVec { x: 0, y: 3_040 }
);
assert_eq!(game.multiball_state, MultiballState::Unavailable);
assert!(!game.special_hole_active());
assert_eq!(game.record_contacts[148], 0);
assert_eq!(game.special_hole_gate, SpecialHoleGate::Suppressed);