113 lines
4.5 KiB
Rust
113 lines
4.5 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use crate::archetype::Archetype;
|
|
use crate::script::Direction;
|
|
|
|
/// Which directions a solid may be pushed in.
|
|
///
|
|
/// Only meaningful for `solid` cells (a non-solid cell is passable, so nothing is
|
|
/// ever pushed into it). `Crate` is [`Pushable::Any`]; the directional crates
|
|
/// constrain pushes to one axis.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub enum Pushable {
|
|
/// Cannot be pushed.
|
|
No,
|
|
/// Pushable in any direction.
|
|
Any,
|
|
/// Pushable east/west only.
|
|
Horizontal,
|
|
/// Pushable north/south only.
|
|
Vertical,
|
|
}
|
|
|
|
impl Pushable {
|
|
/// Whether a push in `dir` is allowed.
|
|
pub fn allows(self, dir: Direction) -> bool {
|
|
match self {
|
|
Pushable::No => false,
|
|
Pushable::Any => true,
|
|
Pushable::Horizontal => matches!(dir, Direction::East | Direction::West),
|
|
Pushable::Vertical => matches!(dir, Direction::North | Direction::South),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The behavioral properties of a board cell at runtime.
|
|
///
|
|
/// `Behavior` is a plain data struct returned by [`Archetype::behavior`]. It
|
|
/// contains the properties the engine needs to simulate a cell — currently
|
|
/// solidity, opacity, and pushability. Future properties (shootable, etc.) can
|
|
/// be added here without changing call sites.
|
|
///
|
|
/// For scripted objects, solidity and opacity are stored directly on
|
|
/// [`ObjectDef`] and will eventually be overridable by Rhai scripts at runtime.
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct Behavior {
|
|
/// Whether this cell blocks / participates in movement. A solid cell stops a
|
|
/// mover (and is the only kind of cell that can later be pushed or receive a
|
|
/// collision event). This is the inverse of the old `passable` flag.
|
|
pub solid: bool,
|
|
/// Whether this cell blocks line of sight (reserved for future rendering).
|
|
pub opaque: bool,
|
|
/// Which directions a mover can shove this cell in (only meaningful when `solid`).
|
|
pub pushable: Pushable,
|
|
}
|
|
|
|
/// A stable, unique identifier for a board object.
|
|
///
|
|
/// Ids are handed out by [`Board::add_object`] from the per-board
|
|
/// [`Board::next_object_id`] counter (starting at 1) and never reused, so a
|
|
/// reference to an object stays valid even as other objects are added or removed.
|
|
/// This replaces the old "index into `Board::objects`" scheme, which shifted when
|
|
/// objects were reordered/destroyed.
|
|
pub type ObjectId = u32;
|
|
|
|
/// The single solid occupant of a board cell, returned by [`Board::solid_at`].
|
|
///
|
|
/// At most one solid — the player, a grid [`Archetype`], *or* an [`ObjectDef`] — may
|
|
/// occupy a cell (the invariant enforced at load time), so this represents the one
|
|
/// thing a mover would collide with there.
|
|
pub enum Solid {
|
|
/// The player occupies the cell. The player is solid (it blocks movers) and
|
|
/// pushable in any direction (see [`Board::is_pushable`]).
|
|
Player,
|
|
/// The cell's grid archetype is itself solid (e.g. [`Archetype::Wall`]).
|
|
Cell(Archetype),
|
|
/// A solid [`ObjectId`] occupies the cell.
|
|
Object(ObjectId),
|
|
}
|
|
|
|
/// 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
|
|
/// stored on [`Board`]. When the player steps onto a portal's cell, they
|
|
/// should be moved to `target_entry` on the board named by `target_map`.
|
|
///
|
|
/// **Not yet runtime-wired.** Portal navigation (multi-board loading and
|
|
/// switching) is a future feature.
|
|
#[derive(Deserialize, Serialize)]
|
|
pub struct PortalDef {
|
|
/// Column of this portal on the board (0-indexed).
|
|
pub x: usize,
|
|
/// Row of this portal on the board (0-indexed).
|
|
pub y: usize,
|
|
/// File name (without extension) of the target board, e.g. `"cave"`.
|
|
pub target_map: String,
|
|
/// Named entry point on the target board where the player arrives.
|
|
pub target_entry: String,
|
|
}
|
|
|
|
/// The player's current position on the board.
|
|
///
|
|
/// The player is currently a special entity rendered on top of the board
|
|
/// rather than being stored as a board cell. This is expected to change:
|
|
/// the player will eventually become a scripted object that responds to
|
|
/// input events, at which point this struct may be removed or made optional.
|
|
/// See the "player may become an object" notes in `CLAUDE.md` for the design
|
|
/// tensions this implies.
|
|
#[derive(Copy, Clone)]
|
|
pub struct Player {
|
|
/// Column position (0-indexed, increasing rightward).
|
|
pub x: i32,
|
|
/// Row position (0-indexed, increasing downward).
|
|
pub y: i32,
|
|
} |