Standardize visual state, and use it instead of transmuting a dead player

This commit is contained in:
Eevee (Evelyn Woods) 2020-09-16 21:08:43 -06:00
parent 171c52acb5
commit e0bfb0aadf
3 changed files with 105 additions and 55 deletions

View File

@ -934,13 +934,15 @@ export class Level {
}
}
fail(message) {
fail(reason) {
this.pending_undo.push(() => {
this.state = 'playing';
this.fail_reason = null;
this.player.fail_reason = null;
});
this.state = 'failure';
this.fail_reason = message;
this.fail_reason = reason;
this.player.fail_reason = reason;
throw new GameEnded;
}

View File

@ -1,4 +1,5 @@
import { DIRECTIONS } from './defs.js';
import TILE_TYPES from './tiletypes.js';
// TODO really need to specify this format more concretely, whoof
// XXX special kinds of drawing i know this has for a fact:
@ -268,19 +269,24 @@ export const CC2_TILESET_LAYOUT = {
// switch
thief_keys: [15, 21],
// TODO moving + swimming + pushing animations
player: {
normal: {
north: [0, 22],
south: [0, 23],
west: [8, 23],
east: [8, 22],
},
moving: {
north: [[0, 22], [1, 22], [2, 22], [3, 22], [4, 22], [5, 22], [6, 22], [7, 22]],
south: [[0, 23], [1, 23], [2, 23], [3, 23], [4, 23], [5, 23], [6, 23], [7, 23]],
west: [[8, 23], [9, 23], [10, 23], [11, 23], [12, 23], [13, 23], [14, 23], [15, 23]],
east: [[8, 22], [9, 22], [10, 22], [11, 22], [12, 22], [13, 22], [14, 22], [15, 22]],
},
standing: {
north: [0, 22],
south: [0, 23],
west: [8, 23],
east: [8, 22],
pushing: {
north: [8, 24],
east: [9, 24],
south: [10, 24],
west: [11, 24],
},
swimming: {
north: [[0, 24], [1, 24]],
@ -288,6 +294,11 @@ export const CC2_TILESET_LAYOUT = {
south: [[4, 24], [5, 24]],
west: [[6, 24], [7, 24]],
},
// These are frames from the splash/explosion animations
drowned: [5, 5],
burned: [1, 5],
exploded: [1, 5],
failed: [1, 5],
},
bogus_player_win: {
overlay: [0, 23],
@ -316,7 +327,7 @@ export const CC2_TILESET_LAYOUT = {
west: [[8, 28], [9, 28], [10, 28], [11, 28], [12, 28], [13, 28], [14, 28], [15, 28]],
east: [[8, 27], [9, 27], [10, 27], [11, 27], [12, 27], [13, 27], [14, 27], [15, 27]],
},
standing: {
normal: {
north: [0, 27],
south: [0, 28],
west: [8, 28],
@ -409,7 +420,6 @@ export const TILE_WORLD_TILESET_LAYOUT = {
explosion_other: [3, 7], // TODO ???
// 3, 8 unused
bogus_player_win: [3, 9], // TODO 10 and 11 too? does this animate?
// TODO player swimming is 3, 12-15
bogus_player_swimming: {
north: [3, 12],
west: [3, 13],
@ -482,10 +492,23 @@ export const TILE_WORLD_TILESET_LAYOUT = {
cleats: [6, 10],
suction_boots: [6, 11],
player: {
north: [6, 12],
south: [6, 14],
west: [6, 13],
east: [6, 15],
normal: {
north: [6, 12],
south: [6, 14],
west: [6, 13],
east: [6, 15],
},
moving: 'normal',
pushing: 'normal',
swimming: {
north: [3, 12],
west: [3, 13],
south: [3, 14],
east: [3, 15],
},
burned: [3, 4], // TODO TW's lynx mode doesn't use this! it uses the generic failed
exploded: [3, 6],
failed: [3, 7],
},
};
@ -573,43 +596,29 @@ export class Tileset {
}
}
// Unwrap animations etc.
if (!(coords instanceof Array)) {
// Must be an object of either tile-specific state, or directions
if (name === 'trap') {
if (tile && tile.open) {
coords = coords.open;
}
else {
coords = coords.closed;
}
// Apply custom per-type visual states
if (TILE_TYPES[name].visual_state) {
// Note that these accept null, too, and return a default
let state = TILE_TYPES[name].visual_state(tile);
// If it's a string, that's an alias for another state
if (typeof coords[state] === 'string') {
coords = coords[coords[state]];
}
else {
// TODO this is getting really ad-hoc and clumsy lol, maybe
// have tiles expose a single 'state' prop or something
if (coords.moving) {
if (! tile) {
coords = coords.standing;
}
else if (coords.swimming &&
// Count as swimming if we're in water, but NOT if we're midway through
// stepping into water from a non-water tile
// TODO umm, only if we have flippers?
tile.cell.some(t => t.type.name === 'water') &&
(! tile.previous_cell || tile.previous_cell.some(t => t.type.name === 'water')))
{
coords = coords.swimming;
}
else if (tile.animation_speed) {
coords = coords.moving;
}
else {
coords = coords.standing;
}
}
coords = coords[(tile && tile.direction) ?? 'south'];
coords = coords[state];
}
if (! coords) {
console.warn("No such state", state, "for tile", name, tile);
}
}
// Generic sprite definitions from here on!
// If we still have an object, it must be a table of directions
if (!(coords instanceof Array)) {
coords = coords[(tile && tile.direction) ?? 'south'];
}
// Deal with animation
if (coords[0] instanceof Array) {
if (tic !== null) {

View File

@ -7,6 +7,36 @@ const LAYER_ACTOR = 2;
const LAYER_OVERLAY = 3;
// TODO cc2 order is: swivel, thinwalls, canopy (and yes you can have them all in the same tile)
function player_visual_state(me) {
if (! me) {
return 'normal';
}
if (me.fail_reason === 'drowned') {
return 'drowned';
}
else if (me.fail_reason === 'burned') {
return 'burned';
}
else if (me.fail_reason === 'exploded') {
return 'exploded';
}
else if (me.fail_reason) {
return 'failed';
}
else if (me.cell.some(t => t.type.name === 'water') &&
(! me.previous_cell || me.previous_cell.some(t => t.type.name === 'water')))
{
return 'swimming';
}
else if (me.animation_speed) {
return 'moving';
}
else {
return 'normal';
}
}
const TILE_TYPES = {
// Floors and walls
floor: {
@ -290,7 +320,6 @@ const TILE_TYPES = {
level.transmute_tile(me, 'water');
}
else if (other.type.is_player) {
level.transmute_tile(other, 'player_burned');
level.fail('burned');
}
else {
@ -311,7 +340,6 @@ const TILE_TYPES = {
level.transmute_tile(me, 'ice');
}
else if (other.type.is_player) {
level.transmute_tile(other, 'splash');
level.fail('drowned');
}
else {
@ -433,11 +461,12 @@ const TILE_TYPES = {
draw_layer: LAYER_ITEM,
on_arrive(me, level, other) {
level.remove_tile(me);
let was_player = other.type.is_player;
level.transmute_tile(other, 'explosion');
if (was_player) {
if (other.type.is_player) {
level.fail('exploded');
}
else {
level.transmute_tile(other, 'explosion');
}
},
},
thief_tools: {
@ -552,11 +581,12 @@ const TILE_TYPES = {
is_required_chip: true,
on_arrive(me, level, other) {
level.remove_tile(me);
let was_player = other.type.is_player;
level.transmute_tile(other, 'explosion');
if (was_player) {
if (other.type.is_player) {
level.fail('exploded');
}
else {
level.transmute_tile(other, 'explosion');
}
},
},
purple_floor: {
@ -605,6 +635,14 @@ const TILE_TYPES = {
level.set_actor_stuck(other, true);
}
},
visual_state(me) {
if (me && me.open) {
return 'open';
}
else {
return 'closed';
}
},
},
transmogrifier: {
draw_layer: LAYER_TERRAIN,
@ -1093,6 +1131,7 @@ const TILE_TYPES = {
infinite_items: {
key_green: true,
},
visual_state: player_visual_state,
},
player2: {
draw_layer: LAYER_ACTOR,