Split teleporting into its own pass, like Lynx

This commit is contained in:
Eevee (Evelyn Woods) 2020-12-13 02:23:14 -07:00
parent 93954135d2
commit 0f5b8098f6

View File

@ -587,6 +587,19 @@ export class Level {
} }
} }
} }
// Mini extra pass: deal with teleporting separately. Otherwise, actors may have been in
// the way of the teleporter but finished moving away during the above loop; this is
// particularly bad when it happens with a block you're pushing.
for (let i = this.actors.length - 1; i >= 0; i--) {
let actor = this.actors[i];
if (! actor.cell)
continue;
if (actor.just_stepped_on_teleporter) {
this.attempt_teleport(actor);
}
}
} }
finish_tic(p1_actions) { finish_tic(p1_actions) {
@ -1087,7 +1100,6 @@ export class Level {
// Step on every tile in a cell we just arrived in // Step on every tile in a cell we just arrived in
step_on_cell(actor, cell) { step_on_cell(actor, cell) {
let teleporter;
// Step on topmost things first -- notably, it's safe to step on water with flippers on top // Step on topmost things first -- notably, it's safe to step on water with flippers on top
for (let tile of Array.from(cell).reverse()) { for (let tile of Array.from(cell).reverse()) {
if (tile === actor) if (tile === actor)
@ -1108,76 +1120,80 @@ export class Level {
} }
} }
else if (tile.type.teleport_dest_order) { else if (tile.type.teleport_dest_order) {
teleporter = tile; // This is used by an extra pass just after our caller, so it doesn't need to undo
actor.just_stepped_on_teleporter = tile;
} }
else if (tile.type.on_arrive) { else if (tile.type.on_arrive) {
tile.type.on_arrive(tile, this, actor); tile.type.on_arrive(tile, this, actor);
} }
} }
}
attempt_teleport(actor) {
let teleporter = actor.just_stepped_on_teleporter;
actor.just_stepped_on_teleporter = null;
// Handle teleporting, now that the dust has cleared // Handle teleporting, now that the dust has cleared
// FIXME something funny happening here, your input isn't ignored while walking out of it? // FIXME something funny happening here, your input isn't ignored while walking out of it?
if (teleporter) { let original_direction = actor.direction;
let original_direction = actor.direction; let success = false;
let success = false; for (let dest of teleporter.type.teleport_dest_order(teleporter, this, actor)) {
for (let dest of teleporter.type.teleport_dest_order(teleporter, this, actor)) { // Teleporters already containing an actor are blocked and unusable
// Teleporters already containing an actor are blocked and unusable if (dest.cell.some(tile => tile.type.is_actor && tile !== actor))
if (dest.cell.some(tile => tile.type.is_actor && tile !== actor)) continue;
continue;
// Physically move the actor to the new teleporter // Physically move the actor to the new teleporter
// XXX lynx treats this as a slide and does it in a pass in the main loop // XXX lynx treats this as a slide and does it in a pass in the main loop
// XXX not especially undo-efficient // XXX not especially undo-efficient
this.remove_tile(actor); this.remove_tile(actor);
this.add_tile(actor, dest.cell); this.add_tile(actor, dest.cell);
// Red and green teleporters attempt to spit you out in every direction before // Red and green teleporters attempt to spit you out in every direction before
// giving up on a destination (but not if you return to the original). // giving up on a destination (but not if you return to the original).
// Note that we use actor.direction here (rather than original_direction) because // Note that we use actor.direction here (rather than original_direction) because
// green teleporters modify it in teleport_dest_order, to randomize the exit // green teleporters modify it in teleport_dest_order, to randomize the exit
// direction // direction
let direction = actor.direction; let direction = actor.direction;
let num_directions = 1; let num_directions = 1;
if (teleporter.type.teleport_try_all_directions && dest !== teleporter) { if (teleporter.type.teleport_try_all_directions && dest !== teleporter) {
num_directions = 4; num_directions = 4;
} }
// FIXME bleugh hardcode // FIXME bleugh hardcode
if (dest === teleporter && teleporter.type.name === 'teleport_yellow') { if (dest === teleporter && teleporter.type.name === 'teleport_yellow') {
break;
}
for (let i = 0; i < num_directions; i++) {
if (this.attempt_out_of_turn_step(actor, direction)) {
success = true;
// Sound plays from the origin cell simply because that's where the sfx player
// thinks the player is currently; position isn't updated til next turn
this.sfx.play_once('teleport', teleporter.cell);
break; break;
} }
for (let i = 0; i < num_directions; i++) { else {
if (this.attempt_out_of_turn_step(actor, direction)) { direction = DIRECTIONS[direction].right;
success = true;
// Sound plays from the origin cell simply because that's where the sfx player
// thinks the player is currently; position isn't updated til next turn
this.sfx.play_once('teleport', teleporter.cell);
break;
}
else {
direction = DIRECTIONS[direction].right;
}
}
if (success) {
break;
}
else if (num_directions === 4) {
// Restore our original facing before continuing
// (For red teleports, we try every possible destination in our original
// movement direction, so this is correct. For green teleports, we only try one
// destination and then fall back to walking through the source in our original
// movement direction, so this is still correct.)
this.set_actor_direction(actor, original_direction);
} }
} }
if (! success && actor.type.has_inventory && teleporter.type.name === 'teleport_yellow') { if (success) {
// Super duper special yellow teleporter behavior: you pick it the fuck up break;
// FIXME not if there's only one in the level? }
this.attempt_take(actor, teleporter); else if (num_directions === 4) {
if (actor === this.player) { // Restore our original facing before continuing
this.sfx.play_once('get-tool', teleporter.cell); // (For red teleports, we try every possible destination in our original
} // movement direction, so this is correct. For green teleports, we only try one
// destination and then fall back to walking through the source in our original
// movement direction, so this is still correct.)
this.set_actor_direction(actor, original_direction);
}
}
if (! success && actor.type.has_inventory && teleporter.type.name === 'teleport_yellow') {
// Super duper special yellow teleporter behavior: you pick it the fuck up
// FIXME not if there's only one in the level?
this.attempt_take(actor, teleporter);
if (actor === this.player) {
this.sfx.play_once('get-tool', teleporter.cell);
} }
} }
} }