Files
systemic-game-design-course/course/09-turn-pipeline/reference/rust/src/engine/death.rs
T
Lucas WintherandClaude Fable 5.2 429137a6ef fix(reference): Death Events remember a right-hand neighbour, not a board index
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>
2026-11-11 09:15:48 +01:00

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))
}