Implement CC2 input handling, bumping, and block slapping

This commit is contained in:
Eevee (Evelyn Woods) 2020-09-12 20:07:26 -06:00
parent 64bd6c49d9
commit 5d39e37ad2
3 changed files with 71 additions and 32 deletions

View File

@ -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;

View File

@ -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!

View File

@ -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');