A Deathrattle summon used the dying minion's board index from before the Death Creation Step removed anything. That index is stale when a minion to its left dies in the same step, so the token landed one place too far right. Each Death Event now records `before`: the nearest minion to the right that is not dying in the same step. The position handed to the effect context is resolved when the trigger resolves: the current index of `before`, or the right end. Applied to the Rust and TS references of Modules 3-10. Module 3 gains two tests, documented in scenarios.md: test_03_summon_position_after_simultaneous_deaths (fails before the fix) and test_03_simultaneous_summons_keep_board_order. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
42 lines
1.7 KiB
Rust
42 lines
1.7 KiB
Rust
//! The Death Creation Step: the one place minions leave play.
|
|
//!
|
|
//! Damage and destroy effects only mark a minion (0 or less Health, or pending
|
|
//! destroy). It stays in play, and keeps triggering, until the outermost Phase
|
|
//! ends. Then this step removes every marked minion at once.
|
|
|
|
use super::event::Event;
|
|
use super::world::{EntityId, World, Zone};
|
|
|
|
/// Remove every mortally wounded or pending-destroy minion from play, simultaneously.
|
|
/// Returns their Death Events in order of play; empty if nothing died.
|
|
pub fn death_creation_step(world: &mut World) -> Vec<Event> {
|
|
// Every neighbour is read before anything moves: removal is simultaneous. Each Death
|
|
// Event remembers where its minion stood as a handle, the minion that stays to its
|
|
// right, not as a board index: an index goes stale as soon as a minion further left
|
|
// leaves play in the same step (Module 1: hold handles, not indexes).
|
|
let mut deaths = Vec::new();
|
|
for id in world.minions_in_play() {
|
|
if world.is_doomed(id) {
|
|
let before = survivor_to_the_right(world, id);
|
|
deaths.push(Event::Destroyed { id, before });
|
|
}
|
|
}
|
|
for death in &deaths {
|
|
if let Event::Destroyed { id, before } = *death {
|
|
world.kill(id, before);
|
|
}
|
|
}
|
|
deaths
|
|
}
|
|
|
|
/// The nearest minion to the right of `id` on its board that is not leaving play in this step, if any.
|
|
fn survivor_to_the_right(world: &World, id: EntityId) -> Option<EntityId> {
|
|
world
|
|
.zone(world.owner_of(id), Zone::Board)
|
|
.iter()
|
|
.copied()
|
|
.skip_while(|&other| other != id)
|
|
.skip(1)
|
|
.find(|&other| !world.is_doomed(other))
|
|
}
|