From 2fd357fb08f03ea8bb3259f3231431e75b311a27 Mon Sep 17 00:00:00 2001
From: Shibari <ShibariTOME@Gmail.com>
Date: Thu, 22 Nov 2018 03:28:38 -0500
Subject: [PATCH] Revise Stealth

(MISC)

- Moved to generic.  This is partly because Rogue is getting another class category unlocked base and has too many.

- Aggro behavior no longer changes with difficulty.  We don't need hidden behavior like this and the number is pretty small anyway

(STEALTH)

- Enemies no longer share target_last_seen information at all if the target is stealthed.

- Enemies will still chain aggro against stealth to prevent cheese but aquiring you as a target will be delayed by 3 turns.

Shadow Dance:

- No longer clears targets or forces you out of stealth.
---
 game/modules/tome/class/NPC.lua               | 11 ++++++++--
 .../tome/data/talents/cunning/cunning.lua     |  2 +-
 .../tome/data/talents/cunning/stealth.lua     | 19 ++++++------------
 .../modules/tome/data/timed_effects/other.lua | 20 +++++++++++++++++++
 .../tome/data/timed_effects/physical.lua      |  8 --------
 5 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index 380d808463..445ea0ab8d 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -230,6 +230,7 @@ function _M:lineFOV(tx, ty, extra_block, block, sx, sy)
 	return core.fov.line(sx, sy, tx, ty, block)
 end
 
+-- NOTE:  Theres some evidence that this is one of the laggiest functions when a large number of NPCs are active because it causes an insane number of hasLOS calls
 --- Gather and share information about enemies from others
 --	applied each turn to every actor in LOS by self:computeFOV (or core.fov.calc_default_fov)
 -- @param who = actor acting (updating its FOV info), calling self:seen_by(who)
@@ -248,7 +249,7 @@ function _M:seen_by(who)
 	if not who.x or not self:hasLOS(who.x, who.y) then return end
 	-- Check if it's actually a being of cold machinery and not of blood and flesh
 	if not who.aiSeeTargetPos then return end
-	if self.ai_target.actor then
+	if self.ai_target.actor and not who_target:isTalentActive(who_target.T_STEALTH) then
 		-- Pass last seen coordinates
 		if self.ai_target.actor == who_target then
 			-- Adding some type-safety checks, but this isn't fixing the source of the errors
@@ -274,7 +275,7 @@ function _M:seen_by(who)
 		-- Don't believe allies if they think the target is too far away (based on distance to ally plus ally to hostile estimate (1.3 * sight range, usually))
 		local tx, ty = who:aiSeeTargetPos(who_target)
 		local distallyhostile = core.fov.distance(who.x, who.y, tx, ty) or 100
-		local range_factor = 1.2 + (tonumber(game.difficulty) or 1)/20 -- NPC's pass targets more freely at higher difficulties
+		local range_factor = 1.2
 		if distallyhostile + core.fov.distance(self.x, self.y, who.x, who.y) > math.min(10, math.max(self.sight, self.infravision or 0, self.heightened_senses or 0, self.sense_radius or 0))*range_factor then return end
 
 		-- Don't believe allies if they saw the target over 10 turns ago
@@ -282,6 +283,12 @@ function _M:seen_by(who)
 	end
 
 	print("[NPC:seen_by] Passing target", who_target.name, "from", who.uid, who.name, "to", self.uid, self.name)
+	
+	-- If we have no current target but the passed target is stealthed, delay aquiring for 3 turns but make sure they can't avoid aggro entirely
+	if who_target:isTalentActive(who_target.T_STEALTH) and not (self.ai_target and self.ai_target.actor) then
+		self:setEffect(self.EFF_STEALTH_SKEPTICAL, 3, {target = {actor=who_target, x=who_target.x, y=who_target.y}})
+		return
+	end
 	self:setTarget(who_target, who.ai_state.target_last_seen)
 end
 
diff --git a/game/modules/tome/data/talents/cunning/cunning.lua b/game/modules/tome/data/talents/cunning/cunning.lua
index 6581263882..c98f5d6cd9 100644
--- a/game/modules/tome/data/talents/cunning/cunning.lua
+++ b/game/modules/tome/data/talents/cunning/cunning.lua
@@ -19,7 +19,7 @@
 
 -- Cunning talents
 newTalentType{ allow_random=true, type="cunning/stealth-base", name = "stealth", description = "Allows the user to enter stealth." }
-newTalentType{ allow_random=true, type="cunning/stealth", name = "stealth", description = "Allows the user to enter stealth." }
+newTalentType{ allow_random=true, type="cunning/stealth", name = "stealth", generic = true, description = "Allows the user to enter stealth." }
 newTalentType{ allow_random=true, type="cunning/trapping", name = "trapping", description = "The knowledge of trap laying and assorted trickeries." }
 newTalentType{ allow_random=true, type="cunning/traps", name = "traps", description = "Collection of known traps." }
 newTalentType{ allow_random=true, type="cunning/poisons", name = "poisons", description = "The knowledge of poisons and how to apply them to 'good' effects." }
diff --git a/game/modules/tome/data/talents/cunning/stealth.lua b/game/modules/tome/data/talents/cunning/stealth.lua
index 63795ab18a..0255b2d46c 100644
--- a/game/modules/tome/data/talents/cunning/stealth.lua
+++ b/game/modules/tome/data/talents/cunning/stealth.lua
@@ -146,7 +146,8 @@ newTalent{
 		You cannot enter stealth if there are foes in sight within range %d%s.
 		Any non-instant, non-movement action will break stealth if not otherwise specified.
 
-		Note that enemies uncertain of your location will still make educated guesses at it, and if any enemy can see you most of their nearby allies will as well.]]):
+		Enemies uncertain of your location will still make educated guesses at it.
+		While stealthed, enemies cannot share information about your location with each other and will be delayed in relaying that you exist at all.]]):
 		format(stealthpower, radius, xs)
 	end,
 }
@@ -206,23 +207,15 @@ newTalent{
 	getRadius = stealthRadius,
 	getDuration = function(self, t) return math.floor(self:combatTalentLimit(t, 7, 2, 5)) end,
 	action = function(self, t)
+		self:setEffect(self.EFF_SHADOW_DANCE, t.getDuration(self,t), {src=self, rad=t.getRadius(self,t)}) 
 		if not self:isTalentActive(self.T_STEALTH) then
 			self:forceUseTalent(self.T_STEALTH, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, silent=true})
-			for act, param in pairs(self.fov.actors) do
-				if act ~= self and act.ai_target and act.ai_target.actor == self then act:setTarget() end
-			end
-		end
-		self:alterTalentCoolingdown(self.T_STEALTH, -20)
-		self:setEffect(self.EFF_SHADOW_DANCE, t.getDuration(self,t), {src=self, rad=t.getRadius(self,t)}) 
-		
+		end	
 		return true
 	end,
 	info = function(self, t)
-		local radius, rad_dark = t.getRadius(self, t, true)
-		xs = rad_dark ~= radius and (" (range %d in an unlit grid)"):format(rad_dark) or ""
 		return ([[Your mastery of stealth allows you to vanish from sight at any time.
-		You automatically enter stealth mode, reset its cooldown, and cause it to not break from unstealthy actions for %d turns.  If you were not already stealthed, all enemies in a direct line of sight completely lose track of you.
-		When your Shadow Dance ends, you must make a stealth check against targets in radius %d%s or be revealed.]]):
-		format(t.getDuration(self, t), radius, xs)
+		You automatically enter stealth and cause it to not break from unstealthy actions for %d turns.]]):
+		format(t.getDuration(self, t))
 	end,
 }
diff --git a/game/modules/tome/data/timed_effects/other.lua b/game/modules/tome/data/timed_effects/other.lua
index 882dd7330f..1c2ec3d462 100644
--- a/game/modules/tome/data/timed_effects/other.lua
+++ b/game/modules/tome/data/timed_effects/other.lua
@@ -3571,3 +3571,23 @@ newEffect{
 		end
 	end,
 }
+
+newEffect{
+	name = "STEALTH_SKEPTICAL", image = "talents/stealth.png",
+	desc = "Skeptical",
+	long_desc = function(self, eff) return "The target doesn't believe it's ally truly saw anything in the shadows." end,
+	type = "other",
+	subtype = { },
+	status = "neutral",
+	parameters = {target = {} },
+	activate = function(self, eff)
+	end,
+	on_merge = function(self, old_eff, new_eff)
+		--old_eff.dur = new_eff.dur
+		old_eff.target = new_eff.target
+		return old_eff
+	end,
+	deactivate = function(self, eff)
+		self:setTarget(eff.target.actor, {x=eff.target.x, y=eff.target.y})
+	end,
+}
diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua
index aa0f7dca60..367dae2fad 100644
--- a/game/modules/tome/data/timed_effects/physical.lua
+++ b/game/modules/tome/data/timed_effects/physical.lua
@@ -3381,14 +3381,6 @@ newEffect{
 		end
 	end,
 	deactivate = function(self, eff)
-		if not eff.no_cancel_stealth and not rng.percent(self.hide_chance or 0) then
-			local detect = self:stealthDetection(eff.rad)
-			local netstealth = (self:callTalent(self.T_STEALTH, "getStealthPower") + (self:attr("inc_stealth") or 0))
-			if detect > 0 and self:checkHit(detect, netstealth) then
-				game.logPlayer(self, "You have been detected!")
-				self:forceUseTalent(self.T_STEALTH, {ignore_energy=true, ignore_cd=true, no_talent_fail=true, silent=false})
-			end
-		end
 	end,
 }
 
-- 
GitLab