diff --git a/js/format-c2m.js b/js/format-c2m.js index db5e5d3..2fcf74a 100644 --- a/js/format-c2m.js +++ b/js/format-c2m.js @@ -485,6 +485,7 @@ export function parse_level(buf) { if (! has_next) break; } + cell.reverse(); level.linear_cells.push(cell); } } diff --git a/js/format-dat.js b/js/format-dat.js index e773547..d8cacf0 100644 --- a/js/format-dat.js +++ b/js/format-dat.js @@ -180,7 +180,7 @@ function parse_level(buf) { continue; } - cell.push({name, direction}); + cell.unshift({name, direction}); } } if (c !== 1024) diff --git a/js/main.js b/js/main.js index 92ca0df..c8da61b 100644 --- a/js/main.js +++ b/js/main.js @@ -231,6 +231,7 @@ class Level { this.hint_shown = null; let n = 0; + let connectables = []; for (let y = 0; y < this.height; y++) { let row = []; this.cells.push(row); @@ -240,6 +241,7 @@ class Level { let stored_cell = this.stored_level.linear_cells[n]; n++; + let has_cloner, has_forbidden; for (let template_tile of stored_cell) { let tile = Tile.from_template(template_tile, x, y); @@ -247,6 +249,11 @@ class Level { // Copy over the tile-specific hint, if any tile.specific_hint = template_tile.specific_hint ?? null; } + + if (tile.type.name === 'cloner') { + has_cloner = true; + } + if (tile.type.is_player) { // TODO handle multiple players, also chip and melinda both // TODO complain if no chip @@ -257,14 +264,48 @@ class Level { this.actors[0] = tile; } else if (tile.type.is_actor) { - this.actors.push(tile); + if (has_cloner) { + tile.stuck = true; + } + else { + this.actors.push(tile); + } } cell.push(tile); + + if (tile.type.connects_to) { + connectables.push(tile); + } } - // Make the bottom tile be /first/ - cell.reverse(); } } + + // Connect buttons and teleporters + let num_cells = this.width * this.height; + for (let connectable of connectables) { + let x = connectable.x; + let y = connectable.y; + let goal = connectable.type.connects_to; + let found = false; + for (let i = 0; i < num_cells - 1; i++) { + x++; + while (x >= this.width) { + x -= this.width; + y++; + y %= this.width; + } + for (let tile of this.cells[y][x]) { + if (tile.type.name === goal) { + // TODO should be weak, but you can't destroy cloners so in practice not a concern + connectable.connection = tile; + found = true; + } + } + if (found) + break; + } + // TODO soft warn for e.g. a button with no cloner? (or a cloner with no button?) + } } advance_tic(player_direction) { @@ -284,6 +325,9 @@ class Level { if (actor.movement_cooldown > 0) continue; } + // XXX does the cooldown drop while in a trap? is this even right? + if (actor.stuck) + continue; let direction_preference; // Actors can't make voluntary moves on ice, so they're stuck with diff --git a/js/tiletypes.js b/js/tiletypes.js index df68c94..613d331 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -278,8 +278,23 @@ const TILE_TYPES = { blocks: true, }, cloner: { - // TODO ??? blocks: true, + activate(me, level) { + let cell = level.cells[me.y][me.x]; + // Clone so we don't end up repeatedly cloning the same object + let current_tiles = Array.from(cell); + for (let tile of current_tiles) { + if (tile !== me && tile.type.is_actor) { + tile.stuck = false; + // TODO precise behavior? is this added immediately and can move later that same turn or what? + level.actors.push(tile); + // FIXME rearrange to make this possible lol + // FIXME go through level for this, and everything else of course + // FIXME add this underneath, just above the cloner + cell._add(new tile.constructor(tile.type, tile.x, tile.y, tile.direction)); + } + } + } }, trap: { // TODO ??? @@ -326,7 +341,13 @@ const TILE_TYPES = { // TODO how do i implement this. }, button_red: { - // TODO + connects_to: 'cloner', + connect_order: 'forward', + on_arrive(me, level, other) { + if (me.connection && ! me.connection.doomed) { + me.connection.type.activate(me.connection, level); + } + } }, // Critters