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() .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)`. /// 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) /// 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 crate::utils::{Direction, ObjectId};
use color::Rgba8; use color::Rgba8;
use std::collections::HashMap; 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. /// Builds an all-empty `w×h` board.
/// ///
@@ -704,6 +735,60 @@ pub(crate) mod tests {
id 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 /// Adds an invisible, script-only [`Sensor`] at `(x, y)` running the world script
/// named `script`, returning its id. /// named `script`, returning its id.
/// ///
+1 -1
View File
@@ -553,7 +553,7 @@ fn step_object(board: &mut Board, id: ObjectId, dir: Direction) {
if solid { if solid {
// This is a real object on the board, try and push it // This is a real object on the board, try and push it
board.push(loc.0, loc.1, dir); board.move_object(loc.0, loc.1, dir);
} else { } else {
// This is a sensor, we can just teleport it // This is a sensor, we can just teleport it
board.move_sensor(id, dir); board.move_sensor(id, dir);
+5
View File
@@ -118,6 +118,11 @@ impl Direction {
Some(if dy > 0 { Direction::South } else { Direction::North }) Some(if dy > 0 { Direction::South } else { Direction::North })
} }
} }
/// Translate the given point in this direction
pub fn from_point(self, x: i64, y: i64) -> (i64, i64) {
(x as i64 + self.dx(), y as i64 + self.dy())
}
} }
/// A value that can be stored in a board's script registry across board transitions. /// A value that can be stored in a board's script registry across board transitions.