diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua
index 1763709e65011a62e709fb26e3761470847c54d8..631850d78bf8a4b1bed865c87c6c826fb01e9965 100644
--- a/game/engines/default/engine/UserChat.lua
+++ b/game/engines/default/engine/UserChat.lua
@@ -417,8 +417,6 @@ function _M:mouseEvent(button, x, y, xrel, yrel, bx, by, event)
 			local item = self.dlist[i]
 			if item.dh and by >= item.dh - self.mouse.delegate_offset_y then citem = self.dlist[i].src ci=i break end
 		end
-		print("================================")
-		util.show_backtrace()
 		for i = 1, #self.dlist do
 			local item = self.dlist[i]
 			if item.dh then print("===", y, by, item.dh - self.mouse.delegate_offset_y, ci==i and "*****" or "") end
diff --git a/game/engines/default/engine/ui/Dialog.lua b/game/engines/default/engine/ui/Dialog.lua
index 6b0529cdc043802db85cea2b94fa037a97c04330..df596139812de4bb34116e260ad06fc540c1e290 100644
--- a/game/engines/default/engine/ui/Dialog.lua
+++ b/game/engines/default/engine/ui/Dialog.lua
@@ -57,7 +57,7 @@ function _M:listPopup(title, text, list, w, h, fct)
 		{left = 3, bottom = 3, ui=l},
 	}
 	d.key:addBind("EXIT", function() game:unregisterDialog(d) if fct then fct() end end)
-	d.key:addBind("ACCEPT", function() game:unregisterDialog(d) if fct then fct(list[l.sel]) end end)
+	d.key:addBind("ACCEPT", function() game:unregisterDialog(d) if list[l.sel].fct then list[l.sel].fct(list[l.sel]) return end if fct then fct(list[l.sel]) end end)
 	d:setFocus(l)
 	d:setupUI(true, true)
 	game:registerDialog(d)
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index e15ca67c945aa89b2b404ef7d0572fbd24d6f5e2..52dfe655fcb0c254de5bf330abaa655e875aa78c 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -292,6 +292,10 @@ function _M:actBase()
 		return
 	end
 
+	if self.__use_build_order then
+		self:useBuildOrder()
+	end
+
 	if self:isTalentActive (self.T_DARKEST_LIGHT) and self.positive > self.negative then
 		self:forceUseTalent(self.T_DARKEST_LIGHT, {ignore_energy=true})
 		game.logSeen(self, "%s's darkness can no longer hold back the light!", self.name:capitalize())
@@ -525,6 +529,131 @@ function _M:act()
 	return true
 end
 
+--- Follow a build order as possible
+function _M:useBuildOrder()
+	local b = self.__use_build_order
+
+	if self.unused_stats > 0 then
+		b.stats.i = b.stats.i or 1
+		local nb = 0
+
+		while self.unused_stats > 0 and nb < #b.stats+1 do
+			local stat = b.stats[b.stats.i]
+
+			if not (self:getStat(stat, nil, nil, true) >= self.level * 1.4 + 20) and
+			   not (self:isStatMax(stat) or self:getStat(stat, nil, nil, true) >= 60 + math.max(0, (self.level - 50))) then
+				self:incStat(stat, 1)
+				self.unused_stats = self.unused_stats - 1
+				nb = -1
+				game.log("#VIOLET#Following build order %s; increasing %s by 1.", b.name, self.stats_def[stat].name)
+			end
+			b.stats.i = util.boundWrap(b.stats.i + 1, 1, #b.stats)
+			nb = nb + 1
+		end
+	end
+
+	if self.unused_talents_types > 0 then
+		self.__increased_talent_types = self.__increased_talent_types or {}
+
+		local learn = true
+		while learn do
+			learn = false
+			for i, tt in ipairs(b.types) do
+				if self.unused_talents_types > 0 and (self.__increased_talent_types[tt] or 0) == 0 then
+					if not self:knowTalentType(tt) then
+						self:learnTalentType(tt)
+					else
+						self.__increased_talent_types[tt] = (self.__increased_talent_types[tt] or 0) + 1
+						self:setTalentTypeMastery(tt, self:getTalentTypeMastery(tt) + 0.2)
+					end
+
+					game.log("#VIOLET#Following build order %s; learning talent category %s.", b.name, tt)
+					self.unused_talents_types = self.unused_talents_types - 1
+					table.remove(b.types, i)
+					learn = true
+					break
+				end
+			end
+		end
+	end
+
+	if self.unused_talents > 0 then
+		local learn = true
+		while learn do
+			learn = false
+			for i, td in ipairs(b.talents) do
+				if td.kind == "class" then
+					local t = self:getTalentFromId(td.tid)
+
+					if self.unused_talents > 0 and self:canLearnTalent(t) and self:getTalentLevelRaw(t.id) < t.points then
+						self:learnTalent(t.id, true)
+						game.log("#VIOLET#Following build order %s; learning talent %s.", b.name, t.name)
+						self.unused_talents = self.unused_talents - 1
+						table.remove(b.talents, i)
+						learn = true
+						break
+					end
+				end
+			end
+		end
+	end
+
+	if self.unused_generics > 0 then
+		local learn = true
+		while learn do
+			learn = false
+			for i, td in ipairs(b.talents) do
+				if td.kind == "generic" then
+					local t = self:getTalentFromId(td.tid)
+
+					if self.unused_generics > 0 and self:canLearnTalent(t) and self:getTalentLevelRaw(t.id) < t.points then
+						self:learnTalent(t.id, true)
+						game.log("#VIOLET#Following build order %s; learning talent %s.", b.name, t.name)
+						self.unused_generics = self.unused_generics - 1
+						table.remove(b.talents, i)
+						learn = true
+						break
+					end
+				end
+			end
+		end
+	end
+end
+
+function _M:loadBuildOrder(file)
+	local f = fs.open("/build-orders/"..file, "r")
+	if not f then return end
+
+	local b = {name="xxx", stats={}, talents={}, types={}}
+
+	local cur = "name"
+	while true do
+		local line = f:readLine()
+		if not line then break end
+
+		if line == "#Name" then cur = "name"
+		elseif line == "#Stats" then cur = "stats"
+		elseif line == "#Talents" then cur = "talents"
+		elseif line == "#Types" then cur = "types"
+		else
+			if cur == "name" then b.name = line
+			elseif cur == "stats" then
+				b.stats = line:split(',')
+			elseif cur == "talents" then
+				local t = line:split(',')
+				table.insert(b.talents, {kind=t[2], tid=t[3]})
+			elseif cur == "types" then
+				local tt = line:split(',')
+				table.insert(b.types, tt[2])
+			end
+		end
+	end
+
+	if #b.stats > 0 and #b.talents > 0 then
+		self.__use_build_order = b
+	end
+end
+
 --- Setup minimap color for this entity
 -- You may overload this method to customize your minimap
 function _M:setupMinimapInfo(mo, map)
@@ -1349,7 +1478,7 @@ function _M:onTakeHit(value, src)
 		t.absorb(self, t, self:isTalentActive(self.T_BONE_SHIELD))
 		value = 0
 	end
-	
+
 	if self.knowTalent and (self:knowTalent(self.T_SEETHE) or self:knowTalent(self.T_GRIM_RESOLVE)) then
 		if not self:hasEffect(self.EFF_CURSED_FORM) then
 			self:setEffect(self.EFF_CURSED_FORM, 1, { increase=0 })
@@ -1706,7 +1835,7 @@ function _M:die(src, death_note)
 	if src and src.knowTalent and src:knowTalent(src.T_UNENDING_FRENZY) then
 		src:incStamina(src:getTalentLevel(src.T_UNENDING_FRENZY) * 2)
 	end
-	
+
 	-- Regain Psi
 	if src and src.attr and src:attr("psi_per_kill") then
 		src:incPsi(src:attr("psi_per_kill"))
@@ -3478,7 +3607,7 @@ end
 -- @return can_project, stop_x, stop_y, radius_x, radius_y.
 function _M:canProject(t, x, y)
 	local can_project, stop_x, stop_y, radius_x, radius_y = engine.interface.ActorProject.canProject(self, t, x, y)
-	
+
 	-- add line of sight to can project unless pass_block_sight or pass_terrain has been set
 	if not t.pass_terain and not t.pass_block_sight and can_project then
 		if not self:hasLOS(x, y) then can_project = false end
@@ -3513,14 +3642,14 @@ function _M:on_project(tx, ty, who, t, x, y, damtype, dam, particles)
 		game.logSeen(self, "%s ignores the spell!", self.name:capitalize())
 		return true
 	end
-	
+
 	-- LOS check (this is also caught by canProject)
 	if not t.pass_terain and not t.pass_block_sight then
 		if not who:hasLOS(tx, ty) then
 			return true
 		end
 	end
-	
+
 	return false
 end
 
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 1ebbdac986a660e6283fc24f3d0ac2dd364aa871..9bf46291ef74ba9229ee5177f8ecad4657c07582 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -1115,7 +1115,7 @@ function _M:setupCommands()
 			end end
 		end end,
 		[{"_g","ctrl"}] = function() if config.settings.cheat then
-			self.state:debugRandomZone()
+			self.player:loadBuildOrder("archmage-1.csv")
 		end end,
 		[{"_f","ctrl"}] = function() if config.settings.cheat then
 			self.player.quests["love-melinda"] = nil
diff --git a/game/modules/tome/data/general/objects/egos/staves.lua b/game/modules/tome/data/general/objects/egos/staves.lua
index 92ab11c841a0a95348ea7ab5751a240c04dfbcfe..b6af17cfb13ac4f2f16544ad8e448a62e5926a10 100644
--- a/game/modules/tome/data/general/objects/egos/staves.lua
+++ b/game/modules/tome/data/general/objects/egos/staves.lua
@@ -221,7 +221,7 @@ newEntity{
 			local tg = {type="bolt", range= 5 + self.material_level, speed=20, display = {particle=particle, trail=trail},}
 			local weapon = who:hasStaffWeapon()
 			local combat = weapon.combat
-			
+
 			local DamageType = require "engine.DamageType"
 			local damtype = combat.damtype
 			if     damtype == DamageType.FIRE then      explosion = "flame"               particle = "bolt_fire"      trail = "firetrail"
@@ -236,16 +236,16 @@ newEntity{
 			elseif damtype == DamageType.TEMPORAL then  explosion = "light"				  particle = "temporal_bolt"  trail = "lighttrail"
 			else                                        explosion = "manathrust"          particle = "bolt_arcane"    trail = "arcanetrail" damtype = DamageType.ARCANE
 			end
-			
+
 			local x, y = who:getTarget(tg)
 			if not x or not y then return nil end
-			
+
 			-- Compute damage
 			local dam = who:combatDamage(combat)
 			local damrange = who:combatDamageRange(combat)
 			dam = rng.range(dam, dam * damrange)
 			dam = who:spellCrit(dam)
-						
+
 			who:projectile(tg, x, y, damtype, dam, {type=explosion})
 
 			game.logSeen(who, "%s fires a bolt from %s!", who.name:capitalize(), self.name)
@@ -308,28 +308,28 @@ newEntity{
 			local tg = {type="ball", range=0, radius=self.material_level + 1, selffire=false}
 			local weapon = who:hasStaffWeapon()
 			local combat = weapon.combat
-			
+
 			local DamageType = require "engine.DamageType"
 			local damtype = combat.damtype
-			if     damtype == DamageType.FIRE then      explosion = "flame"           
-			elseif damtype == DamageType.COLD then      explosion = "freeze"     
-			elseif damtype == DamageType.ACID then      explosion = "acid"              
-			elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" 
-			elseif damtype == DamageType.LIGHT then     explosion = "light"              
-			elseif damtype == DamageType.DARKNESS then  explosion = "dark"               
-			elseif damtype == DamageType.NATURE then    explosion = "slime"              
-			elseif damtype == DamageType.BLIGHT then    explosion = "slime"              
-			elseif damtype == DamageType.PHYSICAL then  explosion = "dark"               
-			elseif damtype == DamageType.TEMPORAL then  explosion = "light"				
+			if     damtype == DamageType.FIRE then      explosion = "flame"
+			elseif damtype == DamageType.COLD then      explosion = "freeze"
+			elseif damtype == DamageType.ACID then      explosion = "acid"
+			elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion"
+			elseif damtype == DamageType.LIGHT then     explosion = "light"
+			elseif damtype == DamageType.DARKNESS then  explosion = "dark"
+			elseif damtype == DamageType.NATURE then    explosion = "slime"
+			elseif damtype == DamageType.BLIGHT then    explosion = "slime"
+			elseif damtype == DamageType.PHYSICAL then  explosion = "dark"
+			elseif damtype == DamageType.TEMPORAL then  explosion = "light"
 			else                                        explosion = "manathrust"         damtype = DamageType.ARCANE
 			end
-		
+
 			-- Compute damage
 			local dam = who:combatDamage(combat)
 			local damrange = who:combatDamageRange(combat)
 			dam = rng.range(dam, dam * damrange)
 			dam = who:spellCrit(dam)
-						
+
 			who:project(tg, who.x, who.y, damtype, dam, {type=explosion})
 
 			game.logSeen(who, "%s unleashes an elemental blastwave from %s!", who.name:capitalize(), self.name)
@@ -351,7 +351,7 @@ newEntity{
 		combat_spellpower = resolvers.mbonus_material(10, 2),
 		mana_regen = resolvers.mbonus_material(30, 10, function(e, v) v=v/100 return 0, v end),
 	},
-	resolvers.charm("channel mana (increasing mana regen by 500% for ten turns)", 30,
+	resolvers.charm("channel mana (increasing mana regen by 500%% for ten turns)", 30,
 		function(self, who)
 			if who.mana_regen > 0 and not who:hasEffect(who.EFF_MANASURGE) then
 				who:setEffect(who.EFF_MANASURGE, 10, {power=who.mana_regen * 5})
@@ -405,31 +405,31 @@ newEntity{
 			local tg = {type="cone", range=0, radius=self.material_level * 2, selffire=false}
 			local weapon = who:hasStaffWeapon()
 			local combat = weapon.combat
-			
+
 			local DamageType = require "engine.DamageType"
 			local damtype = combat.damtype
-			if     damtype == DamageType.FIRE then      explosion = "flame"      
-			elseif damtype == DamageType.COLD then      explosion = "freeze"    
-			elseif damtype == DamageType.ACID then      explosion = "acid"          
-			elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion" 
-			elseif damtype == DamageType.LIGHT then     explosion = "light"              
-			elseif damtype == DamageType.DARKNESS then  explosion = "dark"               
-			elseif damtype == DamageType.NATURE then    explosion = "slime"           
-			elseif damtype == DamageType.BLIGHT then    explosion = "slime"            
-			elseif damtype == DamageType.PHYSICAL then  explosion = "dark"           
-			elseif damtype == DamageType.TEMPORAL then  explosion = "light"				 
+			if     damtype == DamageType.FIRE then      explosion = "flame"
+			elseif damtype == DamageType.COLD then      explosion = "freeze"
+			elseif damtype == DamageType.ACID then      explosion = "acid"
+			elseif damtype == DamageType.LIGHTNING then explosion = "lightning_explosion"
+			elseif damtype == DamageType.LIGHT then     explosion = "light"
+			elseif damtype == DamageType.DARKNESS then  explosion = "dark"
+			elseif damtype == DamageType.NATURE then    explosion = "slime"
+			elseif damtype == DamageType.BLIGHT then    explosion = "slime"
+			elseif damtype == DamageType.PHYSICAL then  explosion = "dark"
+			elseif damtype == DamageType.TEMPORAL then  explosion = "light"
 			else                                        explosion = "manathrust"          damtype = DamageType.ARCANE
 			end
-			
+
 			local x, y = who:getTarget(tg)
 			if not x or not y then return nil end
-			
+
 			-- Compute damage
 			local dam = who:combatDamage(combat)
 			local damrange = who:combatDamageRange(combat)
 			dam = rng.range(dam, dam * damrange)
 			dam = who:spellCrit(dam)
-						
+
 			who:project(tg, x, y, damtype, dam, {type=explosion})
 
 			game.logSeen(who, "%s conjures a cone of elemental energy from %s!", who.name:capitalize(), self.name)
diff --git a/game/modules/tome/data/general/objects/egos/wands.lua b/game/modules/tome/data/general/objects/egos/wands.lua
index 88aada553d85716f41a5e6aafc6933ed034edc55..bfc8973a0188482eaab023d48ddd75ba4a601a43 100644
--- a/game/modules/tome/data/general/objects/egos/wands.lua
+++ b/game/modules/tome/data/general/objects/egos/wands.lua
@@ -23,6 +23,7 @@ newEntity{
 	rarity = 15,
 	cost = 5,
 	resolvers.genericlast(function(e)
+		if not e.use_power or not e.charm_power then return end
 		e.use_power.power = math.ceil(e.use_power.power * rng.float(0.6, 0.8))
 		e.charm_power = math.ceil(e.charm_power * rng.float(0.4, 0.7))
 	end),
@@ -34,6 +35,7 @@ newEntity{
 	rarity = 15,
 	cost = 5,
 	resolvers.genericlast(function(e)
+		if not e.use_power or not e.charm_power then return end
 		e.use_power.power = math.ceil(e.use_power.power * rng.float(1.2, 1.5))
 		e.charm_power = math.ceil(e.charm_power * rng.float(1.3, 1.5))
 	end),
@@ -44,7 +46,7 @@ Wands
 *detection
 *light
 *trap destruction
-*flame
+*firewall
 *lightning
 *conjuration
 
@@ -154,17 +156,19 @@ newEntity{
 }
 
 newEntity{
-	name = " of flames", suffix=true, instant_resolve=true,
+	name = " of firewall", suffix=true, instant_resolve=true,
 	level_range = {15, 50},
 	rarity = 10,
 
 	charm_power_def = {add=25, max=250, floor=true},
-	resolvers.charm("fire a beam of flames (dam %d)", 6, function(self, who)
-		local tg = {type="beam", range=6 + who:getMag(4)}
+	resolvers.charm("creates a wall of flames lasting for 4 turns (dam %d overall)", 6, function(self, who)
+		local tg = {type="wall", range=5, halflength=3, halfmax_spots=3+1}
 		local x, y = who:getTarget(tg)
 		if not x or not y then return nil end
 		local dam = self:getCharmPower()
-		who:project(tg, x, y, engine.DamageType.FIRE, dam, {type="flame"})
+		who:project(tg, x, y, function(px, py)
+			game.level.map:addEffect(who, px, py, 4, engine.DamageType.FIRE, dam / 4, 0, 5, nil, {type="inferno"}, nil, true)
+		end)
 		game:playSoundNear(who, "talents/fire")
 		game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true})
 		return {id=true, used=true}
diff --git a/game/modules/tome/dialogs/LevelupDialog.lua b/game/modules/tome/dialogs/LevelupDialog.lua
index c8fe9e1320442772edbe9aadf267c4074da47b19..8b3d2893dbfae5b6a3854301db6477b21038c4e7 100644
--- a/game/modules/tome/dialogs/LevelupDialog.lua
+++ b/game/modules/tome/dialogs/LevelupDialog.lua
@@ -798,6 +798,7 @@ function _M:learnType(tt, v)
 			self.actor:setTalentTypeMastery(tt, self.actor:getTalentTypeMastery(tt) + 0.2)
 			self.talent_types_learned[tt][2] = true
 		end
+		self:triggerHook{"PlayerLevelup:addTalentType", actor=self.actor, tt=tt}
 		self.actor.unused_talents_types = self.actor.unused_talents_types - 1
 		self.new_talents_changed = true
 	else
@@ -833,6 +834,7 @@ function _M:learnType(tt, v)
 				return
 			end
 		end
+		self:triggerHook{"PlayerLevelup:subTalentType", actor=self.actor, tt=tt}
 	end
 end
 
diff --git a/ideas/todo b/ideas/todo
index 0d3324131ebf7ab377c1566ae71c206ef08ff0bf..fd2a063315958537f45a7695dae782837cc26fbc 100644
--- a/ideas/todo
+++ b/ideas/todo
@@ -2,7 +2,7 @@
 * RSS feed of events in a character's life, exportable to FB
 * PIC TALENTS AT LVL 45 FOR HIGH STAT, CLASS DEPENDANT
 * redo shops
-* redo wands
 * random elites wandering the levels
 * make low level more fun
 * "automatic" storage of various ingredients, replace alch quest
+* auto-leveling for beginners/lazy