From b3a0ff963c7a90a3953cce4bd2a2b2aafcf07f4d Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Sat, 29 Aug 2020 02:10:27 -0600 Subject: [PATCH] Begrudgingly support letter tiles --- js/format-c2m.js | 61 ++++++++++++++++++++++++++-------------- js/main.js | 6 +++- js/tileset.js | 73 +++++++++++++++++++++++++++++++++++++++++------- js/tiletypes.js | 3 ++ 4 files changed, 111 insertions(+), 32 deletions(-) diff --git a/js/format-c2m.js b/js/format-c2m.js index 8be44b9..05b8bf5 100644 --- a/js/format-c2m.js +++ b/js/format-c2m.js @@ -115,13 +115,12 @@ const TILE_ENCODING = { // 0x6e: (Unused) : // 0x6f: Railroad sign : '#next' // 0x70: Custom wall (green) : Modifier allows other styles, see below - // TODO needs a preceding modifier but that's not done yet (and should enforce that a modifier is followed by a modifiable tile?) - 0x71: 'floor_letter', + 0x71: ['#mod8', 'floor_letter'], // 0x72: Purple toggle wall : // 0x73: Purple toggle floor : // 0x74: (Unused) : // 0x75: (Unused) : - // 0x76: 8-bit Modifier (see Modifier section below) : 1 modifier byte, Tile Specification for affected tile + 0x76: ['#mod8', '#next'], // 0x77: 16-bit Modifier (see Modifier section below) : 2 modifier bytes, Tile Specification for affected tile // 0x78: 32-bit Modifier (see Modifier section below) : 4 modifier bytes, Tile Specification for affected tile // 0x79: (Unused) : '#direction', '#next' @@ -313,29 +312,49 @@ export function parse_level(buf) { level.size_x = width; level.size_y = height; let p = 2; + + function read_spec() { + let tile_byte = bytes[p]; + p++; + if (tile_byte >= 0x77 && tile_byte <= 0x78) { + // XXX handle these modifier "tiles" + p += tile_byte - 0x75; + return []; + } + let spec = TILE_ENCODING[tile_byte]; + if (! spec) + throw new Error(`Unrecognized tile type 0x${tile_byte.toString(16)}`); + + let name; + let args = []; + if (spec instanceof Array) { + return spec; + } + else { + return [spec]; + } + } + for (let n = 0; n < width * height; n++) { let cell = new util.StoredCell; while (true) { - let tile_byte = bytes[p]; - p++; - if (tile_byte >= 0x76 && tile_byte <= 0x78) { - // XXX handle these modifier "tiles" - p += tile_byte - 0x75; - continue; - } - let spec = TILE_ENCODING[tile_byte]; - if (! spec) - throw new Error(`Unrecognized tile type 0x${tile_byte.toString(16)}`); + let [name, ...args] = read_spec(); + if (name === undefined) continue; // XXX modifier skip hack - let name; - let args = []; - if (spec instanceof Array) { - [name, ...args] = spec; + let modifier; + if (name === '#mod8') { + if (args[0] !== '#next') + throw new Error(`Tile requires a preceding modifier`); + + modifier = bytes[p]; + p++; + let mod_marker; + [mod_marker, name, ...args] = read_spec(); + if (mod_marker !== '#mod8') + throw new Error(`Expected a tile requiring a modifier`); } - else { - name = spec; - } - let tile = {name}; + + let tile = {name, modifier}; cell.push(tile); let type = TILE_TYPES[name]; if (!type) console.error(name); diff --git a/js/main.js b/js/main.js index 488c736..4ee836e 100644 --- a/js/main.js +++ b/js/main.js @@ -84,7 +84,11 @@ class Tile { static from_template(tile_template, x, y) { let type = TILE_TYPES[tile_template.name]; if (! type) console.error(tile_template.name); - return new this(type, x, y, tile_template.direction); + let tile = new this(type, x, y, tile_template.direction); + if (type.load) { + type.load(tile, tile_template); + } + return tile; } ignores(name) { diff --git a/js/tileset.js b/js/tileset.js index 2c4e44e..44d57c1 100644 --- a/js/tileset.js +++ b/js/tileset.js @@ -1,6 +1,19 @@ export const CC2_TILESET_LAYOUT = { floor: [0, 2], floor_letter: [2, 2], + 'floor_letter#ascii': { + x0: 0, + y0: 0, + width: 16, + height: 1, + }, + 'floor_letter#arrows': { + north: [14, 31], + east: [14.5, 31], + south: [15, 31], + west: [15.5, 31], + }, + wall: [1, 2], fire: [ @@ -89,10 +102,10 @@ export const CC2_TILESET_LAYOUT = { hint: [5, 2], - score_10: [14, 1], - score_100: [13, 1], - score_1000: [12, 1], - score_2x: [15, 1], + score_10: [14, 2], + score_100: [13, 2], + score_1000: [12, 2], + score_2x: [15, 2], }; // XXX need to specify that you can't use this for cc2 levels, somehow @@ -247,10 +260,21 @@ export class Tileset { this.size_y = size_y; } + // Helper to draw to a canvas using tile coordinates + blit(ctx, sx, sy, dx, dy, scale = 1) { + let w = this.size_x * scale; + let h = this.size_y * scale; + ctx.drawImage( + this.image, + sx * this.size_x, sy * this.size_y, w, h, + dx * this.size_x, dy * this.size_y, w, h); + } + draw(tile, ctx, x, y) { - let drawspec = this.layout[tile.type.name]; + let name = tile.type.name; + let drawspec = this.layout[name]; let coords = drawspec; - if (! coords) console.error(tile.type.name); + if (! coords) console.error(name); if (!(coords instanceof Array)) { // Must be an object of directions coords = coords[tile.direction ?? 'south']; @@ -259,9 +283,38 @@ export class Tileset { coords = coords[0]; } - ctx.drawImage( - this.image, - coords[0] * this.size_x, coords[1] * this.size_y, this.size_x, this.size_y, - x * this.size_x, y * this.size_y, this.size_x, this.size_y); + this.blit(ctx, coords[0], coords[1], x, y); + + // Special behavior for special objects + // TODO? hardcode this less? + if (name === 'floor_letter') { + let n = tile.ascii_code - 32; + let scale = 0.5; + let sx, sy; + if (n < 0) { + // Arrows + if (n < -4) { + // Default to south + n = -2; + } + + let direction = ['north', 'east', 'south', 'west'][n + 4]; + [sx, sy] = this.layout['floor_letter#arrows'][direction]; + } + else { + // ASCII text (only up through uppercase) + let letter_spec = this.layout['floor_letter#ascii']; + if (n > letter_spec.width / scale * letter_spec.height / scale) { + n = 0; + } + let w = letter_spec.width / scale; + sx = (letter_spec.x0 + n % w) * scale; + sy = (letter_spec.y0 + Math.floor(n / w)) * scale; + } + let offset = (1 - scale) / 2; + this.blit( + ctx, sx, sy, + x + offset, y + offset, scale); + } } } diff --git a/js/tiletypes.js b/js/tiletypes.js index f40096b..b927931 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -3,6 +3,9 @@ const TILE_TYPES = { floor: { }, floor_letter: { + load(me, template) { + me.ascii_code = template.modifier; + } }, wall: { blocks: true,