From 97e7bd09d99f37e3789863817e1eabb9e34f5b2d Mon Sep 17 00:00:00 2001
From: Hachem_Muche <Hachem_Muche@stanfordalumni.org>
Date: Sun, 26 Mar 2017 12:38:54 -0700
Subject: [PATCH] Fixes issues with major events (that create an additional
 level): sub-vault, rat-lich, damp-cave, old-battle-field, drake-cave,
 naga-portal, fearscape-portal

.no_worldport is set to that of the parent zone.
Actor levels are 5% to 15% higher than the the parent zone and game difficulty adjustments are not compounded.
Object material levels match the parent zone.
Auto explore and minimap settings updated.

Fixed a bug in sub-vault that was preventing the stairs from crumbling as intended.

The player can choose to ignore the naga-portal and fearscape-portal by hitting escape at the pop-up.

Fixed a bug in game:changeLevelReal that was causing the player to incorrectly be placed at level start when params.auto_level_stair was set.

The player is correctly placed on one of the graves when returning from the old-battle-field event.
---
 game/modules/tome/class/Game.lua              |  6 +-
 .../tome/data/general/events/damp-cave.lua    | 20 +++++--
 .../tome/data/general/events/drake-cave.lua   | 29 +++++----
 .../data/general/events/fearscape-portal.lua  | 59 ++++++++++++-------
 .../tome/data/general/events/naga-portal.lua  | 45 ++++++++------
 .../data/general/events/old-battle-field.lua  | 52 ++++++++++------
 .../tome/data/general/events/rat-lich.lua     | 44 +++++++++-----
 .../tome/data/general/events/sub-vault.lua    | 12 ++--
 8 files changed, 167 insertions(+), 100 deletions(-)

diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 8d048a6ea8..f95415654a 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -918,7 +918,7 @@ end
 
 function _M:changeLevelReal(lev, zone, params)
 	local oz, ol = self.zone, self.level
-	
+
 	-- Unlock first!
 	if not params.temporary_zone_shift_back and self.level and self.level.temp_shift_zone then
 		self:changeLevelReal(1, "useless", {temporary_zone_shift_back=true})
@@ -1101,7 +1101,7 @@ function _M:changeLevelReal(lev, zone, params)
 					list[#list+1] = {i, j}
 				end
 			end end
-			if #list > 0 then x, y = unpack(rng.table(list)) end
+			if #list > 0 then list = rng.table(list) x, y = unpack(list) end
 		elseif params.auto_level_stair then
 			-- Dirty but quick
 			local list = {}
@@ -1111,7 +1111,7 @@ function _M:changeLevelReal(lev, zone, params)
 					list[#list+1] = {i, j}
 				end
 			end end
-			if #list > 0 then x, y = unpack(rng.table(list)) end
+			if #list > 0 then list = rng.table(list) x, y = unpack(list) end
 		end
 
 		-- if self.level.exited then -- use the last location, if defined
diff --git a/game/modules/tome/data/general/events/damp-cave.lua b/game/modules/tome/data/general/events/damp-cave.lua
index 2a4e1420a3..44bacae0f7 100644
--- a/game/modules/tome/data/general/events/damp-cave.lua
+++ b/game/modules/tome/data/general/events/damp-cave.lua
@@ -23,15 +23,21 @@ if not x then return false end
 
 local id = "damp-cave-"..game.turn
 
+print("Placing event", id, "at", x, y)
+
 local changer = function(id)
 	local npcs = mod.class.NPC:loadList{"/data/general/npcs/thieve.lua"}
 	local objects = mod.class.Object:loadList("/data/general/objects/objects.lua")
 	local terrains = mod.class.Grid:loadList("/data/general/grids/cave.lua")
 	terrains.CAVE_LADDER_UP_WILDERNESS.change_level_shift_back = true
 	terrains.CAVE_LADDER_UP_WILDERNESS.change_zone_auto_stairs = true
+	terrains.CAVE_LADDER_UP_WILDERNESS.name = "ladder back to "..game.zone.name
+	terrains.CAVE_LADDER_UP_WILDERNESS.change_zone = game.zone.short_name
 	local zone = mod.class.Zone.new(id, {
 		name = "Damp Cave",
-		level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+		level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher actor levels
+		__applied_difficulty = true, -- Difficulty already applied to parent zone
 		level_scheme = "player",
 		max_level = 1,
 		actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
@@ -39,8 +45,10 @@ local changer = function(id)
 		ambient_music = "Swashing the buck.ogg",
 		reload_lists = false,
 		persistent = "zone",
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+		
+		no_worldport = game.zone.no_worldport,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
 		generator =  {
 			map = {
 				class = "engine.generator.map.Cavern",
@@ -66,7 +74,6 @@ local changer = function(id)
 				nb_trap = {6, 9},
 			},
 		},
---		levels = { [1] = { generator = { map = { up = "CAVEFLOOR", }, }, }, },
 		npc_list = npcs,
 		grid_list = terrains,
 		object_list = objects,
@@ -77,6 +84,7 @@ end
 
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
 g.name = "damp cave"
+g.always_remember = true
 g.display='>' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
@@ -84,6 +92,7 @@ if engine.Map.tiles.nicer_tiles then
 	g.add_displays = g.add_displays or {}
 	g.add_displays[#g.add_displays+1] = mod.class.Grid.new{image="terrain/crystal_ladder_down.png", z=5}
 end
+g.nice_tiler = nil
 g:altered()
 g:initGlow()
 g.real_change = changer
@@ -91,8 +100,9 @@ g.change_level_check = function(self)
 	game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
 	self.change_level_check = nil
 	self.real_change = nil
+	self.special_minimap = colors.VIOLET
 	return true
 end
 game.zone:addEntity(game.level, g, "terrain", x, y)
 
-return true
+return x, y
diff --git a/game/modules/tome/data/general/events/drake-cave.lua b/game/modules/tome/data/general/events/drake-cave.lua
index 7268509e7a..d354e7982c 100644
--- a/game/modules/tome/data/general/events/drake-cave.lua
+++ b/game/modules/tome/data/general/events/drake-cave.lua
@@ -18,27 +18,28 @@
 -- darkgod@te4.org
 
 -- Find a random spot
-local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-local tries = 0
-while not game.state:canEventGrid(level, x, y) and tries < 100 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 return false end
+local x, y = game.state:findEventGrid(level)
+if not x then return false end
 
 local kind = rng.table{"fire", "fire", "cold", "cold", "storm", "storm", "multihued"}
 
 local id = kind.."-dragon-cave-"..game.turn
 
+print("Placing event", id, "at", x, y)
+
 local changer = function(id, kind)
 	local npcs = mod.class.NPC:loadList{"/data/general/npcs/"..kind.."-drake.lua"}
 	local objects = mod.class.Object:loadList("/data/general/objects/objects.lua")
 	local terrains = mod.class.Grid:loadList("/data/general/grids/cave.lua")
 	terrains.CAVE_LADDER_UP_WILDERNESS.change_level_shift_back = true
 	terrains.CAVE_LADDER_UP_WILDERNESS.change_zone_auto_stairs = true
+	terrains.CAVE_LADDER_UP_WILDERNESS.name = "ladder back to "..game.zone.name
+	terrains.CAVE_LADDER_UP_WILDERNESS.change_zone = game.zone.short_name
 	local zone = mod.class.Zone.new(id, {
 		name = "Intimidating Cave",
-		level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+		level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher levels
+		__applied_difficulty = true, --Difficulty already applied to parent zone
 		level_scheme = "player",
 		max_level = 1,
 		actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
@@ -46,8 +47,10 @@ local changer = function(id, kind)
 		ambient_music = "Swashing the buck.ogg",
 		reload_lists = false,
 		persistent = "zone",
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+		
+		no_worldport = game.zone.no_worldport,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
 		generator =  {
 			map = {
 				class = "engine.generator.map.Cavern",
@@ -73,7 +76,6 @@ local changer = function(id, kind)
 				nb_trap = {6, 9},
 			},
 		},
---		levels = { [1] = { generator = { map = { up = "CAVEFLOOR", }, }, }, },
 		npc_list = npcs,
 		grid_list = terrains,
 		object_list = objects,
@@ -85,12 +87,14 @@ end
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
 g.name = "intimidating cave"
 g.display='>' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
+g.always_remember = true
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
 if engine.Map.tiles.nicer_tiles then
 	g.add_displays = g.add_displays or {}
 	g.add_displays[#g.add_displays+1] = mod.class.Grid.new{image="terrain/crystal_ladder_down.png", z=5}
 end
+g.nice_tiler = nil
 g:altered()
 g:initGlow()
 g.dragon_kind = kind
@@ -99,6 +103,7 @@ g.change_level_check = function(self)
 	game:changeLevel(1, self.real_change(self.change_zone, self.dragon_kind), {temporary_zone_shift=true, direct_switch=true})
 	self.change_level_check = nil
 	self.real_change = nil
+	self.special_minimap = colors.VIOLET
 	return true
 end
 game.zone:addEntity(game.level, g, "terrain", x, y)
@@ -113,4 +118,4 @@ if m then
 	game.zone:addEntity(game.level, m, "actor", i, j)
 end
 
-return true
+return x, y
diff --git a/game/modules/tome/data/general/events/fearscape-portal.lua b/game/modules/tome/data/general/events/fearscape-portal.lua
index 7e3b944c35..701f9fef4b 100644
--- a/game/modules/tome/data/general/events/fearscape-portal.lua
+++ b/game/modules/tome/data/general/events/fearscape-portal.lua
@@ -18,16 +18,13 @@
 -- darkgod@te4.org
 
 -- Find a random spot
-local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-local tries = 0
-while not game.state:canEventGrid(level, x, y) and tries < 100 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 return false end
+local x, y = game.state:findEventGrid(level)
+if not x then return false end
 
 local id = "fearscape-invasion-"..game.turn
 
+print("Placing event", id, "at", x, y)
+
 local changer = function(id)
 	local npcs = mod.class.NPC:loadList{"/data/general/npcs/minor-demon.lua", "/data/general/npcs/major-demon.lua"}
 	local objects = mod.class.Object:loadList("/data/general/objects/objects.lua")
@@ -37,16 +34,24 @@ local changer = function(id)
 	terrains.PORTAL_BACK = mod.class.Grid.new{
 		type = "floor", subtype = "floor",
 		display = "&", color = colors.BLUE,
-		name = "portal",
+		name = "portal back to "..game.zone.name,
 		image = "terrain/red_floating_rocks05_01.png",
 		add_displays = { mod.class.Grid.new{image="terrain/demon_portal3.png"} },
-		change_level = 1, change_zone = "wilderness",
+		change_level = 1,
+		change_zone = game.zone.short_name,
 		change_level_shift_back = true,
 		change_zone_auto_stairs = true,
+		change_level_check = function(self)
+			game.log("#VIOLET# You escape the Fearscape!")
+			-- May delete old zone file here?
+			return
+		end
 	}
 	local zone = mod.class.Zone.new(id, {
 		name = "orbital fearscape platform",
-		level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+		level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher levels
+		__applied_difficulty = true, -- Difficulty already applied to parent zone
 		level_scheme = "player",
 		max_level = 1,
 		actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
@@ -55,8 +60,10 @@ local changer = function(id)
 		reload_lists = false,
 		projectile_speed_mod = 0.3,
 		persistent = "zone",
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+		
+		no_worldport = game.zone.no_worldport,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
 		effects = {"EFF_ZONE_AURA_FEARSCAPE"},
 		generator =  {
 			map = {
@@ -72,6 +79,7 @@ local changer = function(id)
 				class = "mod.class.generator.actor.Random",
 				nb_npc = {12, 12},
 				guardian = {random_elite={life_rating=function(v) return v * 1.5 + 4 end, nb_rares=4, name_scheme="#rng# the Invader", on_die=function(self) world:gainAchievement("EVENT_FEARSCAPE", game:getPlayer(true)) end}},
+				},
 			},
 			object = {
 				class = "engine.generator.object.Random",
@@ -96,7 +104,6 @@ local changer = function(id)
 			game.zone.world_sphere_rot = (game.zone.world_sphere_rot or 0)
 			game.zone.cloud_sphere_rot = (game.zone.world_cloud_rot or 0)
 		end,
-
 		background = function(level, x, y, nb_keyframes)
 			local Map = require "engine.Map"
 			local parx, pary = level.map.mx / (level.map.w - Map.viewport.mwidth), level.map.my / (level.map.h - Map.viewport.mheight)
@@ -132,8 +139,6 @@ local changer = function(id)
 			core.display.glMatrix(false)
 			core.display.glDepthTest(false)
 		end,
-
---		levels = { [1] = { generator = { map = { up = "CAVEFLOOR", }, }, }, },
 		npc_list = npcs,
 		grid_list = terrains,
 		object_list = objects,
@@ -144,6 +149,8 @@ end
 
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
 g.name = "fearscape invasion portal"
+g.always_remember = true
+g.show_tooltip = true
 g.display='&' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
@@ -152,6 +159,7 @@ if engine.Map.tiles.nicer_tiles then
 	g.add_displays[#g.add_displays+1] = mod.class.Grid.new{image="terrain/demon_portal3.png"}
 end
 g.grow = nil g.dig = nil
+g.nice_tiler = nil
 g:altered()
 g:initGlow()
 g.special = true
@@ -163,24 +171,31 @@ g.change_level_check = function(self)
 	self.real_change = nil
 	return true
 end
-g.on_move = function(self, x, y, who)
+g.on_move = function(self, x, y, who, act, couldpass)
 	if not who or not who.player then return false end
 	if self.broken then
 		game.log("#VIOLET#The portal is already broken!")
 		return false
 	end
 
-	require("engine.ui.Dialog"):yesnoPopup("Fearscape Portal", "Do you wish to enter the portal or just destroy it?", function(ret)
+	require("engine.ui.Dialog"):yesnoPopup("Fearscape Portal", "Do you wish to enter the portal, destroy it, or ignore it (press escape)?", function(ret)
+		if ret == "Quit" then
+			game.log("#VIOLET#Ignoring the portal...")
+			return
+		end
 		game.log("#VIOLET#The portal is broken!")
 		if not ret then
 			self:change_level_check()
 		end
 		self.broken = true
-		self.name = "broken "..self.name
+		self.name = "broken fearscape invasion portal"
 		self.change_level = nil
+		self.change_level_check = nil
+		self.show_tooltip = false
 		self.autoexplore_ignore = true
-	end, "Destroy", "Enter")
-
+		self.special_minimap = colors.VIOLET
+	end, "Destroy", "Enter", false, "Quit")
+	
 	return false
 end
 
@@ -204,7 +219,7 @@ local respawn = function(self)
 	m.faction = "fearscape"
 	m.on_die = function(self) self:fearscape_respawn() end
 	game.zone:addEntity(game.level, m, "actor", i, j)
-	game.logSeen(m, "#VIOLET#A demon steps out of the portal!")
+	game.logSeen(m, "#VIOLET#A demon steps out of the %s!", portal.name)
 end
 
 -- Spawn two that will keep on being replenished
@@ -212,4 +227,4 @@ local base = {fearscape_portal_x=x, fearscape_portal_y=y, fearscape_respawn=resp
 respawn(base)
 respawn(base)
 
-return true
+return x, y
diff --git a/game/modules/tome/data/general/events/naga-portal.lua b/game/modules/tome/data/general/events/naga-portal.lua
index f0ec2c55f3..0cb60b9adf 100644
--- a/game/modules/tome/data/general/events/naga-portal.lua
+++ b/game/modules/tome/data/general/events/naga-portal.lua
@@ -18,13 +18,8 @@
 -- darkgod@te4.org
 
 -- Find a random spot
-local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-local tries = 0
-while not game.state:canEventGrid(level, x, y) and tries < 100 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 return false end
+local x, y = game.state:findEventGrid(level)
+if not x then return false end
 
 local id = "naga-invasion-"..game.turn
 
@@ -36,30 +31,35 @@ local changer = function(id)
 		type = "floor", subtype = "underwater",
 		display = "&", color = colors.BLUE,
 		name = "coral invasion portal",
+		name = "portal back to "..game.zone.name,
 		image = "terrain/underwater/subsea_floor_02.png",
 		add_displays = {mod.class.Grid.new{z=18, image="terrain/naga_portal.png", display_h=2, display_y=-1, embed_particles = {
 			{name="naga_portal_smoke", rad=2, args={smoke="particles_images/smoke_whispery_bright"}},
 			{name="naga_portal_smoke", rad=2, args={smoke="particles_images/smoke_heavy_bright"}},
 			{name="naga_portal_smoke", rad=2, args={smoke="particles_images/smoke_dark"}},
 		}}},
-		change_level = 1, change_zone = "wilderness",
+		change_level = 1,
+		change_zone = game.zone.short_name,
 		change_level_shift_back = true,
 		change_zone_auto_stairs = true,
 	}
 	local zone = mod.class.Zone.new(id, {
 		name = "water cavern",
-		level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+		level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher levels
+		__applied_difficulty = true, -- Difficulty already applied to parent zone
 		level_scheme = "player",
 		max_level = 1,
 		actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
 		width = 30, height = 30,
 		ambient_music = "Dark Secrets.ogg",
 		reload_lists = false,
+		no_worldport = game.zone.no_worldport,
 		color_shown = {0.5, 1, 0.8, 1},
 		color_obscure = {0.5*0.6, 1*0.6, 0.8*0.6, 0.6},
 		persistent = "zone",
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
 		effects = {"EFF_ZONE_AURA_UNDERWATER"},
 		generator =  {
 			map = {
@@ -89,7 +89,6 @@ local changer = function(id)
 			},
 		},
 		post_process = function(level) for uid, e in pairs(level.entities) do e.faction = e.hard_faction or "vargh-republic" end end,
---		levels = { [1] = { generator = { map = { up = "CAVEFLOOR", }, }, }, },
 		npc_list = npcs,
 		grid_list = terrains,
 		object_list = objects,
@@ -100,6 +99,7 @@ end
 
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
 g.name = "naga invasion coral portal"
+g.always_remember = true
 g.display='&' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
@@ -120,26 +120,33 @@ g.change_level_check = function(self)
 	game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
 	self.change_level_check = nil
 	self.real_change = nil
+	self.broken = true
+	self.show_tooltip = false
 	return true
 end
-g.on_move = function(self, x, y, who)
+g.on_move = function(self, x, y, who, act, couldpass)
 	if not who or not who.player then return false end
 	if self.broken then
 		game.log("#VIOLET#The portal is already broken!")
 		return false
 	end
-
-	require("engine.ui.Dialog"):yesnoPopup("Coral Portal", "Do you wish to enter the portal or just destroy it?", function(ret)
+	require("engine.ui.Dialog"):yesnoPopup("Coral Portal", "Do you wish to enter the portal, destroy it, or ignore it (press escape)?", function(ret)
+		if ret == "Quit" then
+			game.log("#VIOLET#Ignoring the portal...")
+			return
+		end
+		
 		game.log("#VIOLET#The portal is broken!")
 		if not ret then
 			self:change_level_check()
 		end
 		self.broken = true
-		self.name = "broken "..self.name
+		self.name = "broken naga invasion coral portal"
 		self.change_level = nil
 		self.autoexplore_ignore = true
-	end, "Destroy", "Enter")
-
+		self.special_minimap = colors.VIOLET
+	end, "Destroy", "Enter", false, "Quit")
+	
 	return false
 end
 
@@ -171,4 +178,4 @@ local base = {naga_portal_x=x, naga_portal_y=y, naga_respawn=respawn}
 respawn(base)
 respawn(base)
 
-return true
+return x, y
diff --git a/game/modules/tome/data/general/events/old-battle-field.lua b/game/modules/tome/data/general/events/old-battle-field.lua
index 439aa63dc4..b14acefce6 100644
--- a/game/modules/tome/data/general/events/old-battle-field.lua
+++ b/game/modules/tome/data/general/events/old-battle-field.lua
@@ -42,9 +42,19 @@ if tries < 100 then
 		local terrains = mod.class.Grid:loadList("/data/general/grids/cave.lua")
 		terrains.CAVE_LADDER_UP_WILDERNESS.change_level_shift_back = true
 		terrains.CAVE_LADDER_UP_WILDERNESS.change_zone_auto_stairs = true
+		terrains.CAVE_LADDER_UP_WILDERNESS.change_level = 1
+		terrains.CAVE_LADDER_UP_WILDERNESS.name = "ramp up to "..game.zone.name
+		terrains.CAVE_LADDER_UP_WILDERNESS.change_zone = game.zone.short_name
+		terrains.CAVE_LADDER_UP_WILDERNESS.change_level_check = function(self, who)
+			game.log("#VIOLET# The ramp crumbles as you climb it, followed by the collapse of the cavern.")
+			-- May delete old zone file here?
+			return
+		end
 		local zone = mod.class.Zone.new(id, {
 			name = "Cavern beneath tombstones",
-			level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+			level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher levels
+			__applied_difficulty = true, -- Difficulty already applied to parent zone
 			level_scheme = "player",
 			max_level = 1,
 			actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
@@ -52,8 +62,10 @@ if tries < 100 then
 			ambient_music = "Swashing the buck.ogg",
 			reload_lists = false,
 			persistent = "zone",
-			min_material_level = game.zone.min_material_level,
-			max_material_level = game.zone.max_material_level,
+
+			no_worldport = game.zone.no_worldport,
+			min_material_level = util.getval(game.zone.min_material_level),
+			max_material_level = util.getval(game.zone.max_material_level),
 			generator =  {
 				map = {
 					class = "engine.generator.map.Static",
@@ -110,11 +122,12 @@ if tries < 100 then
 	end
 
 	local grids = check(x, y)
+	local graves = {}
 	for i = 1, 5 do
 		local p = rng.tableRemove(grids)
 
 		local g = game.level.map(p.x, p.y, engine.Map.TERRAIN):cloneFull()
-		g.name = "grave"
+		g.name = "grave" g.x, g.y = p.x, p.y
 		g.display='&' g.color_r=255 g.color_g=255 g.color_b=255 g.notice = true
 		g.always_remember = true g.special_minimap = colors.OLIVE_DRAB
 		g:removeAllMOs()
@@ -124,25 +137,14 @@ if tries < 100 then
 		end
 		g.grow = nil g.dig = nil
 		g.special = true
+		g.graves = graves
 		g:altered()
 		g.block_move = function(self, x, y, who, act, couldpass)
 			if not who or not who.player or not act then return false end
 			if game.level.event_battlefield_entered then return false end
 			who:runStop("grave")
 			require("engine.ui.Dialog"):yesnoPopup("Grave", "Do you wish to disturb the grave?", function(ret) if ret then
-				local g = game.level.map(x, y, engine.Map.TERRAIN)
-				g:removeAllMOs()
-				if g.add_displays then
-					local ov = g.add_displays[#g.add_displays]
-					ov.image = "terrain/grave_opened_0"..rng.range(1, 3).."_64.png"
-				end
-				g.name = "grave (opened)"
-				game.level.map:updateMap(x, y)
-
-				self.block_move = nil
-				self.autoexplore_ignore = true
 				self:change_level_check()
-				require("engine.ui.Dialog"):simplePopup("Fall...", "As you tried to dig the grave the ground fell under you. You find yourself stranded in an eerie lit cavern.")
 			end end)
 			return false
 		end
@@ -150,14 +152,28 @@ if tries < 100 then
 		g.real_change = changer
 		g.change_level_check = function(self)
 			if game.level.event_battlefield_entered then return true end
+			self:removeAllMOs()
+			if self.add_displays then
+				local ov = self.add_displays[#self.add_displays]
+				ov.image = "terrain/grave_opened_0"..rng.range(1, 3).."_64.png"
+			end
+			self.name = "opened grave"
+			game.level.map:updateMap(self.x, self.y)
 			game.level.event_battlefield_entered = true
 			game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
+			require("engine.ui.Dialog"):simplePopup("Fall...", "As you began digging up the grave, the ground collapsed beneath you. You fall into an eerily lit cavern.")
+			for i, gr in ipairs(self.graves) do
+				gr.change_level_check = nil
+				gr.change_level = nil
+				gr.block_move = nil
+				gr.autoexplore_ignore = true
+			end
 			return true
 		end
 
 		game.zone:addEntity(game.level, g, "terrain", p.x, p.y)
-		print("[EVENT] grave placed at ", p.x, p.y)
+		table.insert(graves, g)
 	end
 end
 
-return true
+return x, y
\ No newline at end of file
diff --git a/game/modules/tome/data/general/events/rat-lich.lua b/game/modules/tome/data/general/events/rat-lich.lua
index 4ac29aa0c7..89030ce3b8 100644
--- a/game/modules/tome/data/general/events/rat-lich.lua
+++ b/game/modules/tome/data/general/events/rat-lich.lua
@@ -20,24 +20,27 @@
 -- Unique
 if game.state:doneEvent(event_id) then return end
 
--- Find a random spot
-local x, y = rng.range(1, level.map.w - 2), rng.range(1, level.map.h - 2)
-local tries = 0
-while not game.state:canEventGrid(level, x, y) and tries < 100 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 return false end
+local x, y = game.state:findEventGrid(level)
+if not x then return false end
 
 local id = "rat-lich-"..game.turn
 
+print("Placing event", id, "at", x, y)
+
 local changer = function(id)
 	local npcs = mod.class.NPC:loadList{"/data/general/npcs/undead-rat.lua"}
 	local objects = mod.class.Object:loadList("/data/general/objects/objects.lua")
 	local terrains = mod.class.Grid:loadList("/data/general/grids/basic.lua")
 	terrains.UP_WILDERNESS.change_level_shift_back = true
 	terrains.UP_WILDERNESS.change_zone_auto_stairs = true
-
+	terrains.UP_WILDERNESS.name = "way up to "..game.zone.name
+	terrains.UP_WILDERNESS.change_zone = game.zone.short_name
+	terrains.UP_WILDERNESS.change_level = 1
+	terrains.UP_WILDERNESS.change_level_check = function(self)
+		game.log("#VIOLET# As you leave the crypt, the stairway collapses in upon itself.")
+		-- May delete old zone file here?
+		return
+	end
 	objects.RATLICH_SKULL = mod.class.Object.new{
 		define_as = "RATLICH_SKULL",
 		power_source = {arcane=true},
@@ -97,7 +100,9 @@ local changer = function(id)
 
 	local zone = mod.class.Zone.new(id, {
 		name = "Forsaken Crypt",
-		level_range = {game.zone:level_adjust_level(game.level, game.zone, "actor"), game.zone:level_adjust_level(game.level, game.zone, "actor")},
+		level_range = game.zone.actor_adjust_level and {math.floor(game.zone:actor_adjust_level(game.level, game.player)*1.05),
+			math.ceil(game.zone:actor_adjust_level(game.level, game.player)*1.15)} or {game.zone.base_level, game.zone.base_level}, -- 5-15% higher levels
+		__applied_difficulty = true, --Difficulty already applied to parent zone
 		level_scheme = "player",
 		max_level = 1,
 		actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end,
@@ -105,8 +110,10 @@ local changer = function(id)
 		ambient_music = "Dark Secrets.ogg",
 		reload_lists = false,
 		persistent = "zone",
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+		no_worldport = game.zone.no_worldport,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
+		
 		generator =  {
 			map = {
 				class = "engine.generator.map.Roomer",
@@ -142,7 +149,10 @@ local changer = function(id)
 end
 
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
-g.name = "forsaken crypt"
+g.name = "stairway leading downwards"
+g.always_remember = true
+g.desc = [[Stairs seem to lead into some kind of crypt.]]
+g.show_tooltip = true
 g.display='>' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
@@ -157,7 +167,11 @@ g.change_level_check = function(self)
 	game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
 	require("engine.ui.Dialog"):simplePopup("Forsaken Crypt", "You hear squeaks and the sounds of clicking bone echo around you... Pure death awaits. Flee!")
 	self.change_level_check = nil
-	self.real_change = nil
+	self.change_level = nil
+	self.name = "collapsed forsaken crypt"
+	self.desc = [[Stairs lead downwards into rubble.]]
+	self.autoexplore_ignore = true
+	self.special_minimap = colors.VIOLET
 	return true
 end
 game.zone:addEntity(game.level, g, "terrain", x, y)
@@ -172,4 +186,4 @@ for z = 1, 3 do
 	end
 end
 
-return true
+return x, y
diff --git a/game/modules/tome/data/general/events/sub-vault.lua b/game/modules/tome/data/general/events/sub-vault.lua
index 519331e9ba..59841431c5 100644
--- a/game/modules/tome/data/general/events/sub-vault.lua
+++ b/game/modules/tome/data/general/events/sub-vault.lua
@@ -73,9 +73,9 @@ local changer = function(id)
 		ambient_music = game.zone.ambient_music,
 		reload_lists = false,
 		persistent = "zone",
---		_max_level_generation_count = 2,
-		min_material_level = game.zone.min_material_level,
-		max_material_level = game.zone.max_material_level,
+--		_max_level_generation_count = 5,
+		min_material_level = util.getval(game.zone.min_material_level),
+		max_material_level = util.getval(game.zone.max_material_level),
 		no_worldport = game.zone.no_worldport,
 		generator =  {
 			map = table.merge(basemap, {
@@ -108,9 +108,11 @@ end
 
 local g = game.level.map(x, y, engine.Map.TERRAIN):cloneFull()
 g.name = "hidden vault"
+g.always_remember = true
 g.desc = [[Crumbling stairs lead down to something.]]
 g.show_tooltip = true
 g.display='>' g.color_r=0 g.color_g=0 g.color_b=255 g.notice = true
+g.special_minimap = colors.VIOLET
 g.change_level=1 g.change_zone=id g.glow=true
 g:removeAllMOs()
 if engine.Map.tiles.nicer_tiles then
@@ -122,19 +124,17 @@ g:altered()
 g:initGlow()
 g.real_change = changer
 g.change_level_check = function(self) -- limit stair scumming
-	game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
 	self._use_count = self._use_count - 1
 	self.name = "collapsing hidden vault"
 	if self._use_count < 1 then
 		self.change_level_check = nil
-		self.real_change = nil
 		self.change_level = nil
 		self.name = "collapsed hidden vault"
 		self.desc = [[A collapsed stairway, leading down]]
 	elseif self._use_count < 2 then
 		self.name = "nearly collapsed hidden vault"
 	end
-	self.special_minimap = colors.BLUE
+	game:changeLevel(1, self.real_change(self.change_zone), {temporary_zone_shift=true, direct_switch=true})
 	return true
 end
 game.zone:addEntity(game.level, g, "terrain", x, y)
-- 
GitLab