diff --git a/game/engines/default/engine/interface/PlayerRun.lua b/game/engines/default/engine/interface/PlayerRun.lua
index 4b63873c81c428ed36fa8edbfcdc4015b7089bc2..c1c769ab5053a927778fde024d047155ed62f2d1 100644
--- a/game/engines/default/engine/interface/PlayerRun.lua
+++ b/game/engines/default/engine/interface/PlayerRun.lua
@@ -224,7 +224,14 @@ function _M:runStep()
 		if not self.running then return false end
 		if not self.running.busy then
 			self.running.cnt = self.running.cnt + 1
-		elseif self.running.busy.no_energy then
+		end
+		-- Check after running to spot actors that may slip away from us; we still won't get a turn but we'll get the next one
+		ret, msg = self:runCheck()
+		if not ret then
+			self:runStop(msg)
+			return false
+		end
+		if self.running.busy and self.running.busy.no_energy then
 			return self:runStep()
 		end
 		return true
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index c868d0384cbe1cef93f1a6694ddf67c2e98064c8..6c29db238a767731fc44fc63c091229ecb3b20de 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -801,7 +801,7 @@ function _M:setTarget(target)
 	return game:targetSetForPlayer(target)
 end
 
-local function spotHostiles(self)
+local function spotHostiles(self, actors_only)
 	local seen = {}
 	if not self.x then return seen end
 
@@ -809,9 +809,36 @@ local function spotHostiles(self)
 	core.fov.calc_circle(self.x, self.y, game.level.map.w, game.level.map.h, self.sight or 10, function(_, x, y) return game.level.map:opaque(x, y) end, function(_, x, y)
 		local actor = game.level.map(x, y, game.level.map.ACTOR)
 		if actor and self:reactionToward(actor) < 0 and self:canSee(actor) and game.level.map.seens(x, y) then
-			seen[#seen + 1] = {x=x,y=y,actor=actor}
+			seen[#seen + 1] = {x=x,y=y,actor=actor, entity=actor, name=actor.name}
 		end
 	end, nil)
+
+	if not actors_only then
+		-- Check for projectiles in line of sight
+		core.fov.calc_circle(self.x, self.y, game.level.map.w, game.level.map.h, self.sight or 10, function(_, x, y) return game.level.map:opaque(x, y) end, function(_, x, y)
+			local proj = game.level.map(x, y, game.level.map.PROJECTILE)
+			if not proj then return end
+
+			-- trust ourselves but not our friends
+			if proj.src and self == proj.src then return end
+			local sx, sy = proj.start_x, proj.start_y
+			local tx, ty
+
+			-- Bresenham is too so check if we're anywhere near the mathematical line of flight
+			if proj.project then
+				tx, ty = proj.project.def.x, proj.project.def.y
+			elseif proj.homing then
+				tx, ty = proj.homing.target.x, proj.homing.target.y
+			end
+			if tx and ty then
+				local dist_to_line = math.abs((self.x - sx) * (ty - sy) - (self.y - sy) * (tx - sx)) / core.fov.distance(sx, sy, tx, ty)
+				local our_way = ((self.x - x) * (tx - x) + (self.y - y) * (ty - y)) > 0
+				if our_way and dist_to_line < 1.5 then
+					seen[#seen+1] = {x=x, y=y, projectile=proj, entity=proj, name=(proj.getName and proj:getName()) or proj.name}
+				end
+			end
+		end, nil)
+	end
 	return seen
 end
 
@@ -824,7 +851,7 @@ function _M:automaticTalents()
 	local uses = {}
 	for tid, c in pairs(self.talents_auto) do
 		local t = self.talents_def[tid]
-		local spotted = spotHostiles(self)
+		local spotted = spotHostiles(self, true)
 		if (t.mode ~= "sustained" or not self.sustain_talents[tid]) and not self.talents_cd[tid] and self:preUseTalent(t, true, true) and (not t.auto_use_check or t.auto_use_check(self, t)) then
 			if (c == 1) or (c == 2 and #spotted <= 0) or (c == 3 and #spotted > 0) then
 				if c ~= 2 then
@@ -904,10 +931,10 @@ function _M:restCheck()
 	local spotted = spotHostiles(self)
 	if #spotted > 0 then
 		for _, node in ipairs(spotted) do
-			node.actor:addParticles(engine.Particles.new("notice_enemy", 1))
+			node.entity:addParticles(engine.Particles.new("notice_enemy", 1))
 		end
 		local dir = game.level.map:compassDirection(spotted[1].x - self.x, spotted[1].y - self.y)
-		return false, ("hostile spotted to the %s (%s%s)"):format(dir or "???", spotted[1].actor.name, game.level.map:isOnScreen(spotted[1].x, spotted[1].y) and "" or " - offscreen")
+		return false, ("hostile spotted to the %s (%s%s)"):format(dir or "???", spotted[1].name, game.level.map:isOnScreen(spotted[1].x, spotted[1].y) and "" or " - offscreen")
 	end
 
 	-- Resting improves regen
@@ -1000,7 +1027,7 @@ function _M:runCheck(ignore_memory)
 	local spotted = spotHostiles(self)
 	if #spotted > 0 then
 		local dir = game.level.map:compassDirection(spotted[1].x - self.x, spotted[1].y - self.y)
-		return false, ("hostile spotted to the %s (%s%s)"):format(dir or "???", spotted[1].actor.name, game.level.map:isOnScreen(spotted[1].x, spotted[1].y) and "" or " - offscreen")
+		return false, ("hostile spotted to the %s (%s%s)"):format(dir or "???", spotted[1].name, game.level.map:isOnScreen(spotted[1].x, spotted[1].y) and "" or " - offscreen")
 	end
 
 	if self:fireTalentCheck("callbackOnRun") then return false, "talent prevented" end
@@ -1101,7 +1128,7 @@ function _M:runStopped()
 	local spotted = spotHostiles(self)
 	if #spotted > 0 then
 		for _, node in ipairs(spotted) do
-			node.actor:addParticles(engine.Particles.new("notice_enemy", 1))
+			node.entity:addParticles(engine.Particles.new("notice_enemy", 1))
 		end
 	end
 
@@ -1342,7 +1369,7 @@ end
 function _M:useOrbPortal(portal)
 	if portal.special then portal:special(self) return end
 
-	local spotted = spotHostiles(self)
+	local spotted = spotHostiles(self, true)
 	if #spotted > 0 then
 		local dir = game.level.map:compassDirection(spotted[1].x - self.x, spotted[1].y - self.y)
 		self:logCombat(spotted[1].actor, "You can not use the Orb with foes watching (#Target# to the %s%s)",dir, game.level.map:isOnScreen(spotted[1].x, spotted[1].y) and "" or " - offscreen")