redoing bump

This commit is contained in:
2026-07-08 13:21:27 -05:00
parent f407b5d9a6
commit e545395ac6
12 changed files with 243 additions and 90 deletions
+35
View File
@@ -252,6 +252,41 @@ impl Board {
.is_some_and(|s| s.pushable().allows(dir))
}
/// The object that a move **into** `(x, y)` heading `dir` bumps, if any.
///
/// Walks the chain of pushable crates from the target cell in `dir` until it
/// reaches something that stops it, and reports the object it presses against:
/// - a solid object in the target cell (or at the end of a crate chain) is the
/// bumped object,
/// - open space or the player means nothing is bumped,
/// - a non-pushable terrain cell (a wall) blocks the chain with no object to bump.
///
/// This is what lets *any* solid — the player, another object, or a pushed
/// crate — trigger a `bump`: the bumper need not be an object, since we only
/// return the *bumped* object's id (the direction it came from is supplied by
/// the caller from its move direction).
pub fn bump_target(&self, x: usize, y: usize, dir: Direction) -> Option<ObjectId> {
let (dx, dy): (i64, i64) = dir.into();
let (mut cx, mut cy) = (x, y);
loop {
match self.solid_at(cx, cy) {
None => return None, // open space: nothing bumped
Some(s) if s.object_id().is_some() => return s.object_id(), // hit an object
Some(s) if s.player() => return None, // the player is never "bumped"
// A terrain cell: a pushable crate is walked through; a wall stops us.
Some(_) if self.is_pushable(cx, cy, dir) => {
let next = (cx as i64 + dx, cy as i64 + dy);
if !self.in_bounds(next) {
return None; // crate chain runs off the board
}
cx = next.0 as usize;
cy = next.1 as usize;
}
Some(_) => return None, // non-pushable terrain (wall): no object behind it here
}
}
}
/// Whether the chain of pushable solids starting at `(x, y)` can be shoved one
/// step in `dir` — i.e. the chain ends at a passable cell rather than the board
/// edge or a non-pushable solid.