2026-06-21 01:32:47 -05:00
|
|
|
// Rotates this object's 8 neighbours one step around a ring every 0.5s, shoving
|
|
|
|
|
// each pushable into the next ring slot via a single simultaneous `swap`. The spin
|
|
|
|
|
// direction comes from the `BUILTIN_spinner_*` tag the map loader attaches (it
|
|
|
|
|
// defaults to clockwise when no tag is present).
|
|
|
|
|
//
|
|
|
|
|
// A neighbour may only rotate if its destination slot will actually be free: the
|
|
|
|
|
// slot is a hole (`passable`), or that slot's own occupant also rotates out. We
|
|
|
|
|
// can't decide that with `can_shift` alone — `can_shift(j) == false` is ambiguous
|
|
|
|
|
// between "j is empty" and "j is a blocked solid" — so we seed with `can_shift`
|
|
|
|
|
// and then cascade-demote using `passable` to spot the genuine holes.
|
|
|
|
|
fn tick(dt) {
|
|
|
|
|
// Only start a new rotation when the previous one (and its delay) has drained,
|
|
|
|
|
// exactly like the built-in pusher's pacing.
|
|
|
|
|
if Queue.length() != 0 { return; }
|
|
|
|
|
|
|
|
|
|
// Direction from the builtin tag; clockwise unless explicitly counter-clockwise.
|
|
|
|
|
let cw = !Me.has_tag("BUILTIN_spinner_ccw");
|
|
|
|
|
|
|
|
|
|
// The 8 neighbour offsets in clockwise order, starting at North.
|
2026-06-21 22:04:10 -05:00
|
|
|
let cw_ring = [
|
|
|
|
|
[Me.x, Me.y-1], // N
|
|
|
|
|
[Me.x+1, Me.y-1], // NE
|
|
|
|
|
[Me.x+1, Me.y], // E
|
|
|
|
|
[Me.x+1, Me.y+1], // SE
|
|
|
|
|
[Me.x, Me.y+1], // S
|
|
|
|
|
[Me.x-1, Me.y+1], // SW
|
|
|
|
|
[Me.x-1, Me.y], // W
|
|
|
|
|
[Me.x-1, Me.y-1], // NW
|
2026-06-21 01:32:47 -05:00
|
|
|
];
|
|
|
|
|
|
2026-06-21 22:04:10 -05:00
|
|
|
// For CCW, it's the same list in reverse
|
|
|
|
|
let ccw_ring = [];
|
|
|
|
|
for neighbor in cw_ring {
|
|
|
|
|
ccw_ring.insert(0, neighbor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rotate the neighbor cells:
|
|
|
|
|
if cw {
|
|
|
|
|
shift(cw_ring);
|
2026-06-21 01:32:47 -05:00
|
|
|
} else {
|
2026-06-21 22:04:10 -05:00
|
|
|
shift(ccw_ring);
|
|
|
|
|
}
|
2026-06-21 01:32:47 -05:00
|
|
|
|
|
|
|
|
// Animate the glyph one frame per rotation (changing only the character): the
|
|
|
|
|
// line spins '/'-'\'-, slash-swapped for counter-clockwise. Frame state lives in
|
|
|
|
|
// the board Registry, keyed per spinner, since script scope resets each tick.
|
|
|
|
|
let frames = if cw { [47, 0xc4, 92, 0xb3] } else { [92, 0xc4, 47, 0xb3] };
|
|
|
|
|
let fkey = `spin_${Me.id}`;
|
|
|
|
|
let f = Registry.get_or(fkey, 0);
|
|
|
|
|
set_tile(frames[f % 4]);
|
|
|
|
|
Registry.set(fkey, (f + 1) % 4);
|
|
|
|
|
|
|
|
|
|
delay(0.5);
|
|
|
|
|
}
|