diff --git a/game/engine/utils.lua b/game/engine/utils.lua
index 69bc2f099b492a1d179c78d193cfceca90020064..0bec443bec6b228f090aecf2677c1dbdeba8e736 100644
--- a/game/engine/utils.lua
+++ b/game/engine/utils.lua
@@ -164,6 +164,10 @@ local Pcode = (lpeg.R"af" + lpeg.R"09" + lpeg.R"AF")
 local Pcolorcode = Pcode * Pcode
 local Pcolorcodefull = Pcolorcode * Pcolorcode * Pcolorcode
 
+function string.removeColorCodes(str)
+	return str:lpegSub("#" * (Puid + Pcolorcodefull + Pcolorname) * "#", "")
+end
+
 function string.splitLine(str, max_width, font)
 	local space_w = font:size(" ")
 	local lines = {}
@@ -263,7 +267,7 @@ getmetatable(tmps).__index.drawColorString = function(s, font, str, x, y, r, g,
 				oldr, oldg, oldb = r, g, b
 				r, g, b = colors[col].r, colors[col].g, colors[col].b
 			end
-		elseif uid and mo then
+		elseif uid and mo and game.level then
 			uid = tonumber(uid)
 			mo = tonumber(mo)
 			local e = __uids[uid]
@@ -312,7 +316,7 @@ getmetatable(tmps).__index.drawColorStringBlended = function(s, font, str, x, y,
 				oldr, oldg, oldb = r, g, b
 				r, g, b = colors[col].r, colors[col].g, colors[col].b
 			end
-		elseif uid and mo then
+		elseif uid and mo and game.level then
 			uid = tonumber(uid)
 			mo = tonumber(mo)
 			local e = __uids[uid]
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 9543a401277c948f5df725ff4b8360f2e3509611..21e1306c6fb2106e9dd5f9124d4c00e7290d571e 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -642,7 +642,7 @@ function _M:die(src)
 	end
 
 	-- Increase vim
-	if src and src:attr("vim_on_death") and not self:attr("undead") then src:incVim(src:attr("vim_on_death")) end
+	if src and src.attr and src:attr("vim_on_death") and not self:attr("undead") then src:incVim(src:attr("vim_on_death")) end
 
 	if src and src.resolveSource and src:resolveSource().player then
 		-- Achievements
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 43611b7075e9d1e5aaf79d3ac352375f28c7ebc2..fca5e7790247872eb2e40537ea25948676fc3631 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -589,6 +589,7 @@ function _M:useOrbPortal(portal)
 		local ok = false
 		self:restInit(20, "using the portal", "used the poral", function(cnt, max)
 			if cnt > max then ok = true end
+			print("*********** portaling one turn", ok)
 			coroutine.resume(co)
 		end)
 		coroutine.yield()
@@ -598,7 +599,7 @@ function _M:useOrbPortal(portal)
 		end
 		return true
 	end
---	if not wait() then return end
+	if not wait() then return end
 
 	if portal.teleport_level then
 		local x, y = util.findFreeGrid(portal.teleport_level.x, portal.teleport_level.y, 2, true, {[Map.ACTOR]=true})
diff --git a/game/modules/tome/class/PlayerDisplay.lua b/game/modules/tome/class/PlayerDisplay.lua
index 30967e803c0f5c7b6ab57b23c05675b4c9deb41f..ab1283c070cceaa6273ce280ff1a685bfd1875a6 100644
--- a/game/modules/tome/class/PlayerDisplay.lua
+++ b/game/modules/tome/class/PlayerDisplay.lua
@@ -104,8 +104,8 @@ function _M:display()
 		self.surface:drawColorStringBlended(self.font, ("#7fffd4#Negative:#ffffff#%d/%d"):format(player:getNegative(), player.max_negative), 0, h, 255, 255, 255) h = h + self.font_h
 	end
 	if player:knowTalent(player.T_VIM_POOL) then
-		self.surface:erase(0xff / 6, 0xcc / 6, 0x80 / 6, 255, self.bars_x, h, self.bars_w, self.font_h)
-		self.surface:erase(0xff / 3, 0xcc / 3, 0x80 / 3, 255, self.bars_x, h, self.bars_w * player:getVim() / player.max_vim, self.font_h)
+		self.surface:erase(0x90 / 6, 0x40 / 6, 0x10 / 6, 255, self.bars_x, h, self.bars_w, self.font_h)
+		self.surface:erase(0x90 / 3, 0x40 / 3, 0x10 / 3, 255, self.bars_x, h, self.bars_w * player:getVim() / player.max_vim, self.font_h)
 		self.surface:drawColorStringBlended(self.font, ("#904010#Vim:     #ffffff#%d/%d"):format(player:getVim(), player.max_vim), 0, h, 255, 255, 255) h = h + self.font_h
 	end
 
diff --git a/game/modules/tome/data/texts/win.lua b/game/modules/tome/data/texts/win.lua
index e6edae43f701a698a02e264196998b8759898d08..f3c4bd48f0691ee732de126e502f9eb5b658234e 100644
--- a/game/modules/tome/data/texts/win.lua
+++ b/game/modules/tome/data/texts/win.lua
@@ -34,6 +34,9 @@ end
 if game.player:isQuestStatus("high-peak", engine.Quest.COMPLETED, "gates-of-morning-destroyed") then
 	desc[#desc+1] = ""
 	desc[#desc+1] = "The Gates of Morning have been destroyed and the Sunwall has fallen, the last remnants of the free people in the Far East will surely disminish and soon only orcs will inhabit this land."
+else
+	desc[#desc+1] = ""
+	desc[#desc+1] = "The orc presence in the Far East has greatly been disminished by the loss of their leaders and the destruction of the Istari. The free people of the Sunwall will be able to prosper and thrive on this land."
 end
 
 desc[#desc+1] = ""
@@ -44,4 +47,6 @@ if game.player.winner ~= "self-sacrifice" then
 	desc[#desc+1] = "You may continue playing and enjoy the rest of the world."
 end
 
+game.player.winner_text = desc
+
 return table.concat(desc, "\n")
diff --git a/game/modules/tome/data/zones/grushnak-pride/npcs.lua b/game/modules/tome/data/zones/grushnak-pride/npcs.lua
index 30a88e259c6e991da78e3989133ee210b73ad072..578dd752205923573bfe837bae716834bddf5b57 100644
--- a/game/modules/tome/data/zones/grushnak-pride/npcs.lua
+++ b/game/modules/tome/data/zones/grushnak-pride/npcs.lua
@@ -51,8 +51,9 @@ newEntity{ base="BASE_NPC_ORC_GRUSHNAK", define_as = "GRUSHNAK",
 		{type="armor", subtype="massive", ego_chance=100, autoreq=true},
 		{type="armor", subtype="head", ego_chance=100, autoreq=true},
 		{type="armor", subtype="feet", ego_chance=100, autoreq=true},
-		{type="jewelry", subtype="amulet", ego_chance=100, autoreq=true},
-		{type="jewelry", subtype="ring", ego_chance=100, autoreq=true},
+--		Commented because this can generate rings of invis or amulets of telepathy and drain the life of the boss
+--		{type="jewelry", subtype="amulet", ego_chance=100, autoreq=true},
+--		{type="jewelry", subtype="ring", ego_chance=100, autoreq=true},
 		{type="jewelry", subtype="ring", defined="PRIDE_GLORY", autoreq=true},
 	},
 	resolvers.drops{chance=100, nb=5, {ego_chance=100} },
diff --git a/game/modules/tome/data/zones/high-peak/grids.lua b/game/modules/tome/data/zones/high-peak/grids.lua
index b8e1190ef7304987c7e2afef676c7bd93fc2a113..9599b81964be7e7ac3c7002b9fd2a17d13cf12da 100644
--- a/game/modules/tome/data/zones/high-peak/grids.lua
+++ b/game/modules/tome/data/zones/high-peak/grids.lua
@@ -75,6 +75,7 @@ This one seems to go to an unknown place, seemingly out of this world. You dare
 }
 
 local invocation_close = function(self, who)
+	if not who:hasQuest("high-peak") or who:hasQuest("high-peak"):isCompleted() then return end
 	game.logPlayer(who, "#LIGHT_BLUE#You use the orb on the portal, shutting it down easily.")
 	-- Remove the level spot
 	local spot = game.level:pickSpot{type="portal", subtype=self.summon}
diff --git a/game/modules/tome/dialogs/CharacterSheet.lua b/game/modules/tome/dialogs/CharacterSheet.lua
index 1565624384b613733b0bda5207ea05da30ba90d6..5744d85b56047c433f3140424122e05fa5ac2304 100644
--- a/game/modules/tome/dialogs/CharacterSheet.lua
+++ b/game/modules/tome/dialogs/CharacterSheet.lua
@@ -64,8 +64,14 @@ function _M:drawDialog(s)
 	if game.player:knowTalent(game.player.T_MANA_POOL) then
 		s:drawColorStringBlended(self.font, ("#7fffd4#Mana:    #00ff00#%d/%d"):format(game.player:getMana(), game.player.max_mana), w, h, 255, 255, 255) h = h + self.font_h
 	end
-	if game.player:knowTalent(game.player.T_SOUL_POOL) then
-		s:drawColorStringBlended(self.font, ("#777777#Soul:    #00ff00#%d/%d"):format(game.player:getSoul(), game.player.max_soul), w, h, 255, 255, 255) h = h + self.font_h
+	if game.player:knowTalent(game.player.T_POSITIVE_POOL) then
+		s:drawColorStringBlended(self.font, ("#7fffd4#Positive:#00ff00#%d/%d"):format(game.player:getPositive(), game.player.max_positive), w, h, 255, 255, 255) h = h + self.font_h
+	end
+	if game.player:knowTalent(game.player.T_NEGATIVE_POOL) then
+		s:drawColorStringBlended(self.font, ("#7fffd4#Negative:#00ff00#%d/%d"):format(game.player:getNegative(), game.player.max_negative), w, h, 255, 255, 255) h = h + self.font_h
+	end
+	if game.player:knowTalent(game.player.T_VIM_POOL) then
+		s:drawColorStringBlended(self.font, ("#904010#Vim:     #00ff00#%d/%d"):format(game.player:getVim(), game.player.max_vim), w, h, 255, 255, 255) h = h + self.font_h
 	end
 	if game.player:knowTalent(game.player.T_EQUILIBRIUM_POOL) then
 		s:drawColorStringBlended(self.font, ("#00ff74#Equi:    #00ff00#%d"):format(game.player:getEquilibrium()), w, h, 255, 255, 255) h = h + self.font_h
@@ -144,6 +150,20 @@ function _M:drawDialog(s)
 		end
 	end
 
+	immune_type = "poison_immune" immune_name = "Poison Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "cut_immune" immune_name = "Bleed Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "confusion_immune" immune_name = "Confusion Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "blind_immune" immune_name = "Blind Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "silence_immune" immune_name = "Silence Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "disarm_immune" immune_name = "Disarm Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "pin_immune" immune_name = "Pinning Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "stun_immune" immune_name = "Stun Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "fear_immune" immune_name = "Fear Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "knockback_immune" immune_name = "Knockback Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "stone_immune" immune_name = "Stoning Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "instakill_immune" immune_name = "Instadeath Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+	immune_type = "teleport_immune" immune_name = "Teleport Resistance" if self.actor:attr(immune_type) then s:drawColorStringBlended(self.font, ("%s: #00ff00#%3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100)), w, h, 255, 255, 255) h = h + self.font_h end
+
 	h = 0
 	w = 600
 	s:drawColorStringBlended(self.font, "#LIGHT_BLUE#Current effects:", w, h, 255, 255, 255) h = h + self.font_h
@@ -167,8 +187,8 @@ function _M:dump()
 	local file = "/character-dumps/"..(game.player.name:gsub("[^a-zA-Z0-9_-.]", "_")).."-"..os.date("%Y%m%d-%H%M%S")..".txt"
 	local fff = fs.open(file, "w")
 	local labelwidth = 17
-	local nl = function(s) fff:write(s or "") fff:write("\n") end
-	local nnl = function(s) fff:write(s or "") end
+	local nl = function(s) s = s or "" fff:write(s:removeColorCodes()) fff:write("\n") end
+	local nnl = function(s) s = s or "" fff:write(s:removeColorCodes()) end
 	--prepare label and value
 	local makelabel = function(s,r) while s:len() < labelwidth do s = s.." " end return ("%s: %s"):format(s, r) end
 
@@ -191,7 +211,7 @@ function _M:dump()
 	nnl(("%-32s"):format(makelabel("Exp", ("%d%%"):format(100 * cur_exp / max_exp))))
 	nl(("CUN:  %d"):format(game.player:getCun()))
 
-	 nnl(("%-32s"):format(makelabel("Gold", ("%.2f"):format(game.player.money))))
+	nnl(("%-32s"):format(makelabel("Gold", ("%.2f"):format(game.player.money))))
 	nl(("CON:  %d"):format(game.player:getCon()))
 
 	 -- All weapons in main hands
@@ -232,9 +252,21 @@ function _M:dump()
 		nl()
 	end
 	nnl(("%-32s"):format(strings[4]))
-	if game.player:knowTalent(game.player.T_SOUL_POOL) then
-		nl(makelabel("Soul", ("    %d/%d"):format(game.player:getSoul(), game.player.max_soul)))
-	 else
+	if game.player:knowTalent(game.player.T_POSITIVE_POOL) then
+		nl(makelabel("Positive", ("    %d/%d"):format(game.player:getPositive(), game.player.max_positive)))
+	else
+		nl()
+	end
+	nnl(("%-32s"):format(strings[4]))
+	if game.player:knowTalent(game.player.T_NEGATIVE_POOL) then
+		nl(makelabel("Negative", ("    %d/%d"):format(game.player:getNegative(), game.player.max_negative)))
+	else
+		nl()
+	end
+	nnl(("%-32s"):format(strings[4]))
+	if game.player:knowTalent(game.player.T_VIM_POOL) then
+		nl(makelabel("Vim", ("    %d/%d"):format(game.player:getVim(), game.player.max_vim)))
+	else
 		nl()
 	end
 	nnl(("%-32s"):format(strings[5]))
@@ -294,6 +326,20 @@ function _M:dump()
 		end
 	end
 
+	immune_type = "poison_immune" immune_name = "Poison Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "cut_immune" immune_name = "Bleed Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "confusion_immune" immune_name = "Confusion Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "blind_immune" immune_name = "Blind Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "silence_immune" immune_name = "Silence Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "disarm_immune" immune_name = "Disarm Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "pin_immune" immune_name = "Pinning Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "stun_immune" immune_name = "Stun Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "fear_immune" immune_name = "Fear Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "knockback_immune" immune_name = "Knockback Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "stone_immune" immune_name = "Stoning Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "instakill_immune" immune_name = "Instadeath Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+	immune_type = "teleport_immune" immune_name = "Teleport Resistance" if self.actor:attr(immune_type) then nl(("%s: %3d%%"):format(immune_name, util.bound(self.actor:attr(immune_type) * 100, 0, 100))) end
+
 	nl()
 	local most_kill, most_kill_max = "none", 0
 	local total_kill = 0
@@ -304,6 +350,15 @@ function _M:dump()
 	nl(("Number of NPC killed: %s"):format(total_kill))
 	nl(("Most killed NPC: %s (%d)"):format(most_kill, most_kill_max))
 
+	if self.actor.winner then
+		nl()
+		nl("  [Winner!]")
+		nl()
+		for i, line in ipairs(self.actor.winner_text) do
+			nl(("%s"):format(line:removeColorCodes()))
+		end
+	end
+
 	-- Talents
 	nl()
 	nl("  [Talents Chart]")
@@ -321,7 +376,7 @@ function _M:dump()
 				for j, t in ipairs(tt.talents) do
 					if not t.hide then
 						local typename = "class"
-						if t.skill then typename = "generic" end
+						if t.generic then typename = "generic" end
 						local skillname = ("    %s (%s)"):format(t.name, typename)
 						nl(("%-37s %d/%d"):format(skillname, self.actor:getTalentLevelRaw(t.id), t.points))
 					end
@@ -353,14 +408,14 @@ function _M:dump()
 	local first = true
 	for id, q in pairs(self.actor.quests or {}) do
 		if q:isEnded() then
-			 if first then
-					 nl()
-					 nl("  [Completed Quests]")
-					 nl()
-					 first=false
-			 end
-			  nl(" -- ".. q.name)
-			  nl(q:desc(self.actor):gsub("#.-#", "   "))
+			if first then
+					nl()
+					nl("  [Completed Quests]")
+					nl()
+					first=false
+			end
+			nl(" -- ".. q.name)
+			nl(q:desc(self.actor):gsub("#.-#", "   "))
 		end
 	end
 
@@ -368,13 +423,13 @@ function _M:dump()
 	for id, q in pairs(self.actor.quests or {}) do
 		if not q:isEnded() then
 			if first then
-					 first=false
-					 nl()
+					first=false
+					nl()
 					nl("  [Active Quests]")
-					 nl()
+					nl()
 				end
-			  nl(" -- ".. q.name)
-			  nl(q:desc(self.actor):gsub("#.-#", "   "))
+			nl(" -- ".. q.name)
+			nl(q:desc(self.actor):gsub("#.-#", "   "))
 		end
 	end
 
@@ -405,9 +460,15 @@ function _M:dump()
 	nl()
 	nl("  [Player Achievements]")
 	nl()
+	local achs = {}
 	for id, data in pairs(self.actor.achievements or {}) do
 		local a = world:getAchievementFromId(id)
-		nl(("%s Was Achieved for %s At %s"):format(a.name,a.desc,data.when))
+		achs[#achs+1] = {id=id, data=data, name=a.name}
+	end
+	table.sort(achs, function(a, b) return a.name < b.name end)
+	for i, d in ipairs(achs) do
+		local a = world:getAchievementFromId(d.id)
+		nl(("'%s' was wchieved for %s At %s"):format(a.name, a.desc, d.data.when))
 	end
 
 	nl()
diff --git a/ideas/quests.ods b/ideas/quests.ods
index f25186fb83d30b7eec9d446a221eb99835a12174..629365d1c26c7860d211a1c30782846c8a0f47d9 100644
Binary files a/ideas/quests.ods and b/ideas/quests.ods differ