object tags

This commit is contained in:
2026-06-07 01:26:18 -05:00
parent 9c2212520c
commit a8d2cb8303
8 changed files with 240 additions and 6 deletions
+59 -4
View File
@@ -51,6 +51,9 @@ pub enum Action {
SetTile(u32),
/// Append a plain (uncolored) line to the game log.
Log(LogLine),
/// Add (`present = true`) or remove (`present = false`) `tag` on `target`.
/// Zero-cost; applied by [`crate::game::GameState`] after the action batch.
SetTag { target: ObjectId, tag: String, present: bool },
}
impl Action {
@@ -61,7 +64,7 @@ impl Action {
pub fn time_cost(&self) -> f64 {
match self {
Action::Move(_) => MOVE_COST,
Action::SetTile(_) | Action::Log(_) => 0.0,
Action::SetTile(_) | Action::Log(_) | Action::SetTag { .. } => 0.0,
}
}
}
@@ -238,7 +241,7 @@ impl ScriptHost {
objects.push(ObjectRuntime {
object_id: id,
script_name: name.clone(),
scope: new_object_scope(board_cell, &queue),
scope: new_object_scope(board_cell, &queue, id),
output_queue: queue,
ready_timer: 0.0,
});
@@ -422,6 +425,38 @@ fn register_read_api(engine: &mut Engine, board: &BoardRef, board_queue: &BoardQ
engine.register_fn("blocked", move |ctx: NativeCallContext, dir: Direction| {
is_blocked(&b, &bq, source_of(&ctx), dir)
});
// has_tag(s) -> bool: does the calling object have this tag?
let b = board.clone();
engine.register_fn("has_tag", move |ctx: NativeCallContext, tag: ImmutableString| {
let src = source_of(&ctx);
b.borrow().objects.get(&src).map_or(false, |o| o.tags.contains(tag.as_str()))
});
// get_tags() -> Array of strings: the calling object's current tag set.
let b = board.clone();
engine.register_fn("get_tags", move |ctx: NativeCallContext| -> rhai::Array {
let src = source_of(&ctx);
b.borrow()
.objects
.get(&src)
.map(|o| o.tags.iter().map(|t| rhai::Dynamic::from(t.clone())).collect())
.unwrap_or_default()
});
// objects_with_tag(s) -> Array of i64: ids of all objects carrying the tag.
let b = board.clone();
engine.register_fn(
"objects_with_tag",
move |_ctx: NativeCallContext, tag: ImmutableString| -> rhai::Array {
b.borrow()
.objects
.iter()
.filter(|(_, o)| o.tags.contains(tag.as_str()))
.map(|(&id, _)| rhai::Dynamic::from(id as i64))
.collect()
},
);
}
/// Whether the object at `source` would bump something by moving in `dir`.
@@ -489,6 +524,24 @@ fn register_write_api(engine: &mut Engine, queues: &QueueMap) {
);
},
);
// set_tag(target_id, tag, present): add (true) or remove (false) a tag on any object.
// Use MY_ID as target_id to mutate the calling object's own tags.
let q = queues.clone();
engine.register_fn(
"set_tag",
move |ctx: NativeCallContext, target: i64, tag: ImmutableString, present: bool| {
emit(
&q,
source_of(&ctx),
Action::SetTag {
target: target as ObjectId,
tag: tag.to_string(),
present,
},
);
},
);
}
/// Registers the `Queue` object: a handle to an object's output queue with `length()`
@@ -519,8 +572,9 @@ fn source_of(ctx: &NativeCallContext) -> ObjectId {
}
/// Builds a fresh per-object scope, seeded with the read-only `Board` view, this
/// object's `Queue`, and the four direction constants (`North`/`South`/`East`/`West`).
fn new_object_scope(board: &BoardRef, queue: &ObjQueue) -> Scope<'static> {
/// object's `Queue`, the four direction constants, and `MY_ID` (the object's own
/// stable [`ObjectId`] as `i64`, for use with `set_tag` and similar calls).
fn new_object_scope(board: &BoardRef, queue: &ObjQueue, object_id: ObjectId) -> Scope<'static> {
let mut scope = Scope::new();
scope.push_constant("Board", board.clone());
scope.push_constant("Queue", queue.clone());
@@ -528,5 +582,6 @@ fn new_object_scope(board: &BoardRef, queue: &ObjQueue) -> Scope<'static> {
scope.push_constant("South", Direction::South);
scope.push_constant("East", Direction::East);
scope.push_constant("West", Direction::West);
scope.push_constant("MY_ID", object_id as i64);
scope
}