Support CC2's multiple hints
This commit is contained in:
parent
a50de91195
commit
a9b1af8e62
@ -194,6 +194,8 @@ export function parse_level(buf) {
|
|||||||
let level = new util.StoredLevel;
|
let level = new util.StoredLevel;
|
||||||
let full_view = new DataView(buf);
|
let full_view = new DataView(buf);
|
||||||
let next_section_start = 0;
|
let next_section_start = 0;
|
||||||
|
let extra_hints;
|
||||||
|
let hint_tiles = [];
|
||||||
while (next_section_start < buf.byteLength) {
|
while (next_section_start < buf.byteLength) {
|
||||||
// Read section header and length
|
// Read section header and length
|
||||||
let section_start = next_section_start;
|
let section_start = next_section_start;
|
||||||
@ -203,23 +205,43 @@ export function parse_level(buf) {
|
|||||||
if (next_section_start > buf.byteLength)
|
if (next_section_start > buf.byteLength)
|
||||||
throw new Error(`Section at byte ${section_start} of type '${section_type}' extends ${buf.length - next_section_start} bytes past the end of the file`);
|
throw new Error(`Section at byte ${section_start} of type '${section_type}' extends ${buf.length - next_section_start} bytes past the end of the file`);
|
||||||
|
|
||||||
if (section_type === 'CC2M' || section_type === 'LOCK' || section_type === 'TITL' || section_type === 'AUTH' || section_type === 'VERS' || section_type === 'CLUE' || section_type === 'NOTE') {
|
if (section_type === 'CC2M' || section_type === 'LOCK' || section_type === 'VERS' ||
|
||||||
|
section_type === 'TITL' || section_type === 'AUTH' ||
|
||||||
|
section_type === 'CLUE' || section_type === 'NOTE')
|
||||||
|
{
|
||||||
// These are all singular strings (with a terminating NUL, for some reason)
|
// These are all singular strings (with a terminating NUL, for some reason)
|
||||||
// XXX character encoding??
|
// XXX character encoding??
|
||||||
// FIXME assign to appropriate fields
|
let str = util.string_from_buffer_ascii(buf.slice(section_start + 8, next_section_start - 1)).replace(/\r\n/g, "\n");
|
||||||
let field = section_type;
|
|
||||||
if (section_type === 'TITL') {
|
// TODO store more of this, at least for idempotence, maybe
|
||||||
field = 'title';
|
if (section_type === 'CC2M') {
|
||||||
|
// File version, doesn't seem interesting
|
||||||
|
}
|
||||||
|
else if (section_type === 'LOCK') {
|
||||||
|
// Unclear, seems to be a comment about the editor...?
|
||||||
|
}
|
||||||
|
else if (section_type === 'VERS') {
|
||||||
|
// Editor version which created this level
|
||||||
|
}
|
||||||
|
else if (section_type === 'TITL') {
|
||||||
|
// Level title
|
||||||
|
level.title = str;
|
||||||
}
|
}
|
||||||
else if (section_type === 'AUTH') {
|
else if (section_type === 'AUTH') {
|
||||||
field = 'author';
|
// Author's name
|
||||||
|
level.author = str;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else if (section_type === 'CLUE') {
|
else if (section_type === 'CLUE') {
|
||||||
field = 'hint';
|
// Level hint
|
||||||
|
level.hint = str;
|
||||||
|
}
|
||||||
|
else if (section_type === 'NOTE') {
|
||||||
|
// Author's comments... but might also include multiple hints
|
||||||
|
// for levels with multiple hint tiles, delineated by [CLUE].
|
||||||
|
// For my purposes, extra hints are associated with the
|
||||||
|
// individual tiles, so we'll map those later
|
||||||
|
[level.comment, ...extra_hints] = str.split(/(?<=^|\n)\[CLUE\]\n/g);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
level[field] = util.string_from_buffer_ascii(buf.slice(section_start + 8, next_section_start - 1)).replace(/\r\n/g, "\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,16 +333,23 @@ export function parse_level(buf) {
|
|||||||
}
|
}
|
||||||
let tile = {name};
|
let tile = {name};
|
||||||
cell.push(tile);
|
cell.push(tile);
|
||||||
let tiledef = TILE_TYPES[name];
|
let type = TILE_TYPES[name];
|
||||||
if (!tiledef) console.error(name);
|
if (!type) console.error(name);
|
||||||
if (tiledef.is_required_chip) {
|
if (type.is_required_chip) {
|
||||||
level.chips_required++;
|
level.chips_required++;
|
||||||
}
|
}
|
||||||
if (tiledef.is_player) {
|
if (type.is_player) {
|
||||||
// TODO handle multiple starts
|
// TODO handle multiple starts
|
||||||
level.player_start_x = n % width;
|
level.player_start_x = n % width;
|
||||||
level.player_start_y = Math.floor(n / width);
|
level.player_start_y = Math.floor(n / width);
|
||||||
}
|
}
|
||||||
|
if (type.is_hint) {
|
||||||
|
// Remember all the hint tiles (in reading order) so we
|
||||||
|
// can map extra hints to them later. Don't do it now,
|
||||||
|
// since the format doesn't technically guarantee that
|
||||||
|
// the metadata sections appear before the map data!
|
||||||
|
hint_tiles.push(tile);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle extra arguments
|
// Handle extra arguments
|
||||||
let has_next = false;
|
let has_next = false;
|
||||||
@ -361,6 +390,16 @@ export function parse_level(buf) {
|
|||||||
// TODO save it, persist when editing level
|
// TODO save it, persist when editing level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(level);
|
|
||||||
|
// Connect extra hints
|
||||||
|
let h = 0;
|
||||||
|
for (let tile of hint_tiles) {
|
||||||
|
if (h > extra_hints.length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
tile.specific_hint = extra_hints[h];
|
||||||
|
h++;
|
||||||
|
}
|
||||||
|
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|||||||
21
js/main.js
21
js/main.js
@ -82,8 +82,9 @@ class Tile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static from_template(tile_template, x, y) {
|
static from_template(tile_template, x, y) {
|
||||||
if (! TILE_TYPES[tile_template.name]) console.error(tile_template.name);
|
let type = TILE_TYPES[tile_template.name];
|
||||||
return new this(TILE_TYPES[tile_template.name], x, y, tile_template.direction);
|
if (! type) console.error(tile_template.name);
|
||||||
|
return new this(type, x, y, tile_template.direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
ignores(name) {
|
ignores(name) {
|
||||||
@ -231,16 +232,20 @@ class Level {
|
|||||||
let cell = new Cell;
|
let cell = new Cell;
|
||||||
row.push(cell);
|
row.push(cell);
|
||||||
|
|
||||||
let template_cell = this.stored_level.linear_cells[n];
|
let stored_cell = this.stored_level.linear_cells[n];
|
||||||
n++;
|
n++;
|
||||||
|
|
||||||
for (let template_tile of template_cell) {
|
for (let template_tile of stored_cell) {
|
||||||
let tile = Tile.from_template(template_tile, x, y);
|
let tile = Tile.from_template(template_tile, x, y);
|
||||||
if (tile.type.is_player) {
|
if (tile.type.is_player) {
|
||||||
// TODO handle multiple players, also chip and melinda both
|
// TODO handle multiple players, also chip and melinda both
|
||||||
// TODO complain if no chip
|
// TODO complain if no chip
|
||||||
this.player = tile;
|
this.player = tile;
|
||||||
}
|
}
|
||||||
|
if (tile.type.is_hint) {
|
||||||
|
// Copy over the tile-specific hint, if any
|
||||||
|
tile.specific_hint = template_tile.specific_hint ?? null;
|
||||||
|
}
|
||||||
if (tile.type.is_actor) {
|
if (tile.type.is_actor) {
|
||||||
this.actors.push(tile);
|
this.actors.push(tile);
|
||||||
}
|
}
|
||||||
@ -436,8 +441,8 @@ class Level {
|
|||||||
if (actor.ignores(tile.type.name))
|
if (actor.ignores(tile.type.name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (actor === this.player && tile.type.name === 'hint') {
|
if (actor === this.player && tile.type.is_hint) {
|
||||||
this.hint_shown = this.stored_level.hint;
|
this.hint_shown = tile.specific_hint ?? this.stored_level.hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile.type.is_item && actor.type.has_inventory) {
|
if (tile.type.is_item && actor.type.has_inventory) {
|
||||||
@ -485,8 +490,8 @@ class Game {
|
|||||||
this.tileset = tileset;
|
this.tileset = tileset;
|
||||||
|
|
||||||
// TODO obey level options; allow overriding
|
// TODO obey level options; allow overriding
|
||||||
this.viewport_size_x = 19;
|
this.viewport_size_x = 9;
|
||||||
this.viewport_size_y = 19;
|
this.viewport_size_y = 9;
|
||||||
|
|
||||||
document.body.innerHTML = GAME_UI_HTML;
|
document.body.innerHTML = GAME_UI_HTML;
|
||||||
this.container = document.body.querySelector('main');
|
this.container = document.body.querySelector('main');
|
||||||
|
|||||||
@ -392,6 +392,7 @@ const TILE_TYPES = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
hint: {
|
hint: {
|
||||||
|
is_hint: true,
|
||||||
},
|
},
|
||||||
socket: {
|
socket: {
|
||||||
blocks: true,
|
blocks: true,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user