Fix green teleporter selection behavior

This commit is contained in:
Eevee (Evelyn Woods) 2021-03-01 21:09:10 -07:00
parent d5b9a2a307
commit 406243d490
2 changed files with 37 additions and 21 deletions

View File

@ -807,11 +807,12 @@ export class Level extends LevelInterface {
// Lynx PRNG, used unchanged in CC2 // Lynx PRNG, used unchanged in CC2
prng() { prng() {
let n = (this._rng1 >> 2) - this._rng1; let n = (this._rng1 >> 2) - this._rng1;
if (!(this._rng1 & 0x02)) --n; if (!(this._rng1 & 0x02)) {
this._rng1 = (this._rng1 >> 1) | (this._rng2 & 0x80); n -= 1;
this._rng2 = (this._rng2 << 1) | (n & 0x01); }
let ret = (this._rng1 ^ this._rng2) & 0xff; this._rng1 = ((this._rng1 >> 1) | (this._rng2 & 0x80)) & 0xff;
return ret; this._rng2 = ((this._rng2 << 1) | (n & 0x01)) & 0xff;
return this._rng1 ^ this._rng2;
} }
// Weird thing done by CC2 to make blobs... more... random // Weird thing done by CC2 to make blobs... more... random

View File

@ -1759,28 +1759,43 @@ const TILE_TYPES = {
teleport_green: { teleport_green: {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'teleport', slide_mode: 'teleport',
teleport_dest_order(me, level, other) { *teleport_dest_order(me, level, other) {
let all = Array.from(level.iter_tiles_in_reading_order(me.cell, 'teleport_green')); let all = Array.from(level.iter_tiles_in_reading_order(me.cell, 'teleport_green'));
if (all.length <= 1) { if (all.length <= 1) {
// If this is the only teleporter, just walk out the other side — and, crucially, do // If this is the only teleporter, just walk out the other side — and, crucially, do
// NOT advance the PRNG // NOT advance the PRNG
return [[me, other.direction]]; yield [me, other.direction];
return;
} }
// Note the iterator starts on the /next/ teleporter, so there's an implicit +1 here. // The green teleporter scheme is:
// The -1 is to avoid spitting us back out of the same teleporter, which will be last in // 1. Use the PRNG to pick another green teleporter
// the list // 2. Use the PRNG to pick an exit direction
let target = all[level.prng() % (all.length - 1)]; // 3. Search the selected exit teleporter for a viable exit direction
// Also pick the actor's exit direction // 4. If that doesn't work, continue searching green teleporters in reading order
// 5. When we reach the entry teleporter, stop and give up
// This means that completely blocked green teleporters are skipped, BUT if the only
// available teleporters are between the entry and chosen exit, they'll never be tried.
// TODO that sucks actually; compat option?
// The iterator starts on the /next/ teleporter, so there's an implicit +1 here. The -1
// avoids spitting us back out of the same teleporter, which will be last in the list
let start_index = level.prng() % (all.length - 1);
// Also pick the initial exit direction
let exit_direction = DIRECTION_ORDER[level.prng() % 4]; let exit_direction = DIRECTION_ORDER[level.prng() % 4];
return [
// Green teleporters allow exiting in any direction, similar to red, but only on the for (let index = start_index; index < all.length - 1; index++) {
// one they found; if that fails, you walk straight across the one you entered let target = all[index];
[target, exit_direction],
[target, DIRECTIONS[exit_direction].right], // Green teleporters allow exiting in any direction, similar to red
[target, DIRECTIONS[exit_direction].opposite], yield [target, exit_direction];
[target, DIRECTIONS[exit_direction].left], yield [target, DIRECTIONS[exit_direction].right];
[me, other.direction], yield [target, DIRECTIONS[exit_direction].opposite];
]; yield [target, DIRECTIONS[exit_direction].left];
}
// We've circled back around to our entry teleporter; give up
yield [me, other.direction];
return;
}, },
}, },
teleport_yellow: { teleport_yellow: {