spinners and fmt
This commit is contained in:
+83
-1
@@ -36,6 +36,13 @@
|
||||
//! - `Board.named(name) -> ObjectInfo | ()` — object with that name (or unit)
|
||||
//! - `Board.get(id) -> ObjectInfo | ()` — look up by id; `-1` returns player info
|
||||
//!
|
||||
//! ## Cell queries (free fns)
|
||||
//!
|
||||
//! - `blocked(dir) -> bool` — would the caller be blocked moving one step in `dir`
|
||||
//! - `can_push(x, y, dir) -> bool` — is the pushable chain at `(x, y)` shovable in `dir`
|
||||
//! - `can_shift(x, y, dir) -> bool` — like `can_push`, but only checks the cell ahead
|
||||
//! - `passable(x, y) -> bool` — is `(x, y)` on-board and free of any solid (a hole)
|
||||
//!
|
||||
//! ## Self-reference API (`Me.*`)
|
||||
//!
|
||||
//! - `Me.id / name / x / y` — getters
|
||||
@@ -47,7 +54,8 @@
|
||||
//!
|
||||
//! `move(dir)`, `delay(secs)`, `now()`, `set_tile(n)`, `log(msg)`, `say(msg)`,
|
||||
//! `set_fg(fg)`, `set_bg(bg)`, `set_color(fg, bg)`, `set_tag(target, tag, present)`,
|
||||
//! `send(target_id, fn_name [, arg])`, `teleport(x, y)`
|
||||
//! `send(target_id, fn_name [, arg])`, `teleport(x, y)`, `push(x, y, dir)`,
|
||||
//! `swap([[src_x, src_y, dst_x, dst_y], …])`
|
||||
//!
|
||||
//! ## Queue API
|
||||
//!
|
||||
@@ -672,6 +680,32 @@ fn register_read_api(
|
||||
is_blocked(&b, &bq, source_of(&ctx), dir)
|
||||
});
|
||||
|
||||
// can_push(x, y, dir) — true if (x, y) holds a pushable whose chain can be
|
||||
// shoved one step in dir (the read-only half of push()). False off-board.
|
||||
let b = board.clone();
|
||||
engine.register_fn("can_push", move |x: i64, y: i64, dir: Direction| -> bool {
|
||||
let board = b.borrow();
|
||||
board.in_bounds((x as i32, y as i32)) && board.can_push(x as usize, y as usize, dir)
|
||||
});
|
||||
|
||||
// can_shift(x, y, dir) — like can_push but inspects only the cell ahead: (x, y)
|
||||
// holds a pushable and the next cell is empty or another pushable. False
|
||||
// off-board. The right gate for a simultaneous shift/rotation via swap().
|
||||
let b = board.clone();
|
||||
engine.register_fn("can_shift", move |x: i64, y: i64, dir: Direction| -> bool {
|
||||
let board = b.borrow();
|
||||
board.in_bounds((x as i32, y as i32)) && board.can_shift(x as usize, y as usize, dir)
|
||||
});
|
||||
|
||||
// passable(x, y) — true if (x, y) is on-board and holds no solid (an empty cell
|
||||
// a mover could enter). Off-board is not passable. Lets a script distinguish a
|
||||
// hole from a blocked solid (which can_shift/can_push alone cannot).
|
||||
let b = board.clone();
|
||||
engine.register_fn("passable", move |x: i64, y: i64| -> bool {
|
||||
let board = b.borrow();
|
||||
board.in_bounds((x as i32, y as i32)) && board.is_passable(x as usize, y as usize)
|
||||
});
|
||||
|
||||
// Board.tagged(tag) -> Array[ObjectInfo]
|
||||
let b = board.clone();
|
||||
engine.register_fn(
|
||||
@@ -983,6 +1017,54 @@ fn register_write_api(engine: &mut Engine, queues: &QueueMap) {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// push(x, y, dir): shove the pushable chain at (x, y) one step in dir. Acts on
|
||||
// arbitrary cells, not the caller, and adds no delay (zero time cost).
|
||||
let q = queues.clone();
|
||||
engine.register_fn(
|
||||
"push",
|
||||
move |ctx: NativeCallContext, x: i64, y: i64, dir: Direction| {
|
||||
emit(
|
||||
&q,
|
||||
source_of(&ctx),
|
||||
Action::Push {
|
||||
x: x as i32,
|
||||
y: y as i32,
|
||||
dir,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// swap(pairs): apply a batch of one-way solid moves simultaneously. `pairs` is
|
||||
// an array whose elements are four-int arrays `[src_x, src_y, dst_x, dst_y]`. A
|
||||
// malformed entry is skipped with a logged error. Zero time cost.
|
||||
let q = queues.clone();
|
||||
engine.register_fn("swap", move |ctx: NativeCallContext, arr: Array| {
|
||||
let src = source_of(&ctx);
|
||||
let mut pairs: Vec<(i32, i32, i32, i32)> = Vec::new();
|
||||
for elem in &arr {
|
||||
// Each entry must be an array of exactly four integers.
|
||||
let coords: Option<Vec<i64>> = elem.read_lock::<Array>().and_then(|inner| {
|
||||
if inner.len() == 4 {
|
||||
inner.iter().map(|v| v.as_int().ok()).collect()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
match coords {
|
||||
Some(c) => pairs.push((c[0] as i32, c[1] as i32, c[2] as i32, c[3] as i32)),
|
||||
None => emit(
|
||||
&q,
|
||||
src,
|
||||
Action::Log(LogLine::error(
|
||||
"swap: each entry must be [src_x, src_y, dst_x, dst_y]".to_string(),
|
||||
)),
|
||||
),
|
||||
}
|
||||
}
|
||||
emit(&q, src, Action::Swap(pairs));
|
||||
});
|
||||
}
|
||||
|
||||
// ── Queue API ─────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user