diff --git a/game/engines/default/engine/generator/map/Octopus.lua b/game/engines/default/engine/generator/map/Octopus.lua
index 963c9c179362169d76743c3ba9a12999dbc6fc61..17d1d05d78016e0691547bdd689072181fdb61de 100644
--- a/game/engines/default/engine/generator/map/Octopus.lua
+++ b/game/engines/default/engine/generator/map/Octopus.lua
@@ -24,16 +24,17 @@ require "engine.generator.map.Roomer"
 --- @classmod engine.generator.map.Octopus
 module(..., package.seeall, class.inherit(engine.generator.map.Roomer))
 
+-- Creates a space (Pod room) at center of map, with a number of 'arms' (Pod rooms) around it connected by tunnels
 function _M:init(zone, map, level, data)
 	engine.generator.map.Roomer.init(self, zone, map, level, data)
 
 	self.spots = {}
 
-	self.nb_rooms = data.nb_rooms or {5, 10}
+	self.nb_rooms = data.nb_rooms or {5, 10} -- number of Pod rooms around center
 	self.base_breakpoint = data.base_breakpoint or 0.4
-	self.arms_range = data.arms_range or {0.5, 0.7}
-	self.arms_radius = data.arms_radius or {0.2, 0.3}
-	self.main_radius = data.main_radius or {0.3, 0.5}
+	self.arms_range = data.arms_range or {0.5, 0.7} -- fraction dist from map center to map edge for each Pod room
+	self.arms_radius = data.arms_radius or {0.2, 0.3} -- *(map.w + map.h)/4 ==> radius of each Pod room
+	self.main_radius = data.main_radius or {0.3, 0.5} -- *(map.w + map.h)/4 ==> radius of Pod at map center
 
 	self.noise = data.noise or "fbm_perlin"
 	self.zoom = data.zoom or 5
@@ -48,15 +49,16 @@ function _M:generate(lev, old_lev)
 	end end
 
 	local spots = self.spots
-
+	local rooms = {}
+	self.map.room_map.rooms = rooms
 	-- Main center room
 	local cx, cy = math.floor(self.map.w / 2), math.floor(self.map.h / 2)
-	self:makePod(cx, cy, rng.float(self.main_radius[1], self.main_radius[2]) * ((self.map.w / 2) + (self.map.h / 2)) / 2, 1, self)
+	rooms[#rooms+1] = self:makePod(cx, cy, rng.float(self.main_radius[1], self.main_radius[2]) * ((self.map.w / 2) + (self.map.h / 2)) / 2, 1, self)
+
 	spots[#spots+1] = {x=cx, y=cy, type="room", subtype="main"}
 
 	-- Rooms around it
 	local nb_rooms = rng.range(self.nb_rooms[1], self.nb_rooms[2])
-	local rooms = {}
 	for i = 0, nb_rooms - 1 do
 		local angle = math.rad(i * 360 / nb_rooms)
 
diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua
index 742f2a88db3c1702758e897c99f46c4dac494964..605305f2e0a42b3851484166407a7a11c3cbdaea 100644
--- a/game/modules/tome/class/GameState.lua
+++ b/game/modules/tome/class/GameState.lua
@@ -2609,7 +2609,7 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 			end,
 			on_grant = function(self, who)
 				game:onTickEnd(function()
-					 -- mark enemies when quest is awarded (to prevent summons and any newly spawned npcs from t preventing completion)
+					 -- mark enemies when quest is awarded (to prevent summons and any newly spawned npcs from preventing completion)
 					for uid, e in pairs(self.check_level.entities) do
 						if who:reactionToward(e) < 0 then
 							e[self.id] = true
@@ -2672,14 +2672,17 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 			end
 		end
 	elseif id_challenge == "mirror-match" then
-		local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-		local tries = 0
-		while not game.player:canMove(x, y) and tries < 100 and not level.map.attrs(x, y, "no_teleport") do
-			x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-			tries = tries + 1
-		end
-		if tries < 100 then
-			local q = self:makeChallengeQuest(level, "Mirror Match", "Find, challenge and kill your mirror clone on the level.", {})
+		local x, y = self:findEventGrid(level, function(self, level, x, y)
+				if x > 10 and x < level.map.w-10 and y > 10 and y < level.map.h and self:canEventGrid(level, x, y)then return x, y end
+			end
+			)
+		if x and y then
+			print("[Infinite Dungeon Challenge] spawning Mirror-Match at", x, y)
+			local q = self:makeChallengeQuest(level, "Mirror Match", "Find, challenge, and kill your mirror clone on the level.", {
+				on_exit_check = function(self, who)
+					if not self:isEnded() then who:setQuestStatus(self.id, self.FAILED) end
+				end,
+			})
 
 			local a = mod.class.NPC.new{}
 			a:replaceWith(game:getPlayer(true):cloneFull())
@@ -2690,6 +2693,7 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 			a.energy.value = 0
 			a.player = nil
 			a.rank = 4
+			a.desc = "An evil twin of "..a.name..(a.desc and ":\n"..a.desc or "")
 			a.name = "Mirror Challenge of "..a.name
 			a.killer_message = "but nobody knew why #sex# suddenly became evil"
 			a.color_r = 150 a.color_g = 150 a.color_b = 150
@@ -2702,13 +2706,26 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 			a.max_life = a.max_life * 2
 			a.life = a.max_life
 			a.id_challenge_quest = q.id
-			a.invulnerable = 1
+			a:attr("stealth", -1000)
+			a:attr("invisible", -1000)
+			a:attr("invulnerable", 1)
+			a:attr("negative_status_effect_immune", 1)
 			a.on_bump = function(self, who)
-				Dialog:yesnoPopup("Challenge: #PURPLE#Mirror Match", "Challenge your mirror clone and triumph!", function(r) if not r then
-					self.invulnerable = nil
+				local p = game:getPlayer(true)
+				if who ~= p then
+					game.logPlayer(who, "#ORCHID#%s does not recognize you.", self.name:capitalize())
+					return
+				end
+				require("engine.ui.Dialog"):yesnoPopup("Challenge: #PURPLE#Mirror Match", "Challenge your mirror clone and triumph!", function(r) if not r then
+					self:attr("invulnerable", -1)
+					self:attr("negative_status_effect_immune", -1)
+					self:attr("stealth", 1000)
+					self:attr("invisible", 1000)
 					self.faction = "enemies"
 					self.ai = "tactical"
-					game.bignews:say(60, "#CRIMSON#FIGHT!")
+					self:setTarget(p)
+					self:teleportRandom(p.x, p.y, 20, 10)
+					game.bignews:say(60, "#CRIMSON#The Fight Is Joined!")
 				end end, "Refuse", "Accept", true)
 			end
 			a.on_die = function(self, who)
@@ -2716,7 +2733,6 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 			end
 
 			game.zone:addEntity(game.level, a, "actor", x, y)
-
 			-- Remove some talents
 			local tids = {}
 			for tid, _ in pairs(a.talents) do
@@ -2744,9 +2760,23 @@ function _M:infiniteDungeonChallengeFinish(zone, level)
 
 		end end, "Refuse", "Accept", true)
 	elseif id_challenge == "multiplicity" then
-		Dialog:yesnoPopup("Challenge: #PURPLE#Multiplicity", "Survive the level while all the foes have the multiply talent, even bosses, for a reward.", function(r) if not r then
+		local turns = level.map.h + level.map.w
+		Dialog:yesnoPopup("Challenge: #PURPLE#Multiplicity", "All foes (including bosses) gain the ability to multiply up to 3 times.  You must survive for at least "..turns.." turns before exiting.", function(r) if not r then
 			self:makeChallengeQuest(level, "Multiplicity", "All foes have the multiply talent!", {
-				on_exit_check = function(self, who) who:setQuestStatus(self.id, self.COMPLETED) end,
+				turns_left = turns,
+				dynamic_desc = function(self, desc)
+					desc[#desc+1] = "Turns left: #LIGHT_GREEN#"..math.max(0, self.turns_left)
+				end,
+				on_exit_check = function(self, who)
+					if who.dead and not self:isEnded() then who:setQuestStatus(self.id, self.FAILED); return end
+					if self.turns_left <= 0 and not who.dead then who:setQuestStatus(self.id, self.COMPLETED) else who:setQuestStatus(self.id, self.FAILED) end
+				end,
+				on_act_base = function(self, who)
+					self.turns_left = self.turns_left - 1
+					if self.turns_left == 0 then
+						game.bignews:say(60, "#LIGHT_GREEN#Multiplicity: You have survived so far. Exit for your reward!")
+					end
+				end,
 			})
 			game:onTickEnd(function()
 				local p = game:getPlayer(true)
diff --git a/game/modules/tome/class/Grid.lua b/game/modules/tome/class/Grid.lua
index 120dbae2b9265c54758b339c6f47009d761f4c87..02d12cb0cd47bbfd70000a7349f7794938391608 100644
--- a/game/modules/tome/class/Grid.lua
+++ b/game/modules/tome/class/Grid.lua
@@ -222,8 +222,9 @@ function _M:tooltip(x, y)
 		-- debugging info
 		if game.level.map.room_map then
 			local data = game.level.map.room_map[x][y]
-			local room = table.get(game.level.map.room_map.rooms, data.room, "room")
-			tstr:add(true, {"color", "PINK"}, ("room_map: rm:%s(%s), spec:%s, c/o:%s, bor:%s, tun:%s, rtun:%s"):format(data.room, room and room.name, data.special, data.can_open, data.border, data.tunnel, data.real_tunnel))
+			local room_base = table.get(game.level.map.room_map.rooms, data.room)
+			local room = room_base and room_base.room
+			tstr:add(true, {"color", "PINK"}, ("room_map:rm:%s(id:%s,name:%s), spec:%s, c/o:%s, bor:%s, tun:%s, rtun:%s"):format(data.room, room_base and room_base.id, room and room.name, data.special, data.can_open, data.border, data.tunnel, data.real_tunnel))
 		end
 		local attrs = game.level.map.attrs[x+y*game.level.map.w]
 		if attrs then
diff --git a/game/modules/tome/data/talents/misc/npcs.lua b/game/modules/tome/data/talents/misc/npcs.lua
index 09b71e1e5e1f6759294c4705967f60dff184ab34..ff99a4ac2e0960f45a1883b605400cf357f8dd44 100644
--- a/game/modules/tome/data/talents/misc/npcs.lua
+++ b/game/modules/tome/data/talents/misc/npcs.lua
@@ -40,7 +40,7 @@ newTalent{
 	cooldown = 3,
 	range = 10,
 	requires_target = true,
-	tactical = { ATTACK = 3 },
+	tactical = { ATTACK = function(self, t, aitarget) return 2*(1.2 + self.level/50) end },
 	action = function(self, t)
 		if not self.can_multiply or self.can_multiply <= 0 then game.logPlayer(self, "You can not multiply anymore.") return nil end
 
diff --git a/game/modules/tome/data/zones/infinite-dungeon/zone.lua b/game/modules/tome/data/zones/infinite-dungeon/zone.lua
index b440164fa59985a7dce2901495887f7f6405ccbf..62448f25d337b63daa7a7638516748ad4624c818 100644
--- a/game/modules/tome/data/zones/infinite-dungeon/zone.lua
+++ b/game/modules/tome/data/zones/infinite-dungeon/zone.lua
@@ -164,10 +164,10 @@ return {
 			{	id_layout_name = "octopus",
 				desc = ", subsided area",
 				class = "engine.generator.map.Octopus",
-				main_radius = {0.3, 0.4},
+				main_radius = {0.25, 0.35},
 				arms_radius = {0.1, 0.2},
 				arms_range = {0.7, 0.8},
-				nb_rooms = {3, 9},
+				nb_rooms = {5, 10},
 			},
 			{	id_layout_name = "hexa",
 				desc = ", geometrically ordered area",