object layer

This commit is contained in:
2026-05-30 19:25:10 -05:00
parent 96ec8e8e92
commit d19737c113
5 changed files with 207 additions and 53 deletions
+24 -10
View File
@@ -178,7 +178,8 @@ impl TryFrom<&str> for Archetype {
match name {
"empty" => Ok(Archetype::Empty),
"wall" => Ok(Archetype::Wall),
"object" => Ok(Archetype::Object),
// "object" is intentionally absent: objects are not valid palette
// entries in map files. They live in [[objects]] with their own glyph.
_ => Err(format!("unknown archetype: {name}")),
}
}
@@ -197,22 +198,28 @@ pub const ALL_ARCHETYPES: &[Archetype] = &[Archetype::Empty, Archetype::Wall, Ar
/// tile. Objects are parsed from `[[objects]]` entries in `.toml` map files
/// and stored on [`Board`].
///
/// Objects are rendered as an overlay on top of the board grid — the grid
/// cell at `(x, y)` holds the background (floor) that is revealed if the
/// object moves away. `glyph` is owned by the object itself and may be
/// mutated by its Rhai script at runtime.
///
/// Script text lives in [`Board::scripts`]; this struct holds only the name
/// used to look it up. Two `ObjectDef`s with the same `script_name` share
/// source text but will run with independent Rhai scopes (independent local
/// variables) when the scripting runtime is wired.
/// source text but will run with independent Rhai scopes when the scripting
/// runtime is wired.
///
/// **Not yet runtime-wired.** Objects are loaded and stored but their scripts
/// are not yet executed. Scripting dispatch is a future feature.
#[derive(Deserialize, Serialize)]
pub struct ObjectDef {
/// Column of this object on the board (0-indexed).
pub x: usize,
/// Row of this object on the board (0-indexed).
pub y: usize,
/// Visual representation of this object. Owned by the object (not derived
/// from the grid cell), so scripts can change tile, fg, and bg at runtime.
pub glyph: Glyph,
/// Name of the Rhai script in [`Board::scripts`] that drives this object.
/// `None` means this object has no script yet.
#[serde(default)]
pub script_name: Option<String>,
}
@@ -316,14 +323,21 @@ impl Board {
&mut self.cells[y * self.width + x]
}
/// Returns `true` if the archetype at `(x, y)` allows entities to pass through.
/// Returns `true` if the cell at `(x, y)` allows entities to pass through.
///
/// Objects block movement before the grid cell archetype is consulted.
/// Panics if `x` or `y` are out of bounds.
pub fn is_passable(&self, x: usize, y: usize) -> bool {
let (_, arch) = self.get(x, y);
// Derive passability from the archetype's behavior.
// Object cells will need special handling here once scripts are wired.
arch.behavior().passable
// An object on this cell always blocks (until scripting overrides this).
if self.object_at(x, y).is_some() {
return false;
}
self.get(x, y).1.behavior().passable
}
/// Returns the index into [`Board::objects`] of the object at `(x, y)`, if any.
pub fn object_at(&self, x: usize, y: usize) -> Option<usize> {
self.objects.iter().position(|o| o.x == x && o.y == y)
}
}