Partially consolidate slide overriding on force floors vs teleports

This commit is contained in:
Eevee (Evelyn Woods) 2021-05-07 23:44:05 -06:00
parent e45a580d1a
commit 8efa3a572a
2 changed files with 51 additions and 46 deletions

View File

@ -658,7 +658,7 @@ export class Level extends LevelInterface {
// not in an un-overrideable slide // not in an un-overrideable slide
return this.player.movement_cooldown === 0 && return this.player.movement_cooldown === 0 &&
(this.player.slide_mode === null || ( (this.player.slide_mode === null || (
this.player.slide_mode === 'force' && this.player.last_move_was_force)); this.player.slide_mode === 'force' && this.player.can_override_slide));
} }
// Randomness ------------------------------------------------------------------------------------- // Randomness -------------------------------------------------------------------------------------
@ -1297,10 +1297,7 @@ export class Level extends LevelInterface {
// as an override. // as an override.
let terrain = actor.cell.get_terrain(); let terrain = actor.cell.get_terrain();
let may_move = ! forced_only && ( let may_move = ! forced_only && (
! actor.slide_mode || ! actor.slide_mode || (actor.can_override_slide && terrain.type.allow_player_override));
(actor.slide_mode === 'force' && actor.last_move_was_force) ||
((actor.slide_mode === 'teleport' || actor.slide_mode === 'teleport-forever') &&
actor.cell.get_terrain().type.teleport_allow_override));
let [dir1, dir2] = this._extract_player_directions(input); let [dir1, dir2] = this._extract_player_directions(input);
// Check for special player actions, which can only happen at decision time. Dropping can // Check for special player actions, which can only happen at decision time. Dropping can
@ -1333,7 +1330,7 @@ export class Level extends LevelInterface {
actor.decision = actor.direction; actor.decision = actor.direction;
if (actor.slide_mode === 'force') { if (actor.slide_mode === 'force') {
this._set_tile_prop(actor, 'last_move_was_force', true); this._set_tile_prop(actor, 'can_override_slide', true);
} }
} }
else if (dir1 === null || forced_only) { else if (dir1 === null || forced_only) {
@ -1397,12 +1394,12 @@ export class Level extends LevelInterface {
// If we're overriding a force floor but the direction we're moving in is blocked, this // If we're overriding a force floor but the direction we're moving in is blocked, this
// counts as a forced move (but only under the CC2 behavior of instant bonking) // counts as a forced move (but only under the CC2 behavior of instant bonking)
if (actor.slide_mode === 'force' && ! open && ! this.compat.bonking_isnt_instant) { if (actor.slide_mode === 'force' && ! open && ! this.compat.bonking_isnt_instant) {
this._set_tile_prop(actor, 'last_move_was_force', true); this._set_tile_prop(actor, 'can_override_slide', true);
} }
else { else {
// Otherwise this is 100% a conscious move so we lose our override power next tic // Otherwise this is 100% a conscious move so we lose our override power next tic
// TODO how does this interact with teleports // TODO how does this interact with teleports
this._set_tile_prop(actor, 'last_move_was_force', false); this._set_tile_prop(actor, 'can_override_slide', false);
} }
} }
@ -1611,18 +1608,20 @@ export class Level extends LevelInterface {
if (tile._trying_to_push) if (tile._trying_to_push)
return false; return false;
if (push_mode === 'bump' || push_mode === 'slap') { if (push_mode === 'bump' || push_mode === 'slap') {
// FIXME this doesn't take railroad curves into account, e.g. it thinks a if (tile.movement_cooldown > 0)
// rover can't push a block through a curve
if (tile.movement_cooldown > 0 ||
! this.check_movement(tile, tile.cell, direction, push_mode))
{
return false; return false;
}
else if (push_mode === 'slap') { let redirected_direction = tile.cell.redirect_exit(tile, direction);
if (! this.check_movement(tile, tile.cell, redirected_direction, push_mode))
return false;
if (push_mode === 'slap') {
if (actor === this.player) { if (actor === this.player) {
this._set_tile_prop(actor, 'is_pushing', true); this._set_tile_prop(actor, 'is_pushing', true);
this.sfx.play_once('push'); this.sfx.play_once('push');
} }
// FIXME we get here for monsters in lynx mode! check this is actually
// possible
tile.decision = direction; tile.decision = direction;
} }
} }
@ -2026,17 +2025,15 @@ export class Level extends LevelInterface {
// other actors cannot. (Normally, a teleport slide ends after one decision phase.) // other actors cannot. (Normally, a teleport slide ends after one decision phase.)
// XXX this is useful when the exit is briefly blocked, but it can also get monsters // XXX this is useful when the exit is briefly blocked, but it can also get monsters
// stuck forever :( // stuck forever :(
// XXX kind of repeating myself here, there must be a more natural approach
this.make_slide(actor, 'teleport-forever'); this.make_slide(actor, 'teleport-forever');
if (actor.type.is_real_player && teleporter.type.allow_player_override) {
this._set_tile_prop(actor, 'can_override_slide', true);
}
// Also, there's no sound and whatnot, so everything else is skipped outright. // Also, there's no sound and whatnot, so everything else is skipped outright.
return; return;
} }
// Explicitly set us as teleport sliding, since in some very obscure cases (auto-dropping a
// yellow teleporter because you picked up an item with a full inventory and immediately
// teleporting through it) it may not have been applied
this.make_slide(actor, 'teleport');
let success = false;
let dest, direction; let dest, direction;
for ([dest, direction] of teleporter.type.teleport_dest_order(teleporter, this, actor)) { for ([dest, direction] 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
@ -2046,29 +2043,8 @@ export class Level extends LevelInterface {
// 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
// FIXME bleugh hardcode if (dest === teleporter &&
if (dest === teleporter && teleporter.type.name === 'teleport_yellow') { teleporter.type.item_priority !== undefined &&
break;
}
// Note that this uses 'bump' even for players; it would be very bad if we could
// initiate movement in this pass (in Lexy rules, anyway), because we might try to push
// something that's still waiting to teleport itself!
// XXX is this correct? it does mean you won't try to teleport to a teleporter that's
// "blocked" by a block that won't be there anyway by the time you try to move, but that
// seems very obscure and i haven't run into a case with it yet. offhand i don't think
// it can even come up under cc2 rules, since teleporting is done after an actor cools
// down and before the next actor even gets a chance to act
if (this.check_movement(actor, dest.cell, direction, 'bump')) {
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;
}
}
if (! success) {
if (teleporter.type.item_priority !== undefined &&
teleporter.type.item_priority >= actor.type.item_pickup_priority && teleporter.type.item_priority >= actor.type.item_pickup_priority &&
this.allow_taking_yellow_teleporters) this.allow_taking_yellow_teleporters)
{ {
@ -2080,6 +2056,30 @@ export class Level extends LevelInterface {
} }
return; return;
} }
// Note that this uses 'bump' even for players; it would be very bad if we could
// initiate movement in this pass (in Lexy rules, anyway), because we might try to push
// something that's still waiting to teleport itself!
// XXX is this correct? it does mean you won't try to teleport to a teleporter that's
// "blocked" by a block that won't be there anyway by the time you try to move, but that
// seems very obscure and i haven't run into a case with it yet. offhand i don't think
// it can even come up under cc2 rules, since teleporting is done after an actor cools
// down and before the next actor even gets a chance to act
if (this.check_movement(actor, dest.cell, direction, 'bump')) {
// 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;
}
}
// Explicitly set us as teleport sliding, since in some very obscure cases (auto-dropping a
// yellow teleporter because you picked up an item with a full inventory and immediately
// teleporting through it) it may not have been applied
this.make_slide(actor, 'teleport');
// Real players might be able to immediately override the resulting slide
if (actor.type.is_real_player && teleporter.type.allow_player_override) {
this._set_tile_prop(actor, 'can_override_slide', true);
} }
this.set_actor_direction(actor, direction); this.set_actor_direction(actor, direction);

View File

@ -956,6 +956,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'force', slide_mode: 'force',
speed_factor: 2, speed_factor: 2,
allow_player_override: true,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
on_arrive(me, level, other) { on_arrive(me, level, other) {
level.set_actor_direction(other, 'north'); level.set_actor_direction(other, 'north');
@ -979,6 +980,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'force', slide_mode: 'force',
speed_factor: 2, speed_factor: 2,
allow_player_override: true,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
on_arrive(me, level, other) { on_arrive(me, level, other) {
level.set_actor_direction(other, 'east'); level.set_actor_direction(other, 'east');
@ -1000,6 +1002,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'force', slide_mode: 'force',
speed_factor: 2, speed_factor: 2,
allow_player_override: true,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
on_arrive(me, level, other) { on_arrive(me, level, other) {
level.set_actor_direction(other, 'south'); level.set_actor_direction(other, 'south');
@ -1021,6 +1024,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'force', slide_mode: 'force',
speed_factor: 2, speed_factor: 2,
allow_player_override: true,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
on_arrive(me, level, other) { on_arrive(me, level, other) {
level.set_actor_direction(other, 'west'); level.set_actor_direction(other, 'west');
@ -1042,6 +1046,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
slide_mode: 'force', slide_mode: 'force',
speed_factor: 2, speed_factor: 2,
allow_player_override: true,
on_begin: on_begin_force_floor, on_begin: on_begin_force_floor,
// TODO ms: this is random, and an acting wall to monsters (!) // TODO ms: this is random, and an acting wall to monsters (!)
blocks(me, level, other) { blocks(me, level, other) {
@ -1839,7 +1844,7 @@ const TILE_TYPES = {
slide_mode: 'teleport', slide_mode: 'teleport',
contains_wire: true, contains_wire: true,
wire_propagation_mode: 'none', wire_propagation_mode: 'none',
teleport_allow_override: true, allow_player_override: true,
on_begin(me, level) { on_begin(me, level) {
// FIXME must be connected to something that can convey current: a wire, a switch, a // FIXME must be connected to something that can convey current: a wire, a switch, a
// blue teleporter, etc; NOT nothing, a wall, a transmogrifier, a force floor, etc. // blue teleporter, etc; NOT nothing, a wall, a transmogrifier, a force floor, etc.
@ -1934,7 +1939,7 @@ const TILE_TYPES = {
layer: LAYERS.terrain, layer: LAYERS.terrain,
item_priority: PICKUP_PRIORITIES.always, item_priority: PICKUP_PRIORITIES.always,
slide_mode: 'teleport', slide_mode: 'teleport',
teleport_allow_override: true, allow_player_override: true,
*teleport_dest_order(me, level, other) { *teleport_dest_order(me, level, other) {
let exit_direction = other.direction; let exit_direction = other.direction;
for (let dest of level.iter_tiles_in_reading_order(me.cell, 'teleport_yellow', true)) { for (let dest of level.iter_tiles_in_reading_order(me.cell, 'teleport_yellow', true)) {