Add a compat flag for pushing a sliding block

The default is now what I /think/ is the Lynx behavior: try to push the
block first, and only give it a pending direction if the push fails.
CC2 always uses the pending mechanism.
This commit is contained in:
Eevee (Evelyn Woods) 2024-04-11 01:18:34 -06:00
parent f896e1bdfd
commit f422b4b395
2 changed files with 22 additions and 14 deletions

View File

@ -242,6 +242,10 @@ export const COMPAT_FLAGS = [
key: 'use_legacy_hooking',
label: "Pulling blocks with the hook happens at decision time",
rulesets: new Set(['steam', 'steam-strict']),
}, {
key: 'no_directly_pushing_sliding_blocks',
label: "Don't directly push sliding blocks",
rulesets: new Set(['steam', 'steam-strict']),
}, {
key: 'use_pgchip_ice_blocks',
label: "Ice blocks emulate pgchip rules",

View File

@ -1661,31 +1661,35 @@ export class Level extends LevelInterface {
if (actor === this.player) {
this._set_tile_prop(actor, 'is_pushing', true);
}
// We can't directly push a sliding block, even one on a force floor that's
// stuck on a wall. Instead, it becomes a pending move for the block, which
// will use this as a decision next time it's allowed to move
// FIXME this is clumsy and creates behavior dependent on actor order. my
// original implementation only did this if the push /failed/; is that worth
// a compat option? also, how does any of this work under lynx rules?
if (tile.is_sliding && ! tile.is_pulled && (tile.movement_cooldown > 0 ||
tile.cell.get_terrain().type.slide_mode === 'force'))
{
let tile_is_stuck_sliding = (tile.is_sliding && ! tile.is_pulled && (
tile.movement_cooldown > 0 || tile.cell.get_terrain().type.slide_mode === 'force'));
if (this.compat.no_directly_pushing_sliding_blocks && tile_is_stuck_sliding) {
// CC2: Can't directly push a sliding block, even one on a force floor
// that's stuck on a wall (and thus not moving). Such a push ALWAYS
// becomes a pending push, so it won't happen until next tic, and we
// remain blocked
this._set_tile_prop(tile, 'pending_push', direction);
// FIXME if the block has already made a decision then this is necessary
// to override it. but i don't like it; (a) it might cause blocks to
// get stuck against walls on force floors, because the code to fix that
// is at decision time; (b) it's done for pulling too and just feels
// hacky?
// If the block already had its decision phase this turn, override it
tile.decision = direction;
return false;
}
// Lexy/Lynx(?) behavior: try to push the block first, then resort to
// pending if the push fails
if (this.attempt_out_of_turn_step(tile, direction)) {
if (actor === this.player) {
this.sfx.play_once('push');
}
}
else {
if (! this.compat.no_directly_pushing_sliding_blocks && tile_is_stuck_sliding) {
// If the push failed and the obstacle is in the middle of a slide,
// remember this as the next move it'll make
this._set_tile_prop(tile, 'pending_push', direction);
tile.decision = direction;
}
return false;
}
}