From 4338b347c8cd46588325919f64328d2081b56f65 Mon Sep 17 00:00:00 2001 From: Hachem_Muche <Hachem_Muche@stanfordalumni.org> Date: Mon, 20 Apr 2015 12:35:59 -0700 Subject: [PATCH] Added support for actor-specific checks for object usability and ai test. Object use talent IDs are remembered for previously equipped objects if possible. (facilitates hotkey settings) Added support for automatic use of object use talents via the Talent Use menu. Added support for ai_talents weights (remembered by reference to individual objects) via party-control interface. --- game/modules/tome/class/Object.lua | 6 + game/modules/tome/class/Player.lua | 3 +- .../tome/class/interface/ActorObjectUse.lua | 289 +++++++++++++----- .../tome/data/general/objects/egos/staves.lua | 2 + .../general/objects/egos/totems-powers.lua | 1 - .../general/objects/egos/wands-powers.lua | 1 + 6 files changed, 231 insertions(+), 71 deletions(-) diff --git a/game/modules/tome/class/Object.lua b/game/modules/tome/class/Object.lua index 66ad2215f6..bac90a1676 100644 --- a/game/modules/tome/class/Object.lua +++ b/game/modules/tome/class/Object.lua @@ -139,6 +139,12 @@ function _M:canUseObject(who) return true, "Object can be used." end +--- Does the actor have inadequate AI to use this object intelligently? +-- @param who = the potential object user +function _M:restrictAIUseObject(who) + return not (who.ai == "tactical" or who.ai_real == "tactical" or (who.ai_state and who.ai_state.ai_party) == "tactical") +end + function _M:useObject(who, ...) -- Make sure the object is registered with the game, if need be if not game:hasEntity(self) then game:addEntity(self) end diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 355369e68f..a5dac8068b 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -857,7 +857,8 @@ function _M:automaticTalents() local t = self.talents_def[tid] local spotted = spotHostiles(self, true) local cd = self:getTalentCooldown(t) or 0 - local turns_used = util.getval(t.no_energy, self, t) == true and 0 or 1 + local turns_used = util.getval(t.no_energy, self, t) == true and 0 or 1 +-- if cd <= turns_used and t.mode ~= "sustained" then if cd <= turns_used and t.mode ~= "sustained" and not t.is_object_use then game.logPlayer(self, "Automatic use of talent %s #DARK_RED#skipped#LAST#: cooldown too low (%d).", t.name, cd) elseif (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 diff --git a/game/modules/tome/class/interface/ActorObjectUse.lua b/game/modules/tome/class/interface/ActorObjectUse.lua index f985b29d21..e484ba5531 100644 --- a/game/modules/tome/class/interface/ActorObjectUse.lua +++ b/game/modules/tome/class/interface/ActorObjectUse.lua @@ -31,7 +31,7 @@ This talent is similar to normal talents, but translates the object definition a The activatable object may have either .use_power (most uniquely defined powers), .use_simple (uniquely defined, mostly for consumables), or .use_talent (many charms and other objects that activate a talent as their power) If more than one of the fields is defined only one will be used: use_power before use_simple before use_talent. Energy use matches the object (based on standard action speed) -Objects with a .use_power field are usable unless the .no_npc_use flag is set. +Objects with a .use_power field are usable unless the .no_npc_use (which may be a function(obj, who)) is true. For these items: use_power = { name = constant or function(object, who), description of the power for the user @@ -48,10 +48,10 @@ For these items: } The raw talent level of the activation talent(defined here) equals the material level of the object. -Objects with a .use_simple field (uniquely defined, mostly for consumables), are not usable unless .allow_npc_use is true or the .tactical field is defined. +Objects with a .use_simple field (uniquely defined, mostly for consumables), are not usable unless .allow_npc_use (which can be a function(obj, who) is true or the .tactical field is defined. They otherwise use the same format as .use_power. -Objects with a .use_talent field use a defined talent as their power. They are usable if .allow_npc_use is true or talent.no_npc_use is not true +Objects with a .use_talent field use a defined talent as their power. They are usable if .allow_npc_use (which can be a function(obj, who)) is true or talent.no_npc_use (may be a function(obj, who) )is not true For these items: use_talent = { id = string, talent_id to use (i.e. Talents.T_ILLUMINATE) @@ -70,6 +70,8 @@ For these items: local base_talent_name = "Activate Object" _M.max_object_use_talents = 50 --(allows for approximately 15 items worn and 35 items carried.) +--_M.max_object_use_talents = 3 + -- returns tid, short_name local useObjectTalentId = function(base_name, num) num = num or 1 @@ -81,13 +83,13 @@ end --- Init object use tables -- Note: this applies to all actors but is only used for npcs (including uncontrolled party members) function _M:init(t) - self.useable_objects_data = self.useable_objects_data or {} + self.object_talent_data = self.object_talent_data or {} end -- call a function within an object talent -- returning values from the object data table, (possibly defaulting to those specified in a talent definition if appropriate) function _M:callObjectTalent(tid, what, ...) - local data = self.useable_objects_data and self.useable_objects_data[tid] + local data = self.object_talent_data and self.object_talent_data[tid] if not data then return end local item = data[what] @@ -113,7 +115,7 @@ print(("[callObjectTalent] %s calculating use_talent (%s) %s for talent level %0 end end --- base Object Actiation talent template +-- base Object Activation talent template _M.useObjectBaseTalent ={ name = base_talent_name, type = {"misc/objects", 1}, @@ -122,7 +124,7 @@ _M.useObjectBaseTalent ={ never_fail = true, -- most actor status effects will not prevent use innate = true, -- make sure this talent can't be put on cooldown by other talents or effects display_name = function(self, t) - local data = self.useable_objects_data[t.id] + local data = self.object_talent_data[t.id] if not (data and data.obj and data.obj:isIdentified()) then return "Activate an object" end local objname = data.obj:getName({no_add_name = true, do_color = true}) return "Activate: "..objname @@ -132,12 +134,14 @@ _M.useObjectBaseTalent ={ no_energy = function(self, t) -- energy use based on object return self:callObjectTalent(t.id, "no_energy") end, +-- cooldown = function(self, t) return 1 end , +-- fixed_cooldown = true, getObject = function(self, t) - return self.useable_objects_data and self.useable_objects_data[t.id] and self.useable_objects_data[t.id].obj + return self.object_talent_data and self.object_talent_data[t.id] and self.object_talent_data[t.id].obj end, on_pre_use = function(self, t, silent, fake) -- test for item usability, not on COOLDOWN, etc. if self.no_inventory_access then return end - local data = self.useable_objects_data[t.id] + local data = self.object_talent_data[t.id] if not data then print("[ActorObjectUse] ERROR: Talent ", t.name, " has no object data") return false @@ -163,7 +167,7 @@ _M.useObjectBaseTalent ={ return true end, on_pre_use_ai = function(self, t, silent, fake) - local data = self.useable_objects_data[t.id] + local data = self.object_talent_data[t.id] if data.on_pre_use_ai or (data.tid and self.talents_def[data.tid].on_pre_use_ai) then return self:callObjectTalent(t.id, "on_pre_use_ai", silent, fake) end @@ -186,7 +190,7 @@ _M.useObjectBaseTalent ={ return self:callObjectTalent(t.id, "target") end, action = function(self, t) - local data = self.useable_objects_data[t.id] + local data = self.object_talent_data[t.id] print(("##[ActorObjectUse]Pre Action Object (%s [uid %d]) Activation by %s [uid %d, energy %d]"):format(data.obj.name, data.obj.uid, self.name, self.uid, self.energy.value)) local obj, inven = data.obj, data.inven_id local ret @@ -213,10 +217,41 @@ print(("##[ActorObjectUse]Post No Use Object: Actor %s (%d energy) Object %s, ") coroutine.resume(co) end, info = function(self, t) - local data = self.useable_objects_data[t.id] - if not (data and data.obj and data.obj:isIdentified()) then return "Activate an object." end - local objname = (data and data.obj and data.obj:getName({do_color = true})) or "(no object)" - local usedesc = (data and data.obj and data.obj:isIdentified() and data.obj:getUseDesc(self)) or "" + local data = self.object_talent_data + local o = t.getObject(self, t) + -- forget settings for objects no longer in the party + if data.cleanup then + for o, r in pairs(data.cleanup) do +game.log("---%s: %s tagged for cleanup", self.name, o.name) + local found = false + for j, mem in ipairs(game.party.m_list) do + if mem:findInAllInventoriesByObject(o) then +game.log("---Found %s with %s", o.name, mem.name) + found = true + break + end + end + if not found then +game.log("#YELLOW# -- Cleaning up: %s", tostring(o.name)) + for j, mem in ipairs(game.party.m_list) do + -- clean up local stored object data + if mem.object_talent_data then mem.object_talent_data[o] = nil end + if mem.ai_talents then mem.ai_talents[o] = nil end + -- clean up summoner stored_ai_talents object data + if mem.stored_ai_talents then + for memname, tt in pairs(mem.stored_ai_talents) do + tt[o] = nil +-- and self.summoner.stored_ai_talents[self.name] then self.summoner.stored_ai_talents[self.name][o] = nil end + end + end + end + end + end + data.cleanup = nil + end + if not (o and o:isIdentified()) then return "Activate an object." end + local objname = o:getName({do_color = true}) or "(no object)" + local usedesc = o and o:getUseDesc(self) or "" return ([[Use %s: %s]]):format(objname, usedesc) @@ -246,51 +281,83 @@ function _M:useObjectTalent(base_name, num) end return t.id, t end +--[[ +local function save_object_use_data(self, o, tid) + self.object_talent_data[o] = {tid = tid, talents_auto = self:isTalentAuto(tid), talents_confirm_use = self:isTalentConfirmable()} --.talents_auto, .talents_confirm_use, .ai_talents +end +local function recover_object_use_data(self, o, tid) + if self.object_talent_data[o] then + self:setTalentAuto(tid, true, self.object_talent_data[o].talents_auto) + self:setTalentConfirmable(tid, self.object_talent_data[o].talents_confirm_use) + --.ai_talents? + end +end +--]] --- Set up an object for actor use via talent interface -- @param o = object to set up to use -- @param inven_id = id of inventory holding object -- @param slot = inventory position of object -- @param returns false or o, talent id, talent definition, talent level if the item is usable function _M:useObjectEnable(o, inven_id, slot, base_name) - if not o:canUseObject() or o.quest or o.lore then -- don't enable certain objects (lore, quest) + if not o:canUseObject() or o.quest or o.lore or (o:wornInven() and not o.wielded and not o.use_no_wear) then -- don't enable certain objects (lore, quest) print(("##[ActorObjectUse] Object %s is ineligible for talent interface"):format(o.name)) return - end -print(("[ActorObjectUse] useObjectEnable: o: %s, inven/slot = %s/%s"):format(o and o.name or "none", inven_id, slot)) - self.useable_objects_data = self.useable_objects_data or {} -- for older actors - -- Check allowance - local data = self.useable_objects_data - if data[o] and o == data[data[o]].obj then -- already enabled - return o, data[o], self:getTalentFromId(data[o]) end + +--print(("[ActorObjectUse] useObjectEnable: o: %s, by %s inven/slot = %s/%s"):format(o and o.name or "none", self.name, inven_id, slot)) +game.log(("#YELLOW#[ActorObjectUse] useObjectEnable: o: %s, by %s inven/slot = %s/%s"):format(o and o.name or "none", self.name, inven_id, slot)) + self.object_talent_data = self.object_talent_data or {} -- for older actors + local data = self.object_talent_data +-- if data[o] and o == data[data[o]].obj then -- already enabled +-- return o, data[o], self:getTalentFromId(data[o]) +-- end local tid, t, place + local oldobjdata = data[o] + if oldobjdata then + if oldobjdata.tid and data[oldobjdata.tid] and data[oldobjdata.tid].obj == o then --object already enabled + return o, data[o], self:getTalentFromId(data[o]) + elseif not self:knowTalent(oldobjdata.tid) then -- use old talent level + tid = oldobjdata.tid + end + end + if not inven_id then -- find the object if needed place, inven_id, slot = self:findInAllInventoriesByObject(o) end - if o:wornInven() and not o.wielded and not o.use_no_wear then - return false - end - - local i = #data + 1 - local talent_level = false - if i <= self.max_object_use_talents then --find an unused talentid - -- find the next open object use talent - for j = 1, self.max_object_use_talents do - tid = useObjectTalentId(base_name, j) - if not self:knowTalent(tid) then break end + local talent_level = false +-- use last used talent id? + if not tid then --find an unused talentid (if possible) + data.last_talent = data.last_talent or 0 + local tries = self.max_object_use_talents + repeat + tries = tries - 1 + data.last_talent = data.last_talent%self.max_object_use_talents + 1 + tid = useObjectTalentId(base_name, data.last_talent) + if not self:knowTalent(tid) then break else tid = nil end + until tries <= 0 +--[[ + local i = #data + 1 + if i <= self.max_object_use_talents then + -- find the next open object use talent + for j = 1, self.max_object_use_talents do + tid = useObjectTalentId(base_name, j) + if not self:knowTalent(tid) then break else tid = nil end + end end - talent_level = self:useObjectSetData(tid, o) - if not talent_level then return false end --includes checks for npc useability - data[i] = tid - data[tid].inven_id = inven_id - data[tid].slot = slot - self:learnTalent(tid, true, talent_level) - self.talents[tid] = talent_level - else - return false + --]] end + if not tid then return false end + + talent_level = self:useObjectSetData(tid, o) + if not talent_level then return false end --includes checks for npc useability +-- data[i] = tid + data[tid].inven_id = inven_id + data[tid].slot = slot + self:learnTalent(tid, true, talent_level) +-- self.talents[tid] = talent_level + -- temporary hotkeys for testing t=self:getTalentFromId(tid) -- Hotkey @@ -307,31 +374,80 @@ end -- disable object use (when object is removed from inventory) function _M:useObjectDisable(o, inven_id, slot, tid, base_name) ---game.log("#YELLOW# useObjectDisable: o: %s, inven/slot = %s/%s {tid = %s}", o and o.name or "none", inven_id, slot, tid) + self.object_talent_data = self.object_talent_data or {} -- for older versions base_name = base_name or base_talent_name if not (o or tid) then --clear all object use data and unlearn all object use talents for i = 1, self.max_object_use_talents do tid = useObjectTalentId(base_name, i) self:unlearnTalentFull(tid) end - self.useable_objects_data = {} + self.object_talent_data = {} return end - + local data = self.object_talent_data if o then - tid = tid or self.useable_objects_data[o] + tid = tid or data[o] and data[o].tid + if (tid and data[tid] and data[tid].obj) ~= o then tid = nil end +game.log("%s tagged for CLEANUP", o.name) + data.cleanup = data.cleanup or {} -- set up object to check for cleanup later + data.cleanup[o]=true else - o = self.useable_objects_data[tid] and self.useable_objects_data[tid].obj + o = data[tid] and data[tid].obj + end +game.log("#YELLOW# useObjectDisable: o: %s, by %s inven/slot = %s/%s (tid = %s)", o and o.name or "none", self.name, inven_id, slot, tid) +-- if o then data[o]=nil end +--[[ + if o then -- keep old object preferences (clean up) +-- game:onTickEnd(function() + if not game.party:findInAllPartyInventoriesBy("name", o.name) then +game.log("Forgetting values") + data[o]=nil + elseif tid then -- save settings for object in case it's enabled again later +-- save_object_use_data(self, o, tid) +game.log("Remembering values") + data[o] = {tid = tid, talents_auto = self:isTalentAuto(tid), talents_confirm_use = self:isTalentConfirmable()} --.talents_auto, .talents_confirm_use, .ai_talents + end +-- end) end - if o then self.useable_objects_data[o]=nil end +--]] +--[[ + if o then -- keep old object preferences (clean up) +-- game:onTickEnd(function() + if tid then -- save settings for object in case it's enabled again later +-- save_object_use_data(self, o, tid) +game.log("Remembering values") + data[o] = {tid = tid, talents_auto = self:isTalentAuto(tid), talents_confirm_use = self:isTalentConfirmable()} --.talents_auto, .talents_confirm_use, .ai_talents + end + data.cleanup = table.merge(data.cleanup or {}, {o}) -- set up to check later +-- end) + end +--]] --auto use/confirmable talents? --self.talents_auto --self.talents_confirm_use if tid then - if self.useable_objects_data[tid].old_talent_level then self.talents[tid] = self.useable_objects_data[tid].old_talent_level end - self.useable_objects_data[tid]=nil - table.removeFromList(self.useable_objects_data, tid) - self.talents[tid] = 1 + if data[tid] and data[tid].old_talent_level then self.talents[tid] = data[tid].old_talent_level end + data[tid]=nil + table.removeFromList(data, tid) + if o then + data[o] = {tid = tid, + talents_auto = self:isTalentAuto(tid), + talents_confirm_use = self:isTalentConfirmable(tid), + ai_talent = self.ai_talents and self.ai_talents[tid],} + -- store with summoner? + if self.summoner and self.summoner.stored_ai_talents and self.summoner.stored_ai_talents[self.name] then + self.summoner.stored_ai_talents[self.name][o] = self.ai_talents and self.ai_talents[tid] +-- data[o].ai_talents = self.ai_talents + end +-- summoner_ai_talents = self.summoner and self.summoner.stored_ai_talents and self.summoner.stored_ai_talents[tid]} --.talents_auto, .talents_confirm_use, .ai_talents +game.log(" #YELLOW# %s Saving talent settings for %s", self.name, tid) +-- data.cleanup = data.cleanup or {} +-- data.cleanup[o]=true -- set up to check later + end +-- self.talents[tid] = 1 + if self.ai_talents then self.ai_talents[tid] = nil end + self:setTalentConfirmable(tid, false) + self:setTalentAuto(tid) end self:unlearnTalentFull(tid) end @@ -347,7 +463,7 @@ end -- function to call base talent-defined tactical functions from the object talent (with overridden talent level) local AOUtactical_translate = function(self, t, aitarget, tactic) -- called by mod.ai.tactical - local data = self.useable_objects_data[t.id] + local data = self.object_talent_data[t.id] local tal = self.talents_def[data.tid] if data.old_talent_level then self.talents[tal.id]=data.old_talent_level end -- recover if talent previously crashed data.old_talent_level = self.talents[tal.id]; self.talents[tal.id]=data.talent_level @@ -356,6 +472,15 @@ local AOUtactical_translate = function(self, t, aitarget, tactic) -- called by m return ret end + +-- if self.summoner and self.summoner.stored_ai_talents and self.summoner.stored_ai_talents[self.name] and self.summoner.stored_ai_talents[self.name][o] then +-- self.ai_talents = self.ai_talents or {} +-- self.ai_talents[tid} = self.summoner.stored_ai_talents[self.name][o] +-- self.summoner.stored_ai_talents[self.name][o] = self.ai_talents and self.ai_talents[tid] +-- data[o].ai_talents = self.ai_talents +-- end + + --- sets up the object data for the talent -- @param tid = the talent id -- @param o = the usable object @@ -364,33 +489,59 @@ end -- o.use_simple is usable if use_simple.allow_npc_use is set or use_simple.tactical is defined -- returns raw talent level if successful function _M:useObjectSetData(tid, o) - self.useable_objects_data[tid] = {obj = o} - self.useable_objects_data[o] = tid - local data = self.useable_objects_data[tid] - local ok = false + self.object_talent_data[tid] = {obj = o} +-- self.object_talent_data[o] = tid +-- self.object_talent_data[o] = {tid = tid, talents_auto = self:isTalentAuto(tid), talents_confirm_use = self:isTalentConfirmable()} --.talents_auto, .talents_confirm_use, .ai_talents +-- recover_object_use_data(self, o, tid) + + if self.object_talent_data[o] then --get talent settings +game.log(" #YELLOW# Recalling talent settings for %s %s", tid, o.name) + self:setTalentAuto(tid, true, self.object_talent_data[o].talents_auto) + self:setTalentConfirmable(tid, self.object_talent_data[o].talents_confirm_use) + -- handle ai_talents weights + if self.summoner and self.summoner.stored_ai_talents and self.summoner.stored_ai_talents[self.name] and self.summoner.stored_ai_talents[self.name][o] then -- get summoner's tactical weight for this actor and object +game.log(" #YELLOW# Recalling summoner (%s) talent settings for %s %s", self.summoner.name, tid, self.name) + self.ai_talents = self.ai_talents or {} + self.ai_talents[tid] = self.summoner.stored_ai_talents[self.name][o] + elseif self.object_talent_data[o].ai_talent then -- get last used tactical weight for this object + self.ai_talents = self.ai_talents or {} + self.ai_talents[tid] = self.object_talent_data[o].ai_talent + end + self.object_talent_data[o].tid = tid + else + self.object_talent_data[o] = {tid = tid} + end +-- self.object_talent_data[o] = self.object_talent_data[o] or {} +-- self.object_talent_data[o].tid = tid + + local data = self.object_talent_data[tid] + local talent_level = false local power + + -- assign use data based on object power definition or used talent if o.use_power then -- power is a general power power = o.use_power - if not power.no_npc_use then - ok = o.material_level or 1 +-- if not power.no_npc_use then + if not util.getval(power.no_npc_use, o, self) then + talent_level = o.material_level or 1 end elseif o.use_simple then -- Generally for consumables power = o.use_simple - if power.allow_npc_use or power.tactical then - ok = o.material_level or 1 +-- if power.allow_npc_use or power.tactical then + if power.tactical or util.getval(power.allow_npc_use, o, self) then + talent_level = o.material_level or 1 end elseif o.use_talent then -- power is a talent local t = self:getTalentFromId(o.use_talent.id) local use_talent = o.use_talent - if t and t.mode == "activated" and (use_talent.allow_npc_use or not t.no_npc_use) then +-- if t and t.mode == "activated" and (use_talent.allow_npc_use or not t.no_npc_use) then + if t and t.mode == "activated" and (not t.no_npc_use or util.getval(use_talent.allow_npc_use, o, self)) then data.tid = o.use_talent.id data.talent_level = use_talent.level data.on_pre_use = use_talent.on_pre_use data.on_pre_use_ai = use_talent.on_pre_use_ai - -- tactical table override not currently supported data.tactical = use_talent.tactical or table.clone(t.tactical) - -- convert tactical table functions to use the talent reference if type(data.tactical) == "table" then for tact, val in pairs(data.tactical) do if type(val) == "function" then @@ -398,14 +549,14 @@ function _M:useObjectSetData(tid, o) end end end - ok = data.talent_level + talent_level = data.talent_level end else print("[ActorObjectUse]: ERROR, object", o.name, o.uid, "has no usable power") end data.no_energy = o.use_no_energy -- talent speed determined by object - if not ok then - self.useable_objects_data[o] = nil + if not talent_level then + self.object_talent_data[o] = nil data = nil elseif power then data.on_pre_use = power.on_pre_use @@ -418,5 +569,5 @@ function _M:useObjectSetData(tid, o) data.tactical = lowerTacticals(power.tactical) end end - return ok -- the raw talent level to use for ai + return talent_level -- the raw talent level to use for ai end diff --git a/game/modules/tome/data/general/objects/egos/staves.lua b/game/modules/tome/data/general/objects/egos/staves.lua index c2e7b7ac84..6b41e87b04 100644 --- a/game/modules/tome/data/general/objects/egos/staves.lua +++ b/game/modules/tome/data/general/objects/egos/staves.lua @@ -394,6 +394,7 @@ newEntity{ radius = function(self, who) return 1 + self.material_level end, target = function(self, who) return {type="ball", range=self.use_power.range, radius=self.use_power.radius(self, who), selffire=false} end, requires_target = true, + no_npc_use = function(self, who) return not self:restrictAIUseObject(who) end, -- don't let dumb ai blow up friends tactical = { ATTACKAREA = function(who, t, aitarget) local weapon = who:hasStaffWeapon() if not weapon or not weapon.combat then return 1 end @@ -522,6 +523,7 @@ newEntity{ radius = function(self, who) return 2*self.material_level end, requires_target = true, target = function(self, who) return {type="cone", range=self.use_power.range, radius=self.use_power.radius(self, who), selffire=false} end, + no_npc_use = function(self, who) return not self:restrictAIUseObject(who) end, -- don't let dumb ai blow up friends tactical = { ATTACKAREA = function(who, t, aitarget) local weapon = who:hasStaffWeapon() if not weapon or not weapon.combat then return 1 end diff --git a/game/modules/tome/data/general/objects/egos/totems-powers.lua b/game/modules/tome/data/general/objects/egos/totems-powers.lua index 25f157320b..62c484dd91 100644 --- a/game/modules/tome/data/general/objects/egos/totems-powers.lua +++ b/game/modules/tome/data/general/objects/egos/totems-powers.lua @@ -25,7 +25,6 @@ Totems *thorny skin ]] - newEntity{ name = " of cure ailments", addon=true, instant_resolve=true, keywords = {ailments=true}, diff --git a/game/modules/tome/data/general/objects/egos/wands-powers.lua b/game/modules/tome/data/general/objects/egos/wands-powers.lua index 9b532b7a86..a38ef69247 100644 --- a/game/modules/tome/data/general/objects/egos/wands-powers.lua +++ b/game/modules/tome/data/general/objects/egos/wands-powers.lua @@ -116,6 +116,7 @@ newEntity{ "T_GLOBAL_CD", {range = 5, requires_target = true, + no_npc_use = function(self, who) return not self:restrictAIUseObject(who) end, -- don't let dumb ai hurt friends target = function(self, who) return {type="wall", range=self.use_power.range, halflength=3, halfmax_spots=3+1} end, tactical = {ATTACKAREA = {FIRE = 2}}, damage = function(self, who) return self:getCharmPower(who) end -- GitLab