diff --git a/js/game.js b/js/game.js index d9b7e34..4a7acdf 100644 --- a/js/game.js +++ b/js/game.js @@ -330,7 +330,7 @@ export class Level { } // Move the game state forwards by one tic - advance_tic(player_direction) { + advance_tic(p1_primary_direction, p1_secondary_direction) { if (this.state !== 'playing') { console.warn(`Level.advance_tic() called when state is ${this.state}`); return; @@ -391,6 +391,10 @@ export class Level { if (actor.type.uses_teeth_hesitation && (this.tic_counter + this.step_parity) % 8 >= 4) continue; + if (actor.type.is_player) { + this._set_prop(actor, 'secondary_direction', p1_secondary_direction); + } + let direction_preference; // Actors can't make voluntary moves on ice, so they're stuck with // whatever they've got @@ -405,10 +409,10 @@ export class Level { // can override forwards??) and DEFINITELY all kinds of stuff // in ms if (actor === this.player && - player_direction && + p1_primary_direction && actor.last_move_was_force) { - direction_preference = [player_direction]; + direction_preference = [p1_primary_direction]; this._set_prop(actor, 'last_move_was_force', false); } else { @@ -419,8 +423,8 @@ export class Level { } } else if (actor === this.player) { - if (player_direction) { - direction_preference = [player_direction]; + if (p1_primary_direction) { + direction_preference = [p1_primary_direction]; this._set_prop(actor, 'last_move_was_force', false); } } @@ -753,6 +757,24 @@ export class Level { } } + // Players can also bump the tiles next to where they landed + if (actor.type.is_player && actor.secondary_direction) { + let neighbor = this.cell_with_offset(actor.cell, actor.secondary_direction); + if (neighbor) { + for (let tile of neighbor) { + // TODO repeating myself with tile.stuck (also should technically check for actor) + if (actor.type.pushes && actor.type.pushes[tile.type.name] && ! tile.stuck) { + // Block slapping: you can shove a block by walking past it sideways + this.set_actor_direction(tile, actor.secondary_direction); + this.attempt_step(tile, actor.secondary_direction); + } + else if (tile.type.on_bump) { + tile.type.on_bump(tile, this, actor); + } + } + } + } + // Handle teleporting, now that the dust has cleared // FIXME something funny happening here, your input isn't ignore while walking out of it? let current_cell = actor.cell; diff --git a/js/main.js b/js/main.js index b564984..7c20ec7 100644 --- a/js/main.js +++ b/js/main.js @@ -414,41 +414,57 @@ class Player extends PrimaryView { advance_by(tics) { for (let i = 0; i < tics; i++) { let input = this.get_input(); - let current_input = input; - if (! input.has('up') && ! input.has('down') && ! input.has('left') && ! input.has('right')) { - //input = this.previous_input; - } - // Choose the movement direction based on the held keys. A - // newly pressed action takes priority; in the case of a tie, - // um, XXX ???? - let chosen_action = null; - let any_action = null; - for (let action of ['up', 'down', 'left', 'right']) { - if (input.has(action)) { - if (this.previous_input.has(action)) { - chosen_action = action; + // Replica of CC2 input handling, based on experimentation + // FIXME unclear how this should interact with undo when playing normally, and + // definitely wrong when playing a replay; should this be in Level?? + if ((input.has('up') && input.has('down')) || (input.has('left') && input.has('right'))) { + // If opposing keys are ever held, stop moving and forget our state + this.primary_action = null; + this.secondary_action = null; + } + else if (this.primary_action && input.has(this.primary_action)) { + // Our primary action is locked in as long as it's held down, but check for a + // newly pressed secondary action; remember, there can't be two opposing keys held, + // because we already checked for that above, so this is only necessary if there's + // not already a secondary action + if (! this.secondary_action) { + for (let action of ['down', 'left', 'right', 'up']) { + if (action !== this.primary_action && + input.has(action) && ! this.previous_input.has(action)) + { + this.secondary_action = action; + break; + } } - any_action = action; } } - if (! chosen_action) { - // No keys are new, so check whether we were previously - // holding a key and are still doing it - if (this.previous_action && input.has(this.previous_action)) { - chosen_action = this.previous_action; - } - else { - // No dice, so use an arbitrary action - chosen_action = any_action; + else { + // Either we weren't holding any keys, or we let go of our primary action; either + // way, act like we're starting from scratch and check keys in priority order + this.primary_action = null; + this.secondary_action = null; + for (let action of ['down', 'left', 'right', 'up']) { + if (! input.has(action)) + continue; + + if (! this.primary_action) { + this.primary_action = action; + } + else { + // Note that because of the opposing keys check, there can never be more + // than two keys held down here + this.secondary_action = action; + } } } - let player_move = chosen_action ? ACTION_DIRECTIONS[chosen_action] : null; - this.previous_action = chosen_action; - this.previous_input = current_input; + this.previous_input = input; - this.level.advance_tic(player_move); + this.level.advance_tic( + this.primary_action ? ACTION_DIRECTIONS[this.primary_action] : null, + this.secondary_action ? ACTION_DIRECTIONS[this.secondary_action] : null, + ); if (this.level.state !== 'playing') { // We either won or lost! diff --git a/js/tiletypes.js b/js/tiletypes.js index bf49974..e2142ad 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -111,6 +111,7 @@ const TILE_TYPES = { }, popdown_floor: { draw_layer: LAYER_TERRAIN, + // FIXME should be on_approach on_arrive(me, level, other) { // FIXME could probably do this with state? or, eh level.transmute_tile(me, 'popdown_floor_visible');