Overhaul collision

Collision now uses bits and masks.  The main upshot is that ghost and
ice/directional blocks collide much more correctly, now.  And turtles
block fireballs.

Also, monsters can now move over "no" signs, and can trample the player
if she's standing on top of an item.

While I was at it, I finished implementing the "bestowal bow", an item
mod (same layer as the "no" sign) that allows any actor to pick up the
item in that tile.
This commit is contained in:
Eevee (Evelyn Woods) 2020-11-23 23:41:32 -07:00
parent fb301b3b3e
commit 5cb29c8f7d
4 changed files with 313 additions and 292 deletions

View File

@ -34,3 +34,35 @@ export const DIRECTIONS = {
opposite: 'west',
},
};
// TODO cc2 order is: swivel, thinwalls, canopy (and yes you can have them all in the same tile)
export const DRAW_LAYERS = {
terrain: 0,
item: 1,
item_mod: 2,
actor: 3,
overlay: 4,
MAX: 5,
};
export const COLLISION = {
player1: 0x0001,
player2: 0x0002,
player: 0x0003,
block_cc1: 0x0004,
block_cc2: 0x0008, // ice + directional
// NOTE: "monster" does NOT include ghost, because it so rarely overlaps anything else
monster: 0x0100,
// Some monsters also have their own extra flag because of weird behavior
fireball: 0x0200,
bug: 0x0400,
rover: 0x1000,
ghost: 0x8000,
// Combo masks used for matching
all_but_ghost: 0xffff & ~0x8000,
all_but_player: 0xffff & ~0x0003,
all: 0xffff,
};

View File

@ -45,20 +45,20 @@ export class Tile {
}
blocks(other, direction, level) {
if (this.type.blocks_all)
// Extremely awkward special case: items don't block monsters if the cell also contains an
// item modifier (i.e. "no" sign) or a player
// TODO would love to get this outta here
if (this.type.is_item &&
this.cell.some(tile => tile.type.item_modifier || tile.type.is_player))
return false;
if (this.type.blocks_collision & other.type.collision_mask)
return true;
if (this.type.thin_walls &&
this.type.thin_walls.has(DIRECTIONS[direction].opposite))
return true;
if (other.type.is_player && this.type.blocks_players)
return true;
if (other.type.is_monster && this.type.blocks_monsters)
return true;
if (other.type.is_block && this.type.blocks_blocks)
return true;
if (this.type.blocks)
return this.type.blocks(this, level, other);
@ -157,6 +157,14 @@ export class Cell extends Array {
return null;
}
get_item_mod() {
for (let tile of this) {
if (tile.type.item_modifier)
return tile;
}
return null;
}
blocks_leaving(actor, direction) {
for (let tile of this) {
if (tile === actor)
@ -1025,9 +1033,9 @@ export class Level {
if (actor.ignores(tile.type.name))
continue;
// TODO some actors can pick up some items...
if (tile.type.is_item &&
(actor.type.is_player || cell.some(t => t.allows_all_pickup)) &&
(actor.type.has_inventory ||
cell.some(t => t.type.item_modifier === 'pickup')) &&
this.attempt_take(actor, tile))
{
if (tile.type.is_key) {
@ -1545,10 +1553,15 @@ export class Level {
// Have an actor try to pick up a particular tile; it's prevented if there's a no sign, and the
// tile is removed if successful
attempt_take(actor, tile) {
if (! tile.cell.some(t => t.type.disables_pickup) &&
this.give_actor(actor, tile.type.name))
{
let mod = tile.cell.get_item_mod();
if (mod && mod.type.item_modifier === 'ignore')
return false;
if (this.give_actor(actor, tile.type.name)) {
this.remove_tile(tile);
if (mod && mod.type.item_modifier === 'pickup') {
this.remove_tile(mod);
}
return true;
}
return false;

View File

@ -500,7 +500,7 @@ const EDITOR_PALETTE = [{
tiles: [
'key_blue', 'key_red', 'key_yellow', 'key_green',
'flippers', 'fire_boots', 'cleats', 'suction_boots',
'no_sign', // 'bestowal_bow',
'no_sign', 'bestowal_bow',
],
}, {
title: "Creatures",

File diff suppressed because it is too large Load Diff