diff --git a/js/game.js b/js/game.js index 2e7b4c9..d10651c 100644 --- a/js/game.js +++ b/js/game.js @@ -1217,29 +1217,33 @@ export class Level extends LevelInterface { _do_post_actor_phase() { if (this.pending_green_toggle) { - // Swap green floors and walls - // TODO could probably make this more compact for undo purposes - for (let cell of this.linear_cells) { - let terrain = cell.get_terrain(); - if (terrain.type.name === 'green_floor') { - this.transmute_tile(terrain, 'green_wall'); - } - else if (terrain.type.name === 'green_wall') { - this.transmute_tile(terrain, 'green_floor'); - } - - let item = cell.get_item(); - if (item && item.type.name === 'green_chip') { - this.transmute_tile(item, 'green_bomb'); - } - else if (item && item.type.name === 'green_bomb') { - this.transmute_tile(item, 'green_chip'); - } - } + // Swap green objects + this.__toggle_green_tiles(); + this._push_pending_undo(() => { + this.__toggle_green_tiles(); + }); this.pending_green_toggle = false; } } + __toggle_green_tiles() { + // This is NOT undo-safe; it's undone by calling it again! + // Assumes: + // 1. Green tile types come in pairs, which toggle into one another + // 2. A pair of green tile types appear on the same layer + for (let cell of this.linear_cells) { + let terrain = cell.get_terrain(); + if (terrain.type.green_toggle_counterpart) { + terrain.type = TILE_TYPES[terrain.type.green_toggle_counterpart]; + } + + let item = cell.get_item(); + if (item && item.type.green_toggle_counterpart) { + item.type = TILE_TYPES[item.type.green_toggle_counterpart]; + } + } + } + _do_cleanup_phase() { // Lynx compat: Any blue tank that still has the reversal flag set here, but is in motion, // should ignore it. Unfortunately this has to be done as its own pass (as it is in Lynx!) diff --git a/js/tiletypes.js b/js/tiletypes.js index a54c363..caf4207 100644 --- a/js/tiletypes.js +++ b/js/tiletypes.js @@ -1317,6 +1317,7 @@ const TILE_TYPES = { }, green_floor: { layer: LAYERS.terrain, + green_toggle_counterpart: 'green_wall', blocks(me, level, other) { // Toggle walls don't toggle until the end of the frame, but the collision takes into // account whether a toggle is coming @@ -1333,6 +1334,7 @@ const TILE_TYPES = { }, green_wall: { layer: LAYERS.terrain, + green_toggle_counterpart: 'green_floor', blocks(me, level, other) { // Same as above return ( @@ -1350,6 +1352,7 @@ const TILE_TYPES = { layer: LAYERS.item, is_chip: true, is_required_chip: true, + green_toggle_counterpart: 'green_bomb', blocks_collision: COLLISION.block_cc1 | COLLISION.monster_typical, item_priority: PICKUP_PRIORITIES.real_player, on_pickup(me, level, other) { @@ -1361,6 +1364,7 @@ const TILE_TYPES = { green_bomb: { layer: LAYERS.item, is_required_chip: true, + green_toggle_counterpart: 'green_chip', on_arrive(me, level, other) { // Unlike regular bombs, these only seem to respond to being stepped on, not stood on level.remove_tile(me);