Index: game/modules/tome/dialogs/orders/Talents.lua =================================================================== --- game/modules/tome/dialogs/orders/Talents.lua (revision 0) +++ game/modules/tome/dialogs/orders/Talents.lua (revision 0) @@ -0,0 +1,116 @@ +-- TE4 - T-Engine 4 +-- Copyright (C) 2009, 2010 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +require "engine.class" +local Dialog = require "engine.ui.Dialog" +local ListColumns = require "engine.ui.ListColumns" +local Textzone = require "engine.ui.Textzone" +local TextzoneList = require "engine.ui.TextzoneList" +local Separator = require "engine.ui.Separator" +local GetQuantity = require "engine.dialogs.GetQuantity" + +module(..., package.seeall, class.inherit(Dialog)) + +function _M:init(actor, def) + self.actor = actor + self.def = def + Dialog.init(self, "Set talent weights:", math.max(800, game.w * 0.8), math.max(600, game.h * 0.8)) + + self.c_tut = Textzone.new{width=math.floor(self.iw / 2 - 10), height=1, auto_height=true, no_color_bleed=true, text=([[ +%s is listening attentively, and wants to know what talents to use. +You can modify the tactical weights of various talents to increase or decrease their use. The weights are multiplicative (zero will turn the talent off) and relative (changing everything to a weight of 2 will not alter how talents are used relative to each other). +Word travels fast in Maj'Eyal, and if %s is a summon all future summons of the same type will remember your preferences. +]]):format(actor.name:capitalize(), actor.name)} + self.c_desc = TextzoneList.new{width=math.floor(self.iw / 2 - 10), height=self.ih, no_color_bleed=true} + + self.c_list = ListColumns.new{width=math.floor(self.iw / 2 - 10), height=self.ih - 10, sortable=true, scrollbar=true, columns={ + {name="", width={20,"fixed"}, display_prop="char", sort="id"}, + {name="Talent Name", width=72, display_prop="name", sort="name"}, + {name="Weight", width=20, display_prop="multiplier", sort="multiplier"}, + }, list={}, fct=function(item) self:use(item) end, select=function(item, sel) self:select(item) end} + + self:generateList() + + self:loadUI{ + {left=0, top=0, ui=self.c_list}, + {right=0, top=self.c_tut.h + 20, ui=self.c_desc}, + {right=0, top=0, ui=self.c_tut}, + {hcenter=0, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}}, + } + self:setFocus(self.c_list) + self:setupUI() + + self.key:addCommands{ + __TEXTINPUT = function(c) + if self.list and self.list.chars[c] then + self:use(self.list[self.list.chars[c]]) + end + end, + } + self.key:addBinds{ + EXIT = function() + -- Store the ai_talents in the summoner + if self.actor.summoner then + self.actor.summoner.stored_ai_talents = self.actor.summoner.stored_ai_talents or {} + self.actor.summoner.stored_ai_talents[self.actor.name] = self.actor.ai_talents + end + game:unregisterDialog(self) + end, + } +end + +function _M:use(item) + if not item then return end + + -- Update the multiplier + if not self.actor.ai_talents then + self.actor.ai_talents = {} + end + game:registerDialog(GetQuantity.new("Enter the talent weight multiplier", "0 is off, 1 is normal", item.multiplier, nil, function(qty) + self.actor.ai_talents[item.tid] = qty + self:generateList() + end), 1) +end + +function _M:select(item) + if item then + self.c_desc:switchItem(item, item.desc) + end +end + +function _M:generateList() + local list = {} + for tid, lvl in pairs(self.actor.talents) do + local t = self.actor:getTalentFromId(tid) + if t.mode ~= "passive" and t.hide ~= "true" then + local multiplier = self.actor.ai_talents and self.actor.ai_talents[tid] or 1 + list[#list+1] = {id=#list+1, name=t.name:capitalize(), multiplier=multiplier, tid=tid, desc=self.actor:getTalentFullDescription(t)} + end + end + + local chars = {} + for i, v in ipairs(list) do + v.char = self:makeKeyChar(i) + chars[self:makeKeyChar(i)] = i + end + list.chars = chars + + self.list = list + self.c_list:setList(list) +end Index: game/modules/tome/dialogs/PartyOrder.lua =================================================================== --- game/modules/tome/dialogs/PartyOrder.lua (revision 2804) +++ game/modules/tome/dialogs/PartyOrder.lua (working copy) @@ -29,6 +29,7 @@ leash = {1, function(actor) return ("Set maximum wander distance [current: %d]"):format(actor.ai_state.tactic_leash) end}, behavior = {2, function(actor) return ("Set behavior [current: %s]"):format(actor.ai_tactic.type or "default") end}, follow = {3, function(actor) return ("Follow party leader [current: %s]"):format(actor.ai_state.tactic_follow_leader and "yes" or "no") end}, + talents = {4, function(actor) return ("Set talent weights") end}, } function _M:init(actor, def) Index: game/modules/tome/class/Party.lua =================================================================== --- game/modules/tome/class/Party.lua (revision 2804) +++ game/modules/tome/class/Party.lua (working copy) @@ -261,6 +261,8 @@ end) elseif order == "behavior" then game:registerDialog(require("mod.dialogs.orders."..order:capitalize()).new(actor, def)) + elseif order == "talents" then + game:registerDialog(require("mod.dialogs.orders."..order:capitalize()).new(actor, def)) ------------------------------------------- -- Escort specifics Index: game/modules/tome/class/Actor.lua =================================================================== --- game/modules/tome/class/Actor.lua (revision 2804) +++ game/modules/tome/class/Actor.lua (working copy) @@ -161,9 +161,6 @@ t.money = t.money or 0 - -- Default melee barehanded damage - self.combat = { dam=1, atk=1, apr=0, dammod={str=1} } - engine.Actor.init(self, t, no_default) engine.interface.ActorInventory.init(self, t) engine.interface.ActorTemporaryEffects.init(self, t) @@ -176,6 +173,10 @@ engine.interface.ActorFOV.init(self, t) mod.class.interface.ActorInscriptions.init(self, t) + -- Default melee barehanded damage + self.combat = self.combat or { dam=1, atk=1, apr=0, dammod={str=1} } + self.talents[self.T_ATTACK] = self.talents[self.T_ATTACK] or 1 + self:resetCanSeeCache() end Index: game/modules/tome/class/interface/Combat.lua =================================================================== --- game/modules/tome/class/interface/Combat.lua (revision 2804) +++ game/modules/tome/class/interface/Combat.lua (working copy) @@ -33,7 +33,7 @@ local reaction = self:reactionToward(target) if reaction < 0 then if target.encounterAttack and self.player then self:onWorldEncounter(target) return end - return self:attackTarget(target) + return self:useTalent(self.T_ATTACK, nil, nil, nil, target) elseif reaction >= 0 then -- Talk ? if self.player and target.can_talk then Index: game/modules/tome/ai/tactical.lua =================================================================== --- game/modules/tome/ai/tactical.lua (revision 2804) +++ game/modules/tome/ai/tactical.lua (working copy) @@ -14,14 +14,15 @@ local t_avail = false print(self.name, self.uid, "tactical ai talents testing", t.name, tid) if t.tactical then - local tg = self:getTalentTarget(t) or {type=util.getval(t.direct_hit, self, t) and "hit" or "bolt"} + local tg = self:getTalentTarget(t) + local default_tg = {type=util.getval(t.direct_hit, self, t) and "hit" or "bolt"} if t.mode == "activated" and not t.no_npc_use and not self:isTalentCoolingDown(t) and self:preUseTalent(t, true, true) and (not self:getTalentRequiresTarget(t) or ( hate and target_dist <= (self:getTalentRange(t) + self:getTalentRadius(t)) and - self:canProject(tg, self.ai_target.actor.x, self.ai_target.actor.y) and + self:canProject(tg or default_tg, self.ai_target.actor.x, self.ai_target.actor.y) and has_los )) then @@ -35,8 +36,8 @@ if t_avail then -- Project the talent if possible, counting foes and allies hit local nb_foes_hit, nb_allies_hit, nb_self_hit - if tg then - local typ = engine.Target:getType(tg) + if tg or self:getTalentRequiresTarget(t) then + local typ = engine.Target:getType(tg or default_tg) local target_actor = self.ai_target.actor or self nb_foes_hit = 0 nb_allies_hit = 0 @@ -59,17 +60,21 @@ end -- Evaluate the tactical weights and weight functions for tact, val in pairs(t.tactical) do - if not avail[tact] then avail[tact] = {} end - -- Save the tactic, if the talent is instant it gets a huge bonus - -- Note the addition of a less than one random value, this means the sorting will randomly shift equal values if type(val) == "function" then val = val(self, t, self.ai_target.actor) end - val = val * (1 + lvl / 5) + val = val * (self.ai_talents and self.ai_talents[t.id] or 1) * (1 + lvl / 5) if nb_foes_hit and (nb_foes_hit > 0 or nb_allies_hit > 0 or nb_self_hit > 0) then - val = val * math.max(0.01, nb_foes_hit - ally_compassion * nb_allies_hit - self_compassion * nb_self_hit) + val = val * (nb_foes_hit - ally_compassion * nb_allies_hit - self_compassion * nb_self_hit) end - avail[tact][#avail[tact]+1] = {val=((t.no_energy==true) and val * 10 or val) + rng.float(0, 0.9), tid=tid, nb_foes_hit=nb_foes_hit, nb_allies_hit=nb_allies_hit, nb_self_hit=nb_self_hit} - print(self.name, self.uid, "tactical ai talents can use", t.name, tid, tact, "weight", avail[tact][#avail[tact]].val) - ok = true + -- Only take values greater than 0... allows the ai_talents to turn talents off + if val > 0 then + if not avail[tact] then avail[tact] = {} end + -- Save the tactic, if the talent is instant it gets a huge bonus + -- Note the addition of a less than one random value, this means the sorting will randomly shift equal values + val = ((t.no_energy==true) and val * 10 or val) + rng.float(0, 0.9) + avail[tact][#avail[tact]+1] = {val=val, tid=tid, nb_foes_hit=nb_foes_hit, nb_allies_hit=nb_allies_hit, nb_self_hit=nb_self_hit} + print(self.name, self.uid, "tactical ai talents can use", t.name, tid, tact, "weight", avail[tact][#avail[tact]].val) + ok = true + end end end end @@ -254,6 +259,7 @@ end) newAI("tactical", function(self) + if self.debugme then require "remdebug.engine" remdebug.engine.start() end local targeted = self:runAI(self.ai_state.ai_target or "target_simple") -- Keep your distance Index: game/modules/tome/ai/target.lua =================================================================== --- game/modules/tome/ai/target.lua (revision 2804) +++ game/modules/tome/ai/target.lua (working copy) @@ -39,7 +39,7 @@ ((act.lite or 0) > 0) or -- Otherwise check if we can see it with our "senses" - (self:canSee(act) and self.fov.actors[act].sqdist <= sqsense) + (self:canSee(act) and (self.fov.actors[act].sqdist <= sqsense) or game.level.map.lites(act.x, act.y)) ) then self.ai_target.actor = act Index: game/modules/tome/data/talents/spells/explosives.lua =================================================================== --- game/modules/tome/data/talents/spells/explosives.lua (revision 2804) +++ game/modules/tome/data/talents/spells/explosives.lua (working copy) @@ -34,6 +34,7 @@ requires_target = true, target = function(self, t) local ammo = self:hasAlchemistWeapon() + if not ammo then return end -- Using friendlyfire, although this could affect escorts etc. local friendlyfire = true local prot = self:getTalentLevelRaw(self.T_ALCHEMIST_PROTECTION) * 20 @@ -191,7 +192,14 @@ direct_hit = true, requires_target = true, target = function(self, t) - return {type="ball", range=self:getTalentRange(t)+(ammo.alchemist_bomb.range or 0), radius=self:getTalentRadius(t), talent=t} + local ammo = self:hasAlchemistWeapon() + -- Using friendlyfire, although this could affect escorts etc. + local friendlyfire = true + local prot = self:getTalentLevelRaw(self.T_ALCHEMIST_PROTECTION) * 20 + if prot > 0 then + friendlyfire = 100 - prot + end + return {type="ball", range=self:getTalentRange(t)+(ammo and ammo.alchemist_bomb and ammo.alchemist_bomb.range or 0), radius=self:getTalentRadius(t), friendlyfire=friendlyfire, talent=t} end, tactical = { ATTACKAREA = 2, DISABLE = 2 }, computeDamage = function(self, t, ammo) Index: game/modules/tome/data/talents/spells/golemancy.lua =================================================================== --- game/modules/tome/data/talents/spells/golemancy.lua (revision 2804) +++ game/modules/tome/data/talents/spells/golemancy.lua (working copy) @@ -137,7 +137,7 @@ self.alchemy_golem = game.zone:finishEntity(game.level, "actor", makeGolem()) game.party:addMember(self.alchemy_golem, { control="full", type="golem", title="Golem", - orders = {leash=true, follow=true}, -- behavior=true}, + orders = {leash=true, follow=true, talents=true}, -- behavior=true}, }) if not self.alchemy_golem then return end self.alchemy_golem.faction = self.faction Index: game/modules/tome/data/talents/corruptions/bone.lua =================================================================== --- game/modules/tome/data/talents/corruptions/bone.lua (revision 2804) +++ game/modules/tome/data/talents/corruptions/bone.lua (working copy) @@ -70,7 +70,7 @@ target:pull(self.x, self.y, tg.range) - DamageType:get(DamageType.PHYSICAL).projector(self, nx, ny, DamageType.PHYSICAL, dam) + DamageType:get(DamageType.PHYSICAL).projector(self, px, py, DamageType.PHYSICAL, dam) if target:checkHit(self:combatSpellpower(), target:combatPhysicalResist(), 0, 95, 10) and target:canBe("pin") then target:setEffect(target.EFF_PINNED, math.floor(3 + self:getTalentLevel(t)), {}) else Index: game/modules/tome/data/talents/misc/inscriptions.lua =================================================================== --- game/modules/tome/data/talents/misc/inscriptions.lua (revision 2804) +++ game/modules/tome/data/talents/misc/inscriptions.lua (working copy) @@ -520,9 +520,12 @@ local data = self:getInscriptionData(t.short_name) return data.range end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, action = function(self, t) local data = self:getInscriptionData(t.short_name) - local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + local tg = self:getTalentTarget(t) self:projectile(tg, self.x, self.y, DamageType.ACID, data.power + data.inc_stat) game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_acid", {radius=tg.radius}) game:playSoundNear(self, "talents/slime") @@ -550,9 +553,12 @@ local data = self:getInscriptionData(t.short_name) return data.range end, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, action = function(self, t) local data = self:getInscriptionData(t.short_name) - local tg = {type="beam", range=self:getTalentRange(t), talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local dam = data.power + data.inc_stat Index: game/modules/tome/data/talents/misc/misc.lua =================================================================== --- game/modules/tome/data/talents/misc/misc.lua (revision 2804) +++ game/modules/tome/data/talents/misc/misc.lua (working copy) @@ -28,6 +28,31 @@ load("/data/talents/misc/inscriptions.lua") load("/data/talents/misc/npcs.lua") +-- Default melee attack +newTalent{ + name = "Attack", + type = {"base/class", 1}, + no_energy = "fake", + hide = true, + points = 1, + range = 1, + message = false, + requires_target = true, + target = {type="hit", range=1}, + tactical = { ATTACK = 1 }, + action = function(self, t) + local tg = self:getTalentTarget(t) + local x, y, target = self:getTarget(tg) + if not target then return end + + self:attackTarget(target) + return true + end, + info = function(self, t) + return ([[Hack and slash, baby!]]) + end, +} + --mindslayer resource newTalent{ name = "Psi Pool", Index: game/modules/tome/data/talents/gifts/summon-utility.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-utility.lua (revision 2804) +++ game/modules/tome/data/talents/gifts/summon-utility.lua (working copy) @@ -97,9 +97,11 @@ range = 10, requires_target = true, tactical = { DEFEND = 2, PROTECT = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -171,10 +173,12 @@ cooldown = 10, range = 10, tactical = { ATTACK = 1, DISABLE = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, requires_target = true, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end Index: game/modules/tome/data/talents/gifts/summon-melee.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-melee.lua (revision 2804) +++ game/modules/tome/data/talents/gifts/summon-melee.lua (working copy) @@ -29,9 +29,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -100,9 +102,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 1, EQUILIBRIUM = 1, }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -182,9 +186,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 2, DISABLE = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -258,10 +264,12 @@ cooldown = 20, range = 10, tactical = { ATTACK = 3, DISABLE = 1 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, requires_target = true, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end Index: game/modules/tome/data/talents/gifts/summon-distance.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-distance.lua (revision 2804) +++ game/modules/tome/data/talents/gifts/summon-distance.lua (working copy) @@ -148,9 +148,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -224,9 +226,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -301,9 +305,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 1, DISABLE = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end @@ -379,9 +385,11 @@ range = 10, requires_target = true, tactical = { ATTACK = 2, DISABLE = 2 }, + on_pre_use = function(self, t, silent) + if not self:canBe("summon") and not silent then game.logPlayer(self, "You can not summon, you are suppressed!") return end + return not checkMaxSummon(self, silent) + end, action = function(self, t) - if not self:canBe("summon") then game.logPlayer(self, "You can not summon, you are suppressed!") return end - if checkMaxSummon(self) then return end local tg = {type="bolt", nowarning=true, range=self:getTalentRange(t), nolock=true, talent=t} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end Index: game/modules/tome/data/talents/gifts/gifts.lua =================================================================== --- game/modules/tome/data/talents/gifts/gifts.lua (revision 2804) +++ game/modules/tome/data/talents/gifts/gifts.lua (working copy) @@ -63,15 +63,19 @@ load("/data/talents/gifts/cold-drake.lua") load("/data/talents/gifts/storm-drake.lua") -function checkMaxSummon(self) +function checkMaxSummon(self, silent) local nb = 0 - for _, e in pairs(game.level.entities) do - if e.summoner and e.summoner == self and e.wild_gift_summon then nb = nb + 1 end + if not game.party then return end + -- Count party members + for act, def in pairs(game.party.members) do + if act.summoner and act.summoner == self and act.wild_gift_summon then nb = nb + 1 end end local max = math.max(1, math.floor(self:getCun() / 10)) if nb >= max then - game.logPlayer(self, "#PINK#You can not summon any more; you have too many summons already (%d). You can increase the limit with higher Cunning(+1 for every 10).", nb) + if not silent then + game.logPlayer(self, "#PINK#You can not summon any more; you have too many summons already (%d). You can increase the limit with higher Cunning(+1 for every 10).", nb) + end return true else return false @@ -85,6 +89,8 @@ m.unused_talents_types = 0 m.ai_state = m.ai_state or {} m.ai_state.tactic_leash = 100 + -- Try to use stored AI talents to preserve tweaking over multiple summons + m.ai_talents = self.stored_ai_talents and self.stored_ai_talents[m.name] or {} local main_weapon = self:getInven("MAINHAND")[1] m:attr("combat_apr", self:combatAPR(main_weapon)) m.inc_damage = table.clone(self.inc_damage, true) @@ -98,7 +104,7 @@ control=self:knowTalent(self.T_SUMMON_CONTROL) and "full" or "no", type="summon", title="Summon", - orders = {leash=true, follow=true}, + orders = {leash=true, follow=true, talents=true}, on_control = function(self) local summoner = self.summoner self:setEffect(self.EFF_SUMMON_CONTROL, 1000, {incdur=2 + summoner:getTalentLevel(self.T_SUMMON_CONTROL) * 3, res=summoner:getCun(7, true) * summoner:getTalentLevelRaw(self.T_SUMMON_CONTROL)})