Move passable and opaque into objectdef
This commit is contained in:
+27
-19
@@ -72,7 +72,7 @@ pub struct FontSpec {
|
||||
///
|
||||
/// For scripted objects (`Archetype::Object`), the behavior will eventually be
|
||||
/// determined by the Rhai script rather than this struct. See the Object variant
|
||||
/// for details.
|
||||
/// for details. (TODO fix this comment)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Behavior {
|
||||
/// Whether an entity can walk through this cell.
|
||||
@@ -104,8 +104,6 @@ pub enum Archetype {
|
||||
Empty,
|
||||
/// A solid wall; impassable and opaque.
|
||||
Wall,
|
||||
/// A scripted object. Behavior defaults to impassable until script-driven.
|
||||
Object,
|
||||
/// Sentinel for map files that reference an unknown archetype name.
|
||||
/// Renders as a yellow `?` on red to make the error visible in-game.
|
||||
ErrorBlock,
|
||||
@@ -125,10 +123,6 @@ impl Archetype {
|
||||
passable: false,
|
||||
opaque: true,
|
||||
},
|
||||
Archetype::Object => Behavior {
|
||||
passable: false,
|
||||
opaque: false,
|
||||
},
|
||||
Archetype::ErrorBlock => Behavior {
|
||||
passable: false,
|
||||
opaque: true,
|
||||
@@ -141,7 +135,6 @@ impl Archetype {
|
||||
match self {
|
||||
Archetype::Empty => "empty",
|
||||
Archetype::Wall => "wall",
|
||||
Archetype::Object => "object",
|
||||
Archetype::ErrorBlock => "error_block",
|
||||
}
|
||||
}
|
||||
@@ -162,11 +155,6 @@ impl Archetype {
|
||||
fg: Rgba8 { r: 0x80, g: 0x80, b: 0x80, a: 255 },
|
||||
bg: Rgba8 { r: 0x60, g: 0x60, b: 0x60, a: 255 },
|
||||
},
|
||||
Archetype::Object => Glyph {
|
||||
tile: 63,
|
||||
fg: Rgba8 { r: 255, g: 255, b: 0, a: 255 }, // yellow
|
||||
bg: Rgba8 { r: 0, g: 0, b: 0, a: 255 },
|
||||
},
|
||||
// Visually distinct so malformed map files are immediately obvious.
|
||||
Archetype::ErrorBlock => Glyph {
|
||||
tile: 63,
|
||||
@@ -199,7 +187,7 @@ impl TryFrom<&str> for Archetype {
|
||||
///
|
||||
/// `ErrorBlock` is excluded — it is a sentinel for load errors, not a valid
|
||||
/// editing choice.
|
||||
pub const ALL_ARCHETYPES: &[Archetype] = &[Archetype::Empty, Archetype::Wall, Archetype::Object];
|
||||
pub const ALL_ARCHETYPES: &[Archetype] = &[Archetype::Empty, Archetype::Wall];
|
||||
|
||||
/// A scripted object placed on the board, loaded from a map file.
|
||||
///
|
||||
@@ -228,11 +216,25 @@ pub struct ObjectDef {
|
||||
/// 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,
|
||||
/// Whether the object blocks movement, of players or other objects
|
||||
pub passable: bool,
|
||||
/// Whether the object blocks line of sight / FOV for the player
|
||||
pub opaque: bool,
|
||||
/// Name of the Rhai script in [`Board::scripts`] that drives this object.
|
||||
/// `None` means this object has no script yet.
|
||||
pub script_name: Option<String>,
|
||||
}
|
||||
|
||||
impl ObjectDef {
|
||||
pub fn default_glyph() -> Glyph {
|
||||
Glyph {
|
||||
tile: 63,
|
||||
fg: Rgba8 { r: 255, g: 255, b: 0, a: 255 }, // yellow
|
||||
bg: Rgba8 { r: 0, g: 0, b: 0, a: 255 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A portal that teleports the player to a named entry point on another board.
|
||||
///
|
||||
/// Portals are loaded from `[[portals]]` entries in `.toml` map files and
|
||||
@@ -345,17 +347,23 @@ impl Board {
|
||||
/// 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 {
|
||||
// An object on this cell always blocks (until scripting overrides this).
|
||||
if self.object_at(x, y).is_some() {
|
||||
return false;
|
||||
// An object on this cell blocks if it's unpassable
|
||||
if let Some(obj) = self.object_at(x, y) && !obj.passable {
|
||||
false
|
||||
} else {
|
||||
self.get(x, y).1.behavior().passable
|
||||
}
|
||||
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> {
|
||||
pub fn object_index_at(&self, x: usize, y: usize) -> Option<usize> {
|
||||
self.objects.iter().position(|o| o.x == x && o.y == y)
|
||||
}
|
||||
|
||||
/// Returns a borrow of the actual object at `(x, y)` if any
|
||||
pub fn object_at(&self, x: usize, y: usize) -> Option<&ObjectDef> {
|
||||
self.object_index_at(x, y).map(|idx| &self.objects[idx])
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the active game board and provides game-logic operations.
|
||||
|
||||
@@ -138,11 +138,19 @@ pub(crate) struct MapFileObjectEntry {
|
||||
fg: String,
|
||||
/// Background color as an `"#RRGGBB"` hex string.
|
||||
bg: String,
|
||||
/// Whether the object blocks player / object movement
|
||||
#[serde(default)]
|
||||
passable: bool,
|
||||
/// Whether the object blocks player line of sight / FOV
|
||||
#[serde(default = "default_true")]
|
||||
opaque: bool,
|
||||
/// Name of the Rhai script in the `[scripts]` table, if any.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
script_name: Option<String>,
|
||||
}
|
||||
|
||||
fn default_true() -> bool { true }
|
||||
|
||||
/// Parses an `"#RRGGBB"` hex color string into an [`Rgba8`].
|
||||
/// Returns opaque black on any parse failure.
|
||||
fn parse_color(hex: &str) -> Rgba8 {
|
||||
@@ -256,6 +264,8 @@ impl TryFrom<MapFile> for Board {
|
||||
fg: parse_color(&e.fg),
|
||||
bg: parse_color(&e.bg),
|
||||
},
|
||||
passable: e.passable,
|
||||
opaque: e.opaque,
|
||||
script_name: e.script_name,
|
||||
})
|
||||
.collect();
|
||||
@@ -365,6 +375,8 @@ impl From<&Board> for MapFile {
|
||||
tile: TileIndex::Num(o.glyph.tile),
|
||||
fg: color_to_hex(o.glyph.fg),
|
||||
bg: color_to_hex(o.glyph.bg),
|
||||
passable: o.passable,
|
||||
opaque: o.opaque,
|
||||
script_name: o.script_name.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Reference in New Issue
Block a user