bug with objects moving

This commit is contained in:
2026-07-25 12:31:13 -05:00
parent a80155188f
commit ed219d74e5
3 changed files with 92 additions and 2 deletions
+86 -1
View File
@@ -396,6 +396,33 @@ impl Board {
.collect()
}
/// Tries to walk the object in x,y in the given direction. Pushes the cell in that direction
/// first. This won't move anything if:
/// - the cell x,y is empty; no-op
/// - x,y is out of bounds, no-op
/// - the target cell can't be pushed in that direction, either because it's `Block` or
/// something in its chain is
pub fn move_object(&mut self, x: usize, y: usize, dir: Direction) {
// Is this even a cell?
if self.in_bounds((x as i64, y as i64)) {
// Is there anything in this cell?
if self.get(x, y).is_some() {
let (tx, ty) = dir.from_point(x as i64, y as i64);
// Is the _target_ in bounds?
if self.in_bounds((tx, ty)) {
// Attempt to push the target out of the way
self.push(tx as usize, ty as usize, dir);
// Is the cell now empty?
if self.get(tx as usize, ty as usize).is_none() {
// Then finally, move the thing:
let thing = self.grid[x + y * self.width].take();
self.grid[tx as usize + ty as usize * self.width] = thing;
}
}
}
}
}
/// Moves the single solid occupant of `(x, y)` one step by `(dx, dy)`.
///
/// A solid object is relocated; otherwise the solid terrain archetype (a crate)
@@ -636,7 +663,11 @@ pub(crate) mod tests {
use crate::utils::{Direction, ObjectId};
use color::Rgba8;
use std::collections::HashMap;
use crate::tile::{DrawLayer, IntoTile, Optics, ScriptAttributes, Sensor, SensorSpec, Tile, TileSpec};
use crate::object_def::ObjectDef;
use crate::tile::{
DrawLayer, EnterResponse, IntoTile, Optics, ScriptAttributes, Sensor, SensorSpec, Tile,
TileSpec,
};
/// Builds an all-empty `w×h` board.
///
@@ -704,6 +735,60 @@ pub(crate) mod tests {
id
}
/// Stamps a scripted object at `(x, y)` running the world script named `script`,
/// answering entry attempts with `enter`, and returns its id.
///
/// The on-grid counterpart to [`sensor_at`]: this object occupies its cell and
/// takes part in collision, so `enter` decides how it responds to something
/// moving into it (`Block` for an ordinary solid, `Push(..)` for a shovable one).
pub(crate) fn object_at(
board: &mut Board,
x: usize,
y: usize,
script: &str,
enter: EnterResponse,
) -> ObjectId {
let tile = TileSpec::Object {
script: Some(script.to_string()),
enter,
glyph: ObjectDef::default_glyph(),
optics: Optics { opaque: true, glow: 0 },
name: None,
tags: Vec::new(),
}
.into_tile(&mut board.next_object_id)
.expect("an object spec always resolves");
let id = match &tile {
Tile::Object(obj) => obj.scripting.id,
Tile::Player => unreachable!("an object spec never resolves to the player"),
};
*board.get_mut(x, y) = Some(tile);
id
}
/// Stamps a solid object at `(x, y)` with **no script attached**, returning its id.
///
/// For exercising the "an object without a script is inert" path; everything
/// else should use [`object_at`].
pub(crate) fn plain_object_at(board: &mut Board, x: usize, y: usize) -> ObjectId {
let tile = TileSpec::Object {
script: None,
enter: EnterResponse::Block,
glyph: ObjectDef::default_glyph(),
optics: Optics { opaque: true, glow: 0 },
name: None,
tags: Vec::new(),
}
.into_tile(&mut board.next_object_id)
.expect("an object spec always resolves");
let id = match &tile {
Tile::Object(obj) => obj.scripting.id,
Tile::Player => unreachable!("an object spec never resolves to the player"),
};
*board.get_mut(x, y) = Some(tile);
id
}
/// Adds an invisible, script-only [`Sensor`] at `(x, y)` running the world script
/// named `script`, returning its id.
///