From 527840a8d718a6206c11404df49c06af3afedfca Mon Sep 17 00:00:00 2001 From: grayswandir <grayswandir76@gmail.com> Date: Sat, 20 Dec 2014 16:52:55 -0500 Subject: [PATCH] Adds a 'lists' system for convenience. Modified stealth and step up to use. This lets talents / effects add themselves to lists at appropriate times. Bascially, just a quicker way than searching for all applied talents/effects for a specific tag. Talents can have a sustain_lists and a learn_lists field. Effects just have a lists field. Example: talent A has the following: learn_lists = {'red', {'blue', 'green'}} When you learn it, your character now has the following fields: self.red = {'T_A'} self.blue.green = {'T_A'} Modified stealth and step up to use this system. So, to make something break when step up does, just add it to the 'break_with_step_up' list. --- .../default/engine/interface/ActorTalents.lua | 52 +++++++++++++++++++ .../interface/ActorTemporaryEffects.lua | 27 ++++++++++ game/engines/default/engine/utils.lua | 20 +++++++ game/modules/tome/class/Actor.lua | 42 ++++++++------- .../tome/data/talents/cunning/stealth.lua | 5 +- .../tome/data/timed_effects/physical.lua | 9 +++- 6 files changed, 133 insertions(+), 22 deletions(-) diff --git a/game/engines/default/engine/interface/ActorTalents.lua b/game/engines/default/engine/interface/ActorTalents.lua index a055f4dda5..9230becb03 100644 --- a/game/engines/default/engine/interface/ActorTalents.lua +++ b/game/engines/default/engine/interface/ActorTalents.lua @@ -197,6 +197,19 @@ function _M:useTalent(id, who, force_level, ignore_cd, force_target, silent, no_ if not self:postUseTalent(ab, ret) then return end self.sustain_talents[id] = ret + + if ab.sustain_lists then + local lists = ab.sustain_lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + table.insert(list, id) + end + end else local old_level if force_level then old_level = who.talents[id]; who.talents[id] = force_level end @@ -214,6 +227,19 @@ function _M:useTalent(id, who, force_level, ignore_cd, force_target, silent, no_ -- Everything went ok? then start cooldown if any if not ignore_cd then self:startTalentCooldown(ab) end self.sustain_talents[id] = nil + + if ab.sustain_lists then + local lists = ab.sustain_lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + table.removeFromList(list, id) + end + end end end) local success, err @@ -353,6 +379,19 @@ function _M:learnTalent(t_id, force, nb) end end end + + if t.learn_lists then + local lists = t.learn_lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + table.insert(list, t.id) + end + end end for i = 1, (nb or 1) do @@ -443,6 +482,19 @@ function _M:unlearnTalent(t_id, nb) end end + if t.learn_lists and not self:knowTalent(t_id) then + local lists = t.learn_lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + table.removeFromList(list, t.id) + end + end + if self.talents[t_id] == nil then self.talents_auto[t_id] = nil end self.changed = true diff --git a/game/engines/default/engine/interface/ActorTemporaryEffects.lua b/game/engines/default/engine/interface/ActorTemporaryEffects.lua index 581a62c35b..1dcbbaf2c8 100644 --- a/game/engines/default/engine/interface/ActorTemporaryEffects.lua +++ b/game/engines/default/engine/interface/ActorTemporaryEffects.lua @@ -141,6 +141,20 @@ function _M:setEffect(eff_id, dur, p, silent) end end if ed.activate then ed.activate(self, p, ed) end + + if ed.lists then + local lists = ed.lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + end + table.insert(list, eff_id) + end + self.changed = true self:check("on_temporary_effect_added", eff_id, ed, p) end @@ -177,6 +191,19 @@ function _M:removeEffect(eff, silent, force) end end if _M.tempeffect_def[eff].deactivate then _M.tempeffect_def[eff].deactivate(self, p, _M.tempeffect_def[eff]) end + if ed.lists then + local lists = ed.lists + if 'table' ~= type(lists) then lists = {lists} end + for _, list in ipairs(lists) do + if 'table' == type(list) then + list = table.getTable(self, unpack(list)) + else + list = table.getTable(self, list) + end + end + table.removeFromList(list, eff_id) + end + self:check("on_temporary_effect_removed", eff, _M.tempeffect_def[eff], p) end diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua index f4a6dcfaef..15b04b91e6 100644 --- a/game/engines/default/engine/utils.lua +++ b/game/engines/default/engine/utils.lua @@ -394,6 +394,26 @@ function table.set(table, ...) table[args[#args - 1]] = args[#args] end +--[=[ + Decends recursively through a table by the given list of keys, + returning the table at the end. Missing keys will have tables + created for them. If a non-table value is encountered, return nil. +]=] +function table.getTable(table, ...) + if 'table' ~= type(table) then return end + local args = {...} + for i = 1, #args do + local key = args[i] + local subtable = table[key] + if not subtable then + subtable = {} + table[key] = subtable + end + if 'table' ~= type(subtable) then return end + table = subtable + end + return table +end -- Taken from http://lua-users.org/wiki/SortedIteration and modified local function cmp_multitype(op1, op2) diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 1c1fb34032..45f72560cb 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -2184,7 +2184,7 @@ function _M:onTakeHit(value, src, death_note) self:removeEffect(self.EFF_PSI_DAMAGE_SHIELD) end end - + if value > 0 and self:attr("shadow_empathy") then -- Absorb damage into a random shadow local shadow = self:callTalent(self.T_SHADOW_EMPATHY, "getRandomShadow") @@ -5082,7 +5082,7 @@ function _M:postUseTalent(ab, ret, silent) end -- Cancel stealth! - if ab.id ~= self.T_STEALTH and ab.id ~= self.T_HIDE_IN_PLAIN_SIGHT and not util.getval(ab.no_break_stealth, self, ab) then self:breakStealth() end + if not util.getval(ab.no_break_stealth, self, ab) then self:breakStealth() end if ab.id ~= self.T_LIGHTNING_SPEED then self:breakLightningSpeed() end if ab.id ~= self.T_GATHER_THE_THREADS and ab.is_spell then self:breakChronoSpells() end if not ab.no_reload_break then self:breakReloading() end @@ -5166,6 +5166,22 @@ function _M:forceUseTalent(t, def) return unpack(ret) end +-- Remove an effect or sustain. +function _M:removeModifier(id) + if 'T_' == id:sub(1, 2) then + self:forceUseTalent(id, {ignore_energy=true}) + elseif 'EFF_' == id:sub(1, 4) then + self:removeEffect(id) + end +end + +-- Remove a list of effects or sustains. +function _M:removeModifierList(list) + for _, id in ipairs(list) do + self:removeModifier(id) + end +end + function _M:breakReloading() if self:hasEffect(self.EFF_RELOADING) then self:removeEffect(self.EFF_RELOADING) @@ -5174,7 +5190,8 @@ end --- Breaks stealth if active function _M:breakStealth() - if self:isTalentActive(self.T_STEALTH) then + local breaks = self.break_with_stealth + if breaks and #breaks > 0 then local chance = 0 if self:knowTalent(self.T_UNSEEN_ACTIONS) then chance = self:callTalent(self.T_UNSEEN_ACTIONS,"getChance") + (self:getLck() - 50) * 0.2 @@ -5182,28 +5199,15 @@ function _M:breakStealth() -- Do not break stealth if rng.percent(chance) then return end - self:forceUseTalent(self.T_STEALTH, {ignore_energy=true}) + self:removeModifierList(breaks) self.changed = true end end --- Breaks step up if active function _M:breakStepUp() - if self:hasEffect(self.EFF_STEP_UP) then - self:removeEffect(self.EFF_STEP_UP) - end - if self:hasEffect(self.EFF_WILD_SPEED) then - self:removeEffect(self.EFF_WILD_SPEED) - end - if self:hasEffect(self.EFF_HUNTER_SPEED) then - self:removeEffect(self.EFF_HUNTER_SPEED) - end - if self:hasEffect(self.EFF_REFLEXIVE_DODGING) then - self:removeEffect(self.EFF_REFLEXIVE_DODGING) - end - if self:hasEffect(self.EFF_SKIRMISHER_DIRECTED_SPEED) then - self:removeEffect(self.EFF_SKIRMISHER_DIRECTED_SPEED) - end + local breaks = self.break_with_step_up + if breaks and #breaks > 0 then self:removeModifierList(breaks) end end --- Breaks lightning speed if active diff --git a/game/modules/tome/data/talents/cunning/stealth.lua b/game/modules/tome/data/talents/cunning/stealth.lua index b605d36201..ffb001310f 100644 --- a/game/modules/tome/data/talents/cunning/stealth.lua +++ b/game/modules/tome/data/talents/cunning/stealth.lua @@ -45,6 +45,7 @@ newTalent{ allow_autocast = true, no_energy = true, tactical = { BUFF = 3 }, + no_break_stealth = true, getStealthPower = function(self, t) return 10 + self:combatScale(math.max(1,self:getCun(10, true) * self:getTalentLevel(t)), 5, 1, 54, 50) end, --TL 5, cun 100 = 54 getRadius = function(self, t) return math.ceil(self:combatTalentLimit(t, 0, 8.9, 4.6)) end, -- Limit to range >= 1 on_pre_use = function(self, t, silent) @@ -58,13 +59,14 @@ newTalent{ -- 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 stealthDetection(self, t.getRadius(self, t)) > 0 then + if stealthDetection(self, t.getRadius(self, t)) > 0 then if not silent then game.logPlayer(self, "You are being observed too closely to enter Stealth!") end return nil end end return true end, + sustain_lists = "break_with_stealth", activate = function(self, t) local res = { stealth = self:addTemporaryValue("stealth", t.getStealthPower(self, t)), @@ -123,6 +125,7 @@ newTalent{ -- 90% (~= 47% chance against 1 opponent (range 1) at talent level 1, 270% (~= 75% chance against 1 opponent (range 1) and 3 opponents (range 6) at talent level 5 -- vs flat 47% at 1, 75% @ 5 previous stealthMult = function(self, t) return self:combatTalentScale(t, 0.9, 2.7) end, + no_break_stealth = true, getChance = function(self, t, fake) local netstealth = t.stealthMult(self, t) * (self:callTalent(self.T_STEALTH, "getStealthPower") + (self:attr("inc_stealth") or 0)) if fake then return netstealth end diff --git a/game/modules/tome/data/timed_effects/physical.lua b/game/modules/tome/data/timed_effects/physical.lua index 21efc23075..d9299aa3fc 100644 --- a/game/modules/tome/data/timed_effects/physical.lua +++ b/game/modules/tome/data/timed_effects/physical.lua @@ -1096,6 +1096,7 @@ newEffect{ local d = game.turn - eff.start_turn return util.bound(360 - d / eff.possible_end_turns * 360, 0, 360) end, + lists = 'break_with_step_up', activate = function(self, eff) eff.start_turn = game.turn eff.possible_end_turns = 10 * (eff.dur+1) @@ -1124,6 +1125,7 @@ newEffect{ local d = game.turn - eff.start_turn return util.bound(360 - d / eff.possible_end_turns * 360, 0, 360) end, + lists = 'break_with_step_up', activate = function(self, eff) eff.start_turn = game.turn eff.possible_end_turns = 10 * (eff.dur+1) @@ -1152,6 +1154,7 @@ newEffect{ local d = game.turn - eff.start_turn return util.bound(360 - d / eff.possible_end_turns * 360, 0, 360) end, + lists = 'break_with_step_up', activate = function(self, eff) eff.start_turn = game.turn eff.possible_end_turns = 10 * (eff.dur+1) @@ -1281,14 +1284,14 @@ newEffect{ callbackOnHit = function(self, eff, cb, src) if not src then return cb.value end local share = cb.value * eff.sharePct - + -- deal the redirected damage as physical because I don't know how to preserve the damage type in a callback if not self.__grapling_feedback_damage then self.__grapling_feedback_damage = true DamageType:get(DamageType.PHYSICAL).projector(self or eff.src, eff.trgt.x, eff.trgt.y, DamageType.PHYSICAL, share) self.__grapling_feedback_damage = nil end - + return cb.value - share end, } @@ -1502,6 +1505,7 @@ newEffect{ parameters = { power=0.1 }, on_gain = function(self, err) return "#Target# speeds up.", "+Reflexive Dodging" end, on_lose = function(self, err) return "#Target# slows down.", "-Reflexive Dodging" end, + lists = 'break_with_step_up', activate = function(self, eff) eff.tmpid = self:addTemporaryValue("global_speed_add", eff.power) end, @@ -2653,6 +2657,7 @@ newEffect { }, status = "beneficial", on_lose = function(self, eff) return "#Target# loses speed.", "-Directed Speed" end, + lists = 'break_with_step_up', callbackOnMove = function(self, eff, moved, force, ox, oy) local angle_start = normalize_direction(math.atan2(self.y - eff.start_y, self.x - eff.start_x)) local angle_last = normalize_direction(math.atan2(self.y - eff.last_y, self.x - eff.last_x)) -- GitLab