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', key: 'use_legacy_hooking',
label: "Pulling blocks with the hook happens at decision time", label: "Pulling blocks with the hook happens at decision time",
rulesets: new Set(['steam', 'steam-strict']), 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', key: 'use_pgchip_ice_blocks',
label: "Ice blocks emulate pgchip rules", label: "Ice blocks emulate pgchip rules",

View File

@ -1661,31 +1661,35 @@ export class Level extends LevelInterface {
if (actor === this.player) { if (actor === this.player) {
this._set_tile_prop(actor, 'is_pushing', true); 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 let tile_is_stuck_sliding = (tile.is_sliding && ! tile.is_pulled && (
// will use this as a decision next time it's allowed to move tile.movement_cooldown > 0 || tile.cell.get_terrain().type.slide_mode === 'force'));
// FIXME this is clumsy and creates behavior dependent on actor order. my
// original implementation only did this if the push /failed/; is that worth if (this.compat.no_directly_pushing_sliding_blocks && tile_is_stuck_sliding) {
// a compat option? also, how does any of this work under lynx rules? // CC2: Can't directly push a sliding block, even one on a force floor
if (tile.is_sliding && ! tile.is_pulled && (tile.movement_cooldown > 0 || // that's stuck on a wall (and thus not moving). Such a push ALWAYS
tile.cell.get_terrain().type.slide_mode === 'force')) // becomes a pending push, so it won't happen until next tic, and we
{ // remain blocked
this._set_tile_prop(tile, 'pending_push', direction); this._set_tile_prop(tile, 'pending_push', direction);
// FIXME if the block has already made a decision then this is necessary // If the block already had its decision phase this turn, override it
// 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?
tile.decision = direction; tile.decision = direction;
return false; 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 (this.attempt_out_of_turn_step(tile, direction)) {
if (actor === this.player) { if (actor === this.player) {
this.sfx.play_once('push'); this.sfx.play_once('push');
} }
} }
else { 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; return false;
} }
} }