From a1f357f3177e03fc8e26874dadc9cf2a04fb688f Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Wed, 10 Apr 2024 18:02:43 -0600 Subject: [PATCH] Make sliding be the tiles' responsibility This seems to simplify things and also explain the CC2 semantics: force floors activate while being stood on (which happens, I guess, during idle), so it applies to objects that start the level on force floors. This was probably done to make force floor flipping work, too. On the other hand, ice still only activates when being stepped on. --- js/game.js | 58 +++++++------------------ js/tiletypes.js | 112 +++++++++++++++++++++--------------------------- 2 files changed, 64 insertions(+), 106 deletions(-) diff --git a/js/game.js b/js/game.js index 612ca64..11f8f5a 100644 --- a/js/game.js +++ b/js/game.js @@ -1238,25 +1238,6 @@ export class Level extends LevelInterface { } this.pending_green_toggle = false; } - - // On the very first tic, check for any actors standing on force floors, and set their slide - // directions. Done here because they do NOT move yet, even if unblocked! - // TODO this feels oddly artificial. is this supposed to happen during idle, maybe? - // FIXME check compat flag for lynx - if (this.tic_counter === 0 && this.frame_offset === 0) { - for (let i = this.actors.length - 1; i >= 0; i--) { - let actor = this.actors[i]; - - let terrain = actor.cell.get_terrain(); - if (terrain && terrain.type.slide_mode === 'force') { - let forced_move = this.get_forced_move(actor, terrain); - if (forced_move) { - this._set_tile_prop(actor, 'is_pending_slide', true) - this.set_actor_direction(actor, forced_move); - } - } - } - } } _do_cleanup_phase() { @@ -1338,22 +1319,6 @@ export class Level extends LevelInterface { return [dir1, dir2]; } - get_forced_move(actor, terrain = null) { - if (! terrain) { - terrain = actor.cell.get_terrain(); - } - if (! terrain.type.slide_mode) - return null; - if (! terrain.type.get_slide_direction) - return null; - if (! (actor.is_pending_slide || terrain.type.slide_automatically)) - return null; - if (actor.ignores(terrain.type.name)) - return null; - - return terrain.type.get_slide_direction(terrain, this, actor); - } - make_player_decision(actor, input, forced_only = false) { // Only reset the player's is_pushing between movement, so it lasts for the whole push this._set_tile_prop(actor, 'is_pushing', false); @@ -2048,23 +2013,23 @@ export class Level extends LevelInterface { // Kind of weird putting slide_ignores here, except that all sliding happens on // on_arrive, and tiles that make you slide in on_arrive don't do anything else, so // for now it works + // XXX that is jank as hell what are you talking about tile.type.on_arrive(tile, this, actor); } + if (tile.type.on_stand && !actor.slide_ignores(tile.type.name)) { + // XXX according to notcc, cc2 also has actors "stand" on tiles immediately upon + // arrival, even though they'll do it anyway on their idle phase + tile.type.on_stand(tile, this, actor); + } + if (tile.type.slide_automatically) { // This keeps a player on force floor consistently using their sliding pose, even if // drawn between moves. It also simplifies checks elsewhere, so that's nice + // FIXME if i'm right about how this works then this may not be necessary? this._set_tile_prop(actor, 'is_pending_slide', true); } } - - // FIXME ingratiate this with the rest of this stuff i think - // FIXME figure out what the hell that comment means - let forced_move = this.get_forced_move(actor); - if (forced_move) { - this._set_tile_prop(actor, 'is_pending_slide', true) - this.set_actor_direction(actor, forced_move); - } } attempt_teleport(actor) { @@ -3031,4 +2996,11 @@ export class Level extends LevelInterface { set_actor_direction(actor, direction) { this._set_tile_prop(actor, 'direction', direction); } + + schedule_actor_slide(actor, direction = null) { + if (direction) { + this.set_actor_direction(actor, direction); + } + this._set_tile_prop(actor, 'is_pending_slide', true); + } } diff --git a/js/tiletypes.js b/js/tiletypes.js index ab41616..909b779 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -58,14 +58,17 @@ function _define_force_floor(direction, opposite_type) { speed_factor: 2, slide_automatically: true, allow_player_override: true, - get_slide_direction(me, level, other) { + on_stand(me, level, other) { + level.schedule_actor_slide(other, direction); + // FIXME i think it's really that in lynx these push on arrival; try that and see if + // it's better + /* if (level.compat.force_floors_inert_on_first_tic && level.tic_counter === 0) { // Lynx: Force floors don't push on the first tic return null; } - return direction; + */ }, - force_floor_direction: direction, activate(me, level) { level.transmute_tile(me, opposite_type); }, @@ -744,9 +747,6 @@ const TILE_TYPES = { contains_wire: true, wire_propagation_mode: 'all', slide_mode: 'turntable', - get_slide_direction(me, level, other) { - return other.direction; - }, on_arrive(me, level, other) { level._set_tile_prop(other, 'is_pending_slide', true); level.set_actor_direction(other, DIRECTIONS[other.direction].right); @@ -754,6 +754,9 @@ const TILE_TYPES = { other.type.on_rotate(other, level, 'right'); } }, + on_stand(me, level, other) { + level.schedule_actor_slide(other); + }, activate(me, level) { level.transmute_tile(me, 'turntable_ccw'); }, @@ -765,9 +768,6 @@ const TILE_TYPES = { contains_wire: true, wire_propagation_mode: 'all', slide_mode: 'turntable', - get_slide_direction(me, level, other) { - return other.direction; - }, on_arrive(me, level, other) { level._set_tile_prop(other, 'is_pending_slide', true); level.set_actor_direction(other, DIRECTIONS[other.direction].left); @@ -775,6 +775,9 @@ const TILE_TYPES = { other.type.on_rotate(other, level, 'left'); } }, + on_stand(me, level, other) { + level.schedule_actor_slide(other); + }, activate(me, level) { level.transmute_tile(me, 'turntable_cw'); }, @@ -886,12 +889,9 @@ const TILE_TYPES = { cracked_ice: { layer: LAYERS.terrain, slide_mode: 'ice', - get_slide_direction(me, level, other) { - return other.direction; - }, speed_factor: 2, on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other); }, on_depart(me, level, other) { level.transmute_tile(me, 'water'); @@ -902,84 +902,73 @@ const TILE_TYPES = { ice: { layer: LAYERS.terrain, slide_mode: 'ice', - get_slide_direction(me, level, other) { - return other.direction; - }, speed_factor: 2, on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other); }, }, ice_sw: { layer: LAYERS.terrain, thin_walls: new Set(['south', 'west']), slide_mode: 'ice', - get_slide_direction(me, level, other) { - return { + speed_factor: 2, + blocks_leaving: blocks_leaving_thin_walls, + on_arrive(me, level, other) { + let direction = { north: 'north', south: 'east', east: 'east', west: 'north', }[other.direction]; - }, - speed_factor: 2, - blocks_leaving: blocks_leaving_thin_walls, - on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other, direction); }, }, ice_nw: { layer: LAYERS.terrain, thin_walls: new Set(['north', 'west']), slide_mode: 'ice', - get_slide_direction(me, level, other) { - return { + speed_factor: 2, + blocks_leaving: blocks_leaving_thin_walls, + on_arrive(me, level, other) { + let direction = { north: 'east', south: 'south', east: 'east', west: 'south', }[other.direction]; - }, - speed_factor: 2, - blocks_leaving: blocks_leaving_thin_walls, - on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other, direction); }, }, ice_ne: { layer: LAYERS.terrain, thin_walls: new Set(['north', 'east']), slide_mode: 'ice', - get_slide_direction(me, level, other) { - return { + speed_factor: 2, + blocks_leaving: blocks_leaving_thin_walls, + on_arrive(me, level, other) { + let direction = { north: 'west', south: 'south', east: 'south', west: 'west', }[other.direction]; - }, - speed_factor: 2, - blocks_leaving: blocks_leaving_thin_walls, - on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other, direction); }, }, ice_se: { layer: LAYERS.terrain, thin_walls: new Set(['south', 'east']), slide_mode: 'ice', - get_slide_direction(me, level, other) { - return { + speed_factor: 2, + blocks_leaving: blocks_leaving_thin_walls, + on_arrive(me, level, other) { + let direction = { north: 'north', south: 'west', east: 'north', west: 'west', }[other.direction]; - }, - speed_factor: 2, - blocks_leaving: blocks_leaving_thin_walls, - on_arrive(me, level, other) { - level._set_tile_prop(other, 'is_pending_slide', true); + level.schedule_actor_slide(other, direction); }, }, force_floor_n: _define_force_floor('north', 'force_floor_s'), @@ -992,16 +981,25 @@ const TILE_TYPES = { slide_automatically: true, speed_factor: 2, allow_player_override: true, - get_slide_direction(me, level, _other) { + blocks(me, level, other) { + return (level.compat.rff_blocks_monsters && + (other.type.collision_mask & COLLISION.monster_typical)); + }, + on_stand(me, level, other) { + // XXX this check is necessary because of step_on_cell and then the idle phase causing + // us to be called twice. who is correct?? is the step_on_cell call supposed to be + // there? + if (! other.is_pending_slide) { + level.schedule_actor_slide(other, level.get_force_floor_direction()); + } + // FIXME i think it's really that in lynx these push on arrival; try that and see if + // it's better + /* if (level.compat.force_floors_inert_on_first_tic && level.tic_counter === 0) { // Lynx: Force floors don't push on the first tic return null; } - return level.get_force_floor_direction(); - }, - blocks(me, level, other) { - return (level.compat.rff_blocks_monsters && - (other.type.collision_mask & COLLISION.monster_typical)); + */ }, }, slime: { @@ -1726,9 +1724,6 @@ const TILE_TYPES = { teleport_blue: { layer: LAYERS.terrain, slide_mode: 'teleport', - get_slide_direction(me, level, other) { - return other.direction; - }, contains_wire: true, wire_propagation_mode: 'all', *teleport_dest_order(me, level, other) { @@ -1816,9 +1811,6 @@ const TILE_TYPES = { teleport_red: { layer: LAYERS.terrain, slide_mode: 'teleport', - get_slide_direction(me, level, other) { - return other.direction; - }, contains_wire: true, wire_propagation_mode: 'none', allow_player_override: true, @@ -1873,9 +1865,6 @@ const TILE_TYPES = { teleport_green: { layer: LAYERS.terrain, slide_mode: 'teleport', - get_slide_direction(me, level, other) { - return other.direction; - }, *teleport_dest_order(me, level, other) { // The CC2 green teleporter scheme is: // 1. Use the PRNG to pick another green teleporter @@ -1947,9 +1936,6 @@ const TILE_TYPES = { layer: LAYERS.terrain, item_priority: PICKUP_PRIORITIES.always, slide_mode: 'teleport', - get_slide_direction(me, level, other) { - return other.direction; - }, allow_player_override: true, *teleport_dest_order(me, level, other) { let exit_direction = other.direction;