diff --git a/game/engines/default/engine/ui/Base.lua b/game/engines/default/engine/ui/Base.lua
index 627074f6b6060ed03e820f8a10740389e3b3e399..ce071c0ebc4b5336315aac60c04930cd48035627 100644
--- a/game/engines/default/engine/ui/Base.lua
+++ b/game/engines/default/engine/ui/Base.lua
@@ -50,10 +50,12 @@ _M.ui_conf = {}
 
 function _M:loadUIDefinitions(file)
 	local f, err = loadfile(file)
-	if not f then print("Error while loading UI definition from", file, ":", err) return end
+	if not f then error("Error while loading UI definition from", file, ":", err) return end
+	self.ui_conf.def = self.ui_conf
 	setfenv(f, self.ui_conf)
 	local ok, err = pcall(f)
-	if not f then print("Error while loading UI definition from", file, ":", err) return end
+	self.ui_conf.def = nil
+	if not f then error("Error while loading UI definition from", file, ":", err) return end
 end
 
 function _M:uiExists(ui)
diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index dca955c76aad1756bf13fc9e88c3320ee6151197..5b02817a610f6140555e9e9782f6cb2bdf5e516c 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -2014,7 +2014,7 @@ end
 
 --- Regenerate life, call it from your actor class act() method
 function _M:regenLife()
-	if self.life_regen and not self:attr("no_life_regen") then
+	if self.life_regen then
 		local regen = self.life_regen * util.bound((self.healing_factor or 1), 0, 2.5)
 
 		-- Solipsism
@@ -2029,11 +2029,13 @@ function _M:regenLife()
 			end
 		end
 
-		self.life = util.bound(self.life + regen, self.die_at, self.max_life)
+		if not self:attr("no_life_regen") then
+			self.life = util.bound(self.life + regen, self.die_at, self.max_life)
 
-		-- Blood Lock
-		if self:attr("blood_lock") then
-			self.life = util.bound(self.life, self.die_at, self:attr("blood_lock"))
+			-- Blood Lock
+			if self:attr("blood_lock") then
+				self.life = util.bound(self.life, self.die_at, self:attr("blood_lock"))
+			end
 		end
 	end
 end
@@ -2052,11 +2054,21 @@ end
 
 --- Called before healing
 function _M:onHeal(value, src)
+	value = value * util.bound((self.healing_factor or 1), 0, 2.5)
+
+	-- Solipsism healing
+	local psi_heal = 0
+	if self:knowTalent(self.T_SOLIPSISM) then
+		local t = self:getTalentFromId(self.T_SOLIPSISM)
+		local ratio = t.getConversionRatio(self, t)
+		psi_heal = value * ratio
+		self:incPsi(psi_heal)
+		value = value - psi_heal
+	end
+
 	if self:hasEffect(self.EFF_UNSTOPPABLE) then return 0 end
 	if self:attr("no_healing") then return 0 end
 
-	value = value * util.bound((self.healing_factor or 1), 0, 2.5)
-
 	--if self:attr("stunned") then value = value / 2 end
 
 	local eff = self:hasEffect(self.EFF_HEALING_NEXUS)
@@ -2083,16 +2095,6 @@ function _M:onHeal(value, src)
 		self:setEffect(self.EFF_REGENERATION, 6, {power=(value * self.fungal_growth / 100) / 6, no_wild_growth=true})
 	end
 
-	-- Solipsism healing
-	local psi_heal = 0
-	if self:knowTalent(self.T_SOLIPSISM) then
-		local t = self:getTalentFromId(self.T_SOLIPSISM)
-		local ratio = t.getConversionRatio(self, t)
-		psi_heal = value * ratio
-		self:incPsi(psi_heal)
-		value = value - psi_heal
-	end
-
 	-- Must be last!
 	if self:attr("blood_lock") then
 		if self.life + value > self:attr("blood_lock") then
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 6cd05ba63d56b3c83377fa6cbed0856185867de9..ddc5af60762fff0d9e8fa0f34d9a788bcb0057c0 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -789,7 +789,7 @@ end
 
 function _M:changeLevel(lev, zone, params)
 	params = params or {}
-	if self:getPlayer(true).last_kill_turn and self:getPlayer(true).last_kill_turn >= self.turn - self:noStairsTime() then
+	if not params.direct_switch and (self:getPlayer(true).last_kill_turn and self:getPlayer(true).last_kill_turn >= self.turn - self:noStairsTime()) then
 		local left = math.ceil((10 + self:getPlayer(true).last_kill_turn - self.turn + self:noStairsTime()) / 10)
 		self.logPlayer(self.player, "#LIGHT_RED#You may not change level so soon after a kill (%d game turns left to wait)!", left)
 		return
diff --git a/game/modules/tome/class/GameState.lua b/game/modules/tome/class/GameState.lua
index 4abd8fe5147e52519cfda2692c5dfb0cc02eb9b1..91de7a3b43fcbadcf16ab832ce7dc7fb45e0d4c7 100644
--- a/game/modules/tome/class/GameState.lua
+++ b/game/modules/tome/class/GameState.lua
@@ -2532,6 +2532,7 @@ function _M:makeChallengeQuest(level, name, desc, data, alter_effect)
 	local q = {
 		id = "id-challenge-"..level.level,
 		name = "Infinite Dungeon Challenge: "..name.." (Level "..level.level..")",
+		use_ui = "quest-idchallenge",
 		challenge_desc = desc,
 		desc = function(self, who)
 			local desc = {}
diff --git a/game/modules/tome/class/interface/Archery.lua b/game/modules/tome/class/interface/Archery.lua
index 3ad78b06ddf0de2ecbaefd41deee099ee2f4398f..04762f517ae5209e58500fd2994f6c62a7550bfc 100644
--- a/game/modules/tome/class/interface/Archery.lua
+++ b/game/modules/tome/class/interface/Archery.lua
@@ -48,7 +48,8 @@ function _M:archery_range(t, type)
 			return 1
 		end
 	end
-	return math.max(weapon and weapon.combat.range or 6, offweapon and offweapon.combat and offweapon.combat.range or 0, pf_weapon and pf_weapon.combat and pf_weapon.combat.range or 0, self:attr("archery_range_override") or 0)
+	local br = (self.archery_bonus_range or 0)
+	return math.max(weapon and br + weapon.combat.range or 6, offweapon and offweapon.combat and br + offweapon.combat.range or 0, pf_weapon and pf_weapon.combat and br + pf_weapon.combat.range or 0, self:attr("archery_range_override") or 0)
 end
 
 --- Look for possible archery targets
@@ -81,7 +82,7 @@ function _M:archeryAcquireTargets(tg, params)
 		game.logPlayer(self, "You do not have enough ammo left!")
 		return nil
 	end
-
+	local br = (self.archery_bonus_range or 0)
 	print("[ARCHERY ACQUIRE TARGETS WITH]", weapon and weapon.name, ammo.name, offweapon and offweapon.name, pf_weapon and pf_weapon.name)
 	tg = tg or {}
 	local max_range, warn_range = self:attr("archery_range_override") or 1, 40
@@ -90,7 +91,7 @@ function _M:archeryAcquireTargets(tg, params)
 	local use_resources
 	if weapon then
 		weaponC = weapon.combat
-		max_range = math.max(max_range, weaponC.range or 6)
+		max_range =  math.max(max_range, weaponC.range or 6)
 		warn_range = math.min(warn_range, weaponC.range or 6)
 		-- check resources
 		use_resources = (weaponC.use_resources or ammo.combat.use_resources) and table.mergeAdd(table.clone(weaponC.use_resources) or {}, ammo.combat.use_resources or {}) or nil
@@ -105,7 +106,7 @@ function _M:archeryAcquireTargets(tg, params)
 	end
 	if offweapon then
 		offweaponC = offweapon.combat
-		max_range = math.max(max_range, offweaponC.range or 6)
+		max_range =  math.max(max_range, offweaponC.range or 6)
 		warn_range = math.min(warn_range, offweaponC.range or 6)
 		use_resources = (offweaponC.use_resources or ammo.combat.use_resources) and table.mergeAdd(table.clone(offweaponC.use_resources) or {}, ammo.combat.use_resources or {}) or nil
 		if use_resources then
@@ -119,7 +120,7 @@ function _M:archeryAcquireTargets(tg, params)
 	end
 	if pf_weapon then
 		pf_weaponC = pf_weapon.combat
-		max_range = math.max(max_range, pf_weaponC.range or 6)
+		max_range =  math.max(max_range, pf_weaponC.range or 6)
 		warn_range = math.min(warn_range, pf_weaponC.range or 6)
 		use_resources = (pf_weaponC.use_resources or ammo.combat.use_resources) and table.mergeAdd(table.clone(pf_weaponC.use_resources) or {}, ammo.combat.use_resources or {}) or nil
 		if use_resources then
@@ -136,9 +137,9 @@ function _M:archeryAcquireTargets(tg, params)
 	-- at least one shot is possible, set up targeting
 	tg.type = tg.type or weaponC and weaponC.tg_type or offweaponC and offweaponC.tg_type or pf_weaponC and pf_weaponC.tg_type or ammo.combat.tg_type or "bolt"
 	if tg.range then
-		tg.warn_range, tg.max_range = math.min(tg.range, warn_range), math.min(tg.range, max_range)
+		tg.warn_range, tg.max_range = br + math.min(tg.range, warn_range), br + math.min(tg.range, max_range)
 	else
-		tg.warn_range, tg.max_range = warn_range, max_range
+		tg.warn_range, tg.max_range = br + warn_range, br + max_range
 	end
 	-- Pass friendly actors
 	if self:attr("archery_pass_friendly") then
@@ -191,7 +192,7 @@ function _M:archeryAcquireTargets(tg, params)
 	local runfire runfire = function(weapon, targets, realweapon)
 		--	Note: if shooters with built-in infinite ammo are reintroduced, handle it here by specifying ammo to use
 		-- calculate the range for the current weapon
-		local weapon_range = math.min(tg.range or 40, math.max(weapon.range or 6, self:attr("archery_range_override") or 1))
+		local weapon_range = math.min(tg.range or 40, math.max(br + weapon.range or 6, self:attr("archery_range_override") or 1))
 		-- don't fire at targets out of range unless in forced target mode
 		if not params.ignore_weapon_range and not core.key.modState("ctrl") and weapon_range < core.fov.distance(x, y, self.x, self.y) then
 			print("[archeryAcquireTargets runfire] NOT FIRING", realweapon.name, x, y, "range limit:", weapon_range)
@@ -377,7 +378,7 @@ local function archery_projectile(tx, ty, tg, self, tmp)
 		end
 		
 		if self and dam > 0 and self.knowTalent and self:isTalentActive(self.T_AIM) and self.__CLASSNAME ~= "mod.class.Grid" then
-			local dist = math.max(0, core.fov.distance(self.x, self.y, target.x, target.y) - 3)
+			local dist = math.min(math.max(0, core.fov.distance(self.x, self.y, target.x, target.y) - 3),8)
 			if dist > 0 then 
 				local dammult = self:callTalent(self.T_AIM, "getDamage") * dist 
 				dam = dam * (1 + (dammult/100))
@@ -695,7 +696,7 @@ function _M:archeryShoot(targets, talent, tg, params)
 			tg.archery.weapon = weapon
 			tg.archery.ammo = targets[i].ammo or ammo.combat
 			-- calculate range, speed, type by shooter/ammo combination
-			tg.range = math.min(tg.range or 40, math.max(weapon.range or 6, self:attr("archery_range_override") or 1))
+			tg.range = math.min(tg.range or 40, math.max((self.archery_bonus_range or 0) + weapon.range or 6, self:attr("archery_range_override") or 1))
 			tg.speed = (tg.speed or 10) + (ammo.travel_speed or 0) + (weapon.travel_speed or 0) + (self.combat and self.combat.travel_speed or 0)
 			tg.type = tg.type or weapon.tg_type or tg.archery.ammo.tg_type or "bolt"
 			tg.display = tg.display or targets[i].display or self:archeryDefaultProjectileVisual(realweapon, ammo)
diff --git a/game/modules/tome/data/chats/escort-quest.lua b/game/modules/tome/data/chats/escort-quest.lua
index eefe42f37aaff38ef0ab9ac61267102183ffb834..503f4f9b9cd707247c22887213c797709955c10b 100644
--- a/game/modules/tome/data/chats/escort-quest.lua
+++ b/game/modules/tome/data/chats/escort-quest.lua
@@ -147,7 +147,7 @@ local reward_types = {
 		},
 		antimagic = {
 			types = {
-				["technique/feedback"] = 0.8,
+				["psionic/feedback"] = 0.8,
 			},
 			talents = {
 				[Talents.T_BIOFEEDBACK] = 1,
diff --git a/game/modules/tome/data/damage_types.lua b/game/modules/tome/data/damage_types.lua
index e0ef013a63757380fb5352a0c0ccf1046688cee6..ec10f29d9ab0e619c547fa40d672fc5fd5b13d07 100644
--- a/game/modules/tome/data/damage_types.lua
+++ b/game/modules/tome/data/damage_types.lua
@@ -1399,7 +1399,7 @@ newDamageType{
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
 			if target:canBe("blind") then
-				target:setEffect(target.EFF_DIM_VISION, 7, {sight=dam, apply_power=src:combatAttack()})
+				target:setEffect(target.EFF_DIM_VISION, 5, {sight=dam, apply_power=src:combatAttack()})
 			else
 				game.logSeen(target, "%s resists!", target.name:capitalize())
 			end
@@ -4038,14 +4038,14 @@ newDamageType{
 }
 
 newDamageType{
-	name = "incendiary smoke", type = "INCENDIARY_SMOKE",
+	name = "sticky pitch", type = "PITCH",
 	projector = function(src, x, y, type, dam, state)
 		state = initState(state)
 		useImplicitCrit(src, state)
 		local target = game.level.map(x, y, Map.ACTOR)
 		if target then
-			if target:canBe("blind") then
-				target:setEffect(target.EFF_INCENDIARY_SMOKE, dam.dur, {sight=dam.dam, resist=dam.fire, apply_power=src:combatAttack()})
+			if target:canBe("slow") then
+				target:setEffect(target.EFF_STICKY_PITCH, dam.dur, {slow=dam.dam/100, resist=dam.fire, apply_power=src:combatAttack()})
 			else
 				game.logSeen(target, "%s resists!", target.name:capitalize())
 			end
@@ -4067,3 +4067,16 @@ newDamageType{
 		end
 	end,
 }
+
+-- Dim vision+confuse
+newDamageType{
+	name = "shadow smoke", type = "SHADOW_SMOKE",
+	projector = function(src, x, y, type, dam, state)
+		state = initState(state)
+		useImplicitCrit(src, state)
+		local target = game.level.map(x, y, Map.ACTOR)
+		if target then
+			target:setEffect(target.EFF_SHADOW_SMOKE, 5, {sight=dam, apply_power=src:combatAttack()})
+		end
+	end,
+}
\ No newline at end of file
diff --git a/game/modules/tome/data/gfx/particles_images/diffuse_point.png b/game/modules/tome/data/gfx/particles_images/diffuse_point.png
new file mode 100644
index 0000000000000000000000000000000000000000..b417a385338260bbc85831109303174aa9338d71
Binary files /dev/null and b/game/modules/tome/data/gfx/particles_images/diffuse_point.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_1.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..275a14bd2426ce28bd463a0f15fff129da6790bf
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_1.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_left.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..86df8cf90a5bbc2e24942a09cc9d7483638454de
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_middle.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a07cd526357cf11c5168632e9e964dff5e64529
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_right.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..b44165977df87f540335114531fcc8ce8e3eeea5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_2_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_3.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..7f7e80e6bef6971199beff7265354d9a602e2207
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_3.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_4.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f30895f17085d713bb70bff21b1d6f6932a3e96
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_4.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_5.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..352b1819230e91b4af39102b1333f9c3e6f2da3c
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_5.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_6.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..41e55c122918e9495952e77b85a292c2eda272d5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_6.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_7.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..439ecfaa91f86cfb87e4850830a34b7e30a33d57
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_7.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_left.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a52da7a04e41c52b1d532263a06e780ba89244d
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_middle.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..b400da5486c86731b967410d03eab546b57c424e
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_right.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ae7842b3c847bb3e6866b0593d9e56ea6dd2c79
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_8_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_9.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_9.png
new file mode 100644
index 0000000000000000000000000000000000000000..ca5c1c69d8919c733befc32c959067d44571676a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_9.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_backglow.png b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_backglow.png
new file mode 100644
index 0000000000000000000000000000000000000000..e10f54248173b3b864c165dcb3d74a7d33d53e59
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/dialogframe_backglow.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox1.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox1.png
new file mode 100644
index 0000000000000000000000000000000000000000..b8f0716583fe3830f591e516431dfa8166a663f5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox1.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox2.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox2.png
new file mode 100644
index 0000000000000000000000000000000000000000..40b67858de0a692e0f657d2374f68f6cd690bb46
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox2.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox3.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox3.png
new file mode 100644
index 0000000000000000000000000000000000000000..000ac508264ecc5d359f2adc6d28dcec08332177
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox3.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox4.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox4.png
new file mode 100644
index 0000000000000000000000000000000000000000..373c0dabfb79c09ce6d27715c20a4a4ad000c1be
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox4.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox5.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox5.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1bc7b8ba499f80cf0d474de44fda7cd1933b82f
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox5.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox6.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox6.png
new file mode 100644
index 0000000000000000000000000000000000000000..4a2c5d012621458ddc8060a9ab6820be5178f53d
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox6.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox7.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox7.png
new file mode 100644
index 0000000000000000000000000000000000000000..3265a7c5997c69733cd898d356cb098e7472d6bd
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox7.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox8.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox8.png
new file mode 100644
index 0000000000000000000000000000000000000000..ddf26cf533d08d9397536ab5a883b204da9b02a5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox8.png differ
diff --git a/game/modules/tome/data/gfx/quest-escort-ui/textbox9.png b/game/modules/tome/data/gfx/quest-escort-ui/textbox9.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a015c58b91cc456755c4c93a599cda2b89eda31
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-escort-ui/textbox9.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_1.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..a19dddda89a6a5c895af8ea639a011cfa79551a7
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_1.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_left.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..7a5a20987ef7464cbf8ebdc769227bc6404eb94c
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_middle.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff80f0a66b943b755b5f595ef19205a2841a5b82
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_right.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..6b2a1c4fa3b53a35cf2a78fcf92e80db5b06492a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_2_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_3.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd5028d73e54577779d4178e70bedffba93b177f
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_3.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_4.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..8cb63beda2d5763cea5b810447896d1b1f0dd9b2
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_4.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_5.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb27087a9d1866c0875f114b173fabb3af19bfb3
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_5.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_6.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..14c3bd7fdf618b6d44898d6d1bf11b8fca046669
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_6.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_7.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..4bf0603ff7fc93dc92c7e6fefd9b65a9484b71d6
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_7.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_left.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..34eec077bbadf2ffcd30a97b655deacfc649fd4b
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_middle.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9bcf7f54d225ed506c732e1b8637dd07fda2214
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_right.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..c03a5d6588317b68e3f88e0fa7f0d3032b27e508
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_8_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_9.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_9.png
new file mode 100644
index 0000000000000000000000000000000000000000..68b49ac2b8f874e519a14025a4b61365ec129f6e
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_9.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_backglow.png b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_backglow.png
new file mode 100644
index 0000000000000000000000000000000000000000..edf94601c90fa60cca8d8ff193643137e2340c22
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/dialogframe_backglow.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox1.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox1.png
new file mode 100644
index 0000000000000000000000000000000000000000..3855a022445da0945e95997b12a423e556c3567a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox1.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox2.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox2.png
new file mode 100644
index 0000000000000000000000000000000000000000..413f95396a41cdfd41e66c32043befd5b1f41667
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox2.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox3.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox3.png
new file mode 100644
index 0000000000000000000000000000000000000000..eee2f6f38b845eeaa36b06d0393f7b7292acbf34
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox3.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox4.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox4.png
new file mode 100644
index 0000000000000000000000000000000000000000..83f51af774d53fecb9a9e041867d4fec7e7631de
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox4.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox5.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox5.png
new file mode 100644
index 0000000000000000000000000000000000000000..7f6e35cfa09c563e171915d5a3283054113b50d5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox5.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox6.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox6.png
new file mode 100644
index 0000000000000000000000000000000000000000..016f98ddb90a8faaf59e86214f2e7add53cdeb8a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox6.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox7.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox7.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8e22b85a8e2e304ea66e629466c1763c9004a9c
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox7.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox8.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox8.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1f952c1a36534e7b64112c89849b436e21d7807
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox8.png differ
diff --git a/game/modules/tome/data/gfx/quest-fail-ui/textbox9.png b/game/modules/tome/data/gfx/quest-fail-ui/textbox9.png
new file mode 100644
index 0000000000000000000000000000000000000000..06749a4f0f4ef8646dcbe87f6c3be5452901e11f
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-fail-ui/textbox9.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_1.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..2086d67acf3ffd209ab0f802b454086c72918572
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_1.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_left.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc4c5220fde00071bd70f5e774f640532af38c51
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_middle.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..d2c642d06cb203e0d6cb4dd66774ee6b6d645873
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_right.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..6f250636bc029b36b6228c2560f6337ec8230cc5
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_2_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_3.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..46dea6f758038dbdbb577a7dd846fee90c2d9c88
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_3.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_4.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..4e4c24759279a93a2a3744edf2c3b5931d1a1347
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_4.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_5.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9d4974a3817ceb404e941df9a03f412f7a189fe
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_5.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_6.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd7f238d45a442103956a8fa0aff181dbe29994a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_6.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_7.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..dd42a76ca99049de847894638995825a6366181c
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_7.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_left.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc1bdbb78052f32608c030568276d9fafe38278d
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_left.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_middle.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e79f8f87f9fad09ca9fa412515f92faa06ec99f
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_middle.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_right.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..c1ea2db9e872ac9bedb9353be850644a380f9ef1
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_8_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_9.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_9.png
new file mode 100644
index 0000000000000000000000000000000000000000..739ea46cef40b93fb3dc838762c33f7e4ac506d8
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_9.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_backglow.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_backglow.png
new file mode 100644
index 0000000000000000000000000000000000000000..0980fd7801742c337e942497e7a07e8c966b153d
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/dialogframe_backglow.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox1.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox1.png
new file mode 100644
index 0000000000000000000000000000000000000000..b7ba9fd43168ae57cfd2eb54b1bbf37b24913c7b
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox1.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox2.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox2.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b95d6556eeea7e81d9ece8f68e403b9de1d98b1
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox2.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox3.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox3.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d3633487d09f04fcd6b78514bf71a0b7fb6bb9a
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox3.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox4.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox4.png
new file mode 100644
index 0000000000000000000000000000000000000000..a203a282ad7f858160d47532988afb43601bc239
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox4.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox5.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox5.png
new file mode 100644
index 0000000000000000000000000000000000000000..a7b4b27ec9b9398c2fe97fdc9c0fb86833d35099
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox5.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox6.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox6.png
new file mode 100644
index 0000000000000000000000000000000000000000..80ecaa185bca9dd34476e00308eeb7dca6611be9
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox6.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox7.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox7.png
new file mode 100644
index 0000000000000000000000000000000000000000..92f4b399792716837aec1ba05be4dbbe1864c2dc
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox7.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox8.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox8.png
new file mode 100644
index 0000000000000000000000000000000000000000..43f346f9d5a55c6561c7db518ebfcf655db35608
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox8.png differ
diff --git a/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox9.png b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox9.png
new file mode 100644
index 0000000000000000000000000000000000000000..96bb9778cee6f851d1b2ecd887e53575462b26a9
Binary files /dev/null and b/game/modules/tome/data/gfx/quest-idchallenge-ui/textbox9.png differ
diff --git a/game/modules/tome/data/gfx/quest-ui/dialogframe_8_right.png b/game/modules/tome/data/gfx/quest-ui/dialogframe_8_right.png
index a7d0a62f780a3dec065b5fc91b9fa97c88055b40..658b2f8a3194e0a5959aeee7b1dfb97693c8d727 100644
Binary files a/game/modules/tome/data/gfx/quest-ui/dialogframe_8_right.png and b/game/modules/tome/data/gfx/quest-ui/dialogframe_8_right.png differ
diff --git a/game/modules/tome/data/gfx/quest-ui/dialogframe_9.png b/game/modules/tome/data/gfx/quest-ui/dialogframe_9.png
index 6a4d3ab7e3c45fa2eb277405f5921c714534a4f0..b40eae326f415d432f1a69f2858054a125e52ba5 100644
Binary files a/game/modules/tome/data/gfx/quest-ui/dialogframe_9.png and b/game/modules/tome/data/gfx/quest-ui/dialogframe_9.png differ
diff --git a/game/modules/tome/data/gfx/quest-ui/dialogframe_backglow.png b/game/modules/tome/data/gfx/quest-ui/dialogframe_backglow.png
index c4518e9c129acbd9eb184e51e72409f962dea04b..5b0288e353180562631cbcb847ad2a455d2ae775 100644
Binary files a/game/modules/tome/data/gfx/quest-ui/dialogframe_backglow.png and b/game/modules/tome/data/gfx/quest-ui/dialogframe_backglow.png differ
diff --git a/game/modules/tome/data/gfx/ui/definitions/quest.lua b/game/modules/tome/data/gfx/ui/definitions/quest.lua
index b604ccf3cfe33874a17646bf7a70a053ced16a7d..ab0f47ca764acc2eb0012b9e69553ab5f056e852 100644
--- a/game/modules/tome/data/gfx/ui/definitions/quest.lua
+++ b/game/modules/tome/data/gfx/ui/definitions/quest.lua
@@ -18,7 +18,6 @@
 -- darkgod@te4.org
 
 quest = {
-	-- frame_shadow = {x=15, y=15, a=0.3},
 	frame_alpha = 1,
 	frame_darkness = 0.6,
 	frame_ox1 = -60,
@@ -26,4 +25,34 @@ quest = {
 	frame_oy1 = -154,
 	frame_oy2 =  60,
 	dialog_h_middles = true,
-}
\ No newline at end of file
+}
+
+def['quest-fail'] = {
+	frame_alpha = 1,
+	frame_darkness = 0.6,
+	frame_ox1 = -60,
+	frame_ox2 =  60,
+	frame_oy1 = -154,
+	frame_oy2 =  60,
+	dialog_h_middles = true,
+}
+
+def['quest-idchallenge'] = {
+	frame_alpha = 1,
+	frame_darkness = 0.6,
+	frame_ox1 = -60,
+	frame_ox2 =  60,
+	frame_oy1 = -154,
+	frame_oy2 =  60,
+	dialog_h_middles = true,
+}
+
+def['quest-escort'] = {
+	frame_alpha = 1,
+	frame_darkness = 0.6,
+	frame_ox1 = -60,
+	frame_ox2 =  60,
+	frame_oy1 = -154,
+	frame_oy2 =  60,
+	dialog_h_middles = true,
+}
diff --git a/game/modules/tome/data/quests/escort-duty.lua b/game/modules/tome/data/quests/escort-duty.lua
index b57a15f9afe46bcee7ccd806646a8f179516fef2..fa94b4887e587997b2d01f2c40bf2213a773129f 100644
--- a/game/modules/tome/data/quests/escort-duty.lua
+++ b/game/modules/tome/data/quests/escort-duty.lua
@@ -22,6 +22,8 @@ local Stats = require("engine.interface.ActorStats")
 local NameGenerator = require("engine.NameGenerator")
 local Astar = require("engine.Astar")
 
+use_ui = "quest-escort"
+
 --------------------------------------------------------------------------------
 -- Quest data
 --------------------------------------------------------------------------------
diff --git a/game/modules/tome/data/talents/techniques/agility.lua b/game/modules/tome/data/talents/techniques/agility.lua
index 83d6ab5f221287f2abf4fc42aebe67db88cf30d8..a6832aa7d2c5f71bc1513a542996e688667c2353 100644
--- a/game/modules/tome/data/talents/techniques/agility.lua
+++ b/game/modules/tome/data/talents/techniques/agility.lua
@@ -80,7 +80,7 @@ newTalent{
 	points = 5,
 	no_unlearn_last = true,
 	mode = "passive",
-	getChance = function(self, t) return math.floor(self:combatTalentScale(t, 15, 40)) end,
+	getChance = function(self, t) return math.floor(self:combatTalentScale(t, 15, 45)) end,
 	on_learn = function(self, t)
 		self:attr("show_shield_combat", 1)
 	end,
@@ -90,6 +90,15 @@ newTalent{
 	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, tmp)
 		local chance = t.getChance(self, t)
 		if not rng.percent(chance) then return end
+		--this might be worth doing later, but for now let it block DoTs
+		--local psrc = src.__project_source
+		--if psrc then
+		--	local kind = util.getval(psrc.getEntityKind)
+		--	if kind == "projectile" or kind == "trap" or kind == "object" then
+		--	else
+		--		return
+		--	end
+		--end
 		local lastdam = dam
 		local shield = self:hasShield()
 		if not shield then return end
@@ -105,7 +114,7 @@ newTalent{
 	info = function(self, t)
 		local chance = t.getChance(self, t)
 		return ([[You are trained in an agile, mobile fighting technique combining sling and shield. This allows shields to be equipped, using Dexterity instead of Strength as a requirement.
-While you have a shield equip and block is not on cooldown, you have a %d%% chance to deflect any incoming damage, reducing it by 50%% of your shield’s block value.]])
+While you have a shield equip and your Block talent is not on cooldown, you have a %d%% chance to deflect any incoming damage, reducing it by 50%% of your shield’s block value.]])
 			:format(chance)
 	end,
 }
@@ -130,9 +139,8 @@ newTalent{
 	getDist = function(self, t) return math.floor(self:combatTalentScale(t, 3, 5)) end,
 	action = function(self, t)
 		local shield, shield_combat = self:hasShield()
-		local sling = self:hasArcheryWeapon()
-		if not shield or not sling then
-			game.logPlayer(self, "You require a ranged weapon and a shield to use this talent.")
+		if not shield then
+			game.logPlayer(self, "You require a shield to use this talent.")
 			return nil
 		end
 
@@ -210,7 +218,7 @@ newTalent{
 	tactical = { ATTACK = { weapon = 1 } },
 	requires_target = true,
 	on_pre_use = function(self, t, silent)
-		if not archerPreUse(self, t, silent) then return false end
+		if not archerPreUse(self, t, silent, "sling") then return false end
 		if self:attr("never_move") then return false end
 		return true
 	end,
@@ -220,7 +228,7 @@ newTalent{
 			self.talents_cd[t.id] = math.max(cooldown - 1, 0)
 		end
 	end,
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 2.4) end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.4, 2.6) end, --high damage, high opportunity cost
 	getDist = function(self, t) if self:getTalentLevel(t) >= 3 then return 2 else return 1 end end,
 	archery_onhit = function(self, t, target, x, y)
 		if not target or not target:canBe("knockback") then return end
@@ -264,7 +272,8 @@ newTalent{
 	info = function(self, t)
 		return ([[You rush toward your foe, readying your shot. If you reach the enemy, you release the shot, imbuing it with great power.
 		The shot does %d%% weapon damage and knocks back your target by %d.
-		The cooldown of this talent is reduced by 1 each time you move.]]):
+		The cooldown of this talent is reduced by 1 each time you move.
+		This requires a sling to use.]]):
 		format(t.getDamage(self,t)*100, t.getDist(self, t))
 	end,
 }
@@ -281,16 +290,19 @@ newTalent{
 	tactical = { BUFF = 2 },
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent) end,
 	getAttackSpeed = function(self, t) return math.floor(self:combatTalentScale(t, 5, 20))/100 end,
-	getMovementSpeed = function(self, t) return math.floor(self:combatTalentScale(t, 30, 70))/100 end,
-	getTurn = function(self, t) return math.floor(self:combatTalentScale(t, 5, 15)) end,
+	getMovementSpeed = function(self, t) return math.floor(self:combatTalentScale(t, 25, 60))/100 end,
+	getTurn = function(self, t) return math.floor(self:combatTalentLimit(t, 35, 10, 22)) end,
+	on_pre_use = function(self, t, silent)
+		if not archerPreUse(self, t, silent, "sling") then return false end
+		return true
+	end,
 	callbackOnArcheryAttack = function(self, t, target, hitted)
 		local dist = math.max(0, core.fov.distance(self.x, self.y, target.x, target.y) - 3)
 		if hitted and not target.turn_procs.rapid_fire and dist < 5 then
 			target.turn_procs.rapid_fire = true
-			turn = t.getTurn(self,t)
+			turn = t.getTurn(self,t)/100
 			energy = turn - (turn * dist * 0.2)
-			local energy = (game.energy_to_act * energy)/100
-			self.energy.value = self.energy.value + energy
+			self.energy.value = self.energy.value + game.energy_to_act*energy
 		end
 		game:onTickEnd(function() 
 			self:setEffect(self.EFF_RAPID_MOVEMENT, 1, {src=self, power=t.getMovementSpeed(self,t)})
diff --git a/game/modules/tome/data/talents/techniques/archery.lua b/game/modules/tome/data/talents/techniques/archery.lua
index e0f4e22cf61d5e99d1335cafb214b8d8f641b113..44bd9dc400de8dde71d6b43bf282ac60be8cd859 100644
--- a/game/modules/tome/data/talents/techniques/archery.lua
+++ b/game/modules/tome/data/talents/techniques/archery.lua
@@ -99,7 +99,7 @@ newTalent{
 				local eff = target:hasEffect(target.EFF_PIN_DOWN)
 				chance = chance + eff.mark
 			end
-			if self.turn_procs.first_blood_ss then chance = chance * 2 end
+			if self.turn_procs.first_blood_shoot then chance = chance + 50 end
 			if rng.percent(chance) then target:setEffect(target.EFF_MARKED, 5, {src=self}) end
 		end
 		if self.turn_procs.first_blood_shoot then
@@ -109,6 +109,7 @@ newTalent{
 				target:setEffect(target.EFF_CUT, 5, {power=life_diff * scale / 5, src=self, apply_power=self:combatPhysicalpower(), no_ct_effect=true})
 			end
 		end
+		if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
 	end,
 	action = function(self, t)
 		local swap = not self:attr("disarmed") and (self:attr("warden_swap") and doWardenWeaponSwap(self, t, "bow"))
@@ -178,17 +179,17 @@ newTalent{
 	tactical = { ATTACK = { weapon = 2 } },
 	getDamage = function(self, t)
 		local dam = self:combatTalentWeaponDamage(t, 1.0, 1.8)
-		if self:hasEffect(self.EFF_TAKING_AIM) then	
-			local eff = self:hasEffect(self.EFF_TAKING_AIM)
-			dam = dam + (dam * eff.power/100)
+		if self:hasEffect(self.EFF_CONCEALMENT) then	
+			local eff = self:hasEffect(self.EFF_CONCEALMENT)
+			if eff.dam > 0 then dam = dam + (dam * eff.dam/100) end
 		end
 		return dam
 	end,
 	getChance = function(self,t) 
 		local chance = 20 + math.floor(self:combatTalentScale(t, 2, 10))
-		if self:hasEffect(self.EFF_TAKING_AIM) then	
-			local eff = self:hasEffect(self.EFF_TAKING_AIM)
-			chance = chance + (eff.charges * 30)
+		if self:hasEffect(self.EFF_CONCEALMENT) then	
+			local eff = self:hasEffect(self.EFF_CONCEALMENT)
+			if eff.dam > 0 then chance = chance + 100 end
 		end
 		if self:hasEffect(self.EFF_TRUESHOT) then chance = chance * 2 end
 		return math.min(100, chance)
@@ -212,7 +213,7 @@ newTalent{
 			local eff = target:hasEffect(target.EFF_PIN_DOWN)
 			chance = chance + eff.mark
 		end
-		if self.turn_procs.first_blood_ss then chance = chance * 2 end
+		if self.turn_procs.first_blood_ss then chance = chance + 50 end
 		if rng.percent(chance) then target:setEffect(target.EFF_MARKED, 5, {src=self}) end
 		
 		if self.turn_procs.first_blood_ss then
@@ -222,8 +223,9 @@ newTalent{
 				target:setEffect(target.EFF_CUT, 5, {power=life_diff * scale / 5, src=self, apply_power=self:combatPhysicalpower(), no_ct_effect=true})
 			end
 		end
-		
-		self:removeEffect(self.EFF_TAKING_AIM)
+		if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
+		local eff = self:hasEffect(self.EFF_CONCEALMENT) 
+		if eff then eff.dam = 0 end
 	end,
 	action = function(self, t)
 		local targets = self:archeryAcquireTargets(nil, {one_shot=true})
@@ -258,7 +260,7 @@ newTalent{
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.5, 1.1) end,
 	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 2.5, 5)) end,
 	getMarkChance = function(self, t) return math.floor(self:combatTalentScale(t, 5, 20)) end,
-	getCritPower = function(self, t) return math.floor(self:combatTalentScale(t, 10, 25)) end,
+	getCritPower = function(self, t) return math.floor(self:combatTalentScale(t, 8, 20)) end,
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent) end,
 	getChance = function(self,t) 
 		local chance = 20 + math.floor(self:combatTalentScale(t, 2, 10)) 
@@ -455,20 +457,27 @@ newTalent{
 	no_energy = "fake",
 	points = 5,
 	random_ego = "attack",
-	cooldown = 0,
-	require = techs_dex_req1,
+	cooldown = function(self, t) -- this makes it a bit less likely that a mob could lob chain headshots at you
+		if self.ai and self.ai == "party_member" then 
+			return 0
+		elseif self.ai then
+			return 3
+		else
+			return 3
+		end
+	end,	require = techs_dex_req1,
 	range = archery_range,
 	requires_target = true,
 	tactical = { ATTACK = { weapon = 2 } },
 	getDamage = function(self, t)
-		local dam = self:combatTalentWeaponDamage(t, 1.1, 2.3)
+		local dam = self:combatTalentWeaponDamage(t, 1.1, 2.4)
 --		if self:hasEffect(self.EFF_TAKING_AIM) then	
 --			local eff = self:hasEffect(self.EFF_TAKING_AIM)
 --			dam = dam + (dam * eff.power/100)
 --		end
 		return dam
 	end,
-	getApr = function(self, t) return self:getDex(100,true) end,
+	getApr = function(self, t) return self:getDex(40,true) end,
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent) end,
 	archery_onhit = function(self, t, target, x, y)
 		target:removeEffect(target.EFF_MARKED)
@@ -497,7 +506,8 @@ newTalent{
 		local dam = t.getDamage(self,t)*100
 		local apr = t.getApr(self,t)
 		return ([[Fire a precise shot dealing %d%% weapon damage, with %d increased armor penetration and 100 increased accuracy. This shot will bypass other enemies between you and your target.
-Only usable against marked targets, and consumes the mark on hit.]]):
+Only usable against marked targets, and consumes the mark on hit.
+The armor penetration increases with your Dexterity.]]):
 		format(dam, apr)
 	end,
 }
@@ -581,7 +591,7 @@ newTalent{
 		
 		target:removeEffect(target.EFF_MARKED)
 		if self:knowTalent(self.T_BULLSEYE) then self:callTalent(self.T_BULLSEYE, "proc") end
-		if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
+--		if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
 		
 		game.target.forced = old_target_forced
 		return true
@@ -621,7 +631,7 @@ newTalent{
 		if target:hasEffect(target.EFF_MARKED) then 
 			target:removeEffect(target.EFF_MARKED) 
 			if self:knowTalent(self.T_BULLSEYE) then self:callTalent(self.T_BULLSEYE, "proc") end
-			if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
+--			if self:knowTalent(self.T_FIRST_BLOOD) then self:incStamina(self:callTalent(self.T_FIRST_BLOOD, "getStamina")) end
 		end
 		if not target.turn_procs.called_shot_silence then
 			target.turn_procs.called_shot_silence = true
@@ -681,9 +691,8 @@ newTalent{
 	points = 5,
 	mode = "passive",
 	require = techs_dex_req4,
-	cooldown = 3,
-	getSpeed = function(self, t) return math.floor(self:combatTalentScale(t, 15, 40))/100 end,
-	getTalentCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3)) end,
+	getSpeed = function(self, t) return math.floor(self:combatTalentScale(t, 10, 35))/100 end,
+	getTalentCount = function(self, t) return math.floor(self:combatTalentLimit(t, 4, 1, 2.5)) end,
 	getCooldown = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3)) end,
 	proc = function(self, t)
 		if not self:isTalentCoolingDown(t) then 
@@ -717,8 +726,7 @@ newTalent{
 		local speed = t.getSpeed(self,t)*100
 		local nb = t.getTalentCount(self,t)
 		local cd = t.getCooldown(self,t)
-		return ([[Each time you trigger a mark, you gain %d%% increased attack speed for 3 turns and the cooldown of %d random techniques are reduced by %d turns.
-This talent has a cooldown.]]):
+		return ([[Each time you consume a mark, you gain %d%% increased attack speed for 2 turns and the cooldown of %d random techniques are reduced by %d turns.]]):
 		format(speed, nb, cd)
 	end,
 }
diff --git a/game/modules/tome/data/talents/techniques/duelist.lua b/game/modules/tome/data/talents/techniques/duelist.lua
index 6c2bee97ccf6a46b2bf264a8b7effc13f39ab331..fac95ceee966e9fdc519c431c3f42b68e4129559 100644
--- a/game/modules/tome/data/talents/techniques/duelist.lua
+++ b/game/modules/tome/data/talents/techniques/duelist.lua
@@ -109,7 +109,7 @@ newTalent{
 		local speed = t.getSpeed(self,t)
 		return ([[The flow of battle invigorates you, allowing you to press your advantage as the fight progresses.
 		Up to once each per turn, while dual wielding, you may:
-		Reposte -- If a melee or archery attack misses you or you parry it, you instantly restore %0.1f stamina and gain %d%% of a turn.
+		Riposte -- If a melee or archery attack misses you or you parry it, you instantly restore %0.1f stamina and gain %d%% of a turn.
 		Recover -- On performing a critical strike with your offhand weapon, you instantly restore %0.1f stamina.]]):format(sta, speed, sta)
 	end,
 }
diff --git a/game/modules/tome/data/talents/techniques/marksmanship.lua b/game/modules/tome/data/talents/techniques/marksmanship.lua
index 8e0f1069a9f5ba03f1e4c9d82f7f6648855d1ccd..db5bb66bfbabda2672494cd3b6b3ed5c9a07051b 100644
--- a/game/modules/tome/data/talents/techniques/marksmanship.lua
+++ b/game/modules/tome/data/talents/techniques/marksmanship.lua
@@ -102,12 +102,12 @@ newTalent{
 	mode = "passive",
 	require = techs_dex_req2,
 	getBleed = function(self, t) return self:combatTalentScale(t, 0.3, 1.0) end,
-	getStamina = function(self, t) return math.floor(self:combatTalentScale(t, 5, 15)) end,
+	getStamina = function(self, t) return self:combatTalentScale(t, 1.5, 4) end,
 	info = function(self, t)
 		local bleed = t.getBleed(self,t)*100
 		local sta = t.getStamina(self,t)
-		return ([[You take advantage of unwary foes, doubling the chance for Steady Shot and Shoot to mark targets and bleeding them for %d%% additional damage over 5 turns if the target is at or above 90%% life.
-In addition, each time you trigger a mark or marked target dies you gain %d stamina.]])
+		return ([[You take advantage of unwary foes, giving Steady Shot and Shoot an additional 50%% chance to mark targets and bleeding them for %d%% additional damage over 5 turns if the target is at or above 90%% life.
+In addition, your Steady Shot, Shoot and Headshot now restore %0.1f stamina on hit.]])
 		:format(bleed, sta)
 	end,
 }
@@ -170,7 +170,7 @@ newTalent{
 	require = techs_dex_req4,
 	random_ego = "attack",
 	tactical = { BUFF = 3 },
-	getSpeed = function(self, t) return self:combatTalentScale(t, 15, 50)/100 end,
+	getSpeed = function(self, t) return self:combatTalentLimit(t, 60, 15, 45)/100 end,
 	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 4, 7)) end,
 	action = function(self, t)
 		local dur = t.getDuration(self,t)
diff --git a/game/modules/tome/data/talents/techniques/mobility.lua b/game/modules/tome/data/talents/techniques/mobility.lua
index 6cc68652fe21f56a4a8ec8939e7fb8da3b9fb1af..1a05668443ccdd93b38c57fe1ec1cebfa8419130 100644
--- a/game/modules/tome/data/talents/techniques/mobility.lua
+++ b/game/modules/tome/data/talents/techniques/mobility.lua
@@ -188,7 +188,7 @@ newTalent{
 	base_stamina = 25,
 	stamina = mobility_stamina,
 	no_energy = true,
-	getDur = function(self, t) return 5 end,
+	getDur = function(self, t) return 4 end,
 	getChanceDef = function(self, t)
 		if self.perfect_evasion then return 100, 0 end
 		return self:combatLimit(5*self:getTalentLevel(t) + self:getDex(50,true), 50, 10, 10, 37.5, 75),
@@ -266,10 +266,10 @@ newTalent {
 	sustain_stamina = 10,
 	no_energy = true,
 	tactical = { DEFEND = 2 },
-	pinImmune = function(self, t) return self:combatTalentLimit(t, 1, .17, .5) end, -- limit < 100%
-	passives = function(self, t, p)
-		self:talentTemporaryValue(p, "pin_immune", t.pinImmune(self, t))
-	end,
+--	pinImmune = function(self, t) return self:combatTalentLimit(t, 1, .17, .5) end, -- limit < 100%
+--	passives = function(self, t, p)
+--		self:talentTemporaryValue(p, "pin_immune", t.pinImmune(self, t))
+--	end,
 	on_pre_use = function(self, t, silent, fake)
 		if self:hasHeavyArmor() then
 			if not silent then game.logPlayer(self, "%s is not usable while wearing heavy armour.", t.name) end
@@ -278,11 +278,11 @@ newTalent {
 		return true
 	end,
 	getReduction = function(self, t, fake) -- % reduction based on both TL and Defense
-		return math.max(0.1, self:combatTalentLimit(t, 0.8, 0.25, 0.65))*self:combatLimit(self:combatDefense(fake), 1.0, 0.25, 0, 0.78, 50) -- vs TL/def: 1/10 == ~12%, 1.3/10 == ~17%, 1.3/50 == ~27%, 6.5/50 == ~53%, 6.5/100 = ~59%
+		return self:combatTalentLimit(t, 1, 0.15, 0.50) * self:combatLimit(self:combatDefense(), 1, 0.15, 10, 0.5, 50) -- Limit < 100%, 25% for TL 5.0 and 50 defense
 	end,
-	getStamina = function(self, t) return 20*(1 + self:combatFatigue()/100)*math.max(0.1, self:combatTalentLimit(t, 0.8, 0.25, 0.65)) end, -- Stamina increases in proportion to talent-based effectiveness.  Stamina Efficiency increased with level through higher Defense (Automatic from the increased Dexterity required for higher talent levels)
+	getStamina = function(self, t) return 8 end, -- as per Shibari's comment, this can get pretty annoying if cost was any higher
 	getLifeTrigger = function(self, t)
-		return self:combatTalentLimit(t, 10, 35, 20)
+		return self:combatTalentLimit(t, 10, 30, 15) -- Limit trigger > 10% life
 	end,
 	callbackOnTakeDamage = function(self, t, src, x, y, type, dam, state)
 		if dam > 0 and state and not (self:attr("encased_in_ice") or self:attr("invulnerable")) then
@@ -304,8 +304,7 @@ newTalent {
 			end
 			stam, stam_cost = self:getStamina(), stam_cost or t.getStamina(self, t)
 			local lt = t.getLifeTrigger(self, t)/100
-			local min_dam = self.max_life*0.05
-			if stam_cost == 0 or dam > min_dam and dam > self.life*lt then
+			if stam_cost == 0 or dam > self.max_life*lt then
 				--print(("[PROJECTOR: Trained Reactions] PASSED life/stam test for %s: %s %s damage (%s) (%0.1f/%0.1f stam) from %s (state:%s)"):format(self.name, dam, type, is_attk, stam_cost, stam, src.name, state)) -- debugging
 				self.turn_procs[t.id] = state
 				self:incStamina(-stam_cost) -- Note: force_talent_ignore_ressources has no effect on this
@@ -327,16 +326,16 @@ newTalent {
 		return true
 	end,
 	info = function(self, t)
+--		local pin = t.pinImmune(self,t)
 		local stam = t.getStamina(self, t)
 		local trigger = t.getLifeTrigger(self, t)
 		local reduce = t.getReduction(self, t, true)*100
 		return ([[You have trained to be very light on your feet and have conditioned your reflexes to react faster than thought to damage you take.
-		You permanently gain %d%% pinning immunity.
-		While this talent is active, you instantly react to any direct damage (not from status effects, etc.) that would hit you for at least %d%% of your current life or %d%% of your maximum life (whichever is greater).
+		While this talent is active, you instantly react to any direct damage (not from status effects, etc.) that would hit you for at least %d%% of your maximum life.
 		This requires %0.1f stamina and reduces the damage by %d%%.
 		Your reactions are too slow for this if you are wearing heavy armour.
 		The damage reduction improves with your Defense.]])
-		:format(t.pinImmune(self, t)*100, trigger, 5, stam, reduce)
+		:format(trigger, stam, reduce)
 	end,
 }
 
diff --git a/game/modules/tome/data/talents/techniques/munitions.lua b/game/modules/tome/data/talents/techniques/munitions.lua
index ae1410bf2b7058a642400a07ad199ffc77bb470f..0c8b4a7d01d4d568beab17f2b89b17663b6d7e80 100644
--- a/game/modules/tome/data/talents/techniques/munitions.lua
+++ b/game/modules/tome/data/talents/techniques/munitions.lua
@@ -83,9 +83,9 @@ newTalent{
 	getIncendiaryDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.1, 0.4) end,
 	getIncendiaryRadius = function(self, t) if self:getTalentLevel(t)>=3 then return 2 else return 1 end end,
 	getPoisonDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 20, 180) end,
-	getNumb = function(self, t) return 5 + self:combatTalentLimit(t, 30, 5, 15) end,
-	getArmorSaveReduction = function(self, t) return 5 + self:combatTalentPhysicalDamage(t, 5, 30) end,
-	getResistPenalty = function(self, t) return self:combatTalentLimit(t, 100, 15, 35, true) end,
+	getNumb = function(self, t) return 5 + self:combatTalentLimit(t, 25, 5, 15) end,
+	getArmorSaveReduction = function(self, t) return self:combatTalentLimit(t, 30, 5, 25, 0.75) end,
+	getResistPenalty = function(self, t) return self:combatTalentLimit(t, 35, 10, 25, true) end,
 	on_learn = function(self, t)
 		local lev = self:getTalentLevelRaw(t)
 		if lev == 1 then
@@ -336,15 +336,15 @@ newTalent{
 	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1.3, 2.7)) end,
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.5, 1.5) end,
 	getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3.3, 5.5)) end,
-	getSightLoss = function(self, t) return math.floor(self:combatTalentScale(t,1, 6, "log", 0, 4)) end, -- 1@1 6@5
+	getSlow = function(self, t) return math.floor(self:combatTalentLimit(t, 40, 10, 25)) end,	
 	getFireResist = function(self, t) return math.floor(self:combatTalentScale(t, 10, 40)) end,	
 	getPoisonDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 15, 100) end,
-	getPoisonFailure = function(self, t) return math.floor(self:combatTalentScale(t, 10, 30)) end,
-	getRemoveCount = function(self, t) return math.floor(self:combatTalentScale(t, 2, 4)) end,
+	getPoisonFailure = function(self, t) return math.floor(self:combatTalentScale(t, 10, 20)) end,
+	getRemoveCount = function(self, t) return self:combatTalentLimit(t, 4, 1, 2.5) end,
 	archery_onreach = function(self, t, x, y)
 		local tg = self:getTalentTarget(t)
 		if self:isTalentActive(self.T_INCENDIARY_AMMUNITION) then
-			self:project(tg, x, y, DamageType.INCENDIARY_SMOKE, {dam=t.getSightLoss(self,t), dur=t.getDuration(self,t), fire=t.getFireResist(self,t)})
+			self:project(tg, x, y, DamageType.PITCH, {dam=t.getSlow(self,t), dur=t.getDuration(self,t), fire=t.getFireResist(self,t)})
 		end
 		if self:isTalentActive(self.T_VENOMOUS_AMMUNITION) then
 				game.level.map:addEffect(self,
@@ -408,7 +408,7 @@ newTalent{
 		if not targets then return end
 		local dam = t.getDamage(self,t)
 		if self:isTalentActive(self.T_PIERCING_AMMUNITION) then
-			self:archeryShoot(targets, t, tg, {mult=dam*1.5, damtype=DamageType.PHYSICAL})
+			self:archeryShoot(targets, t, tg, {mult=dam, damtype=DamageType.PHYSICAL})
 		elseif self:isTalentActive(self.T_VENOMOUS_AMMUNITION) then
 			self:archeryShoot(targets, t, nil, {mult=dam, damtype=DamageType.NATURE})
 		elseif self:isTalentActive(self.T_INCENDIARY_AMMUNITION) then
@@ -420,17 +420,17 @@ newTalent{
 		local dam = t.getDamage(self,t)*100
 		local radius = self:getTalentRadius(t)
 		local dur = t.getDuration(self,t)
-		local sight = t.getSightLoss(self,t)
+		local slow = t.getSlow(self,t)
 		local fire = t.getFireResist(self,t)
 		local poison = t.getPoisonDamage(self,t)
 		local fail = t.getPoisonFailure(self,t)
 		local nb = t.getRemoveCount(self,t)
 		return ([[Fires a special shot based on your currently loaded ammo:
-Incendiary - Fire a shot that deals %d%% weapon damage as fire and covers targets in radius %d in incendiary smoke for %d turns, reducing their sight range by %d and increasing fire damage taken by %d%%.
+Incendiary - Fire a shot that deals %d%% weapon damage as fire and covers targets in radius %d in sticky pitch for %d turns, reducing global speed by %d%% and increasing fire damage taken by %d%%.
 Venomous - Fire a shot that deals %d%% weapon damage as nature and explodes into a radius %d cloud of crippling poison for %d turns, dealing %0.2f nature damage each turn and giving affected targets a %d%% chance to fail talent usage.
 Piercing - Fire a shot that explodes into a radius %d burst of shredding shrapnel, dealing %d%% weapon damage as physical and removing %d beneficial physical effects or sustains.
 The poison damage dealt increases with your Physical Power, and status chance increases with your Accuracy.]]):
-		format(dam, radius, dur, sight, fire, dam, radius, dur, damDesc(self, DamageType.NATURE, poison), fail, radius, dam*1.5, nb)
+		format(dam, radius, dur, slow, fire, dam, radius, dur, damDesc(self, DamageType.NATURE, poison), fail, radius, dam, nb)
 	end,
 }
 
@@ -439,12 +439,12 @@ newTalent{
 	type = {"technique/munitions", 3},
 	mode = "passive",
 	points = 5,
-	cooldown = 6,
+	cooldown = 8,
 	require = techs_dex_req_high3,
 	fixed_cooldown = true,
 	getFireDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 10, 100) end,
 	getPoisonDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 20, 240) end,
-	getResistPenalty = function(self, t) return math.floor(self:combatTalentScale(t, 10, 25)) end,
+	getResistPenalty = function(self, t) return math.floor(self:combatTalentLimit(t, 25, 5, 20)) end,
 	info = function(self, t)
 		local fire = t.getFireDamage(self,t)
 		local poison = t.getPoisonDamage(self,t)
@@ -468,9 +468,9 @@ newTalent{
 	getPoisonDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.1, 0.4) end,
 	getPoisonRadius = function(self, t) if self:getTalentLevel(t)>=3 then return 2 else return 1 end end,
 	getPhysicalDamage = function(self, t) return self:combatTalentPhysicalDamage(t, 20, 180) end,
-	getNumb = function(self, t) return 5 + self:combatTalentLimit(t, 30, 5, 15) end,
-	getArmorSaveReduction = function(self, t) return 5 + self:combatTalentPhysicalDamage(t, 5, 30) end,
-	getResistPenalty = function(self, t) return self:combatTalentLimit(t, 100, 15, 35, true) end,
+	getNumb = function(self, t) return 5 + self:combatTalentLimit(t, 25, 5, 15) end,
+	getArmorSaveReduction = function(self, t) return self:combatTalentLimit(t, 30, 5, 25, 0.75) end,
+	getResistPenalty = function(self, t) return self:combatTalentLimit(t, 35, 10, 25, true) end,
 	info = function(self, t)
 		local poison = t.getPoisonDamage(self,t)*100
 		local radius = t.getPoisonRadius(self,t)
diff --git a/game/modules/tome/data/talents/techniques/reflexes.lua b/game/modules/tome/data/talents/techniques/reflexes.lua
index 1296f7d5cedd15adf49326b1d109b06aed8c3555..36534f5c6c0e0e0d01fe8830477f9003041dc8ad 100644
--- a/game/modules/tome/data/talents/techniques/reflexes.lua
+++ b/game/modules/tome/data/talents/techniques/reflexes.lua
@@ -173,6 +173,7 @@ newTalent{
 	range = archery_range,
 	requires_target = true,
 	no_npc_use = true,
+	fixed_cooldown = true, -- there's probably some sort of unexpected interaction that would let you chain this infinitely with cooldown reducers
 	getTalentCount = function(self, t) return math.floor(self:combatTalentScale(t, 1, 4)) end, --Limit < 100%
 	getCooldown = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3)) end, --Limit < 100%
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent) end,
diff --git a/game/modules/tome/data/talents/techniques/sniper.lua b/game/modules/tome/data/talents/techniques/sniper.lua
index 6bec4a637dd69acc29a91f4e60aecf9be506d9fe..1f8c45adf64e8513b698d7e9b67c22501c45856f 100644
--- a/game/modules/tome/data/talents/techniques/sniper.lua
+++ b/game/modules/tome/data/talents/techniques/sniper.lua
@@ -90,6 +90,22 @@ Talents.wardenPreUse = wardenPreUse
 
 archery_range = Talents.main_env.archery_range
 
+local function concealmentDetection(self, radius, estimate)
+	if not self.x then return nil end
+	local dist = 0
+	local closest, detect = math.huge, 0
+	for i, act in ipairs(self.fov.actors_dist) do
+		dist = core.fov.distance(self.x, self.y, act.x, act.y)
+		if dist > radius then break end
+		if act ~= self and act:reactionToward(self) < 0 and not act:attr("blind") and (not act.fov or not act.fov.actors or act.fov.actors[self]) and (not estimate or self:canSee(act)) then
+			detect = detect + act:combatSeeStealth() * (1.1 - dist/10) -- detection strength reduced 10% per tile
+			if dist < closest then closest = dist end
+		end
+	end
+	return detect, closest
+end
+Talents.concealmentDetection = concealmentDetection
+
 newTalent{
 	name = "Concealment",
 	type = {"technique/sniper", 1},
@@ -97,41 +113,48 @@ newTalent{
 	mode = "sustained",
 	require = techs_dex_req_high1,
 	cooldown = 10,
+	no_energy = true,
 	tactical = { BUFF = 2 },
-	no_npc_use = true, -- getting 1 shot from an invisible ranged attacker = no
-	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent, "bow") end,
-	getDamage = function(self, t) return math.floor(self:combatTalentScale(t, 10, 35)) end,
-	getAvoidance = function(self, t) return math.floor(self:combatTalentScale(t, 15, 40)) end,
+	no_npc_use = true, -- range 13 mobs are a bit excessive
+	on_pre_use = function(self, t, silent, fake)
+		if not archerPreUse(self, t, silent, "bow") then return false end
+		if self:isTalentActive(t.id) then return true end
+		
+		-- Check nearby actors detection ability
+		if not self.x or not self.y or not game.level then return end
+		if not rng.percent(self.hide_chance or 0) then
+			if concealmentDetection(self, t.getRadius(self, t)) > 0 then
+				if not silent then game.logPlayer(self, "You are being observed too closely to enter Concealment!") end
+				return nil
+			end
+		end
+		return true
+	end,
+	getDamage = function(self, t) return math.floor(self:combatTalentScale(t, 35, 75)) end,
+	getAvoidance = function(self, t) return math.floor(self:combatTalentLimit(t, 30, 10, 22)) end,
+	getSight = function(self, t) return math.floor(self:combatTalentScale(t, 1, 3, "log")) end,
+	getRadius = function(self, t) return math.ceil(self:combatTalentLimit(t, 0, 8.9, 4.6)) end,
 	sustain_lists = "break_with_stealth",
 	activate = function(self, t)
 		local ret = {}
-		local chance = t.getAvoidance(self, t)
-		self:talentTemporaryValue(ret, "cancel_damage_chance", chance)
-		self:talentTemporaryValue(ret, "concealment", 6)
+		self:setEffect(self.EFF_CONCEALMENT, 3, {power=t.getAvoidance(self,t), dam=t.getDamage(self,t), sight=t.getSight(self,t), charges=3})
 		return ret
 	end,
 	deactivate = function(self, t, p)
 		return true
 	end,
-	hasFoes = function(self)
-		for i = 1, #self.fov.actors_dist do
-			local act = self.fov.actors_dist[i]
-			if act and self:reactionToward(act) < 0 and self:canSee(act) then return true end
-		end
-		return false
-	end,
 	callbackOnActBase = function(self, t)
-		if t.hasFoes(self) then
-			self:setEffect(self.EFF_TAKING_AIM, 2, {power=t.getDamage(self,t), max_stacks=3, max_power=t.getDamage(self,t)*3 })
-		end
+		self:setEffect(self.EFF_CONCEALMENT, 3, {power=t.getAvoidance(self,t), max_power=t.getAvoidance(self,t)*3, dam=t.getDamage(self,t), sight=t.getSight(self,t), charges=3})
 	end,
 	info = function(self, t)
-		local avoid = t.getAvoidance(self,t)
+		local avoid = t.getAvoidance(self,t)*3
 		local dam = t.getDamage(self,t)
-		return ([[Enter a concealed sniping stance. You gain a %d%% chance to completely avoid incoming damage and status effects, and enemies further than 6 tiles away will be unable to clearly see you, effectively blinding them.
-While in this stance, you will take aim if a foe is visible. Each stack of take aim increases the damage of your next Steady Shot by %d%% and the chance to mark by 30%%, stacking up to 3 times.
-This requires a bow to use.]]):
-		format(avoid, dam, dam*3)
+		local range = t.getSight(self,t)
+		local radius = t.getRadius(self,t)
+		return ([[Enter a concealed sniping stance, increasing our weapon's attack range and vision range by %d, giving all incoming damage a %d%% chance to miss you, and increasing the damage dealt by Steady Shot by %d%% and chance to mark by 100%%.
+Any non-instant, non-movement action will break concealment, but the increased range and vision and damage avoidance will persist for 3 turns, with the damage avoidance decreasing in power by 33%% each turn.
+This requires a bow to use, and cannot be used if there are foes in sight within range %d.]]):
+		format(range, avoid, dam, radius)
 	end,
 }
 
@@ -151,48 +174,15 @@ newTalent{
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent, "bow") end,
 	radius = function(self, t) return math.floor(self:combatTalentScale(t, 1, 2.7)) end,
 	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.9) end,
-	archery_onreach = function(self, t, x, y)
-		local tg = self:getTalentTarget(t)
-		self:project(tg, x, y, function(px, py)
-			local e = Object.new{
-				block_sight=true,
-				temporary = 4,
-				x = px, y = py,
-				canAct = false,
-				act = function(self)
-					local t = self.summoner:getTalentFromId(self.summoner.T_SHADOW_SHOT)
-					local rad = self.summoner:getTalentRadius(t)
-					local Map = require "engine.Map"
-					self:useEnergy()
-					local actor = game.level.map(self.x, self.y, Map.ACTOR)
-					self.temporary = self.temporary - 1
-					if self.temporary <= 0 then
-						if self.particles then game.level.map:removeParticleEmitter(self.particles) end
-						game.level.map:remove(self.x, self.y, engine.Map.TERRAIN+rad)
-						self.smokeBomb = nil
-						game.level:removeEntity(self)
-						game.level.map:scheduleRedisplay()
-					end
-				end,
-				summoner_gain_exp = true,
-				summoner = self,
-			}
-			e.smokeBomb = e -- used for checkAllEntities to return the dark Object itself
-			game.level:addEntity(e)
-			game.level.map(px, py, Map.TERRAIN+self:getTalentRadius(t), e)
-			e.particles = Particles.new("creeping_dark", 1, { })
-			e.particles.x = px
-			e.particles.y = py
-			game.level.map:addParticleEmitter(e.particles)
-
-			end, nil, {type="dark"})
-
-		game.level.map:redisplay()
-	end,
+	getSightLoss = function(self, t) return math.floor(self:combatTalentScale(t,1, 6, "log", 0, 4)) end, -- 1@1 6@5
 	target = function(self, t)
 		local weapon, ammo = self:hasArcheryWeapon()
 		return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t), selffire=false, display=self:archeryDefaultProjectileVisual(weapon, ammo)}
 	end,
+	archery_onreach = function(self, t, x, y)
+		local tg = self:getTalentTarget(t)
+		self:project(tg, x, y, DamageType.SHADOW_SMOKE, t.getSightLoss(self,t), {type="dark"})
+	end,
 	action = function(self, t)
 		local tg = self:getTalentTarget(t)
 		local targets = self:archeryAcquireTargets(nil, {one_shot=true})
@@ -200,9 +190,9 @@ newTalent{
 		local dam = t.getDamage(self,t)
 		self:archeryShoot(targets, t, nil, {mult=dam})
 		game:onTickEnd(function()
-			if self:knowTalent(self.T_CONCEALMENT) and not self:isTalentActive(self.T_CONCEALMENT)  then
-				self.talents_cd[self.T_CONCEALMENT] = 0
-				self:forceUseTalent(self.T_CONCEALMENT, {ignore_energy=true, silent = true})
+			if self:knowTalent(self.T_CONCEALMENT) and not self:isTalentActive(self.T_CONCEALMENT) then
+				self:alterTalentCoolingdown(self.T_CONCEALMENT, -20)
+				self:forceUseTalent(self.T_CONCEALMENT, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, silent=true})
 			end
 		end)
 		game.level.map:redisplay()
@@ -211,9 +201,11 @@ newTalent{
 	info = function(self, t)
 		local dam = t.getDamage(self,t)*100
 		local radius = self:getTalentRadius(t)
-		return ([[Fire an arrow tipped with a smoke bomb, inflicting %d%% damage. The bomb will create a radius %d cloud of smoke on impact for 4 turns that blocks line of sight.
-You take advantage of this distraction to immediately enter Concealment.]]):
-		format(dam, radius)
+		local sight = t.getSightLoss(self,t)
+		return ([[Fire an arrow tipped with a smoke bomb inflicting %d%% damage and creating a radius %d cloud of thick, disorientating smoke. Those caught within will be confused (power 50%%) and have their vision range reduced by %d for 5 turns.
+You take advantage of this distraction to immediately enter Concealment, regardless of it's cooldown.
+The chance for the smoke bomb to affect your targets increases with your Accuracy.]]):
+		format(dam, radius, sight)
 	end,
 }
 
@@ -227,16 +219,11 @@ newTalent{
 	sustain_stamina = 50,
 	tactical = { BUFF = 2 },
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent, "bow") end,
-	getPower = function(self, t) return math.floor(self:combatTalentScale(t, 10, 45)) end,
-	getSpeed = function(self, t) return math.floor(self:combatTalentLimit(t, 150, 50, 110)) end,
-	getDamage = function(self, t) return math.floor(self:combatTalentLimit(t, 10, 1, 5)) end,
+	getPower = function(self, t) return self:combatScale(self:getTalentLevel(t) * self:getDex(10, true), 4, 0, 54, 50) end,
+	getSpeed = function(self, t) return math.floor(self:combatTalentLimit(t, 150, 50, 100)) end,
+	getDamage = function(self, t) return 1 + math.min(math.floor(self:getTalentLevel(t)),6) end, --we really don't want a flat damage bonus like this going up past 35%
 	sustain_slots = 'archery_stance',
 	activate = function(self, t)
-		local weapon = self:hasArcheryWeapon()
-		if not weapon then
-			game.logPlayer(self, "You cannot use Aim without a bow or sling!")
-			return nil
-		end
 
 		local power = t.getPower(self,t)
 		local speed = t.getSpeed(self,t)
@@ -257,8 +244,9 @@ newTalent{
 		local speed = t.getSpeed(self,t)
 		local dam = t.getDamage(self,t)
 		return ([[Enter a calm, focused stance, increasing physical power and accuracy by %d and projectile speed by %d%%.
-This makes your shots more effective at range, increasing all damage dealt by %d%% per tile travelled beyond 3, to a maximum of %d%% damage at range 10.]]):
-		format(power, speed, dam, dam*7)
+This makes your shots more effective at range, increasing all damage dealt by %d%% per tile travelled beyond 3, to a maximum of %d%% damage at range 8.
+The physical power and accuracy increase with your Dexterity.]]):
+		format(power, speed, dam, dam*5)
 	end,
 }
 
@@ -275,8 +263,8 @@ newTalent{
 	tactical = { ATTACK = { weapon = 3 }, },
 	no_npc_use = true, --no way am i giving a npc a 300%+ ranged shot
 	on_pre_use = function(self, t, silent) return archerPreUse(self, t, silent, "bow") end,
-	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.4, 3.0) end, -- very high damage as this effectively takes 2 turns
-	getDamageReduction = function(self, t) return math.floor(self:combatTalentLimit(t, 100, 25, 70)) end,
+	getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.7, 3.5) end, -- very high damage as this effectively takes 2 turns
+	getDamageReduction = function(self, t) return math.floor(self:combatTalentLimit(t, 90, 30, 70)) end,
 	action = function(self, t)
 		local dam = t.getDamage(self,t)
 		local reduction = t.getDamageReduction(self,t)
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index f020dbe2969d62762a838ac3a29ff989d872fd41..dd21e92193b03d3ef340401e2e3f9a1606f96d5b 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -3208,9 +3208,9 @@ newEffect{
 	deactivate = function(self, eff)
 		self:removeParticles(eff.particle)
 	end,
-	on_die = function(self,eff)
-		if eff.src and eff.src:knowTalent(eff.src.T_FIRST_BLOOD) then eff.src:incStamina(eff.src:callTalent(eff.src.T_FIRST_BLOOD, "getStamina")) end
-	end,
+--	on_die = function(self,eff)
+--		if eff.src and eff.src:knowTalent(eff.src.T_FIRST_BLOOD) then eff.src:incStamina(eff.src:callTalent(eff.src.T_FIRST_BLOOD, "getStamina")) end
+--	end,
 }
 
 newEffect{
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index 6928442314874dd780b002d4571bd88083a9bb2f..e7eb8ffeb94e21b81fdad70d5d669015f5b13ced 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -3729,26 +3729,22 @@ newEffect{
 }
 
 newEffect{
-	name = "INCENDIARY_SMOKE", image = "talents/sticky_smoke.png",
-	desc = "Incendiary Smoke",
-	long_desc = function(self, eff) return ("The target's vision range is decreased by %d and fire resistance by %d%%."):format(eff.sight, eff.resist) end,
+	name = "STICKY_PITCH", image = "talents/sticky_smoke.png",
+	desc = "Sticky Pitch",
+	long_desc = function(self, eff) return ("The target's global speed is reduced by %d%% and fire resistance by %d%%."):format(eff.slow, eff.resist) end,
 	type = "physical",
-	subtype = { sense=true },
+	subtype = { slow=true },
 	status = "detrimental",
-	parameters = { sight=5, resist=10 },
-	on_gain = function(self, err) return "#Target# is surrounded by a thick, incendiary smoke.", "+Sticky Flame" end,
-	on_lose = function(self, err) return "The smoke around #target# dissipate.", "-Sticky Flame" end,
+	parameters = { slow=0.1, resist=10 },
+	on_gain = function(self, err) return "#Target# is covered in sticky, flammable pitch.", "+Pitch" end,
+	on_lose = function(self, err) return "#Target# is free from the pitch.", "-Pitch" end,
 	activate = function(self, eff)
-		if self.sight - eff.sight < 1 then eff.sight = self.sight - 1 end
-		eff.tmpid = self:addTemporaryValue("sight", -eff.sight)
+		eff.tmpid = self:addTemporaryValue("global_speed_add", -eff.slow)
 		eff.resid = self:addTemporaryValue("resists", {[DamageType.FIRE] = -eff.resist})
-		self:setTarget(nil) -- Loose target!
-		self:doFOV()
 	end,
 	deactivate = function(self, eff)
-		self:removeTemporaryValue("sight", eff.tmpid)
+		self:removeTemporaryValue("global_speed_add", eff.tmpid)
 		self:removeTemporaryValue("resists", eff.resid)
-		self:doFOV()
 	end,
 }
 
@@ -3856,22 +3852,63 @@ newEffect{
 }
 
 newEffect{
-	name = "TAKING_AIM", image = "talents/concealment.png",
-	desc = "Taking Aim",
-	long_desc = function(self, eff) return ("The target is taking aim, increasing the damage of their next marked shot by %d%%."):format(eff.power) end,
+	name = "CONCEALMENT", image = "talents/concealment.png",
+	desc = "Concealment",
+	long_desc = function(self, eff) return ("The target is concealed, increasing sight and attack range by %d and chance to avoid damage by %d%%."):format(eff.sight, eff.power*eff.charges) end,
 	type = "physical",
 	subtype = { tactic=true },
 	status = "beneficial",
 	charges = function(self, eff) return eff.charges end,
-	parameters = { power=5, duration=1, max_power=15, charges=1 },
-	on_merge = function(self, old_eff, new_eff)
-		new_eff.charges = math.min(old_eff.charges + 1, 3)
-		new_eff.power = math.min(new_eff.power + old_eff.power, new_eff.max_power)
-		return new_eff
-	end,
+	parameters = { power=5, duration=1, sight=1, dam=10, max_power=15, charges=3 },
 	activate = function(self, eff)
-		eff.charges = 1
+		self:effectTemporaryValue(eff, "cancel_damage_chance", eff.max_power)
+		self:effectTemporaryValue(eff, "sight", eff.sight)
+		self:effectTemporaryValue(eff, "infravision", eff.sight)
+		self:effectTemporaryValue(eff, "heightened_senses", eff.sight)
+		self:effectTemporaryValue(eff, "archery_bonus_range", eff.sight)
+		self:doFOV()
 	end,
 	deactivate = function(self, eff)
+		self:doFOV()
+	end,
+	on_timeout = function(self, eff)
+		if not self:isTalentActive(self.T_CONCEALMENT) then 
+			eff.charges = eff.charges -1
+			eff.max_power = eff.power*eff.charges
+			if eff.charges == 0 then self:removeEffect(self.EFF_CONCEALMENT) end
+		end
 	end,
 }
+
+newEffect{
+	name = "SHADOW_SMOKE", image = "talents/shadow_shot.png",
+	desc = "Shadow Smoke",
+	long_desc = function(self, eff) return ("The target is wrapped in disorientating smoke, confusing them and reducing vision range by %d."):format(eff.sight) end,
+	type = "physical",
+	subtype = { sense=true },
+	status = "detrimental",
+	parameters = { sight=5 },
+	on_gain = function(self, err) return "#Target# is surrounded by a thick smoke.", "+Shadow Smoke" end,
+	on_lose = function(self, err) return "The smoke around #target# dissipate.", "-Shadow Smoke" end,
+	charges = function(self, eff) return -eff.sight end,
+	activate = function(self, eff)
+		if self:canBe("blind") then
+			if self.sight - eff.sight < 1 then eff.sight = self.sight - 1 end
+			eff.tmpid = self:addTemporaryValue("sight", -eff.sight)
+	--		self:setTarget(nil) -- Loose target!
+			self:doFOV()
+		end
+		if self:canBe("confusion") then
+			eff.cid = self:addTemporaryValue("confused", 50)
+		end
+	end,
+	deactivate = function(self, eff)
+		if eff.tmpid then 
+			self:removeTemporaryValue("sight", eff.tmpid)
+			self:doFOV()
+		end
+		if eff.cid then
+			self:removeTemporaryValue("confused", eff.cid)
+		end
+	end,
+}
\ No newline at end of file
diff --git a/game/modules/tome/dialogs/QuestPopup.lua b/game/modules/tome/dialogs/QuestPopup.lua
index 4c641c4efbe580c0a2052e4651d8bb95eb21ab4c..0f2a576dbffa7bb86c50fbe0f5566de5de3fb12a 100644
--- a/game/modules/tome/dialogs/QuestPopup.lua
+++ b/game/modules/tome/dialogs/QuestPopup.lua
@@ -35,8 +35,12 @@ local statuses = {
 }
 
 function _M:init(quest, status)
+	local use_ui = "quest"
+	if quest.use_ui then use_ui = quest.use_ui end
+	if status == Quest.FAILED then use_ui = "quest-fail" end
+
 	self.quest = quest
-	self.ui = "quest"
+	self.ui = use_ui
 	Dialog.init(self, "", 666, 150)
 
 	local add = ''
@@ -53,7 +57,7 @@ function _M:init(quest, status)
 	info:setTextShadow(3)
 	info:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 2)
 	
-	local status = Textzone.new{ui="quest", auto_width=true, auto_height=true, text="#cc9f33#"..(statuses[status] or "????"), has_box=true, font={FontPackage:getFont("bignews")}}
+	local status = Textzone.new{ui=use_ui, auto_width=true, auto_height=true, text="#cc9f33#"..(statuses[status] or "????"), has_box=true, font={FontPackage:getFont("bignews")}}
 	status:setTextShadow(3)
 	status:setShadowShader(Shader.default.textoutline and Shader.default.textoutline.shad, 2)