Files
kiln/kiln-core/src/object_def.rs
T

102 lines
4.5 KiB
Rust
Raw Normal View History

2026-06-07 00:19:53 -05:00
use crate::glyph::Glyph;
2026-06-07 01:26:18 -05:00
use crate::utils::ObjectId;
2026-06-15 23:35:18 -05:00
use color::Rgba8;
use std::collections::HashSet;
2026-06-07 00:19:53 -05:00
/// A scripted object placed on the board, loaded from a map file.
///
/// `ObjectDef` represents a tile that has Rhai script attached to it.
/// Scripts can respond to events like the player touching or shooting the
/// 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 run with independent Rhai scopes (see [`crate::script`]).
///
/// Scripts are executed by [`crate::script::ScriptHost`]: an object's optional
/// `init()` and `tick(dt)` functions are called via [`GameState::run_init`] and
/// [`GameState::tick`]. Other event hooks (touch, shoot, …) are future work.
pub struct ObjectDef {
2026-06-07 01:26:18 -05:00
/// Stable identity assigned by [`crate::board::Board::add_object`].
/// `0` is the sentinel meaning "not yet inserted into a board".
/// Real ids start at 1 and never change after assignment.
/// Not serialized — the id is stamped on insert, not stored in map files.
pub id: ObjectId,
2026-06-07 00:19:53 -05:00
/// Column of this object on the board (0-indexed).
pub x: usize,
/// Row of this object on the board (0-indexed).
pub y: usize,
2026-06-15 23:35:18 -05:00
/// Index of the layer this object belongs to (0 = bottom). Determines its
/// draw order: objects on higher layers render above lower-layer terrain and
/// objects. Set at load from the layer the object's palette char appeared in.
pub z: usize,
2026-06-07 00:19:53 -05:00
/// 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 / participates in movement. A solid object stops
/// a mover walking into it; at most one solid (object or grid archetype) may
/// occupy a cell. Inverse of the old `passable` flag.
pub solid: bool,
/// Whether the object blocks line of sight / FOV for the player
pub opaque: bool,
/// Whether the object can be shoved by a mover. Unused for now (no push
/// mechanic yet); defaults to `false`.
pub pushable: 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>,
2026-06-16 14:34:42 -05:00
/// Embedded built-in script source, set when a script-backed archetype (e.g. a
/// `pusher_*`) is expanded into an object at load time (see
/// [`crate::builtin_scripts`]). Takes precedence over [`script_name`](ObjectDef::script_name)
/// and is not part of the map file (it is regenerated from the archetype on load).
pub builtin_script: Option<&'static str>,
2026-06-07 01:26:18 -05:00
/// Open-ended string labels for this object. Serialized as a TOML array;
/// not subject to any rate limit — mutations take effect immediately after
/// the frame's action queue is drained.
pub tags: HashSet<String>,
2026-06-08 19:50:43 -05:00
/// Optional unique human-readable name for this object. `None` if unnamed.
/// Names are validated for uniqueness at map-load time; a duplicate name is
/// cleared to `None` (the object survives but becomes anonymous).
pub name: Option<String>,
2026-06-07 00:19:53 -05:00
}
impl ObjectDef {
/// Returns the default glyph for a newly placed object: tile 63 (`?`) in yellow on black.
#[rustfmt::skip]
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 },
}
}
/// Creates a new object at `(x, y)` with default glyph and blocking behavior.
///
/// Defaults: `solid = true`, `opaque = true`, `pushable = false`, no script.
/// These match the serde defaults in the map file format so new objects
/// round-trip correctly.
pub fn new(x: usize, y: usize) -> Self {
Self {
2026-06-07 01:26:18 -05:00
id: 0,
2026-06-07 00:19:53 -05:00
x,
y,
2026-06-15 23:35:18 -05:00
z: 0,
2026-06-07 00:19:53 -05:00
glyph: Self::default_glyph(),
solid: true,
opaque: true,
pushable: false,
script_name: None,
2026-06-16 14:34:42 -05:00
builtin_script: None,
2026-06-07 01:26:18 -05:00
tags: HashSet::new(),
2026-06-08 19:50:43 -05:00
name: None,
2026-06-07 00:19:53 -05:00
}
}
2026-06-15 23:35:18 -05:00
}