diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua index 380d80846391040434a21959a95a1003ff916dca..445ea0ab8d50a4cca679f542eeb6fe15f9b31f0e 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 65812638820d4846d7d98084d4545f7021dfa914..c98f5d6cd951eaea6a1e3d8f77999dba837b81a2 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 63795ab18a41daf9dfda124d0802521c9042e50f..0255b2d46c86b7281241b46cf4e0467f5d9d8536 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 882dd7330fdf281e3f798cc941a51f68edcf0be3..1c2ec3d46290f7132b43d2ccac69aa73dc34aa8d 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 aa0f7dca604c53e798ec6df320615fe99f084ebe..367dae2fad033cb9171afdb18b45f41f1bd3fe05 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, }