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.pending_undo.push(() => {
this.state = 'playing'; this.state = 'playing';
this.fail_reason = null; this.fail_reason = null;
this.player.fail_reason = null;
}); });
this.state = 'failure'; this.state = 'failure';
this.fail_reason = message; this.fail_reason = reason;
this.player.fail_reason = reason;
throw new GameEnded; throw new GameEnded;
} }

View File

@ -1,4 +1,5 @@
import { DIRECTIONS } from './defs.js'; import { DIRECTIONS } from './defs.js';
import TILE_TYPES from './tiletypes.js';
// TODO really need to specify this format more concretely, whoof // TODO really need to specify this format more concretely, whoof
// XXX special kinds of drawing i know this has for a fact: // XXX special kinds of drawing i know this has for a fact:
@ -268,19 +269,24 @@ export const CC2_TILESET_LAYOUT = {
// switch // switch
thief_keys: [15, 21], thief_keys: [15, 21],
// TODO moving + swimming + pushing animations
player: { player: {
normal: {
north: [0, 22],
south: [0, 23],
west: [8, 23],
east: [8, 22],
},
moving: { moving: {
north: [[0, 22], [1, 22], [2, 22], [3, 22], [4, 22], [5, 22], [6, 22], [7, 22]], 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]], 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]], 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]], east: [[8, 22], [9, 22], [10, 22], [11, 22], [12, 22], [13, 22], [14, 22], [15, 22]],
}, },
standing: { pushing: {
north: [0, 22], north: [8, 24],
south: [0, 23], east: [9, 24],
west: [8, 23], south: [10, 24],
east: [8, 22], west: [11, 24],
}, },
swimming: { swimming: {
north: [[0, 24], [1, 24]], north: [[0, 24], [1, 24]],
@ -288,6 +294,11 @@ export const CC2_TILESET_LAYOUT = {
south: [[4, 24], [5, 24]], south: [[4, 24], [5, 24]],
west: [[6, 24], [7, 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: { bogus_player_win: {
overlay: [0, 23], 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]], 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]], east: [[8, 27], [9, 27], [10, 27], [11, 27], [12, 27], [13, 27], [14, 27], [15, 27]],
}, },
standing: { normal: {
north: [0, 27], north: [0, 27],
south: [0, 28], south: [0, 28],
west: [8, 28], west: [8, 28],
@ -409,7 +420,6 @@ export const TILE_WORLD_TILESET_LAYOUT = {
explosion_other: [3, 7], // TODO ??? explosion_other: [3, 7], // TODO ???
// 3, 8 unused // 3, 8 unused
bogus_player_win: [3, 9], // TODO 10 and 11 too? does this animate? bogus_player_win: [3, 9], // TODO 10 and 11 too? does this animate?
// TODO player swimming is 3, 12-15
bogus_player_swimming: { bogus_player_swimming: {
north: [3, 12], north: [3, 12],
west: [3, 13], west: [3, 13],
@ -482,10 +492,23 @@ export const TILE_WORLD_TILESET_LAYOUT = {
cleats: [6, 10], cleats: [6, 10],
suction_boots: [6, 11], suction_boots: [6, 11],
player: { player: {
north: [6, 12], normal: {
south: [6, 14], north: [6, 12],
west: [6, 13], south: [6, 14],
east: [6, 15], 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. // Apply custom per-type visual states
if (!(coords instanceof Array)) { if (TILE_TYPES[name].visual_state) {
// Must be an object of either tile-specific state, or directions // Note that these accept null, too, and return a default
if (name === 'trap') { let state = TILE_TYPES[name].visual_state(tile);
if (tile && tile.open) { // If it's a string, that's an alias for another state
coords = coords.open; if (typeof coords[state] === 'string') {
} coords = coords[coords[state]];
else {
coords = coords.closed;
}
} }
else { else {
// TODO this is getting really ad-hoc and clumsy lol, maybe coords = coords[state];
// have tiles expose a single 'state' prop or something }
if (coords.moving) {
if (! tile) { if (! coords) {
coords = coords.standing; console.warn("No such state", state, "for tile", name, tile);
}
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'];
} }
} }
// 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 // Deal with animation
if (coords[0] instanceof Array) { if (coords[0] instanceof Array) {
if (tic !== null) { if (tic !== null) {

View File

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