transporters
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// Built-in script for the `transporter_*` archetypes (see archetype.rs).
|
||||
//
|
||||
// A transporter is a solid, see-through, unpushable machine that teleports
|
||||
// whatever bumps into it from its facing side. It animates through a 4-frame
|
||||
// loop (500 ms/frame) and, on a front bump, moves the bumper either to the cell
|
||||
// just past it or — if that's blocked — out of the nearest opposite-facing
|
||||
// transporter further along its axis (skipping any whose entrance is blocked).
|
||||
//
|
||||
// The direction is not baked into this source: every transporter shares one
|
||||
// compiled copy and reads its `BUILTIN_transporter_<dir>` tag. The world is
|
||||
// reached through the global `Board`/`Player` constants; `teleport(id, x, y)`
|
||||
// moves an arbitrary entity (`-1` is the player).
|
||||
|
||||
// This transporter's facing unit vector, from its direction tag.
|
||||
fn facing(me) {
|
||||
if me.has_tag("BUILTIN_transporter_north") { [0, -1] }
|
||||
else if me.has_tag("BUILTIN_transporter_south") { [0, 1] }
|
||||
else if me.has_tag("BUILTIN_transporter_east") { [1, 0] }
|
||||
else { [-1, 0] }
|
||||
}
|
||||
|
||||
// The tag of the opposite-facing transporter this one pairs with.
|
||||
fn opposite_tag(me) {
|
||||
if me.has_tag("BUILTIN_transporter_north") { "BUILTIN_transporter_south" }
|
||||
else if me.has_tag("BUILTIN_transporter_south") { "BUILTIN_transporter_north" }
|
||||
else if me.has_tag("BUILTIN_transporter_east") { "BUILTIN_transporter_west" }
|
||||
else { "BUILTIN_transporter_east" }
|
||||
}
|
||||
|
||||
// The 4-frame animation loop for this direction (CP437 tile codes).
|
||||
fn frames(me) {
|
||||
if me.has_tag("BUILTIN_transporter_north") { [94, 45, 94, 126] } // ^ - ^ ~
|
||||
else if me.has_tag("BUILTIN_transporter_south") { [118, 95, 118, 45] } // v _ v -
|
||||
else if me.has_tag("BUILTIN_transporter_east") { [41, 124, 41, 62] } // ) | ) >
|
||||
else { [40, 124, 40, 60] } // ( | ( <
|
||||
}
|
||||
|
||||
fn tick(me, dt) {
|
||||
// Advance one animation frame every 0.5s, like the spinner: frame state lives
|
||||
// in the board Registry (script scope resets each tick), keyed per instance.
|
||||
if me.waiting { return; }
|
||||
let fs = frames(me);
|
||||
let fkey = `xport_${me.id}`;
|
||||
let f = Board.registry.get_or(fkey, 0);
|
||||
set_tile(fs[f % 4]);
|
||||
Board.registry.set(fkey, (f + 1) % 4);
|
||||
me.delay(0.15);
|
||||
}
|
||||
|
||||
fn bump(me, id) {
|
||||
let d = facing(me);
|
||||
let dx = d[0];
|
||||
let dy = d[1];
|
||||
|
||||
// Only transport things that hit us from the front — the entrance cell at
|
||||
// (me - d). A bump from any other side does nothing.
|
||||
let bx;
|
||||
let by;
|
||||
if id == -1 {
|
||||
bx = Player.x;
|
||||
by = Player.y;
|
||||
} else {
|
||||
let o = Board.get(id);
|
||||
if o == () { return; }
|
||||
bx = o.x;
|
||||
by = o.y;
|
||||
}
|
||||
if bx != me.x - dx || by != me.y - dy { return; }
|
||||
|
||||
// 1. The cell just past us (the opposite side): if nothing solid is there,
|
||||
// drop the bumper onto it.
|
||||
let fx = me.x + dx;
|
||||
let fy = me.y + dy;
|
||||
if Board.passable(fx, fy) {
|
||||
teleport(id, fx, fy); now();
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Otherwise scan along our axis for the nearest opposite-facing transporter
|
||||
// whose entrance (the cell just before it) is free, and drop the bumper
|
||||
// there. A blocked pair is skipped; give up at the board edge.
|
||||
let opp = Board.tagged(opposite_tag(me));
|
||||
let cx = fx;
|
||||
let cy = fy;
|
||||
loop {
|
||||
cx += dx;
|
||||
cy += dy;
|
||||
if cx < 0 || cy < 0 || cx >= Board.width || cy >= Board.height {
|
||||
return;
|
||||
}
|
||||
// Is one of the opposite transporters sitting at (cx, cy)?
|
||||
let here = false;
|
||||
for o in opp {
|
||||
if o.x == cx && o.y == cy { here = true; }
|
||||
}
|
||||
if here {
|
||||
let ex = cx + dx;
|
||||
let ey = cy + dy;
|
||||
if Board.passable(ex, ey) {
|
||||
teleport(id, ex, ey); now();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user