Finish CC1 parser; show hints; improve ice
This commit is contained in:
parent
3084ca7b49
commit
0dd190fc5a
@ -7,13 +7,19 @@ const CC1_TILE_ENCODING = {
|
||||
0x02: 'chip',
|
||||
0x03: 'water',
|
||||
0x04: 'fire',
|
||||
// invis wall
|
||||
// thin walls...
|
||||
0x05: 'wall_invisible',
|
||||
0x06: 'thinwall_n',
|
||||
0x07: 'thinwall_w',
|
||||
0x08: 'thinwall_s',
|
||||
0x09: 'thinwall_e',
|
||||
0x0a: 'dirt_block',
|
||||
0x0b: 'dirt',
|
||||
0x0c: 'ice',
|
||||
0x0d: 'force_floor_s',
|
||||
// cloners
|
||||
0x0e: ['clone_block', 'north'],
|
||||
0x0f: ['clone_block', 'west'],
|
||||
0x10: ['clone_block', 'south'],
|
||||
0x11: ['clone_block', 'east'],
|
||||
0x12: 'force_floor_n',
|
||||
0x13: 'force_floor_e',
|
||||
0x14: 'force_floor_w',
|
||||
@ -22,24 +28,37 @@ const CC1_TILE_ENCODING = {
|
||||
0x17: 'door_red',
|
||||
0x18: 'door_green',
|
||||
0x19: 'door_yellow',
|
||||
0x1a: 'ice_se',
|
||||
0x1b: 'ice_sw',
|
||||
0x1c: 'ice_nw',
|
||||
0x1d: 'ice_nw',
|
||||
// fake blocks
|
||||
// 0x20 unused
|
||||
// thief
|
||||
0x1a: 'ice_nw',
|
||||
0x1b: 'ice_ne',
|
||||
0x1c: 'ice_se',
|
||||
0x1d: 'ice_sw',
|
||||
0x1e: 'fake_floor',
|
||||
0x1f: 'fake_wall',
|
||||
0x20: 'wall_invisible', // unused
|
||||
0x21: 'thief_tools',
|
||||
0x22: 'socket',
|
||||
// green button
|
||||
// red button
|
||||
// green tile
|
||||
// more buttons, teleports, bombs, traps
|
||||
0x2f: 'clue',
|
||||
|
||||
0x23: 'button_green',
|
||||
0x24: 'button_red',
|
||||
0x25: 'green_wall',
|
||||
0x26: 'green_floor',
|
||||
0x27: 'button_brown',
|
||||
0x28: 'button_blue',
|
||||
0x29: 'teleport_blue',
|
||||
0x2a: 'bomb',
|
||||
0x2b: 'trap',
|
||||
0x2c: 'wall_appearing',
|
||||
0x2d: 'gravel',
|
||||
0x2e: 'popwall',
|
||||
0x2f: 'hint',
|
||||
0x30: 'thinwall_se',
|
||||
0x31: 'cloner',
|
||||
0x32: 'force_floor_all',
|
||||
0x33: 'player_drowned',
|
||||
0x34: 'player_burned',
|
||||
//0x35: player_burned, XXX is this burned off a tile or?
|
||||
// 0x36 - 0x38 unused
|
||||
0x36: 'wall_invisible', // unused
|
||||
0x37: 'wall_invisible', // unused
|
||||
0x38: 'wall_invisible', // unused
|
||||
//0x39: exit_player,
|
||||
0x3a: 'exit',
|
||||
0x3b: 'exit', // i think this is for the second frame of the exit animation?
|
||||
@ -48,7 +67,38 @@ const CC1_TILE_ENCODING = {
|
||||
0x41: ['bug', 'west'],
|
||||
0x42: ['bug', 'south'],
|
||||
0x43: ['bug', 'east'],
|
||||
|
||||
0x44: ['fireball', 'north'],
|
||||
0x45: ['fireball', 'west'],
|
||||
0x46: ['fireball', 'south'],
|
||||
0x47: ['fireball', 'east'],
|
||||
0x48: ['ball', 'north'],
|
||||
0x49: ['ball', 'west'],
|
||||
0x4a: ['ball', 'south'],
|
||||
0x4b: ['ball', 'east'],
|
||||
0x4c: ['tank_blue', 'north'],
|
||||
0x4d: ['tank_blue', 'west'],
|
||||
0x4e: ['tank_blue', 'south'],
|
||||
0x4f: ['tank_blue', 'east'],
|
||||
0x50: ['glider', 'north'],
|
||||
0x51: ['glider', 'west'],
|
||||
0x52: ['glider', 'south'],
|
||||
0x53: ['glider', 'east'],
|
||||
0x54: ['teeth', 'north'],
|
||||
0x55: ['teeth', 'west'],
|
||||
0x56: ['teeth', 'south'],
|
||||
0x57: ['teeth', 'east'],
|
||||
0x58: ['walker', 'north'],
|
||||
0x59: ['walker', 'west'],
|
||||
0x5a: ['walker', 'south'],
|
||||
0x5b: ['walker', 'east'],
|
||||
0x5c: ['blob', 'north'],
|
||||
0x5d: ['blob', 'west'],
|
||||
0x5e: ['blob', 'south'],
|
||||
0x5f: ['blob', 'east'],
|
||||
0x60: ['paramecium', 'north'],
|
||||
0x61: ['paramecium', 'west'],
|
||||
0x62: ['paramecium', 'south'],
|
||||
0x63: ['paramecium', 'east'],
|
||||
0x64: 'key_blue',
|
||||
0x65: 'key_red',
|
||||
0x66: 'key_green',
|
||||
@ -75,7 +125,6 @@ function parse_level(buf) {
|
||||
|
||||
let view = new DataView(buf);
|
||||
let bytes = new Uint8Array(buf);
|
||||
console.log(bytes);
|
||||
|
||||
// Header
|
||||
let level_number = view.getUint16(0, true);
|
||||
@ -138,11 +187,11 @@ function parse_level(buf) {
|
||||
let meta_length = view.getUint16(p, true);
|
||||
p += 2;
|
||||
let end = p + meta_length;
|
||||
while (p < meta_length) {
|
||||
while (p < end) {
|
||||
// Common header
|
||||
let field_type = view.getUint16(p, true);
|
||||
let field_length = view.getUint16(p + 2, true);
|
||||
p += 4;
|
||||
let field_type = view.getUint8(p, true);
|
||||
let field_length = view.getUint8(p + 1, true);
|
||||
p += 2;
|
||||
if (field_type === 0x01) {
|
||||
// Level time; unnecessary since it's already in the level header
|
||||
// TODO check, compare, warn?
|
||||
@ -213,14 +262,12 @@ export function parse_game(buf) {
|
||||
// And now, the levels
|
||||
let p = 6;
|
||||
for (let l = 1; l <= level_count; l++) {
|
||||
console.log('level', l);
|
||||
let length = full_view.getUint16(p, true);
|
||||
let level_buf = buf.slice(p + 2, p + 2 + length);
|
||||
p += 2 + length;
|
||||
|
||||
let level = parse_level(level_buf);
|
||||
game.levels.push(level);
|
||||
break;
|
||||
}
|
||||
|
||||
return game;
|
||||
|
||||
@ -9,6 +9,7 @@ export class StoredLevel {
|
||||
constructor() {
|
||||
this.title = '';
|
||||
this.password = null;
|
||||
this.hint = '';
|
||||
this.chips_required = 0;
|
||||
this.time_limit = 0;
|
||||
this.viewport_size = 9;
|
||||
|
||||
70
js/main.js
70
js/main.js
@ -64,7 +64,7 @@ class Tile {
|
||||
this.direction = 'south';
|
||||
}
|
||||
|
||||
this.is_sliding = false;
|
||||
this.slide_mode = null;
|
||||
|
||||
if (type.has_inventory) {
|
||||
this.inventory = {};
|
||||
@ -204,6 +204,8 @@ class Level {
|
||||
this.actors = [];
|
||||
this.chips_remaining = this.stored_level.chips_required;
|
||||
|
||||
this.hint_shown = null;
|
||||
|
||||
let n = 0;
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
let row = [];
|
||||
@ -240,7 +242,7 @@ class Level {
|
||||
}
|
||||
|
||||
for (let actor of this.actors) {
|
||||
if (actor.is_sliding) {
|
||||
if (actor.slide_mode !== null) {
|
||||
// TODO do we stop sliding if we hit something, too?
|
||||
this.attempt_step(actor, actor.direction);
|
||||
}
|
||||
@ -258,6 +260,10 @@ class Level {
|
||||
|
||||
for (let actor of this.actors) {
|
||||
// TODO skip doomed? strip them out? hm
|
||||
if (actor.slide_mode === 'ice') {
|
||||
// Actors can't make voluntary moves on ice
|
||||
continue;
|
||||
}
|
||||
if (actor === this.player) {
|
||||
if (player_direction) {
|
||||
actor.direction = player_direction;
|
||||
@ -310,12 +316,16 @@ class Level {
|
||||
}
|
||||
blocks = true;
|
||||
// XXX should i break here, or bump everything?
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (blocks)
|
||||
if (blocks) {
|
||||
if (actor.slide_mode === 'ice') {
|
||||
// Actors on ice turn around when they hit something
|
||||
actor.direction = DIRECTIONS[DIRECTIONS[direction].left].left;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're clear!
|
||||
this.move_to(actor, goal_x, goal_y);
|
||||
@ -329,7 +339,7 @@ class Level {
|
||||
let goal_cell = this.cells[y][x];
|
||||
let original_cell = this.cells[actor.y][actor.x];
|
||||
original_cell._remove(actor);
|
||||
actor.is_sliding = false;
|
||||
actor.slide_mode = null;
|
||||
goal_cell._add(actor);
|
||||
actor.x = x;
|
||||
actor.y = y;
|
||||
@ -338,11 +348,19 @@ class Level {
|
||||
goal_cell.is_dirty = true;
|
||||
|
||||
// Step on all the tiles in the new cell
|
||||
if (actor === this.player) {
|
||||
this.hint_shown = null;
|
||||
}
|
||||
goal_cell.each(tile => {
|
||||
if (tile === actor)
|
||||
return;
|
||||
if (actor.ignores(tile.type.name))
|
||||
return;
|
||||
|
||||
if (actor === this.player && tile.type.name === 'hint') {
|
||||
this.hint_shown = this.stored_level.hint;
|
||||
}
|
||||
|
||||
if (tile.type.is_item && actor.type.has_inventory) {
|
||||
actor.give_item(tile.type.name);
|
||||
tile.destroy();
|
||||
@ -361,12 +379,20 @@ class Level {
|
||||
|
||||
// TODO make a set of primitives for actually altering the level that also
|
||||
// record how to undo themselves
|
||||
make_slide(actor, mode) {
|
||||
actor.slide_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
const GAME_UI_HTML = `
|
||||
<main>
|
||||
<div class="level"><!-- level canvas and any overlays go here --></div>
|
||||
<div class="meta"></div>
|
||||
<div class="nav">
|
||||
<button class="nav-prev" type="button">«</button>
|
||||
<button class="nav-browse" type="button">Choose level...</button>
|
||||
<button class="nav-next" type="button">»</button>
|
||||
</div>
|
||||
<div class="hint"></div>
|
||||
<div class="chips"></div>
|
||||
<div class="time"></div>
|
||||
@ -375,7 +401,8 @@ const GAME_UI_HTML = `
|
||||
</main>
|
||||
`;
|
||||
class Game {
|
||||
constructor(tileset, level) {
|
||||
constructor(stored_game, tileset) {
|
||||
this.stored_game = stored_game;
|
||||
this.tileset = tileset;
|
||||
|
||||
// TODO obey level options; allow overriding
|
||||
@ -386,13 +413,29 @@ class Game {
|
||||
this.container.innerHTML = GAME_UI_HTML;
|
||||
this.level_el = this.container.querySelector('.level');
|
||||
this.meta_el = this.container.querySelector('.meta');
|
||||
this.nav_el = this.container.querySelector('.nav');
|
||||
this.hint_el = this.container.querySelector('.hint');
|
||||
this.chips_el = this.container.querySelector('.chips');
|
||||
this.time_el = this.container.querySelector('.time');
|
||||
this.inventory_el = this.container.querySelector('.inventory');
|
||||
this.bummer_el = this.container.querySelector('.bummer');
|
||||
|
||||
this.load_level(level);
|
||||
this.nav_prev_button = this.nav_el.querySelector('.nav-prev');
|
||||
this.nav_next_button = this.nav_el.querySelector('.nav-next');
|
||||
this.nav_prev_button.addEventListener('click', ev => {
|
||||
// TODO confirm
|
||||
if (this.level_index > 0) {
|
||||
this.load_level(this.level_index - 1);
|
||||
}
|
||||
});
|
||||
this.nav_next_button.addEventListener('click', ev => {
|
||||
// TODO confirm
|
||||
if (this.level_index < this.stored_game.levels.length - 1) {
|
||||
this.load_level(this.level_index + 1);
|
||||
}
|
||||
});
|
||||
|
||||
this.load_level(0);
|
||||
|
||||
this.level_canvas = mk('canvas', {width: tileset.size_x * this.camera_size_x, height: tileset.size_y * this.camera_size_y});
|
||||
this.level_el.append(this.level_canvas);
|
||||
@ -446,10 +489,14 @@ class Game {
|
||||
requestAnimationFrame(this.do_frame.bind(this));
|
||||
}
|
||||
|
||||
load_level(level) {
|
||||
this.level = level;
|
||||
load_level(level_index) {
|
||||
this.level_index = level_index;
|
||||
this.level = new Level(this.stored_game.levels[level_index]);
|
||||
// FIXME do better
|
||||
this.meta_el.textContent = this.level.stored_level.title;
|
||||
|
||||
this.nav_prev_button.disabled = level_index <= 0;
|
||||
this.nav_next_button.disabled = level_index >= this.stored_game.levels.length;
|
||||
this.update_ui();
|
||||
}
|
||||
|
||||
@ -476,7 +523,9 @@ class Game {
|
||||
}
|
||||
|
||||
update_ui() {
|
||||
// TODO can we do this only if they actually changed?
|
||||
this.chips_el.textContent = this.level.chips_remaining;
|
||||
this.hint_el.textContent = this.level.hint_shown ?? '';
|
||||
|
||||
if (this.level.state === 'failure') {
|
||||
this.bummer_el.textContent = this.level.fail_message;
|
||||
@ -555,8 +604,7 @@ async function main() {
|
||||
// TODO also support tile world's DAC when reading from local??
|
||||
// TODO ah, there's more metadata in CCX, crapola
|
||||
let stored_game = await load_game('levels/CCLP1.ccl');
|
||||
let level = new Level(stored_game.levels[0]);
|
||||
let game = new Game(tileset, level);
|
||||
let game = new Game(stored_game, tileset);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
@ -62,18 +62,27 @@ export const CC2_TILESET_LAYOUT = {
|
||||
west: [[12, 7], [13, 7], [14, 7], [15, 7]],
|
||||
},
|
||||
|
||||
ball: [[10, 10], [11, 10], [12, 10], [13, 10], [14, 10]],
|
||||
|
||||
fireball: [[12, 9], [13, 9], [14, 9], [15, 9]],
|
||||
|
||||
cleats: [2, 6],
|
||||
suction_boots: [3, 6],
|
||||
fire_boots: [1, 6],
|
||||
flippers: [0, 6],
|
||||
|
||||
clue: [5, 2],
|
||||
hint: [5, 2],
|
||||
};
|
||||
|
||||
export const TILE_WORLD_TILESET_LAYOUT = {
|
||||
floor: [0, 0],
|
||||
wall: [0, 1],
|
||||
thinwall_n: [0, 6],
|
||||
thinwall_w: [0, 7],
|
||||
thinwall_s: [0, 8],
|
||||
thinwall_e: [0, 9],
|
||||
ice: [0, 12],
|
||||
|
||||
ice_sw: [1, 13],
|
||||
ice_nw: [1, 10],
|
||||
ice_ne: [1, 11],
|
||||
@ -84,6 +93,9 @@ export const TILE_WORLD_TILESET_LAYOUT = {
|
||||
force_floor_e: [1, 3],
|
||||
force_floor_s: [0, 13],
|
||||
force_floor_w: [1, 4],
|
||||
// TODO there are two of these, which seems self-defeating??
|
||||
fake_wall: [1, 14],
|
||||
fake_floor: [1, 15],
|
||||
|
||||
exit: [[3, 10], [3, 11]],
|
||||
|
||||
@ -93,6 +105,7 @@ export const TILE_WORLD_TILESET_LAYOUT = {
|
||||
west: [6, 13],
|
||||
east: [6, 15],
|
||||
},
|
||||
cloner: [3, 1],
|
||||
player_drowned: [3, 3],
|
||||
player_burned: [3, 4],
|
||||
// TODO the tileset has several of these...? why?
|
||||
@ -118,13 +131,62 @@ export const TILE_WORLD_TILESET_LAYOUT = {
|
||||
south: [4, 2],
|
||||
west: [4, 1],
|
||||
},
|
||||
fireball: {
|
||||
north: [4, 4],
|
||||
east: [4, 7],
|
||||
south: [4, 6],
|
||||
west: [4, 5],
|
||||
},
|
||||
ball: {
|
||||
north: [4, 8],
|
||||
east: [4, 11],
|
||||
south: [4, 10],
|
||||
west: [4, 9],
|
||||
},
|
||||
tank_blue: {
|
||||
north: [4, 12],
|
||||
east: [4, 15],
|
||||
south: [4, 14],
|
||||
west: [4, 5],
|
||||
},
|
||||
glider: {
|
||||
north: [5, 0],
|
||||
east: [5, 3],
|
||||
south: [5, 2],
|
||||
west: [5, 1],
|
||||
},
|
||||
teeth: {
|
||||
north: [5, 4],
|
||||
east: [5, 7],
|
||||
south: [5, 6],
|
||||
west: [5, 5],
|
||||
},
|
||||
walker: {
|
||||
north: [5, 8],
|
||||
east: [5, 11],
|
||||
south: [5, 10],
|
||||
west: [5, 9],
|
||||
},
|
||||
blob: {
|
||||
north: [5, 12],
|
||||
east: [5, 15],
|
||||
south: [5, 14],
|
||||
west: [5, 5],
|
||||
},
|
||||
|
||||
paramecium: {
|
||||
north: [6, 0],
|
||||
east: [6, 3],
|
||||
south: [6, 2],
|
||||
west: [6, 1],
|
||||
},
|
||||
|
||||
cleats: [6, 10],
|
||||
suction_boots: [6, 11],
|
||||
fire_boots: [6, 9],
|
||||
flippers: [6, 8],
|
||||
|
||||
clue: [2, 15],
|
||||
hint: [2, 15],
|
||||
};
|
||||
|
||||
export class Tileset {
|
||||
|
||||
118
js/tiletypes.js
118
js/tiletypes.js
@ -1,4 +1,10 @@
|
||||
export const TILE_TYPES = {
|
||||
cloner: {
|
||||
blocks: true,
|
||||
},
|
||||
|
||||
|
||||
|
||||
floor: {
|
||||
cc2_byte: 0x01,
|
||||
},
|
||||
@ -6,8 +12,42 @@ export const TILE_TYPES = {
|
||||
cc2_byte: 0x02,
|
||||
blocks: true,
|
||||
},
|
||||
wall_invisible: {
|
||||
blocks: true,
|
||||
},
|
||||
wall_appearing: {
|
||||
blocks: true,
|
||||
},
|
||||
thinwall_n: {
|
||||
thin_walls: new Set(['north']),
|
||||
},
|
||||
thinwall_s: {
|
||||
thin_walls: new Set(['south']),
|
||||
},
|
||||
thinwall_e: {
|
||||
thin_walls: new Set(['east']),
|
||||
},
|
||||
thinwall_w: {
|
||||
thin_walls: new Set(['west']),
|
||||
},
|
||||
fake_wall: {
|
||||
blocks: true,
|
||||
on_bump(me, level, other) {
|
||||
me.become('wall');
|
||||
}
|
||||
},
|
||||
fake_floor: {
|
||||
blocks: true,
|
||||
on_bump(me, level, other) {
|
||||
me.become('floor');
|
||||
}
|
||||
},
|
||||
|
||||
ice: {
|
||||
cc2_byte: 0x03,
|
||||
on_arrive(me, level, other) {
|
||||
level.make_slide(other, 'ice');
|
||||
}
|
||||
},
|
||||
ice_sw: {
|
||||
cc2_byte: 0x04,
|
||||
@ -15,6 +55,15 @@ export const TILE_TYPES = {
|
||||
south: true,
|
||||
west: true,
|
||||
},
|
||||
on_arrive(me, level, other) {
|
||||
if (other.direction === 'south') {
|
||||
other.direction = 'east';
|
||||
}
|
||||
else {
|
||||
other.direction = 'north';
|
||||
}
|
||||
level.make_slide(other, 'ice');
|
||||
}
|
||||
},
|
||||
ice_nw: {
|
||||
cc2_byte: 0x05,
|
||||
@ -22,6 +71,15 @@ export const TILE_TYPES = {
|
||||
north: true,
|
||||
west: true,
|
||||
},
|
||||
on_arrive(me, level, other) {
|
||||
if (other.direction === 'north') {
|
||||
other.direction = 'east';
|
||||
}
|
||||
else {
|
||||
other.direction = 'south';
|
||||
}
|
||||
level.make_slide(other, 'ice');
|
||||
}
|
||||
},
|
||||
ice_ne: {
|
||||
cc2_byte: 0x06,
|
||||
@ -29,6 +87,15 @@ export const TILE_TYPES = {
|
||||
north: true,
|
||||
east: true,
|
||||
},
|
||||
on_arrive(me, level, other) {
|
||||
if (other.direction === 'north') {
|
||||
other.direction = 'west';
|
||||
}
|
||||
else {
|
||||
other.direction = 'south';
|
||||
}
|
||||
level.make_slide(other, 'ice');
|
||||
}
|
||||
},
|
||||
ice_se: {
|
||||
cc2_byte: 0x07,
|
||||
@ -36,6 +103,15 @@ export const TILE_TYPES = {
|
||||
south: true,
|
||||
east: true,
|
||||
},
|
||||
on_arrive(me, level, other) {
|
||||
if (other.direction === 'south') {
|
||||
other.direction = 'west';
|
||||
}
|
||||
else {
|
||||
other.direction = 'north';
|
||||
}
|
||||
level.make_slide(other, 'ice');
|
||||
}
|
||||
},
|
||||
water: {
|
||||
cc2_byte: 0x08,
|
||||
@ -70,28 +146,28 @@ export const TILE_TYPES = {
|
||||
cc2_byte: 0x0a,
|
||||
on_arrive(me, level, other) {
|
||||
other.direction = 'north';
|
||||
other.is_sliding = true;
|
||||
level.make_slide(other, 'push');
|
||||
}
|
||||
},
|
||||
force_floor_e: {
|
||||
cc2_byte: 0x0b,
|
||||
on_arrive(me, level, other) {
|
||||
other.direction = 'east';
|
||||
other.is_sliding = true;
|
||||
level.make_slide(other, 'push');
|
||||
}
|
||||
},
|
||||
force_floor_s: {
|
||||
cc2_byte: 0x0c,
|
||||
on_arrive(me, level, other) {
|
||||
other.direction = 'south';
|
||||
other.is_sliding = true;
|
||||
level.make_slide(other, 'push');
|
||||
}
|
||||
},
|
||||
force_floor_w: {
|
||||
cc2_byte: 0x0d,
|
||||
on_arrive(me, level, other) {
|
||||
other.direction = 'west';
|
||||
other.is_sliding = true;
|
||||
level.make_slide(other, 'push');
|
||||
}
|
||||
},
|
||||
|
||||
@ -222,6 +298,36 @@ export const TILE_TYPES = {
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
paramecium: {
|
||||
cc2_byte: 0x34,
|
||||
is_actor: true,
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
ball: {
|
||||
cc2_byte: 0x35,
|
||||
is_actor: true,
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
blob: {
|
||||
cc2_byte: 0x36,
|
||||
is_actor: true,
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
teeth: {
|
||||
cc2_byte: 0x37,
|
||||
is_actor: true,
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
fireball: {
|
||||
cc2_byte: 0x38,
|
||||
is_actor: true,
|
||||
has_direction: true,
|
||||
is_top_layer: true,
|
||||
},
|
||||
|
||||
cleats: {
|
||||
cc2_byte: 0x3b,
|
||||
@ -253,7 +359,7 @@ export const TILE_TYPES = {
|
||||
item_ignores: new Set(['water']),
|
||||
},
|
||||
|
||||
clue: {
|
||||
hint: {
|
||||
cc2_byte: 0x45,
|
||||
},
|
||||
};
|
||||
@ -264,7 +370,7 @@ CC2_TILE_TYPES.fill(null);
|
||||
for (let [name, tiledef] of Object.entries(TILE_TYPES)) {
|
||||
tiledef.name = name;
|
||||
|
||||
if (tiledef.cc2_byte === null)
|
||||
if (tiledef.cc2_byte === null || tiledef.cc2_byte === undefined)
|
||||
continue;
|
||||
|
||||
let existing = CC2_TILE_TYPES[tiledef.cc2_byte];
|
||||
|
||||
@ -16,6 +16,7 @@ main {
|
||||
display: grid;
|
||||
grid:
|
||||
"level meta" min-content
|
||||
"level nav" min-content
|
||||
"level chips" min-content
|
||||
"level time" min-content
|
||||
"level hint" 1fr
|
||||
@ -43,6 +44,14 @@ main {
|
||||
background: black;
|
||||
text-align: center;
|
||||
}
|
||||
.nav {
|
||||
grid-area: nav;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
}
|
||||
.nav .nav-browse {
|
||||
flex: 1;
|
||||
}
|
||||
.chips {
|
||||
grid-area: chips;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user