From 1a4d894336f66ee6268ea3cf02a644fc1b83659f Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Tue, 11 Aug 2026 01:33:15 -0500 Subject: [PATCH] wip 4 remove enterresponse --- kiln-core/src/board.rs | 12 +++--- kiln-core/src/builtin.rs | 31 +++++++------ kiln-core/src/game.rs | 6 +-- kiln-core/src/object_def.rs | 10 ++--- kiln-core/src/tile.rs | 86 ++++--------------------------------- maps/start.toml | 14 +++--- 6 files changed, 43 insertions(+), 116 deletions(-) diff --git a/kiln-core/src/board.rs b/kiln-core/src/board.rs index 7ae2231..c9490cd 100644 --- a/kiln-core/src/board.rs +++ b/kiln-core/src/board.rs @@ -6,7 +6,7 @@ use crate::utils::{Direction, Point}; use crate::utils::{ObjectId, RegistryValue}; use std::collections::{HashMap, HashSet}; use crate::portal::Portal; -use crate::tile::{DrawLayer, EnterResponse, Hookable, IntoTile, LocatedObject, ScriptAttributes, Sensor, Tile, TileSpec}; +use crate::tile::{DrawLayer, Hookable, IntoTile, LocatedObject, ScriptAttributes, Sensor, Tile, TileSpec}; /// The complete state of one game board (a single room or screen). /// @@ -502,7 +502,7 @@ pub(crate) mod tests { use std::collections::HashMap; use crate::object_def::ObjectDef; use crate::tile::{ - DrawLayer, EnterResponse, IntoTile, Optics, ScriptAttributes, Sensor, SensorSpec, Tile, + DrawLayer, IntoTile, Optics, ScriptAttributes, Sensor, SensorSpec, Tile, TileSpec, }; @@ -583,11 +583,11 @@ pub(crate) mod tests { x: usize, y: usize, script: &str, - enter: EnterResponse, + mobile: bool, ) -> ObjectId { let tile = TileSpec::Object { script: Some(script.to_string()), - enter, + mobile, glyph: ObjectDef::default_glyph(), optics: Optics { opaque: true, glow: 0 }, name: None, @@ -612,11 +612,11 @@ pub(crate) mod tests { board: &mut Board, x: usize, y: usize, - enter: EnterResponse, + mobile: bool, ) -> ObjectId { let tile = TileSpec::Object { script: None, - enter, + mobile, glyph: ObjectDef::default_glyph(), optics: Optics { opaque: true, glow: 0 }, name: None, diff --git a/kiln-core/src/builtin.rs b/kiln-core/src/builtin.rs index 45f17dc..14c27f9 100644 --- a/kiln-core/src/builtin.rs +++ b/kiln-core/src/builtin.rs @@ -5,7 +5,7 @@ use color::Rgba8; use lazy_static::lazy_static; use crate::keys::KeyType; use serde::{Serialize, Deserialize}; -use crate::tile::{EnterResponse, Optics, ScriptKey}; +use crate::tile::{Optics, ScriptKey}; /// Declares the set of script-backed archetype families. /// @@ -27,7 +27,7 @@ macro_rules! builtins { ( $( $variant:ident => [ $( $name:literal => $glyph:expr ),+ $(,)? ] { - enter: $enter:expr, + mobile: $mobile:expr, optics: $optics:expr, script: $script:expr $(,)? } @@ -63,10 +63,10 @@ macro_rules! builtins { } } - /// Returns the uniform enter response shared by all aliases in this family. - pub fn enter_response(self) -> EnterResponse { + /// Returns the uniform mobility flag shared by all aliases in this family. + pub fn mobile(self) -> bool { match self { - $( Builtin::$variant => $enter, )+ + $( Builtin::$variant => $mobile, )+ } } @@ -112,12 +112,12 @@ const fn g(tile: char, r: u8, gr: u8, b: u8) -> Glyph { builtins! { Gem => ["gem" => g('♦', 0x50, 0x50, 0xFF)] { - enter: EnterResponse::Block, + mobile: true, optics: Optics { opaque: false, glow: 0 }, script: ScriptKey::Builtin("gem"), }, Heart => ["heart" => g('♡', 0xCC, 0x22, 0x22)] { - enter: EnterResponse::Block, + mobile: true, optics: Optics { opaque: false, glow: 0 }, script: ScriptKey::Builtin("heart"), }, @@ -127,7 +127,7 @@ builtins! { "pusher_east" => g('►', 0xAA, 0xAA, 0xAA), "pusher_west" => g('◄', 0xAA, 0xAA, 0xAA), ] { - enter: EnterResponse::Block, + mobile: true, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::Builtin("pusher"), }, @@ -135,7 +135,7 @@ builtins! { "spinner_cw" => g('/', 0xAA, 0xAA, 0xAA), "spinner_ccw" => g('\\', 0xAA, 0xAA, 0xAA), ] { - enter: EnterResponse::Block, + mobile: false, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::Builtin("spinner"), }, @@ -147,7 +147,7 @@ builtins! { "transporter_east" => g(')', 0x55, 0xFF, 0xFF), // ')' "transporter_west" => g('(', 0x55, 0xFF, 0xFF), // '(' ] { - enter: EnterResponse::Block, + mobile: false, optics: Optics { opaque: false, glow: 0 }, script: ScriptKey::Builtin("transporter"), }, @@ -161,7 +161,7 @@ builtins! { "key_yellow" => KeyType::Yellow.glyph(), "key_white" => KeyType::White.glyph(), ] { - enter: EnterResponse::Grab, + mobile: true, optics: Optics { opaque: false, glow: 0 }, script: ScriptKey::Builtin("key"), }, @@ -169,23 +169,22 @@ builtins! { tile: '#', fg: Rgba8 { r: 0x80, g: 0x80, b: 0x80, a: 255 }, bg: Rgba8 { r: 0x60, g: 0x60, b: 0x60, a: 255 }}] { - enter: EnterResponse::Block, + mobile: false, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::None }, Crate => ["crate" => g('■', 0xaa, 0xaa, 0xaa)] { // CP437 ■ (small filled square) - //enter: EnterResponse::Push(Pushable::Any), - enter: EnterResponse::Block, + mobile: true, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::Builtin("crate") }, HCrate => ["hcrate" => g('↔', 0xaa, 0xaa, 0xaa)] { // CP437 ↔ (left-right arrow) — pushable east/west - enter: EnterResponse::Push(Pushable::Horizontal), + mobile: true, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::Builtin("hcrate") }, VCrate => ["vcrate" => g('↕', 0xaa, 0xaa, 0xaa)] { // CP437 ↕ (up-down arrow) — pushable north/south - enter: EnterResponse::Push(Pushable::Vertical), + mobile: true, optics: Optics { opaque: true, glow: 0 }, script: ScriptKey::Builtin("vcrate") }, diff --git a/kiln-core/src/game.rs b/kiln-core/src/game.rs index 1402295..65462c2 100644 --- a/kiln-core/src/game.rs +++ b/kiln-core/src/game.rs @@ -2,11 +2,9 @@ use crate::action::{apply_shift, apply_teleport, Action, BoardAction, SendArg}; use crate::board::Board; use crate::log::LogLine; use crate::script::ScriptHost; -use crate::utils::{Direction, ObjectId, Point, Pushable}; +use crate::utils::{Direction, ObjectId, Point}; use crate::world::World; use std::cell::{Ref, RefMut}; -use std::collections::{BTreeSet, HashSet, VecDeque}; -use std::fmt::format; use std::hash::Hash; use std::time::Duration; @@ -18,7 +16,7 @@ pub const SAY_DURATION: f64 = 3.0; pub use crate::action::ScrollLine; use crate::player::{Player, PlayerRef}; use crate::portal::Portal; -use crate::tile::{EnterResponse, Tile}; +use crate::tile::Tile; /// An active scroll overlay opened by a scripted object via `scroll()`. /// diff --git a/kiln-core/src/object_def.rs b/kiln-core/src/object_def.rs index b82f87f..5aac364 100644 --- a/kiln-core/src/object_def.rs +++ b/kiln-core/src/object_def.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Formatter}; use crate::glyph::Glyph; use color::Rgba8; -use crate::tile::{EnterResponse, Optics, ScriptAttributes}; +use crate::tile::{Optics, ScriptAttributes}; /// A scripted object placed on the board, loaded from a map file. /// @@ -24,8 +24,8 @@ use crate::tile::{EnterResponse, Optics, ScriptAttributes}; /// [`GameState::tick`]. Other event hooks (touch, shoot, …) are future work. #[derive(Clone)] pub struct ObjectDef { - /// How this object affects movement - pub enter_response: EnterResponse, + /// Can this be moved _by other objects_ + pub mobile: bool, /// Everything we need to run our script pub scripting: ScriptAttributes, } @@ -49,12 +49,12 @@ impl ObjectDef { /// Creates a new object with default glyph and blocking behavior. /// - /// Defaults: block on enter, opaque no glow, no script + /// Defaults: non-mobile, opaque no glow, no script /// These match the serde defaults in the map file format so new objects /// round-trip correctly. pub fn new() -> Self { Self { - enter_response: EnterResponse::Block, + mobile: false, scripting: ScriptAttributes { id: 0, glyph: Self::default_glyph(), diff --git a/kiln-core/src/tile.rs b/kiln-core/src/tile.rs index edbcd69..a741631 100644 --- a/kiln-core/src/tile.rs +++ b/kiln-core/src/tile.rs @@ -1,77 +1,12 @@ use std::collections::{HashMap, HashSet}; use serde::{Deserialize, Serialize}; use crate::api::queue::ObjQueue; -use crate::{Builtin, Direction}; +use crate::Builtin; use crate::builtin::BUILTIN_SOURCES; use crate::floor::{Floor, FloorBiome}; use crate::glyph::Glyph; use crate::object_def::ObjectDef; -use crate::utils::{ObjectId, Point, Pushable}; -use crate::utils::Pushable::No; - -/// The various ways that a tile might respond to another tile trying to move on top of it -#[derive(Serialize, Deserialize, PartialEq, Copy, Clone, Debug)] -#[serde(rename_all = "lowercase")] -pub enum EnterResponse { - /// Flat denial: don't let the move happen, block it. - Block, - /// If the player moves, call the `grab` hook and then remove this object. Anything else, act as - /// `Pushable::Any`. - /// TODO will do something different once inventory exists as a concept - Grab, - /// Attempt to exit the cell ourselves, the opposite direction. This of course recurses; if our move - /// is denied then this is the same as a block. - Push(Pushable), - /// Call an `enter` hook and do something. The hook is responsible for resolving the conflict: - /// placing the moving-object somewhere else, moving ourselves somewhere else, or whatever. - /// It should return `true` or `false`: this return value is passed back up a `Push` chain to - /// the original moving object, determining whether the moves should happen. - /// Example: a teleporter moves anything that enters it to another spot, if it's unblocked. It - /// will check if the target cell is open and move the object there if it is, returning true. - /// If you push a crate into it, it returning true means you should move (into the space the crate - /// left behind); it returning false means the crate wasn't teleported so your move is blocked - /// also. - /// The hook return value is only used for _other_ things in the chain: regardless of what's returned, - /// the engine won't touch the crate or the teleporter; the hook is responsible for handling the - /// actual collision. A teleporter that teleports the crate and returns false will leave an empty - /// space behind (the player won't move into it because it returned false); a teleporter that - /// returns true without teleporting the crate, the crate will be destroyed by the player moving - /// on top of it. - Hook, - /// Swap places with whatever moved on top of you, as long as it was the player. Anything else, - /// act as `Pushable::Any`. - Swap, - /// Get overwritten and destroyed by whatever moved on top of us. Right now, equivalent to `Grab` - /// if the hook does nothing (but in the future `Grab` will have other builtin behavior) - Squish -} - -impl EnterResponse { - /// Returns whether this object will transmit a push of the given direction through it: - /// - `Push(p)`, if p allows that direction - /// - `Grab`, because grabbable things act like push if something pushes them - /// - `Swap`, same reason - pub fn transmits_push(self, dir: Direction) -> bool { - match self { - EnterResponse::Grab | EnterResponse::Swap => true, - EnterResponse::Push(p) if p.allows(dir) => true, - _ => false - } - } - - /// Returns whether this object will sense a bump from the given direction: - /// - `Push(p)`, if p disallows that direction - /// - `Block`, because nothing can move through it - /// - `Hook`, because it's obligated to handle the entry and not pass it on - /// - but nothing else - pub fn bumpable(self, dir: Direction) -> bool { - match self { - EnterResponse::Block | EnterResponse::Hook => true, - EnterResponse::Push(p) if !p.allows(dir) => true, - _ => false - } - } -} +use crate::utils::{ObjectId, Point}; /// Where `Sensor`s are drawn, in relation to the grid: /// - `Above` is above everything, including the player. If the glyph has a nonzero tile, and it's @@ -323,13 +258,7 @@ impl Tile { pub fn shiftable(&self) -> bool { match self { Tile::Player => true, // Player will shift anywhere - Tile::Object(obj) => { - match obj.enter_response { - EnterResponse::Push(p) => p != No, - EnterResponse::Hook | EnterResponse::Block => false, // Blockers never shift - EnterResponse::Grab | EnterResponse::Swap | EnterResponse::Squish => true, - } - } + Tile::Object(obj) => obj.mobile } } } @@ -342,7 +271,8 @@ pub enum TileSpec { Object { #[serde(default, skip_serializing_if = "Option::is_none")] script: Option, - enter: EnterResponse, + #[serde(default = "default_as_true")] + mobile: bool, #[serde(flatten)] glyph: Glyph, #[serde(flatten, default)] @@ -375,9 +305,9 @@ impl IntoTile for TileSpec { // }; // Ok(Tile::Portal(Box::new(def))) // } - TileSpec::Object { script, enter, glyph, optics, name, tags } => { + TileSpec::Object { script, mobile, glyph, optics, name, tags } => { let def = ObjectDef { - enter_response: enter, + mobile, scripting: ScriptAttributes { id: *next_object_id, glyph, @@ -395,7 +325,7 @@ impl IntoTile for TileSpec { TileSpec::Builtin { kind, glyph } => { if let Some((builtin, variant)) = Builtin::from_name(&kind) { let def = ObjectDef { - enter_response: builtin.enter_response(), + mobile: builtin.mobile(), scripting: ScriptAttributes { id: *next_object_id, glyph: glyph.unwrap_or(builtin.default_glyph_for(variant)), diff --git a/maps/start.toml b/maps/start.toml index bac2668..8e30a97 100644 --- a/maps/start.toml +++ b/maps/start.toml @@ -243,7 +243,7 @@ grid = """ [boards.start.palette.V] type = "object" script = "mover" -enter = "block" +mobile = false tile = 1 fg = "#33aa33" bg = "#000000" @@ -252,7 +252,7 @@ bg = "#000000" type = "object" script = "muffin" name = "muffin" -enter = "block" +mobile = true tile = 15 fg = "#ffdd88" bg = "#000000" @@ -261,7 +261,7 @@ bg = "#000000" type = "object" script = "noticeboard" name = "noticeboard" -enter = "block" +mobile = false tile = 240 fg = "#cc9944" bg = "#000000" @@ -270,7 +270,7 @@ bg = "#000000" type = "object" script = "shifter" name = "shifter" -enter = "block" +mobile = false tile = 240 fg = "#cc9944" bg = "#000000" @@ -345,7 +345,7 @@ grid = """ type = "object" script = "bookshelf" name = "bookshelf" -enter = "block" +mobile = false tile = 240 fg = "#aa7733" bg = "#3d1c00" @@ -354,7 +354,7 @@ bg = "#3d1c00" type = "object" script = "fireplace" name = "fireplace" -enter = "block" +mobile = false tile = 15 fg = "#ff8800" bg = "#220000" @@ -363,7 +363,7 @@ bg = "#220000" type = "object" script = "chest" name = "chest" -enter = "block" +mobile = true tile = 240 fg = "#ccaa44" bg = "#222200"