Fix rovers once and for all; make helmet work more often; rename some stuff; simplify attempt_step
This commit is contained in:
parent
7cf92f7841
commit
d4da572940
@ -1128,7 +1128,7 @@ export function parse_level(buf, number = 1) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn(`Unrecognized section type '${type}' at offset ${bytes.byteOffset}`);
|
||||
console.warn(`Unrecognized section type '${type}' at offset ${bytes.byteOffset}`, view);
|
||||
// TODO save it, persist when editing level
|
||||
}
|
||||
}
|
||||
|
||||
306
js/game.js
306
js/game.js
@ -52,8 +52,6 @@ export class Tile {
|
||||
// Extremely awkward special case: items don't block monsters if the cell also contains an
|
||||
// item modifier (i.e. "no" sign) or a real player
|
||||
// TODO would love to get this outta here
|
||||
// FIXME i think this can be removed if monster/player interaction stops being a literal
|
||||
// collision and starts being a result of even attempting to move
|
||||
if (this.type.is_item &&
|
||||
this.cell.some(tile => tile.type.item_modifier || tile.type.is_real_player))
|
||||
return false;
|
||||
@ -104,7 +102,7 @@ export class Tile {
|
||||
direction = tile.cell.redirect_exit(tile, direction);
|
||||
// Need to explicitly check this here, otherwise you could /attempt/ to push a block,
|
||||
// which would fail, but it would still change the block's direction
|
||||
return ! tile.cell.blocks_leaving(tile, direction);
|
||||
return tile.cell.try_leaving(tile, direction);
|
||||
}
|
||||
|
||||
// Inventory stuff
|
||||
@ -195,57 +193,55 @@ export class Cell extends Array {
|
||||
return this.some(tile => tile.name === name);
|
||||
}
|
||||
|
||||
blocks_leaving(actor, direction) {
|
||||
try_leaving(actor, direction) {
|
||||
for (let tile of this) {
|
||||
if (tile === actor)
|
||||
continue;
|
||||
|
||||
if (tile.type.traps && tile.type.traps(tile, actor))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
if (tile.type.blocks_leaving && tile.type.blocks_leaving(tile, actor, direction))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if this actor can move this direction into this cell. May have side effects, depending
|
||||
// on the value of push_mode:
|
||||
// - null: Default. Treat pushable objects as blocking.
|
||||
// - 'ignore': Treat pushable objects as nonblocking.
|
||||
// - 'trace': Don't try to move pushable objects, but do check whether they could be pushed,
|
||||
// recursively if necessary.
|
||||
// - 'move': Attempt to move pushable objects out of the way immediately.
|
||||
blocks_entering(actor, direction, level, push_mode = null) {
|
||||
// Check if this actor can move this direction into this cell. Returns true on success. May
|
||||
// have side effects, depending on the value of push_mode:
|
||||
// - null: Default. Do not impact game state. Treat pushable objects as blocking.
|
||||
// - 'bump': Fire bump triggers. Don't move pushable objects, but do check whether they /could/
|
||||
// be pushed, recursively if necessary.
|
||||
// - 'push': Fire bump triggers. Attempt to move pushable objects out of the way immediately.
|
||||
try_entering(actor, direction, level, push_mode = null) {
|
||||
let pushable_tiles = [];
|
||||
let blocked = false;
|
||||
for (let tile of this) {
|
||||
// (Note that here, and anywhere else that has any chance of altering the cell's contents,
|
||||
// we iterate over a copy of the cell to insulate ourselves from tiles appearing or
|
||||
// disappearing mid-iteration.)
|
||||
for (let tile of Array.from(this)) {
|
||||
// TODO check ignores here?
|
||||
if (actor.type.on_bump) {
|
||||
actor.type.on_bump(actor, level, tile, direction);
|
||||
}
|
||||
if (tile.type.on_bumped) {
|
||||
tile.type.on_bumped(tile, level, actor);
|
||||
}
|
||||
|
||||
if (! tile.blocks(actor, direction, level))
|
||||
continue;
|
||||
|
||||
if (push_mode === null)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
if (! actor.can_push(tile, direction)) {
|
||||
if (push_mode === 'move') {
|
||||
// Track this instead of returning immediately, because 'move' mode also bumps
|
||||
if (push_mode === 'push') {
|
||||
// Track this instead of returning immediately, because 'push' mode also bumps
|
||||
// every tile in the cell
|
||||
blocked = true;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (push_mode === 'ignore')
|
||||
continue;
|
||||
|
||||
if (push_mode === 'move') {
|
||||
if (actor.type.on_bump) {
|
||||
actor.type.on_bump(actor, level, tile);
|
||||
}
|
||||
if (tile.type.on_bumped) {
|
||||
tile.type.on_bumped(tile, level, actor);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,27 +250,37 @@ export class Cell extends Array {
|
||||
}
|
||||
|
||||
if (blocked)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
// If we got this far, all that's left is to deal with pushables
|
||||
if (pushable_tiles.length > 0) {
|
||||
let neighbor_cell = level.get_neighboring_cell(this, direction);
|
||||
if (! neighbor_cell)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
for (let tile of pushable_tiles) {
|
||||
if (push_mode === 'trace') {
|
||||
if (neighbor_cell.blocks_entering(tile, direction, level, push_mode))
|
||||
return true;
|
||||
if (push_mode === 'bump') {
|
||||
// FIXME and leaving!
|
||||
if (! neighbor_cell.try_entering(tile, direction, level, push_mode))
|
||||
return false;
|
||||
}
|
||||
else if (push_mode === 'move') {
|
||||
if (! level.attempt_step(tile, direction))
|
||||
return true;
|
||||
else if (push_mode === 'push') {
|
||||
if (actor === this.player) {
|
||||
this._set_tile_prop(actor, 'is_pushing', true);
|
||||
}
|
||||
if (! level.attempt_out_of_turn_step(tile, direction)) {
|
||||
if (tile.slide_mode !== null && tile.movement_cooldown !== 0) {
|
||||
// If the push failed and the obstacle is in the middle of a slide,
|
||||
// remember this as the next move it'll make
|
||||
level._set_tile_prop(tile, 'pending_push', direction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special railroad ability: change the direction we attempt to leave
|
||||
@ -729,6 +735,10 @@ export class Level {
|
||||
success = this.attempt_step(actor, actor.decision);
|
||||
}
|
||||
|
||||
if (! success && actor.type.on_blocked) {
|
||||
actor.type.on_blocked(actor, this, actor.decision);
|
||||
}
|
||||
|
||||
// Track whether the player is blocked, for visual effect
|
||||
if (actor === this.player && actor.decision && ! success) {
|
||||
this.sfx.play_once('blocked');
|
||||
@ -848,7 +858,7 @@ export class Level {
|
||||
else if (actor.slide_mode === 'ice') {
|
||||
// A sliding player that bonks into a wall still needs to turn around, but in this
|
||||
// case they do NOT start pushing blocks early
|
||||
if (! try_direction(actor.direction, 'trace')) {
|
||||
if (! try_direction(actor.direction, 'bump')) {
|
||||
this._handle_slide_bonk(actor);
|
||||
}
|
||||
}
|
||||
@ -863,7 +873,7 @@ export class Level {
|
||||
let open;
|
||||
if (dir2 === null) {
|
||||
// Only one direction is held, but for consistency, "check" it anyway
|
||||
open = try_direction(dir1, 'move');
|
||||
open = try_direction(dir1, 'push');
|
||||
actor.decision = dir1;
|
||||
}
|
||||
else {
|
||||
@ -871,8 +881,8 @@ export class Level {
|
||||
// one, UNLESS it's blocked AND the other isn't
|
||||
if (dir1 === actor.direction || dir2 === actor.direction) {
|
||||
let other_direction = dir1 === actor.direction ? dir2 : dir1;
|
||||
let curr_open = try_direction(actor.direction, 'move');
|
||||
let other_open = try_direction(other_direction, 'move');
|
||||
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;
|
||||
@ -887,8 +897,8 @@ export class Level {
|
||||
// FIXME i'm told cc2 prefers orthogonal actually, but need to check on that
|
||||
// FIXME lynx only checks horizontal, what about cc2? it must check both
|
||||
// because of the behavior where pushing into a corner always pushes horizontal
|
||||
let open1 = try_direction(dir1, 'move');
|
||||
let open2 = try_direction(dir2, 'move');
|
||||
let open1 = try_direction(dir1, 'push');
|
||||
let open2 = try_direction(dir2, 'push');
|
||||
if (open1 && ! open2) {
|
||||
actor.decision = dir1;
|
||||
open = true;
|
||||
@ -978,7 +988,7 @@ export class Level {
|
||||
|
||||
direction = actor.cell.redirect_exit(actor, direction);
|
||||
|
||||
if (this.check_movement(actor, actor.cell, direction, 'trace')) {
|
||||
if (this.check_movement(actor, actor.cell, direction, 'bump')) {
|
||||
// We found a good direction! Stop here
|
||||
actor.decision = direction;
|
||||
all_blocked = false;
|
||||
@ -1023,8 +1033,8 @@ export class Level {
|
||||
check_movement(actor, orig_cell, direction, push_mode) {
|
||||
let dest_cell = this.get_neighboring_cell(orig_cell, direction);
|
||||
return (dest_cell &&
|
||||
! orig_cell.blocks_leaving(actor, direction) &&
|
||||
! dest_cell.blocks_entering(actor, direction, this, push_mode));
|
||||
orig_cell.try_leaving(actor, direction) &&
|
||||
dest_cell.try_entering(actor, direction, this, push_mode));
|
||||
}
|
||||
|
||||
// Try to move the given actor one tile in the given direction and update their cooldown.
|
||||
@ -1043,90 +1053,82 @@ export class Level {
|
||||
|
||||
let move = DIRECTIONS[direction].movement;
|
||||
let goal_cell = this.get_neighboring_cell(actor.cell, direction);
|
||||
if (! goal_cell)
|
||||
return false;
|
||||
|
||||
// TODO this could be a lot simpler if i could early-return! should ice bumping be
|
||||
// somewhere else?
|
||||
let blocked;
|
||||
if (goal_cell) {
|
||||
// Only bother touching the goal cell if we're not already trapped in this one
|
||||
if (actor.cell.blocks_leaving(actor, direction)) {
|
||||
blocked = true;
|
||||
// Only bother touching the goal cell if we're not already trapped in this one
|
||||
if (! actor.cell.try_leaving(actor, direction))
|
||||
return false;
|
||||
|
||||
if (! goal_cell.try_entering(actor, direction, this, 'push'))
|
||||
return false;
|
||||
|
||||
// FIXME this feels clunky
|
||||
let terrain = goal_cell.get_terrain();
|
||||
if (terrain && terrain.type.slide_mode && ! actor.ignores(terrain.type.name)) {
|
||||
double_speed = true;
|
||||
}
|
||||
|
||||
// FIXME this can probably reuse try_entering now
|
||||
// Try to move into the cell. This is usually a simple check of whether we can
|
||||
// enter it (similar to Cell.try_entering), but if the only thing blocking us is
|
||||
// a pushable object, we have to do two more passes: one to push anything pushable,
|
||||
// then one to check whether we're blocked again.
|
||||
/*
|
||||
let blocked_by_pushable = false;
|
||||
for (let tile of goal_cell) {
|
||||
if (tile.blocks(actor, direction, this)) {
|
||||
if (actor.can_push(tile, direction)) {
|
||||
blocked_by_pushable = true;
|
||||
}
|
||||
else {
|
||||
blocked = true;
|
||||
// Don't break here, because we might still want to bump other tiles
|
||||
}
|
||||
}
|
||||
|
||||
if (actor.ignores(tile.type.name))
|
||||
continue;
|
||||
|
||||
if (tile.type.slide_mode) {
|
||||
double_speed = true;
|
||||
}
|
||||
|
||||
// Bump tiles that we're even attempting to move into; this mostly reveals
|
||||
// invisible walls, blue floors, etc.
|
||||
// XXX how to guarantee this only happens once...
|
||||
if (actor.type.on_bump) {
|
||||
if (actor.type.on_bump(actor, this, tile) === false)
|
||||
return;
|
||||
}
|
||||
if (tile.type.on_bumped) {
|
||||
tile.type.on_bumped(tile, this, actor);
|
||||
}
|
||||
}
|
||||
|
||||
// (Note that here, and anywhere else that has any chance of
|
||||
// altering the cell's contents, we iterate over a copy of the cell
|
||||
// to insulate ourselves from tiles appearing or disappearing
|
||||
// mid-iteration.)
|
||||
// FIXME actually, this prevents flicking!
|
||||
if (! blocked) {
|
||||
// FIXME this can probably reuse blocks_entering now
|
||||
// Try to move into the cell. This is usually a simple check of whether we can
|
||||
// enter it (similar to Cell.blocks_entering), but if the only thing blocking us is
|
||||
// a pushable object, we have to do two more passes: one to push anything pushable,
|
||||
// then one to check whether we're blocked again.
|
||||
let blocked_by_pushable = false;
|
||||
for (let tile of goal_cell) {
|
||||
if (tile.blocks(actor, direction, this)) {
|
||||
if (actor.can_push(tile, direction)) {
|
||||
blocked_by_pushable = true;
|
||||
}
|
||||
else {
|
||||
blocked = true;
|
||||
// Don't break here, because we might still want to bump other tiles
|
||||
}
|
||||
}
|
||||
|
||||
if (actor.ignores(tile.type.name))
|
||||
// If the only thing blocking us can be pushed, give that a shot
|
||||
if (! blocked && blocked_by_pushable) {
|
||||
// This time make a copy, since we're modifying the contents of the cell
|
||||
for (let tile of Array.from(goal_cell)) {
|
||||
if (! actor.can_push(tile, direction))
|
||||
continue;
|
||||
|
||||
if (tile.type.slide_mode) {
|
||||
double_speed = true;
|
||||
if (! this.attempt_out_of_turn_step(tile, direction) &&
|
||||
tile.slide_mode !== null && tile.movement_cooldown !== 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Bump tiles that we're even attempting to move into; this mostly reveals
|
||||
// invisible walls, blue floors, etc.
|
||||
// XXX how to guarantee this only happens once...
|
||||
if (actor.type.on_bump) {
|
||||
if (actor.type.on_bump(actor, this, tile) === false)
|
||||
return;
|
||||
}
|
||||
if (tile.type.on_bumped) {
|
||||
tile.type.on_bumped(tile, this, actor);
|
||||
if (actor === this.player) {
|
||||
this._set_tile_prop(actor, 'is_pushing', true);
|
||||
}
|
||||
}
|
||||
|
||||
// If the only thing blocking us can be pushed, give that a shot
|
||||
if (! blocked && blocked_by_pushable) {
|
||||
// This time make a copy, since we're modifying the contents of the cell
|
||||
for (let tile of Array.from(goal_cell)) {
|
||||
if (! actor.can_push(tile, direction))
|
||||
continue;
|
||||
|
||||
if (! this.attempt_out_of_turn_step(tile, direction) &&
|
||||
tile.slide_mode !== null && tile.movement_cooldown !== 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
if (actor === this.player) {
|
||||
this._set_tile_prop(actor, 'is_pushing', true);
|
||||
}
|
||||
}
|
||||
|
||||
// Now check if we're still blocked
|
||||
blocked = goal_cell.blocks_entering(actor, direction, this);
|
||||
}
|
||||
// Now check if we're still blocked
|
||||
blocked = goal_cell.try_entering(actor, direction, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Hit the edge
|
||||
blocked = true;
|
||||
}
|
||||
|
||||
if (blocked) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// We're clear!
|
||||
if (double_speed || actor.has_item('speed_boots')) {
|
||||
@ -1200,33 +1202,12 @@ export class Level {
|
||||
this.hint_shown = null;
|
||||
}
|
||||
for (let tile of goal_cell) {
|
||||
if (actor.type.is_real_player && tile.type.is_monster) {
|
||||
this.fail(tile.type.name);
|
||||
}
|
||||
else if (actor.type.is_monster && tile.type.is_real_player) {
|
||||
this.fail(actor.type.name);
|
||||
}
|
||||
else if (actor.type.is_block && tile.type.is_real_player) {
|
||||
this.fail('squished');
|
||||
}
|
||||
|
||||
// FIXME this could go in on_approach now
|
||||
if (actor === this.player && tile.type.is_hint) {
|
||||
this.hint_shown = tile.hint_text ?? this.stored_level.hint;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're stepping directly on the player, that kills them too; the player and a monster
|
||||
// must be at least 5 tics apart
|
||||
// TODO the rules in lynx might be slightly different?
|
||||
if (actor.type.is_monster && goal_cell === this.player.previous_cell &&
|
||||
// Player has decided to leave their cell, but hasn't actually taken a step yet
|
||||
this.player.movement_cooldown === this.player.movement_speed &&
|
||||
// See the extensive comment in attempt_out_of_turn_step
|
||||
this.player.cooldown_delay_hack !== 2)
|
||||
{
|
||||
this.fail(actor.type.name);
|
||||
}
|
||||
|
||||
if (actor === this.player && goal_cell[0].type.name === 'floor') {
|
||||
this.sfx.play_once('step-floor');
|
||||
}
|
||||
@ -1240,6 +1221,22 @@ export class Level {
|
||||
if (actor.ignores(tile.type.name))
|
||||
continue;
|
||||
|
||||
// Possibly kill a player
|
||||
if (actor.has_item('helmet') || tile.has_item('helmet')) {
|
||||
// Helmet disables this, do nothing
|
||||
}
|
||||
else if (actor.type.is_real_player && tile.type.is_monster) {
|
||||
this.fail(tile.type.name);
|
||||
}
|
||||
else if (actor.type.is_monster && tile.type.is_real_player) {
|
||||
this.fail(actor.type.name);
|
||||
}
|
||||
else if (actor.type.is_block && tile.type.is_real_player) {
|
||||
// Note that blocks squish players if they move for ANY reason, even if pushed by
|
||||
// another player!
|
||||
this.fail('squished');
|
||||
}
|
||||
|
||||
if (tile.type.on_approach) {
|
||||
tile.type.on_approach(tile, this, actor);
|
||||
}
|
||||
@ -1248,6 +1245,21 @@ export class Level {
|
||||
}
|
||||
}
|
||||
|
||||
// If we're a monster stepping on the player's tail, that also kills her immediately; the
|
||||
// player and a monster must be strictly more than 4 tics apart
|
||||
// FIXME this only works for the /current/ player but presumably applies to all of them,
|
||||
// though i'm having trouble coming up with a test
|
||||
// TODO the rules in lynx might be slightly different?
|
||||
if (actor.type.is_monster && goal_cell === this.player.previous_cell &&
|
||||
// Player has decided to leave their cell, but hasn't actually taken a step yet
|
||||
this.player.movement_cooldown === this.player.movement_speed &&
|
||||
! actor.has_item('helmet') && ! this.player.has_item('helmet') &&
|
||||
// See the extensive comment in attempt_out_of_turn_step
|
||||
this.player.cooldown_delay_hack !== 2)
|
||||
{
|
||||
this.fail(actor.type.name);
|
||||
}
|
||||
|
||||
if (this.compat.tiles_react_instantly) {
|
||||
this.step_on_cell(actor, actor.cell);
|
||||
}
|
||||
@ -1294,7 +1306,7 @@ export class Level {
|
||||
let teleporter = actor.just_stepped_on_teleporter;
|
||||
actor.just_stepped_on_teleporter = null;
|
||||
|
||||
let push_mode = actor === this.player ? 'move' : 'trace';
|
||||
let push_mode = actor === this.player ? 'push' : 'bump';
|
||||
let original_direction = actor.direction;
|
||||
let success = false;
|
||||
let dest, direction;
|
||||
|
||||
@ -27,7 +27,7 @@ function on_ready_force_floor(me, level) {
|
||||
let neighbor = level.get_neighboring_cell(me.cell, actor.direction);
|
||||
if (! neighbor)
|
||||
return;
|
||||
if (! neighbor.blocks_entering(actor, actor.direction, level, 'trace'))
|
||||
if (neighbor.try_entering(actor, actor.direction, level))
|
||||
return;
|
||||
let item = me.cell.get_item();
|
||||
if (! item)
|
||||
@ -975,7 +975,7 @@ const TILE_TYPES = {
|
||||
draw_layer: DRAW_LAYERS.item,
|
||||
is_chip: true,
|
||||
is_required_chip: true,
|
||||
blocks_collision: COLLISION.block_cc1 | COLLISION.monster_solid,
|
||||
blocks_collision: COLLISION.block_cc1 | (COLLISION.monster_solid & ~COLLISION.rover),
|
||||
on_arrive(me, level, other) {
|
||||
if (other.type.is_real_player) {
|
||||
level.collect_chip();
|
||||
@ -1991,34 +1991,14 @@ const TILE_TYPES = {
|
||||
},
|
||||
_emulatees: ['teeth', 'glider', 'bug', 'ball', 'teeth_timid', 'fireball', 'paramecium', 'walker'],
|
||||
decide_movement(me, level) {
|
||||
level._set_tile_prop(me, 'attempted_moves', me.attempted_moves + 1);
|
||||
if (me.attempted_moves >= 32) {
|
||||
level._set_tile_prop(me, 'attempted_moves', me.attempted_moves - 32); // XXX unsure if this is 0 or -32
|
||||
level._set_tile_prop(me, 'attempted_moves', 0);
|
||||
level._set_tile_prop(me, 'current_emulatee', (me.current_emulatee + 1) % me.type._emulatees.length);
|
||||
}
|
||||
|
||||
let emulatee = me.type._emulatees[me.current_emulatee];
|
||||
let preference = TILE_TYPES[emulatee].decide_movement(me, level);
|
||||
// Rig up the preference so a failure counts as two moves
|
||||
if (preference) {
|
||||
level._set_tile_prop(me, 'attempted_moves', me.attempted_moves + 1);
|
||||
let last_direction = preference[preference.length - 1];
|
||||
if (typeof last_direction === 'function') {
|
||||
// This is tricky! We want this function to only be called ONCE max, since the
|
||||
// walker uses it to carefully tune the PRNG, so replace it with one that lazily
|
||||
// overwrites 'last_direction'
|
||||
preference.pop();
|
||||
let lazy = last_direction;
|
||||
preference.push(function() {
|
||||
last_direction = lazy();
|
||||
return last_direction;
|
||||
});
|
||||
}
|
||||
preference.push(function() {
|
||||
level._set_tile_prop(me, 'attempted_moves', me.attempted_moves + 1);
|
||||
return last_direction;
|
||||
});
|
||||
}
|
||||
return preference;
|
||||
return TILE_TYPES[emulatee].decide_movement(me, level);
|
||||
},
|
||||
visual_state(me) {
|
||||
if (me && me.current_emulatee !== undefined) {
|
||||
@ -2226,6 +2206,7 @@ const TILE_TYPES = {
|
||||
draw_layer: DRAW_LAYERS.actor,
|
||||
is_actor: true,
|
||||
has_inventory: true,
|
||||
can_reveal_walls: true,
|
||||
// FIXME ???????
|
||||
collision_mask: COLLISION.block_cc2,
|
||||
// FIXME do i start moving immediately when dropped, or next turn?
|
||||
@ -2233,20 +2214,22 @@ const TILE_TYPES = {
|
||||
decide_movement(me, level) {
|
||||
return [me.direction];
|
||||
},
|
||||
// FIXME feel like this should be on_blocked?
|
||||
// FIXME specific case for player!
|
||||
on_bump(me, level, other) {
|
||||
on_blocked(me, level, direction) {
|
||||
if (me.slide_mode)
|
||||
return;
|
||||
if (other.type.is_actor) {
|
||||
level.transmute_tile(me, 'explosion');
|
||||
level.transmute_tile(other, 'explosion');
|
||||
return false;
|
||||
}
|
||||
else if (other.blocks(me, me.direction, level)) {
|
||||
level.transmute_tile(me, 'explosion');
|
||||
return false;
|
||||
let cell = level.get_neighboring_cell(me.cell, direction);
|
||||
if (cell) {
|
||||
let other = cell.get_actor();
|
||||
if (other) {
|
||||
if (other.is_real_player) {
|
||||
level.fail(me.type.name);
|
||||
}
|
||||
else {
|
||||
level.transmute_tile(other, 'explosion');
|
||||
}
|
||||
}
|
||||
}
|
||||
level.transmute_tile(me, 'explosion');
|
||||
},
|
||||
},
|
||||
xray_eye: {
|
||||
@ -2424,7 +2407,7 @@ const TILE_TYPES = {
|
||||
draw_layer: DRAW_LAYERS.item,
|
||||
is_chip: true,
|
||||
is_required_chip: true,
|
||||
blocks_collision: COLLISION.block_cc1 | COLLISION.monster_solid,
|
||||
blocks_collision: COLLISION.block_cc1 | (COLLISION.monster_solid & ~COLLISION.rover),
|
||||
on_arrive(me, level, other) {
|
||||
if (other.type.is_real_player) {
|
||||
level.collect_chip();
|
||||
@ -2435,7 +2418,7 @@ const TILE_TYPES = {
|
||||
chip_extra: {
|
||||
draw_layer: DRAW_LAYERS.item,
|
||||
is_chip: true,
|
||||
blocks_collision: COLLISION.block_cc1 | COLLISION.monster_solid,
|
||||
blocks_collision: COLLISION.block_cc1 | (COLLISION.monster_solid & ~COLLISION.rover),
|
||||
on_arrive(me, level, other) {
|
||||
if (other.type.is_real_player) {
|
||||
level.collect_chip();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user