diff --git a/js/format-dat.js b/js/format-dat.js index d8cacf0..af80c89 100644 --- a/js/format-dat.js +++ b/js/format-dat.js @@ -209,14 +209,31 @@ function parse_level(buf) { level.title = util.string_from_buffer_ascii(buf.slice(p, p + field_length - 1)); } else if (field_type === 0x04) { - // Trap linkages - // TODO read this - // TODO under lynx rules these aren't even used, and they cause bugs in mscc1! + // Trap linkages (MSCC only, not in Lynx or CC2) + let field_view = new DataView(buf.slice(p, p + field_length)); + let q = 0; + while (q < field_length) { + let button_x = field_view.getUint16(q + 0, true); + let button_y = field_view.getUint16(q + 2, true); + let trap_x = field_view.getUint16(q + 4, true); + let trap_y = field_view.getUint16(q + 6, true); + // Fifth u16 is always zero, possibly live game state + q += 10; + level.custom_trap_wiring[button_x + button_y * level.size_x] = trap_x + trap_y * level.size_x; + } } else if (field_type === 0x05) { - // Trap linkages - // TODO read this - // TODO under lynx rules these aren't even used, and they cause bugs in mscc1! + // Cloner linkages (MSCC only, not in Lynx or CC2) + let field_view = new DataView(buf.slice(p, p + field_length)); + let q = 0; + while (q < field_length) { + let button_x = field_view.getUint16(q + 0, true); + let button_y = field_view.getUint16(q + 2, true); + let cloner_x = field_view.getUint16(q + 4, true); + let cloner_y = field_view.getUint16(q + 6, true); + q += 8; + level.custom_cloner_wiring[button_x + button_y * level.size_x] = cloner_x + cloner_y * level.size_x; + } } else if (field_type === 0x06) { // Password, with trailing NUL, and otherwise XORed with 0x99 (?!) diff --git a/js/format-util.js b/js/format-util.js index 3211ab0..cc0fe70 100644 --- a/js/format-util.js +++ b/js/format-util.js @@ -22,6 +22,11 @@ export class StoredLevel { this.player_start_x = 0; this.player_start_y = 0; + + // Maps of button positions to trap/cloner positions, as scalar indexes + // in the linear cell list + this.custom_trap_wiring = {}; + this.custom_cloner_wiring = {}; } check() { diff --git a/js/main.js b/js/main.js index e7675b2..17c5543 100644 --- a/js/main.js +++ b/js/main.js @@ -289,15 +289,44 @@ class Level { // Connect buttons and teleporters let num_cells = this.width * this.height; + console.log(this.stored_level.custom_trap_wiring); + console.log(this.stored_level.custom_cloner_wiring); for (let connectable of connectables) { let x = connectable.x; let y = connectable.y; let goal = connectable.type.connects_to; + let found = false; + + // Check for custom wiring, for MSCC .DAT levels + let n = x + y * this.width; + console.log(x, y, n); + let target_cell_n = null; + if (goal === 'trap') { + target_cell_n = this.stored_level.custom_trap_wiring[n] ?? null; + } + else if (goal === 'cloner') { + target_cell_n = this.stored_level.custom_cloner_wiring[n] ?? null; + } + if (target_cell_n) { + // TODO this N could be outside the map bounds + let target_cell_x = target_cell_n % this.width; + let target_cell_y = Math.floor(target_cell_n / this.width); + for (let tile of this.cells[target_cell_y][target_cell_x]) { + if (tile.type.name === goal) { + connectable.connection = tile; + found = true; + break; + } + } + if (found) + continue; + } + + // Otherwise, look in reading order let direction = 1; - if (connectable.type.connect_order == 'backward') { + if (connectable.type.connect_order === 'backward') { direction = -1; } - let found = false; for (let i = 0; i < num_cells - 1; i++) { x += direction; if (x >= this.width) { @@ -314,6 +343,7 @@ class Level { // TODO should be weak, but you can't destroy cloners so in practice not a concern connectable.connection = tile; found = true; + break; } } if (found) diff --git a/js/tiletypes.js b/js/tiletypes.js index a34110a..29ab723 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -364,7 +364,6 @@ const TILE_TYPES = { connect_order: 'forward', on_arrive(me, level, other) { if (me.connection && ! me.connection.doomed) { - // TODO do gray buttons affect traps? if so this should use activate() let trap = me.connection; trap.open = true; for (let tile of level.cells[trap.y][trap.x]) { @@ -376,7 +375,6 @@ const TILE_TYPES = { }, on_depart(me, level, other) { if (me.connection && ! me.connection.doomed) { - // TODO do gray buttons affect traps? if so this should use activate() let trap = me.connection; trap.open = false; for (let tile of level.cells[trap.y][trap.x]) {