From 05005185373d5a73a8575b4a5557ce301afdab0e Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Sat, 26 Dec 2020 03:15:00 -0700 Subject: [PATCH] Move sliding back to arrive time, but force floor bonking to movement time --- js/game.js | 42 +++++++++++----------- js/tiletypes.js | 93 +++++++++++++++++++++++++++++-------------------- 2 files changed, 76 insertions(+), 59 deletions(-) diff --git a/js/game.js b/js/game.js index da5c440..2c20d13 100644 --- a/js/game.js +++ b/js/game.js @@ -878,21 +878,24 @@ export class Level extends LevelInterface { // Actor is allowed to move, so do so let success = this.attempt_step(actor, direction); - // FIXME not convinced that ice bonking should actually go here. in cc2 it appears to - // happen every frame, fwiw, but i'm not sure if that includes frames with forced moves - // (though i guess that's impossible) + // CC2 handles bonking for all kinds of sliding here -- bonking on ice causes an immediate + // turnaround, and bonking on an RFF rolls a new direction and tries again + // TODO this assumes the slide comes from the terrain, which is always the case atm if (! success) { let terrain = actor.cell.get_terrain(); - if (terrain.type.slide_mode === 'ice' && (! actor.ignores(terrain.type.name) || + if (terrain && ( + (actor.slide_mode && ! actor.ignores(terrain.type.name)) || // TODO weird cc2 quirk/bug: ghosts bonk on ice even though they don't slide on it // FIXME and if they have cleats, they get stuck instead (?!) - (actor.type.name === 'ghost' && actor.cell.get_terrain().type.slide_mode === 'ice'))) + (actor.type.name === 'ghost' && terrain.type.slide_mode === 'ice'))) { - // Bonk on ice: turn the actor around, consult the tile in case it's an ice - // corner, and try again - actor.direction = DIRECTIONS[direction].opposite; - direction = terrain.type.get_slide_direction(terrain, this, actor); - success = this.attempt_step(actor, direction); + // Turn the actor around (so ice corners bonk correctly), pretend they stepped on + // the tile again (so RFFs roll again), and try moving again + this.set_actor_direction(actor, DIRECTIONS[direction].opposite); + if (terrain.type.on_arrive) { + terrain.type.on_arrive(terrain, this, actor); + } + success = this.attempt_step(actor, actor.direction); } } @@ -1083,10 +1086,6 @@ export class Level extends LevelInterface { // succeed, even if overriding in the same direction we're already moving, that does count // as an override. let terrain = actor.cell.get_terrain(); - let forced_decision; - if (actor.slide_mode) { - forced_decision = terrain.type.get_slide_direction(terrain, this, actor); - } let may_move = ! forced_only && (! actor.slide_mode || (actor.slide_mode === 'force' && actor.last_move_was_force)); let [dir1, dir2] = this._extract_player_directions(input); @@ -1116,7 +1115,7 @@ export class Level extends LevelInterface { if (actor.slide_mode && ! (may_move && dir1)) { // This is a forced move and we're not overriding it, so we're done - actor.decision = forced_decision; + actor.decision = actor.direction; if (actor.slide_mode === 'force') { this._set_tile_prop(actor, 'last_move_was_force', true); @@ -1140,17 +1139,16 @@ export class Level extends LevelInterface { // one, UNLESS it's blocked AND the other isn't. // Note that if this is an override, then the forced direction is still used to // interpret our input! - let facing = forced_decision ?? actor.direction; - if (dir1 === facing || dir2 === facing) { - let other_direction = dir1 === facing ? dir2 : dir1; - let curr_open = try_direction(facing, 'push'); + if (dir1 === actor.direction || dir2 === actor.direction) { + let other_direction = dir1 === actor.direction ? dir2 : dir1; + let curr_open = try_direction(actor.direction, 'push'); let other_open = try_direction(other_direction, 'push'); if (! curr_open && other_open) { actor.decision = other_direction; open = true; } else { - actor.decision = facing; + actor.decision = actor.direction; open = curr_open; } } @@ -1184,7 +1182,7 @@ export class Level extends LevelInterface { // force floor takes priority (and we've already bumped the wall(s)) if (actor.slide_mode && ! open) { this._set_tile_prop(actor, 'last_move_was_force', true); - actor.decision = forced_decision; + actor.decision = actor.direction; } else { // Otherwise this is 100% a conscious move so we lose our override power next tic @@ -1217,7 +1215,7 @@ export class Level extends LevelInterface { (actor.type.name === 'ghost' && terrain.type.slide_mode === 'ice')) { // Actors can't make voluntary moves while sliding; they just, ah, slide. - actor.decision = terrain.type.get_slide_direction(terrain, this, actor); + actor.decision = actor.direction; return; } if (forced_only) diff --git a/js/tiletypes.js b/js/tiletypes.js index 06a6b45..2f095d0 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -7,6 +7,7 @@ function activate_me(me, level) { function on_ready_force_floor(me, level) { // At the start of the level, if there's an actor on a force floor: + // - use on_arrive to set the actor's direction // - set the slide_mode (normally done by the main game loop) // - item bestowal: if they're being pushed into a wall and standing on an item, pick up the // item, even if they couldn't normally pick items up @@ -15,6 +16,7 @@ function on_ready_force_floor(me, level) { if (! actor) return; + me.type.on_arrive(me, level, actor); if (me.type.slide_mode) { actor.slide_mode = me.type.slide_mode; } @@ -663,21 +665,19 @@ const TILE_TYPES = { ice: { draw_layer: DRAW_LAYERS.terrain, slide_mode: 'ice', - get_slide_direction(me, level, other) { - return other.direction; - }, }, ice_sw: { draw_layer: DRAW_LAYERS.terrain, thin_walls: new Set(['south', 'west']), slide_mode: 'ice', blocks_leaving: blocks_leaving_thin_walls, - get_slide_direction(me, level, other) { - if (other.direction === 'south') - return 'east'; - if (other.direction === 'west') - return 'north'; - return other.direction; + on_arrive(me, level, other) { + if (other.direction === 'south') { + level.set_actor_direction(other, 'east'); + } + else if (other.direction === 'west') { + level.set_actor_direction(other, 'north'); + } }, }, ice_nw: { @@ -685,12 +685,13 @@ const TILE_TYPES = { thin_walls: new Set(['north', 'west']), slide_mode: 'ice', blocks_leaving: blocks_leaving_thin_walls, - get_slide_direction(me, level, other) { - if (other.direction === 'north') - return 'east'; - if (other.direction === 'west') - return 'south'; - return other.direction; + on_arrive(me, level, other) { + if (other.direction === 'north') { + level.set_actor_direction(other, 'east'); + } + else if (other.direction === 'west') { + level.set_actor_direction(other, 'south'); + } }, }, ice_ne: { @@ -698,12 +699,13 @@ const TILE_TYPES = { thin_walls: new Set(['north', 'east']), slide_mode: 'ice', blocks_leaving: blocks_leaving_thin_walls, - get_slide_direction(me, level, other) { - if (other.direction === 'north') - return 'west'; - if (other.direction === 'east') - return 'south'; - return other.direction; + on_arrive(me, level, other) { + if (other.direction === 'north') { + level.set_actor_direction(other, 'west'); + } + else if (other.direction === 'east') { + level.set_actor_direction(other, 'south'); + } }, }, ice_se: { @@ -711,23 +713,28 @@ const TILE_TYPES = { thin_walls: new Set(['south', 'east']), slide_mode: 'ice', blocks_leaving: blocks_leaving_thin_walls, - get_slide_direction(me, level, other) { - if (other.direction === 'south') - return 'west'; - if (other.direction === 'east') - return 'north'; - return other.direction; + on_arrive(me, level, other) { + if (other.direction === 'south') { + level.set_actor_direction(other, 'west'); + } + else if (other.direction === 'east') { + level.set_actor_direction(other, 'north'); + } }, }, force_floor_n: { draw_layer: DRAW_LAYERS.terrain, slide_mode: 'force', on_ready: on_ready_force_floor, - get_slide_direction(me, level, other) { - return 'north'; + on_arrive(me, level, other) { + level.set_actor_direction(other, 'north'); }, activate(me, level) { level.transmute_tile(me, 'force_floor_s'); + let actor = me.cell.get_actor(); + if (actor && actor.movement_cooldown <= 0) { + this.on_arrive(me, level, actor); + } }, on_gray_button: activate_me, on_power: activate_me, @@ -736,11 +743,15 @@ const TILE_TYPES = { draw_layer: DRAW_LAYERS.terrain, slide_mode: 'force', on_ready: on_ready_force_floor, - get_slide_direction(me, level, other) { - return 'east'; + on_arrive(me, level, other) { + level.set_actor_direction(other, 'east'); }, activate(me, level) { level.transmute_tile(me, 'force_floor_w'); + let actor = me.cell.get_actor(); + if (actor && actor.movement_cooldown <= 0) { + this.on_arrive(me, level, actor); + } }, on_gray_button: activate_me, on_power: activate_me, @@ -749,11 +760,15 @@ const TILE_TYPES = { draw_layer: DRAW_LAYERS.terrain, slide_mode: 'force', on_ready: on_ready_force_floor, - get_slide_direction(me, level, other) { - return 'south'; + on_arrive(me, level, other) { + level.set_actor_direction(other, 'south'); }, activate(me, level) { level.transmute_tile(me, 'force_floor_n'); + let actor = me.cell.get_actor(); + if (actor && actor.movement_cooldown <= 0) { + this.on_arrive(me, level, actor); + } }, on_gray_button: activate_me, on_power: activate_me, @@ -762,11 +777,15 @@ const TILE_TYPES = { draw_layer: DRAW_LAYERS.terrain, slide_mode: 'force', on_ready: on_ready_force_floor, - get_slide_direction(me, level, other) { - return 'west'; + on_arrive(me, level, other) { + level.set_actor_direction(other, 'west'); }, activate(me, level) { level.transmute_tile(me, 'force_floor_e'); + let actor = me.cell.get_actor(); + if (actor && actor.movement_cooldown <= 0) { + this.on_arrive(me, level, actor); + } }, on_gray_button: activate_me, on_power: activate_me, @@ -776,8 +795,8 @@ const TILE_TYPES = { slide_mode: 'force', on_ready: on_ready_force_floor, // TODO ms: this is random, and an acting wall to monsters (!) - get_slide_direction(me, level, other) { - return level.get_force_floor_direction(); + on_arrive(me, level, other) { + level.set_actor_direction(other, level.get_force_floor_direction()); }, }, slime: {