Index: game/engines/default/engine/Map.lua =================================================================== --- game/engines/default/engine/Map.lua (revision 2714) +++ game/engines/default/engine/Map.lua (working copy) @@ -782,7 +782,10 @@ -- @param dir the numpad direction of the effect, 5 for a ball effect -- @param overlay either a simple display entity to draw upon the map or a Particle class -- @param update_fct optional function that will be called each time the effect is updated with the effect itself as parameter. Use it to change radius, move around .... -function _M:addEffect(src, x, y, duration, damtype, dam, radius, dir, angle, overlay, update_fct, friendlyfire) +-- @param selffire percent chance to damage the source actor (default 100) +-- @param friendlyfire percent chance to damage friendly actors (default 100) +function _M:addEffect(src, x, y, duration, damtype, dam, radius, dir, angle, overlay, update_fct, selffire, friendlyfire) + if selffire == nil then selffire = true end if friendlyfire == nil then friendlyfire = true end local grids @@ -799,7 +802,7 @@ src=src, x=x, y=y, duration=duration, damtype=damtype, dam=dam, radius=radius, dir=dir, angle=angle, overlay=overlay.__CLASSNAME and overlay, grids = grids, - update_fct=update_fct, friendlyfire=friendlyfire + update_fct=update_fct, selffire=selffire, friendlyfire=friendlyfire, } if not overlay.__CLASSNAME then @@ -843,7 +846,11 @@ -- Now display each grids for lx, ys in pairs(e.grids) do for ly, _ in pairs(ys) do - if e.friendlyfire or not (lx == e.src.x and ly == e.src.y) then + local act = game.level.map(lx, ly, engine.Map.ACTOR) + if act and act == e.src and not ((type(e.selffire) == "number" and rng.percent(e.selffire)) or (type(e.selffire) ~= "number" and e.selffire)) then + elseif act and e.src and e.src.reactionToward and (e.src:reactionToward(act) >= 0) and not ((type(e.friendlyfire) == "number" and rng.percent(typ.friendlyfire)) or (type(e.friendlyfire) ~= "number" and e.friendlyfire)) then + -- Otherwise hit + else DamageType:get(e.damtype).projector(e.src, lx, ly, e.damtype, e.dam) end end Index: game/engines/default/engine/Target.lua =================================================================== --- game/engines/default/engine/Target.lua (revision 2714) +++ game/engines/default/engine/Target.lua (working copy) @@ -134,6 +134,7 @@ -- Default type def local target_type = { range=20, + selffire=true, friendlyfire=true, block_path = function(typ, lx, ly) if not typ.no_restrict then Index: game/engines/default/engine/interface/ActorProject.lua =================================================================== --- game/engines/default/engine/interface/ActorProject.lua (revision 2714) +++ game/engines/default/engine/interface/ActorProject.lua (working copy) @@ -108,16 +108,12 @@ for px, ys in pairs(grids) do for py, _ in pairs(ys) do -- Call the projected method of the target grid if possible - if not game.level.map:checkAllEntities(x, y, "projected", self, t, x, y, damtype, dam, particles) then - -- Friendly fire ? - if px == self.x and py == self.y then - if typ.friendlyfire then - if type(damtype) == "function" then if damtype(px, py, tg, self) then stop=true break end - else DamageType:get(damtype).projector(self, px, py, damtype, dam, tmp) end - if particles then - game.level.map:particleEmitter(px, py, 1, particles.type, particles.args) - end - end + if not game.level.map:checkAllEntities(px, py, "projected", self, t, px, py, damtype, dam, particles) then + -- Check self- and friendly-fire, and if the projection "misses" + local act = game.level.map(px, py, engine.Map.ACTOR) + if act and act == self and not ((type(typ.selffire) == "number" and rng.percent(typ.selffire)) or (type(typ.selffire) ~= "number" and typ.selffire)) then + elseif act and self.reactionToward and (self:reactionToward(act) >= 0) and not ((type(typ.friendlyfire) == "number" and rng.percent(typ.friendlyfire)) or (type(typ.friendlyfire) ~= "number" and typ.friendlyfire)) then + -- Otherwise hit else if type(damtype) == "function" then if damtype(px, py, tg, self) then stop=true break end else DamageType:get(damtype).projector(self, px, py, damtype, dam, tmp) end @@ -222,15 +218,11 @@ -- Now project on each grid, one type -- Call the projected method of the target grid if possible if not game.level.map:checkAllEntities(px, py, "projected", self, typ, px, py, damtype, dam, particles) then - -- Friendly fire ? - if px == self.x and py == self.y then - if typ.friendlyfire then - if type(damtype) == "function" then if damtype(px, py, tg, self) then return true end - else DamageType:get(damtype).projector(self, px, py, damtype, dam, tmp) end - if particles and type(particles) == "table" then - game.level.map:particleEmitter(px, py, 1, particles.type, particles.args) - end - end + -- Check self- and friendly-fire, and if the projection "misses" + local act = game.level.map(px, py, engine.Map.ACTOR) + if act and act == self and not ((type(typ.selffire) == "number" and rng.percent(typ.selffire)) or (type(typ.selffire) ~= "number" and typ.selffire)) then + elseif act and self.reactionToward and (self:reactionToward(act) >= 0) and not ((type(typ.friendlyfire) == "number" and rng.percent(typ.friendlyfire)) or (type(typ.friendlyfire) ~= "number" and typ.friendlyfire)) then + -- Otherwise hit else if type(damtype) == "function" then if damtype(px, py, tg, self) then return true end else DamageType:get(damtype).projector(self, px, py, damtype, dam, tmp) end Index: game/engines/default/engine/interface/ActorTalents.lua =================================================================== --- game/engines/default/engine/interface/ActorTalents.lua (revision 2714) +++ game/engines/default/engine/interface/ActorTalents.lua (working copy) @@ -507,6 +507,25 @@ return t.range end +--- Returns the radius of a talent +function _M:getTalentRadius(t) + if not t.radius then return 0 end + if type(t.radius) == "function" then return t.radius(self, t) end + return t.radius +end + +--- Returns the target type of a talent +function _M:getTalentTarget(t) + if type(t.target) == "function" then return t.target(self, t) end + return t.target +end + +-- Returns whether the talent needs a target or not +function _M:getTalentRequiresTarget(t) + if type(t.requires_target) == "function" then return t.requires_target(self, t) end + return t.requires_target +end + --- Returns the projectile speed of a talent function _M:getTalentProjectileSpeed(t) if not t.proj_speed then return nil end Index: game/engines/default/engine/interface/GameTargeting.lua =================================================================== --- game/engines/default/engine/interface/GameTargeting.lua (revision 2714) +++ game/engines/default/engine/interface/GameTargeting.lua (working copy) @@ -264,6 +264,6 @@ -- This method should be called by your Player:setTarget() method, it will handle everything function _M:targetSetForPlayer(target) self.target.target.entity = target - self.target.target.x = target.x - self.target.target.y = target.y + self.target.target.x = (type(target) == "table" and target.x) or nil + self.target.target.y = (type(target) == "table" and target.y) or nil end Index: game/engines/default/modules/boot/data/talents.lua =================================================================== --- game/engines/default/modules/boot/data/talents.lua (revision 2714) +++ game/engines/default/modules/boot/data/talents.lua (working copy) @@ -114,7 +114,7 @@ direct_hit = true, requires_target = true, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t, display={particle="bolt_fire", trail="firetrail"}} + local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), selffire=false, talent=t, display={particle="bolt_fire", trail="firetrail"}} local x, y = self:getTarget(tg) if not x or not y then return nil end self:projectile(tg, x, y, DamageType.FIRE, rng.range(4, 8) * self:getTalentLevel(t), function(self, tg, x, y, grids) Index: game/modules/tome/class/generator/actor/ValleyMoon.lua =================================================================== --- game/modules/tome/class/generator/actor/ValleyMoon.lua (revision 2714) +++ game/modules/tome/class/generator/actor/ValleyMoon.lua (working copy) @@ -54,7 +54,7 @@ game.logSeen(_M.limmir, "Limmir summons a blast of holy light!") local rad = 2 local dam = 50 + (800 - self.level.turn_counter / 10) / 7 - local grids = _M.limmir:project({type="ball", radius=rad, friendlyfire=false}, _M.limmir.x, _M.limmir.y, DamageType.HOLY_LIGHT, dam) + local grids = _M.limmir:project({type="ball", radius=rad, selffire=false}, _M.limmir.x, _M.limmir.y, DamageType.HOLY_LIGHT, dam) game.level.map:particleEmitter(_M.limmir.x, _M.limmir.y, rad, "sunburst", {radius=rad, grids=grids, tx=_M.limmir.x, ty=_M.limmir.y}) end end Index: game/modules/tome/class/Actor.lua =================================================================== --- game/modules/tome/class/Actor.lua (revision 2714) +++ game/modules/tome/class/Actor.lua (working copy) @@ -740,7 +740,7 @@ -- Explode! game.logSeen(self, "%s unleashes the stored damage in retribution!", self.name:capitalize()) - local tg = {type="ball", range=0, radius=self:getTalentRange(self:getTalentFromId(self.T_RETRIBUTION)), friendlyfire=false, talent=t} + local tg = {type="ball", range=0, radius=self:getTalentRange(self:getTalentFromId(self.T_RETRIBUTION)), selffire=false, talent=t} local grids = self:project(tg, self.x, self.y, DamageType.LIGHT, dam) game.level.map:particleEmitter(self.x, self.y, tg.radius, "sunburst", {radius=tg.radius, grids=grids, tx=self.x, ty=self.y}) end Index: game/modules/tome/class/interface/Combat.lua =================================================================== --- game/modules/tome/class/interface/Combat.lua (revision 2714) +++ game/modules/tome/class/interface/Combat.lua (working copy) @@ -300,7 +300,7 @@ -- Shattering Impact if hitted and self:attr("shattering_impact") then local dam = dam * self.shattering_impact - self:project({type="ball", radius=1, friendlyfire=false}, target.x, target.y, DamageType.PHYSICAL, dam) + self:project({type="ball", radius=1, selffire=false}, target.x, target.y, DamageType.PHYSICAL, dam) self:incStamina(-15) end @@ -651,8 +651,10 @@ --- Do we get hit by our own AOE ? function _M:spellFriendlyFire() - print("[SPELL] friendly fire chance", self:getTalentLevelRaw(self.T_SPELL_SHAPING) * 20 + (self:getLck() - 50) * 0.2) - return not rng.percent(self:getTalentLevelRaw(self.T_SPELL_SHAPING) * 20 + (self:getLck() - 50) * 0.2) + local chance = self:getTalentLevelRaw(self.T_SPELL_SHAPING) * 20 + (self:getLck() - 50) * 0.2 + chance = 100 - chance + print("[SPELL] friendly fire chance", chance) + return chance end --- Gets mindpower Index: game/modules/tome/ai/tactical.lua =================================================================== --- game/modules/tome/ai/tactical.lua (revision 2714) +++ game/modules/tome/ai/tactical.lua (working copy) @@ -7,42 +7,68 @@ local target_dist = self.ai_target.actor and math.floor(core.fov.distance(self.x, self.y, self.ai_target.actor.x, self.ai_target.actor.y)) local hate = self.ai_target.actor and (self:reactionToward(self.ai_target.actor) < 0) local has_los = self.ai_target.actor and self:hasLOS(self.ai_target.actor.x, self.ai_target.actor.y) + local self_compassion = (self.ai_state.self_compassion == false and 0) or self.ai_state.self_compassion or 5 + local ally_compassion = (self.ai_state.ally_compassion == false and 0) or self.ai_state.ally_compassion or 1 for tid, lvl in pairs(self.talents) do local t = self:getTalentFromId(tid) + local t_avail = false -- print(self.name, self.uid, "dumb ai talents can try use", t.name, tid, "::", t.mode, not self:isTalentCoolingDown(t), target_dist <= self:getTalentRange(t), self:preUseTalent(t, true), self:canProject({type="bolt"}, self.ai_target.actor.x, self.ai_target.actor.y)) - if t.mode == "activated" and not t.no_npc_use and - not self:isTalentCoolingDown(t) and - self:preUseTalent(t, true, true) and - (not t.requires_target or ( - hate and - target_dist <= self:getTalentRange(t) and - self:canProject({type=util.getval(t.direct_hit, self, t) and "hit" or "bolt"}, self.ai_target.actor.x, self.ai_target.actor.y) and - has_los - )) - then - if t.tactical then - 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 - val = val * (1 + lvl / 5) - avail[tact][#avail[tact]+1] = {val=((t.no_energy==true) and val * 10 or val) + rng.float(0, 0.9), tid=tid} - print(self.name, self.uid, "tactical ai talents can use", t.name, tid, tact) - ok = true + if t.tactical then + 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({type=util.getval(t.direct_hit, self, t) and "hit" or "bolt"}, self.ai_target.actor.x, self.ai_target.actor.y) and + has_los + )) + then + t_avail = true + elseif t.mode == "sustained" and not t.no_npc_use and not self:isTalentCoolingDown(t) and + not self:isTalentActive(t.id) and + self:preUseTalent(t, true, true) + then + t_avail = true + end + if t_avail then + -- Project the talent if possible, counting foes and allies hit + local nb_foes_hit, nb_allies_hit, nb_self_hit + local tg = self:getTalentTarget(t) + if tg then + local typ = engine.Target:getType(tg) + local target_actor = self.ai_target.actor or self + nb_foes_hit = 0 + nb_allies_hit = 0 + nb_self_hit = 0 + self:project(self:getTalentTarget(t), target_actor.x, target_actor.y, function(px, py) + local act = game.level.map(px, py, engine.Map.ACTOR) + if act and not act.dead then + if self:reactionToward(act) < 0 then + print("[DEBUG] hit a foe!") + nb_foes_hit = nb_foes_hit + 1 + elseif (typ.selffire) and (act == self) then + print("[DEBUG] hit self!") + nb_self_hit = nb_self_hit + (type(typ.selffire) == "number" and typ.selffire / 100 or 1) + elseif typ.friendlyfire then + print("[DEBUG] hit an ally!") + nb_allies_hit = nb_allies_hit + (type(typ.friendlyfire) == "number" and typ.friendlyfire / 100 or 1) + end + end + end) end - end - elseif t.mode == "sustained" and not t.no_npc_use and not self:isTalentCoolingDown(t) and - not self:isTalentActive(t.id) and - self:preUseTalent(t, true, true) - then - if t.tactical then + -- 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) - avail[tact][#avail[tact]+1] = {val=((t.no_energy==true) and val * 10 or val) + rng.float(0, 0.9), tid=tid} - print(self.name, self.uid, "tactical ai talents can activate", t.name, tid, tact) + 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) + 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 end end @@ -116,35 +142,54 @@ end -- Surrounded - local nb_foes = 0 + local nb_foes_seen = 0 + local nb_allies_seen = 0 local arr = self.fov.actors_dist local act local sqsense = 2 * 2 for i = 1, #arr do act = self.fov.actors_dist[i] - if act and self:reactionToward(act) < 0 and not act.dead and self.fov.actors[act].sqdist <= sqsense then nb_foes = nb_foes + 1 end + if act and not act.dead and self.fov.actors[act].sqdist <= sqsense then + if self:reactionToward(act) < 0 then + nb_foes_seen = nb_foes_seen + 1 + else + nb_allies_seen = nb_allies_seen + 1 + end + end end if avail.surrounded then - want.surrounded = nb_foes + want.surrounded = nb_foes_seen end -- Need defence - if avail.defend and need_heal and nb_foes > 0 then - want.defend = 1 + need_heal / 2 + nb_foes * 0.5 + if avail.defend and need_heal and nb_foes_seen > 0 then + table.sort(avail.defend, function(a,b) return a.val > b.val end) + want.defend = 1 + need_heal / 2 + nb_foes_seen * 0.5 end -- Attacks - if avail.attack and self.ai_target.actor then want.attack = 1 end - if avail.disable and self.ai_target.actor then want.disable = (want.attack or 0) + 1 end - if avail.attackarea and self.ai_target.actor then want.attackarea = (want.attack or 0) + nb_foes * 0.6 end + if avail.attack and self.ai_target.actor then + -- Use the foe/ally ration from the best attack talent + table.sort(avail.attack, function(a,b) return a.val > b.val end) + want.attack = (avail.attack[1].nb_foes_hit or 1) - ally_compassion * (avail.attack[1].nb_allies_hit or 0) - self_compassion * (avail.attack[1].nb_self_hit or 0) + end + if avail.disable and self.ai_target.actor then + -- Use the foe/ally ration from the best disable talent + table.sort(avail.disable, function(a,b) return a.val > b.val end) + want.disable = (want.attack or 0) + (avail.disable[1].nb_foes_hit or 1) - ally_compassion * (avail.disable[1].nb_allies_hit or 0) - self_compassion * (avail.disable[1].nb_self_hit or 0) + end + if avail.attackarea and self.ai_target.actor then + -- Use the foe/ally ration from the best attackarea talent + table.sort(avail.attackarea, function(a,b) return a.val > b.val end) + want.attackarea = (want.attack or 0) + (avail.attackarea[1].nb_foes_hit or nb_foes_seen) - ally_compassion * (avail.attackarea[1].nb_allies_hit or nb_allies_seen) - self_compassion * (avail.attackarea[1].nb_self_hit or 0) + end -- Need buffs if avail.buff and want.attack and want.attack > 0 then want.buff = math.max(0.01, want.attack - 1) end - print("Tactical ai report for", self.name) local res = {} for k, v in pairs(want) do Index: game/modules/tome/data/timed_effects.lua =================================================================== --- game/modules/tome/data/timed_effects.lua (revision 2714) +++ game/modules/tome/data/timed_effects.lua (working copy) @@ -1932,7 +1932,7 @@ self:removeParticles(eff.particle) end, on_timeout = function(self, eff) - self:project({type="ball", radius=eff.radius, friendlyfire=false}, self.x, self.y, function(xx, yy) + self:project({type="ball", radius=eff.radius, selffire=false}, self.x, self.y, function(xx, yy) local target = game.level.map(xx, yy, game.level.map.ACTOR) if target and target ~= self and target ~= eff.source and target:canBe("knockback") and (target.never_move or 0) ~= 1 then -- attempt to move target away from self @@ -2129,7 +2129,7 @@ on_gain = function(self, err) return "#Target# is caught inside a Hurricane.", "+Hurricane" end, on_lose = function(self, err) return "The Hurricane around #Target# dissipates.", "-Hurricane" end, on_timeout = function(self, eff) - local tg = {type="ball", x=self.x, y=self.y, radius=eff.radius, friendlyfire=false} + local tg = {type="ball", x=self.x, y=self.y, radius=eff.radius, selffire=false} local dam = eff.dam eff.src:project(tg, self.x, self.y, DamageType.LIGHTNING, rng.avg(dam / 3, dam, 3)) local x, y = self.x, self.y Index: game/modules/tome/data/damage_types.lua =================================================================== --- game/modules/tome/data/damage_types.lua (revision 2714) +++ game/modules/tome/data/damage_types.lua (working copy) @@ -247,6 +247,7 @@ local target = game.level.map(x, y, Map.ACTOR) -- Spread diseases if possible if realdam > 0 and target and target:attr("diseases_spread_on_blight") and (not extra or not extra.from_disease) then + game.logSeen(src, "The diseases of %s spread!", src.name) if rng.percent(20 + math.sqrt(realdam) * 5) then local t = src:getTalentFromId(src.T_EPIDEMIC) t.do_spread(src, t, target) Index: game/modules/tome/data/talents/chronomancy/anomalies.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/anomalies.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/anomalies.lua (working copy) @@ -106,10 +106,12 @@ type = {"chronomancy/anomalies", 1}, points = 1, range = 6, + radius = function(self, t) + return math.floor(self:getParadox()/200) + end, direct_hit = true, type_no_req = true, getTargetCount = function(self, t) return 1 end, - getRadius = function(self, t) return math.floor(self:getParadox()/200) end, getStop = function(self, t) return (self:getParadox()/100) end, message = "@Source@ has created a bubble of nul time.", action = function(self, t) @@ -123,7 +125,7 @@ end end -- Randomly take targets - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t), friendlyfire=self:spellFriendlyFire(), talent=t} + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t} for i = 1, t.getTargetCount(self, t) do if #tgts <= 0 then break end local a, id = rng.table(tgts) @@ -145,10 +147,12 @@ type = {"chronomancy/anomalies", 1}, points = 1, range = 6, + radius = function(self, t) + return 1 - 1 / (1 + (self:getParadox()/15) / 100) + end, direct_hit = true, type_no_req = true, getTargetCount = function(self, t) return 1 end, - getRadius = function(self, t) return math.floor(self:getParadox()/200) end, getSlow = function(self, t) return 1 - 1 / (1 + (self:getParadox()/15) / 100) end, message = "@Source@ has created a bubble of slow time.", action = function(self, t) @@ -162,7 +166,7 @@ end end -- Randomly take targets - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t), friendlyfire=self:spellFriendlyFire(), talent=t} + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t} for i = 1, t.getTargetCount(self, t) do if #tgts <= 0 then break end local a, id = rng.table(tgts) @@ -561,4 +565,4 @@ info = function(self, t) return (Clones the caster) end, -}]] \ No newline at end of file +}]] Index: game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/spacetime-weaving.lua (working copy) @@ -156,9 +156,13 @@ paradox = 20, cooldown = 20, tactical = { ESCAPE = 2 }, + range = function (self, t) + return 10 + math.floor(self:getTalentLevel(t)/2) + end, + radius = function(self, t) + return math.floor(7 - self:getTalentLevel(t)) + end, requires_target = function(self, t) return self:getTalentLevel(t) >= 4 end, - getRadius = function(self, t) return math.floor(7 - self:getTalentLevel(t)) end, - getRange = function (self, t) return 10 + math.floor (self:getTalentLevel(t)/2) end, getDuration = function (self, t) return 5 + math.floor(self:getTalentLevel(t)*getParadoxModifier(self, pm)) end, no_npc_use = true, action = function(self, t) @@ -178,9 +182,9 @@ -- First, find the center possible exit locations local x, y, radius, minimum_distance if self:getTalentLevel(t) >= 4 then - radius = t.getRadius(self, t) + radius = self:getTalentRadius(t) minimum_distance = 0 - local tg = {type="ball", nolock=true, pass_terrain=true, nowarning=true, range=t.getRange(self, t), radius=radius} + local tg = {type="ball", nolock=true, pass_terrain=true, nowarning=true, range=self:getTalentRange(t), radius=radius} x, y = self:getTarget(tg) if not x then return nil end -- See if we can actually project to the selected location @@ -267,7 +271,7 @@ end, info = function(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[You fold the space between two points, allowing travel back and forth between them for the next %d turns. At level 4 you may choose the exit location target area (radius %d). The duration will scale with your Paradox.]]) :format(duration, radius) Index: game/modules/tome/data/talents/chronomancy/timetravel.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/timetravel.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/timetravel.lua (working copy) @@ -27,13 +27,18 @@ paradox = 5, cooldown = 6, tactical = { ATTACKAREA = 2 }, - range = 1, + range = 0, + radius = function(self, t) + return 4 + math.floor(self:getTalentLevelRaw (t)/2) + end, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t} + end, getDamage = function(self, t) return (self:combatTalentSpellDamage(t, 10, 120)*getParadoxModifier(self, pm)) end, getPercent = function(self, t) return (30 + (self:combatTalentSpellDamage(t, 10, 30)*getParadoxModifier(self, pm))) / 100 end, - getRadius = function (self, t) return 4 + math.floor(self:getTalentLevelRaw (t)/2) end, action = function(self, t) - local tg = {type="cone", range=0, radius=t.getRadius(self, t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.TEMPORAL, self:spellCrit(t.getDamage(self, t))) @@ -44,7 +49,7 @@ end, info = function(self, t) local percent = t.getPercent(self, t) * 100 - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) return ([[Creates a temporal echo in a %d radius cone. Affected targets will take %0.2f temporal damage and %d%% of the difference between their current life and max life as additional temporal damage. The percentage and damage scales with your Paradox and the Magic stat.]]): Index: game/modules/tome/data/talents/chronomancy/speed-control.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/speed-control.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/speed-control.lua (working copy) @@ -46,14 +46,19 @@ points = 5, paradox = 10, cooldown = 20, - tactical = { DISABLE = 3 }, + tactical = { ATTACKAREA = 1, DISABLE = 3 }, range = 6, + radius = function(self, t) + return 1 + math.floor(self:getTalentLevel(t) / 3) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t} + end, getDuration = function(self, t) return 2 + math.ceil(((self:getTalentLevel(t) / 2)) * getParadoxModifier(self, pm)) end, - getRadius = function(self, t) return 1 + math.floor(self:getTalentLevel(t) / 3) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t), friendlyfire=self:spellFriendlyFire(), talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) @@ -63,7 +68,7 @@ return true end, info = function(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local duration = t.getDuration(self, t) return ([[Attempts to stun all creatures in a radius %d ball for %d turns. The stun duration will scale with your Paradox.]]): @@ -80,13 +85,18 @@ cooldown = 30, tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 6, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevel(t)/4) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getSlow = function(self, t) return 1 - 1 / (1 + ((10 + (self:combatTalentSpellDamage(t, 10, 50) * getParadoxModifier(self, pm))) / 100)) end, - getRadius = function (self, t) return 2 + math.floor(self:getTalentLevel(t)/4) end, getDuration = function(self, t) return 5 + math.ceil(self:getTalentLevel(t)) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t)} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) @@ -95,7 +105,7 @@ game.level.map:addEffect(self, x, y, t.getDuration(self, t), DamageType.CHRONOSLOW, t.getSlow(self, t), - t.getRadius(self, t), + self:getTalentRadius(t), 5, nil, {type="temporal_cloud"}, nil, self:spellFriendlyFire() @@ -105,7 +115,7 @@ end, info = function(self, t) local slow = t.getSlow(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local duration = t.getDuration(self, t) return ([[Creates a time distortion in a radius of %d that lasts for %d turns, decreasing affected targets global speed by %d%% for 2 turns and inflicting %0.2f temporal damage each turn they remain in the area. The slow effect and damage will scale with your Paradox and Magic stat.]]): Index: game/modules/tome/data/talents/chronomancy/gravity.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/gravity.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/gravity.lua (working copy) @@ -47,14 +47,19 @@ points = 5, paradox = 10, cooldown = 10, - tactical = { ATTACK = 2, DISABLE = 2 }, + tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 6, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevel(t) / 3) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 170)*getParadoxModifier(self, pm) end, - getRadius = function (self, t) return 2 + math.floor(self:getTalentLevel(t) / 3) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t)} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) @@ -74,7 +79,7 @@ end, info = function(self, t) local damage = t.getDamage(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Creates a gravity spike in a radius of %d moving all targets towards the spells center and inflicting %0.2f physical damage. The damage will scale with your Paradox and Magic Stat.]]):format(radius, damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t))) end, @@ -88,12 +93,17 @@ paradox = 12, cooldown = 12, tactical = { ATTACKAREA = 2, ESCAPE = 2 }, - range = 1, + range = 0, + radius = function(self, t) + return 4 + math.floor(self:getTalentLevelRaw (t)/2) + end, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 170)*getParadoxModifier(self, pm) end, - getRadius = function (self, t) return 4 + math.floor(self:getTalentLevelRaw (t)/2) end, action = function(self, t) - local tg = {type="cone", range=0, radius=t.getRadius(self, t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.PHYSICAL, self:spellCrit(t.getDamage(self, t))) @@ -104,7 +114,7 @@ end, info = function(self, t) local damage = t.getDamage(self, t) - local radius = t.getRadius (self, t) + local radius = self:getTalentRadius(t) return ([[Sends out a wave of repulsion in a %d radius cone, dealing %0.2f physical damage and knocking back creatures caught in the area. Pinned creatures are immune to this knockback. The damage will scale with your Paradox and Magic stat.]]): format(radius, damDesc(self, DamageType.PHYSICAL, t.getDamage(self, t))) @@ -119,18 +129,23 @@ points = 5, paradox = 20, cooldown = 30, - tactical = { ATTACK = 2, DISABLE = 2 }, + tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 6, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevel(t) / 3) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 80)*getParadoxModifier(self, pm) end, getDuration = function (self, t) return 3 + math.ceil(self:getTalentLevel(t)) end, - getRadius = function (self, t) return 2 + math.floor(self:getTalentLevel(t) / 3) end, action = function(self, t) local duration = t.getDuration(self,t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local dam = t.getDamage(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) @@ -150,8 +165,8 @@ info = function(self, t) local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Increases local gravity, doing %0.2f physical damage with a chance to pin in a radius of %d each turn for %d turns. The damage will scale with your Paradox and Magic stat]]):format(damDesc(self, DamageType.PHYSICAL, damage), radius, duration) end, -} \ No newline at end of file +} Index: game/modules/tome/data/talents/chronomancy/age-manipulation.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/age-manipulation.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/age-manipulation.lua (working copy) @@ -100,13 +100,18 @@ paradox = 15, cooldown = 15, tactical = { ATTACKAREA = 2, DISABLE= 2 }, - range = 1, + range = 0, + radius = function(self, t) + return 4 + math.floor(self:getTalentLevelRaw (t)/2) + end, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, getConfuseDuration = function(self, t) return math.floor((self:getTalentLevel(t) + 2) * getParadoxModifier(self, pm)) end, getConfuseEfficency = function(self, t) return (50 + self:getTalentLevelRaw(t) * 10) * getParadoxModifier(self, pm) end, - getRadius = function (self, t) return 4 + math.floor(self:getTalentLevelRaw (t)/2) end, action = function(self, t) - local tg = {type="cone", range=0, radius=t.getRadius(self, t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end print (check) @@ -120,7 +125,7 @@ end, info = function(self, t) local duration = t.getConfuseDuration(self, t) - local radius = t.getRadius (self, t) + local radius = self:getTalentRadius(t) return ([[Reverts the minds of all creatures in a %d radius cone to an infantile state, in effect confusing them for %d turns. The duration and power of the confuse will scale with your Paradox.]]): format(radius, duration) @@ -135,13 +140,19 @@ paradox = 20, cooldown = 20, tactical = { ATTACKAREA = 2 }, + range = 0, + radius = 3, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 8, 135)*getParadoxModifier(self, pm) end, getDuration = function(self, t) return 5 + math.ceil(self:getTalentLevel(t)) end, action = function(self, t) + local tg = self:getTalentTarget(t) game.level.map:addEffect(self, self.x, self.y, t.getDuration(self, t), DamageType.WASTING, t.getDamage(self, t), - 3, + tg.radius, 5, nil, engine.Entity.new{alpha=100, display='', color_br=176, color_bg=196, color_bb=222}, function(e) @@ -149,7 +160,7 @@ e.y = e.src.y return true end, - false + tg.selffire ) game:playSoundNear(self, "talents/cloud") return true @@ -160,4 +171,4 @@ return ([[You surround yourself with a radius 3 aura of time distortion for %d turns that deals %0.2f stacking temporal damage over 3 turns to all other creatures. The damage will scale with your Paradox and Magic stat]]):format(duration, damDesc(self, DamageType.TEMPORAL, damage)) end, -} \ No newline at end of file +} Index: game/modules/tome/data/talents/chronomancy/spacetime-folding.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/spacetime-folding.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/spacetime-folding.lua (working copy) @@ -59,12 +59,14 @@ tactical = { ESCAPE = 2, CLOSEIN = 2 }, requires_target = true, direct_hit = true, - getRange = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)*getParadoxModifier(self, pm)) end, + range = function(self, t) + return 3 + math.ceil(self:getTalentLevel(t)*getParadoxModifier(self, pm)) + end, action = function(self, t) - local tg = {type="hit", range=t.getRange(self, t)} + local tg = {type="hit", range=self:getTalentRange(t)} local tx, ty, target = self:getTarget(tg) if not tx or not ty then return nil end - if math.floor(core.fov.distance(self.x, self.y, tx, ty)) > t.getRange(self, t) then return nil end + if math.floor(core.fov.distance(self.x, self.y, tx, ty)) > self:getTalentRange(t) then return nil end if not self:canBe("teleport") or game.level.map.attrs(tx, ty, "no_teleport") or game.level.map.attrs(self.x, self.y, "no_teleport") then game.logSeen(self, "The spell fizzles!") return true @@ -103,14 +105,12 @@ return true end, info = function(self, t) - local range = t.getRange(self, t) + local range = self:getTalentRange(t) return ([[You manipulate the spacetime continuum in such a way that you switch places with another creature with in a range of %d. - ]]):format (range) + ]]):format(range) end, } - - newTalent{ name = "Temporal Wake", type = {"chronomancy/spacetime-folding", 4}, @@ -124,9 +124,12 @@ direct_hit = true, reflectable = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), selffire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 200) * getParadoxModifier(self, pm) end, action = function(self, t) - local tg = {type="beam", range=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end if self:hasLOS(x, y) and not game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move") then @@ -154,4 +157,4 @@ damDesc(self, DamageType.LIGHTNING, damage / 2), damDesc(self, DamageType.TEMPORAL, damage / 2)) end, -} \ No newline at end of file +} Index: game/modules/tome/data/talents/chronomancy/matter.lua =================================================================== --- game/modules/tome/data/talents/chronomancy/matter.lua (revision 2714) +++ game/modules/tome/data/talents/chronomancy/matter.lua (working copy) @@ -29,9 +29,12 @@ direct_hit = true, reflectable = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 220)*getParadoxModifier(self, pm) end, action = function(self, t) - 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 x, y = checkBackfire(self, x, y) @@ -87,12 +90,17 @@ cooldown = 20, tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 6, + radius = function(self, t) + return 1 + math.floor(self:getTalentLevel(t) / 4) + end, direct_hit = true, requires_target = true, - getRadius = function (self, t) return 1 + math.floor(self:getTalentLevel(t) / 4) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDuration = function(self, t) return 2 + math.floor(self:getTalentLevel(t) * getParadoxModifier(self, pm)) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t)} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) @@ -111,7 +119,7 @@ return true end, info = function(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local duration = t.getDuration(self, t) return ([[Attempts to turn all targets in a radius of %d to stone for %d turns. Stoned creatures are unable to act or regen life and are very brittle. If a stoned creature is hit by an attack that deals more than 30%% of its life it will shattered and be destroyed. @@ -132,9 +140,12 @@ direct_hit = true, reflectable = true, requires_target = true, + target = function(self, t) + return {type="hit", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 230)*getParadoxModifier(self, pm) end, action = function(self, t) - local tg = {type="hit", range=self:getTalentRange(t), talent=t} + local tg = self:getTalentTarget(t) local x, y, target = self:getTarget(tg) if not x or not y then return nil end x, y = checkBackfire(self, x, y) Index: game/modules/tome/data/talents/spells/ice.lua =================================================================== --- game/modules/tome/data/talents/spells/ice.lua (revision 2714) +++ game/modules/tome/data/talents/spells/ice.lua (working copy) @@ -26,11 +26,15 @@ cooldown = 3, tactical = { ATTACKAREA = 1, ATTACK = 1 }, range = 10, + radius = 1, proj_speed = 3, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 18, 200) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=1, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local grids = self:project(tg, x, y, function(px, py) @@ -62,10 +66,14 @@ cooldown = 10, requires_target = true, tactical = { ATTACKAREA = 2, DISABLE = 1 }, - range = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRange(t), selffire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 180) end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local grids = self:project(tg, self.x, self.y, DamageType.COLDNEVERMOVE, {dur=4, dam=self:spellCrit(t.getDamage(self, t))}) game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_ice", {radius=tg.radius}) game:playSoundNear(self, "talents/ice") Index: game/modules/tome/data/talents/spells/explosives.lua =================================================================== --- game/modules/tome/data/talents/spells/explosives.lua (revision 2714) +++ game/modules/tome/data/talents/spells/explosives.lua (working copy) @@ -27,8 +27,21 @@ range = function(self, t) return math.ceil(5 + self:getDex(6)) end, + radius = function(self, t) + return 1+self:getTalentLevelRaw(self.T_EXPLOSION_EXPERT) + end, direct_hit = true, requires_target = true, + target = function(self, 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 }, computeDamage = function(self, t, ammo) local inc_dam = 0 @@ -54,7 +67,7 @@ return end - local tg = {type="ball", range=self:getTalentRange(t)+(ammo.alchemist_bomb.range or 0), radius=1+self:getTalentLevelRaw(self.T_EXPLOSION_EXPERT), talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end @@ -173,8 +186,12 @@ range = function(self, t) return math.ceil(5 + self:getDex(6)) end, + radius = 2, 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} + end, tactical = { ATTACKAREA = 2, DISABLE = 2 }, computeDamage = function(self, t, ammo) local inc_dam = 0 @@ -192,7 +209,7 @@ return end - local tg = {type="ball", range=self:getTalentRange(t)+(ammo.alchemist_bomb.range or 0), radius=2, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end Index: game/modules/tome/data/talents/spells/golem.lua =================================================================== --- game/modules/tome/data/talents/spells/golem.lua (revision 2714) +++ game/modules/tome/data/talents/spells/golem.lua (working copy) @@ -88,11 +88,17 @@ return 20 - self:getTalentLevelRaw(t) * 2 end, range = 10, + radius = function(self, t) + return self:getTalentLevelRaw(t) / 2 + end, stamina = 5, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, tactical = { PROTECT = 3 }, action = function(self, t) - local tg = {type="ball", radius=self:getTalentLevelRaw(t) / 2, range=self:getTalentRange(t)} + local tg = self:getTalentTarget(t) local olds = game.target.source_actor game.target.source_actor = self local x, y = self:getTarget(tg) @@ -184,8 +190,12 @@ points = 5, cooldown = 15, range = 5, + radius = 2, stamina = 5, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), selffire=false, range=self:getTalentRange(t)} + end, getGolemDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.4, 1.1) end, @@ -194,7 +204,7 @@ action = function(self, t) if self:attr("never_move") then game.logPlayer(self, "Your golem can not do that currently.") return end - local tg = {type="ball", radius=2, friendlyfire=false, range=self:getTalentRange(t)} + local tg = self:getTalentTarget(t) local olds = game.target.source_actor game.target.source_actor = self local x, y, target = self:getTarget(tg) @@ -217,7 +227,7 @@ if self.ai_target then self.ai_target.target = target end -- Attack & daze - self:project({type="ball", radius=2, friendlyfire=false}, tx, ty, function(xx, yy) + self:project(tg, tx, ty, function(xx, yy) if xx == self.x and yy == self.y then return end local target = game.level.map(xx, yy, Map.ACTOR) if target and self:attackTarget(target, nil, t.getGolemDamage(self, t), true) then @@ -254,10 +264,13 @@ range = 7, mana = 10, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 220) end, tactical = { ATTACK = 3 }, action = function(self, t) - 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 @@ -338,12 +351,18 @@ require = spells_req3, points = 5, cooldown = 15, - range = function(self, t) return 3 + self:getTalentLevel(t) / 2 end, + range = 0, + radius = function(self, t) + return 3 + self:getTalentLevel(t) / 2 + end, mana = 20, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), selffire=false, radius=self:getTalentRadius(t), talent=t} + end, tactical = { ATTACKAREA = 2 }, action = function(self, t) - local tg = {type="ball", range=0, friendlyfire=false, radius=self:getTalentRange(t), talent=t} + local tg = self:getTalentTarget(t) local done = {} self:project(tg, self.x, self.y, function(px, py) local target = game.level.map(px, py, Map.ACTOR) @@ -371,16 +390,20 @@ points = 5, mana = 60, cooldown = 15, + range = 0, + radius = 3, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, tactical = { ATTACKAREA = 2 }, action = function(self, t) local duration = 5 + self:getTalentLevel(t) - local radius = 3 local dam = self:combatTalentSpellDamage(t, 12, 120) -- Add a lasting map effect game.level.map:addEffect(self, self.x, self.y, duration, DamageType.GOLEM_FIREBURN, dam, - radius, + self:getTalentRadius(t), 5, nil, engine.Entity.new{alpha=100, display='', color_br=200, color_bg=60, color_bb=30}, function(e) Index: game/modules/tome/data/talents/spells/storm.lua =================================================================== --- game/modules/tome/data/talents/spells/storm.lua (revision 2714) +++ game/modules/tome/data/talents/spells/storm.lua (working copy) @@ -25,12 +25,18 @@ mana = 12, cooldown = 8, tactical = { ATTACKAREA = 2, DISABLE =1 }, + range = 0, + radius = function(self, t) + return math.floor(2 + self:getTalentLevel(t) * 0.7) + end, direct_hit = true, requires_target = true, - range = function(self, t) return math.floor(2 + self:getTalentLevel(t) * 0.7) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 170) end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local dam = self:spellCrit(t.getDamage(self, t)) self:project(tg, self.x, self.y, DamageType.LIGHTNING_DAZE, {daze=75, dam=rng.avg(dam / 3, dam, 3)}) local x, y = self.x, self.y Index: game/modules/tome/data/talents/spells/wildfire.lua =================================================================== --- game/modules/tome/data/talents/spells/wildfire.lua (revision 2714) +++ game/modules/tome/data/talents/spells/wildfire.lua (working copy) @@ -27,10 +27,14 @@ tactical = { ATTACKAREA = 2, DISABLE = 2, ESCAPE = 2 }, direct_hit = true, requires_target = true, - range = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + talent = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 180) end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local grids = self:project(tg, self.x, self.y, DamageType.FIREKNOCKBACK, {dist=3, dam=self:spellCrit(t.getDamage(self, t))}) game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_fire", {radius=tg.radius}) if self:attr("burning_wake") then Index: game/modules/tome/data/talents/spells/fire-alchemy.lua =================================================================== --- game/modules/tome/data/talents/spells/fire-alchemy.lua (revision 2714) +++ game/modules/tome/data/talents/spells/fire-alchemy.lua (working copy) @@ -104,6 +104,11 @@ random_ego = "attack", mana = 40, cooldown = 30, + range = 0, + radius = 3, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, tactical = { ATTACKAREA = 2 }, getDuration = function(self, t) return 5 + self:combatSpellpower(0.05) + self:getTalentLevel(t) end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 90) end, Index: game/modules/tome/data/talents/spells/stone-alchemy.lua =================================================================== --- game/modules/tome/data/talents/spells/stone-alchemy.lua (revision 2714) +++ game/modules/tome/data/talents/spells/stone-alchemy.lua (working copy) @@ -163,10 +163,14 @@ else return math.floor(self:getTalentLevel(t)) end end, requires_target = true, + target = function(self, t) + local tg = {type="beam", range=self:getTalentRange(t), talent=t} + if self:getTalentLevel(t) >= 3 then tg.type = "beam" end + return tg + end, getDuration = function(self, t) return math.floor((3 + self:getTalentLevel(t)) / 1.5) end, action = function(self, t) - local tg = {type="beam", range=self:getTalentRange(t), talent=t} - if self:getTalentLevel(t) >= 3 then tg.type = "beam" end + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(tx, ty) Index: game/modules/tome/data/talents/spells/phantasm.lua =================================================================== --- game/modules/tome/data/talents/spells/phantasm.lua (revision 2714) +++ game/modules/tome/data/talents/spells/phantasm.lua (working copy) @@ -25,14 +25,19 @@ points = 5, mana = 5, cooldown = 14, - tactical = { DISABLE = 2 }, - getRadius = function(self, t) return 5 + self:getTalentLevel(t) end, + range = 0, + radius = function(self, t) return 5 + self:getTalentLevel(t) end, + tactical = { DISABLE = function(self, t) + if self:getTalentLevel(t) >= 3 then + return 2 + end + end}, getBlindPower = function(self, t) return 3 + self:getTalentLevel(t) end, action = function(self, t) - local tg = {type="ball", range=0, friendlyfire=true, radius=t.getRadius(self, t), talent=t} + local tg = {type="ball", range=self:getTalentRange(t), selffire=true, radius=self:getTalentRadius(t), talent=t} self:project(tg, self.x, self.y, DamageType.LITE, 1) if self:getTalentLevel(t) >= 3 then - tg.friendlyfire = false + tg.selffire= false self:project(tg, self.x, self.y, DamageType.BLIND, t.getBlindPower(self, t)) end game:playSoundNear(self, "talents/heal") Index: game/modules/tome/data/talents/spells/air.lua =================================================================== --- game/modules/tome/data/talents/spells/air.lua (revision 2714) +++ game/modules/tome/data/talents/spells/air.lua (working copy) @@ -30,9 +30,12 @@ direct_hit = true, reflectable = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 290) end, action = function(self, t) - 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 = self:spellCrit(t.getDamage(self, t)) @@ -84,7 +87,7 @@ first = actor print("[Chain lightning] looking for more targets", nb, " at ", dx, dy, "radius ", 10, "from", actor.name) - self:project({type="ball", friendlyfire=false, x=dx, y=dy, radius=10, range=0}, dx, dy, function(bx, by) + self:project({type="ball", selffire=false, x=dx, y=dy, radius=10, range=0}, dx, dy, function(bx, by) local actor = game.level.map(bx, by, Map.ACTOR) if actor and not affected[actor] and self:reactionToward(actor) < 0 then print("[Chain lightning] found possible actor", actor.name, bx, by, "distance", core.fov.distance(dx, dy, bx, by)) @@ -108,7 +111,7 @@ local sx, sy = self.x, self.y for i, actor in ipairs(targets) do - local tgr = {type="beam", range=self:getTalentRange(t), friendlyfire=false, talent=t, x=sx, y=sy} + local tgr = {type="beam", range=self:getTalentRange(t), selffire=false, talent=t, x=sx, y=sy} print("[Chain lightning] jumping from", sx, sy, "to", actor.x, actor.y) local dam = self:spellCrit(t.getDamage(self, t)) self:project(tgr, actor.x, actor.y, DamageType.LIGHTNING, rng.avg(rng.avg(dam / 3, dam, 3), dam, 5)) Index: game/modules/tome/data/talents/spells/water.lua =================================================================== --- game/modules/tome/data/talents/spells/water.lua (revision 2714) +++ game/modules/tome/data/talents/spells/water.lua (working copy) @@ -27,12 +27,16 @@ cooldown = 8, tactical = { ATTACKAREA = 2 }, range = 8, + radius = 3, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 4, 50) end, getDuration = function(self, t) return self:getTalentLevel(t) + 2 end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=3} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -40,7 +44,7 @@ game.level.map:addEffect(self, x, y, t.getDuration(self, t), DamageType.ACID, t.getDamage(self, t), - 3, + self:getTalentRadius(t), 5, nil, {type="vapour"}, nil, self:spellFriendlyFire() @@ -97,6 +101,13 @@ cooldown = 8, tactical = { ESCAPE = 2, ATTACKAREA = 1, DISABLE = 1 }, direct_hit = true, + range = 0, + radius = function(self, t) + return 1 + 0.5 * t.getDuration(self, t) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 90) end, getDuration = function(self, t) return 5 + self:combatSpellpower(0.01) * self:getTalentLevel(t) end, action = function(self, t) @@ -134,6 +145,11 @@ mana = 40, cooldown = 30, tactical = { ATTACKAREA = 2 }, + range = 0, + radius = 3, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 90) end, getDuration = function(self, t) return 5 + self:combatSpellpower(0.05) + self:getTalentLevel(t) end, action = function(self, t) Index: game/modules/tome/data/talents/spells/fire.lua =================================================================== --- game/modules/tome/data/talents/spells/fire.lua (revision 2714) +++ game/modules/tome/data/talents/spells/fire.lua (working copy) @@ -30,10 +30,14 @@ reflectable = true, proj_speed = 20, requires_target = true, + target = function(self, t) + local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_fire", trail="firetrail"}} + if self:getTalentLevel(t) >= 5 then tg.type = "beam" end + return tg + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 25, 290) end, action = function(self, t) - local tg = {type="bolt", range=self:getTalentRange(t), talent=t, display={particle="bolt_fire", trail="firetrail"}} - if self:getTalentLevel(t) >= 5 then tg.type = "beam" end + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local grids = nil @@ -79,12 +83,18 @@ mana = 30, cooldown = 18, tactical = { ATTACK = 1, DISABLE = 3 }, - range = 1, + range = 0, + radius = function(self, t) + return 3 + self:getTalentLevelRaw(t) + end, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 120) end, getStunDuration = function(self, t) return self:getTalentLevelRaw(t) + 2 end, action = function(self, t) - local tg = {type="cone", range=0, radius=3 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.FLAMESHOCK, {dur=t.getStunDuration(self, t), dam=self:spellCrit(t.getDamage(self, t))}) @@ -126,13 +136,18 @@ cooldown = 8, tactical = { ATTACKAREA = 2 }, range = 7, + radius = function(self, t) + return 1 + self:getTalentLevelRaw(t) + end, proj_speed = 4, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t, display={particle="bolt_fire", trail="firetrail"}} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 280) end, - getRadius = function(self, t) return 1 + self:getTalentLevelRaw(t) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t), friendlyfire=self:spellFriendlyFire(), talent=t, display={particle="bolt_fire", trail="firetrail"}} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:projectile(tg, x, y, DamageType.FIRE, self:spellCrit(t.getDamage(self, t)), function(self, tg, x, y, grids) @@ -144,7 +159,7 @@ tg.radius, 5, nil, {type="inferno"}, - nil, self:spellFriendlyFire() + nil, tg.selffire ) end end) @@ -153,7 +168,7 @@ end, info = function(self, t) local damage = t.getDamage(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Conjures up a bolt of fire moving toward the target that explodes into a flash of fire doing %0.2f fire damage in a radius of %d. The damage will increase with the Magic stat]]): format(damDesc(self, DamageType.FIRE, damage), radius) @@ -170,13 +185,16 @@ cooldown = 30, tactical = { ATTACKAREA = 3 }, range = 10, + radius = 5, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 80) end, getDuration = function(self, t) return 5 + self:getTalentLevel(t) end, action = function(self, t) - local radius = 5 - local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -184,7 +202,7 @@ game.level.map:addEffect(self, x, y, t.getDuration(self, t), DamageType.INFERNO, t.getDamage(self, t), - radius, + self:getTalentRadius(t), 5, nil, {type="inferno"}, nil, self:spellFriendlyFire() @@ -196,8 +214,9 @@ info = function(self, t) local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) - return ([[Raging flames burn foes and allies alike doing %0.2f fire damage in a radius of 5 each turn for %d turns. + local radius = self:getTalentRadius(t) + return ([[Raging flames burn foes and allies alike doing %0.2f fire damage in a radius of %d each turn for %d turns. The damage will increase with the Magic stat]]): - format(damDesc(self, DamageType.FIRE, damage), duration) + format(damDesc(self, DamageType.FIRE, damage), radius, duration) end, } Index: game/modules/tome/data/talents/spells/stone.lua =================================================================== --- game/modules/tome/data/talents/spells/stone.lua (revision 2714) +++ game/modules/tome/data/talents/spells/stone.lua (working copy) @@ -135,14 +135,18 @@ cooldown = 30, tactical = { ATTACKAREA = 2, DISABLE = 3 }, range = 10, + radius = function(self, t) + return 2 + (self:getTalentLevel(t)/2) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 15, 70) end, getDuration = function(self, t) return 3 + self:getTalentLevel(t) end, - getRadius = function(self, t) return 2 + (self:getTalentLevel(t)/2) end, action = function(self, t) - local radius = t.getRadius(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -150,7 +154,7 @@ game.level.map:addEffect(self, x, y, t.getDuration(self, t), DamageType.PHYSICAL_STUN, t.getDamage(self, t), - radius, + self:getTalentRadius(t), 5, nil, {type="quake"}, nil, self:spellFriendlyFire() @@ -161,7 +165,7 @@ end, info = function(self, t) local damage = t.getDamage(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local duration = t.getDuration(self, t) return ([[Causes a violent earthquake that deals %0.2f physical damage in a radius of %d each turn for %d turns and potentially stuns all creatures it affects. The damage will increase with the Magic stat]]): Index: game/modules/tome/data/talents/spells/arcane.lua =================================================================== --- game/modules/tome/data/talents/spells/arcane.lua (revision 2714) +++ game/modules/tome/data/talents/spells/arcane.lua (working copy) @@ -63,10 +63,14 @@ direct_hit = function(self, t) if self:getTalentLevel(t) >= 3 then return true else return false end end, reflectable = true, requires_target = true, + target = function(self, t) + local tg = {type="bolt", range=self:getTalentRange(t), talent=t} + if self:getTalentLevel(t) >= 3 then tg.type = "beam" end + return tg + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 230) end, action = function(self, t) - local tg = {type="bolt", range=self:getTalentRange(t), talent=t} - if self:getTalentLevel(t) >= 3 then tg.type = "beam" end + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.ARCANE, self:spellCrit(t.getDamage(self, t)), nil) Index: game/modules/tome/data/talents/psionic/focus.lua =================================================================== --- game/modules/tome/data/talents/psionic/focus.lua (revision 2714) +++ game/modules/tome/data/talents/psionic/focus.lua (working copy) @@ -50,7 +50,7 @@ --local gem_level = getGemLevel(self) --local dam = (5 + self:getTalentLevel(t) * self:getWil(40))*(1 + 0.3*gem_level) local dam = t.getDamage(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=0, friendlyfire=false, talent=t} + local tg = {type="ball", range=self:getTalentRange(t), radius=0, selffire=false, talent=t} local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.PHYSICAL, self:spellCrit(rng.avg(0.8*dam, dam)), {type="flame"}) @@ -79,7 +79,8 @@ end, psi = 20, tactical = { ATTACK = 2 }, - range = function(self, t) + range = 0, + radius = function(self, t) local r = 5 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) @@ -90,12 +91,15 @@ local gem_level = getGemLevel(self) return self:combatTalentIntervalDamage(t, "wil", 21, 281)*(1 + 0.3*gem_level) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) local gem_level = getGemLevel(self) --local dam = (20 + self:getTalentLevel(t) * self:getWil(40))*(1 + 0.3*gem_level) local dam = t.getDamage(self, t) local tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) + local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRadius(t), true) for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local a = game.level.map(x, y, Map.ACTOR) if a and self:reactionToward(a) < 0 then @@ -151,4 +155,4 @@ return ([[You can channel more energy with your auras and shields using a telekinetically-wielded gemstone as a focus. Increases the base strength of all auras and shields by %0.2f to %0.2f, depending on the quality of the gem used as a focus.]]): format(inc, 5*inc) end, -} \ No newline at end of file +} Index: game/modules/tome/data/talents/psionic/voracity.lua =================================================================== --- game/modules/tome/data/talents/psionic/voracity.lua (revision 2714) +++ game/modules/tome/data/talents/psionic/voracity.lua (working copy) @@ -28,27 +28,27 @@ end, tactical = { DEFEND = 1, DISABLE = 2 }, direct_hit = true, - range = function(self, t) + range = 0, + radius = function(self, t) local r = 2 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) return math.ceil(r*mult) 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 tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) - for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do - local a = game.level.map(x, y, Map.ACTOR) - if a and self:reactionToward(a) < 0 then - tgts[#tgts+1] = a - end - end end local en = ( 3 + self:getTalentLevel(t)) * (100 + self:getWil())/100 - self:incPsi(en*#tgts) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} local dam = .1 + 0.03*self:getTalentLevel(t) - self:project(tg, self.x, self.y, DamageType.MINDSLOW, dam) - local x, y = self.x, self.y + local tg = self:getTalentTarget(t) + self:project(tg, self.x, self.y, function(tx, ty) + DamageType:get(DamageType.MINDSLOW).projector(self, tx, ty, DamageType.MINDSLOW, dam) + local act = game.level.map(tx, ty, engine.Map.ACTOR) + if act then + self:incPsi(en) + end + end) return true end, info = function(self, t) @@ -71,28 +71,27 @@ end, psi = 0, tactical = { DEFEND = 2, DISABLE = 2 }, - range = function(self, t) + range = 0, + radius = function(self, t) local r = 1 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) return math.ceil(r*mult) 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 tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) - for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do - local a = game.level.map(x, y, Map.ACTOR) - if a and self:reactionToward(a) < 0 then - tgts[#tgts+1] = a - end - end end local en = ( 4 + self:getTalentLevel(t)) * (100 + self:getWil())/85 - self:incPsi(en*#tgts) - local duration = self:getTalentLevel(t) + 2 - local radius = self:getTalentRange(t) local dam = math.ceil(1 + 0.5*self:getTalentLevel(t)) - local tg = {type="ball", range=0, radius=radius, friendlyfire=false} - self:project(tg, self.x, self.y, DamageType.MINDFREEZE, dam) + local tg = self:getTalentTarget(t) + self:project(tg, self.x, self.y, function(tx, ty) + DamageType:get(DamageType.MINDFREEZE).projector(self, tx, ty, DamageType.MINDFREEZE, dam) + local act = game.level.map(tx, ty, engine.Map.ACTOR) + if act then + self:incPsi(en) + end + end) return true end, info = function(self, t) @@ -117,12 +116,16 @@ end, tactical = { DEFEND = 2, DAMAGE = 2, DISABLE = 1 }, direct_hit = true, - range = function(self, t) + range = 0, + radius = function(self, t) local r = 2 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) return math.ceil(r*mult) 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 tgts = {} local grids = core.fov.circle_grids(self.x, self.y, self:getTalentRange(t), true) @@ -134,7 +137,7 @@ end end local en = ( 5 + self:getTalentLevel(t)) * (100 + self:getWil())/75 self:incPsi(en*#tgts) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local dam = self:spellCrit(self:combatTalentMindDamage(t, 28, 270)) self:project(tg, self.x, self.y, DamageType.LIGHTNING_DAZE, rng.avg(dam / 3, dam, 3)) local x, y = self.x, self.y Index: game/modules/tome/data/talents/psionic/psi-fighting.lua =================================================================== --- game/modules/tome/data/talents/psionic/psi-fighting.lua (revision 2714) +++ game/modules/tome/data/talents/psionic/psi-fighting.lua (working copy) @@ -35,6 +35,7 @@ cooldown = 10, psi = 10, range = 1, + requires_target = true, tactical = { ATTACK = 2 }, action = function(self, t) local tkweapon = self:getInven("MAINHAND")[1] @@ -100,7 +101,12 @@ mode = "sustained", sustain_psi = 0, points = 5, - tactical = { ATTACK = 2 }, + tactical = { ATTACK = function(self, t) + local k_aura_on = self:isTalentActive(self.T_KINETIC_AURA) + local t_aura_on = self:isTalentActive(self.T_THERMAL_AURA) + local c_aura_on = self:isTalentActive(self.T_CHARGED_AURA) + return (k_aura_on and 1 or 0) + (t_aura_on and 1 or 0) + (c_aura_on and 1 or 0) + end}, activate = function(self, t) local ret = { k_aura_on = self:isTalentActive(self.T_KINETIC_AURA), Index: game/modules/tome/data/talents/psionic/projection.lua =================================================================== --- game/modules/tome/data/talents/psionic/projection.lua (revision 2714) +++ game/modules/tome/data/talents/psionic/projection.lua (working copy) @@ -94,6 +94,42 @@ end end +local function aura_range(self, t) + -- Spiked ability + if self:isTalentActive(t.id) then + if type(t.getSpikedRange) == "function" then return t.getSpikedRange(self, t) end + return t.getSpikedRange + -- Normal ability + else + if type(t.getNormalRange) == "function" then return t.getNormalRange(self, t) end + return t.getNormalRange + end +end + +local function aura_radius(self, t) + -- Spiked ability + if self:isTalentActive(t.id) then + if type(t.getSpikedRadius) == "function" then return t.getSpikedRadius(self, t) end + return t.getSpikedRadius + -- Normal ability + else + if type(t.getNormalRadius) == "function" then return t.getNormalRadius(self, t) end + return t.getNormalRadius + end +end + +local function aura_target(self, t) + -- Spiked ability + if self:isTalentActive(t.id) then + if type(t.getSpikedTarget) == "function" then return t.getSpikedTarget(self, t) end + return t.getSpikedTarget + -- Normal ability + else + if type(t.getNormalTarget) == "function" then return t.getNormalTarget(self, t) end + return t.getNormalTarget + end +end + newTalent{ name = "Kinetic Aura", type = {"psionic/projection", 1}, @@ -106,14 +142,43 @@ return 15 - (self:getTalentLevelRaw(self.T_AURA_DISCIPLINE) or 0) end, tactical = { ATTACKAREA = 2 }, - range = function(self, t) + range = aura_range, + radius = aura_radius, + target = aura_target, + getSpikedRange = function(self, t) local r = 6 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) r = math.floor(r*mult) return math.min(r, 10) end, - direct_hit = true, + getNormalRange = function(self, t) + return 0 + end, + getSpikedRadius = function(self, t) + return 0 + end, + getNormalRadius = function(self, t) + return 1 + end, + getSpikedTarget = function(self, t) + return {type="beam", nolock=true, range=t.getSpikedRange(self, t), talent=t} + end, + getNormalTarget = function(self, t) + return {type="ball", range=t.getNormalRange(self, t), radius=t.getNormalRadius(self, t), selffire=false} + end, + requires_target = function(self, t) + -- Spiked ability + if self:isTalentActive(t.id) and self:getPsi() > t.getSpikeCost(self, t) then + return true + -- Normal ability + else + return false + end + end, + getSpikeCost = function(self, t) + return t.sustain_psi - 2*getGemLevel(self) + end, getAuraStrength = function(self, t) local add = 0 if self:knowTalent(self.T_FOCUSED_CHANNELING) then @@ -126,29 +191,16 @@ return 3 + math.floor(self:getTalentLevel(t)) end, do_kineticaura = function(self, t) - local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) local dam = t.getAuraStrength(self, t) - local tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, 1, true) - for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do - local a = game.level.map(x, y, Map.ACTOR) - if a and self:reactionToward(a) < 0 then - tgts[#tgts+1] = a + local tg = t.getNormalTarget(self, t) + self:project(tg, self.x, self.y, function(tx, ty) + DamageType:get(DamageType.PHYSICAL).projector(self, tx, ty, DamageType.PHYSICAL, dam) + local act = game.level.map(tx, ty, engine.Map.ACTOR) + if act then + self:incPsi(-dam/mast) end - end end - - -- Randomly take targets - local tg = {type="hit", range=1, talent=t} - for i = 1, 10 do - if #tgts <= 0 then break end - local a, id = rng.table(tgts) - table.remove(tgts, id) - self:project(tg, a.x, a.y, DamageType.PHYSICAL, dam) - --game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(a.x-self.x), math.abs(a.y-self.y)), "lightning", {tx=a.x-self.x, ty=a.y-self.y}) - self:incPsi(-dam/mast) - end - + end) end, activate = function(self, t) if self:isTalentActive(self.T_THERMAL_AURA) and self:isTalentActive(self.T_CHARGED_AURA) then @@ -159,13 +211,13 @@ end, deactivate = function(self, t, p) local dam = 50 + 0.4 * t.getAuraStrength(self, t)*t.getAuraStrength(self, t) - local cost = t.sustain_psi - 2*getGemLevel(self) + local cost = t.getSpikeCost(self, t) if self:getPsi() <= cost then game.logPlayer(self, "The aura dissipates without producing a spike.") return true end - local tg = {type="beam", nolock=true, range=self:getTalentRange(t), talent=t} + local tg = t.getSpikedTarget(self, t) local x, y = self:getTarget(tg) if not x or not y then return nil end local actor = game.level.map(x, y, Map.ACTOR) @@ -183,7 +235,7 @@ local dam = t.getAuraStrength(self, t) local spikedam = 50 + 0.4 * dam * dam local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) - local spikecost = t.sustain_psi - 2*getGemLevel(self) + local spikecost = t.getSpikeCost(self, t) return ([[Fills the air around you with reactive currents of force that do %d physical damage to all who approach. All damage done by the aura will drain one point of energy per %0.2f points of damage dealt. When deactivated, if you have at least %d energy, a massive spike of kinetic energy is released as a beam, smashing targets for %d physical damage and sending them flying. Telekinetically wielding a gem instead of a weapon will result in improved spike efficiency. The damage will increase with the Willpower stat. @@ -204,14 +256,39 @@ return 15 - (self:getTalentLevelRaw(self.T_AURA_DISCIPLINE) or 0) end, tactical = { ATTACKAREA = 2 }, - range = function(self, t) + range = aura_range, + radius = aura_radius, + target = aura_target, + getSpikedRange = function(self, t) + return 0 + end, + getNormalRange = function(self, t) + return 0 + end, + getSpikedRadius = function(self, t) local r = 6 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) r = math.floor(r*mult) - return math.min(r, 10) + return math.min(r, 10) end, + getNormalRadius = function(self, t) + return 1 end, - direct_hit = true, + getSpikedTarget = function(self, t) + return {type="cone", range=t.getSpikedRange(self, t), radius=t.getSpikedRadius(self, t), selffire=false, talent=t} + end, + getNormalTarget = function(self, t) + return {type="ball", range=t.getNormalRange(self, t), radius=t.getNormalRadius(self, t), selffire=false} + end, + requires_target = function(self, t) + -- Spiked ability + if self:isTalentActive(t.id) and self:getPsi() > t.getSpikeCost(self, t) then + return true + -- Normal ability + else + return false + end + end, getAuraStrength = function(self, t) local add = 0 if self:knowTalent(self.T_FOCUSED_CHANNELING) then @@ -220,30 +297,20 @@ --return 5 + (1+ self:getWil(5))*self:getTalentLevel(t) + add return self:combatTalentIntervalDamage(t, "wil", 6, 50) + add end, + getSpikeCost = function(self, t) + return t.sustain_psi - 2*getGemLevel(self) + end, do_thermalaura = function(self, t) - local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) local dam = t.getAuraStrength(self, t) - local tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, 1, true) - for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do - local a = game.level.map(x, y, Map.ACTOR) - if a and self:reactionToward(a) < 0 then - tgts[#tgts+1] = a + local tg = t.getNormalTarget(self, t) + self:project(tg, self.x, self.y, function(tx, ty) + DamageType:get(DamageType.FIRE).projector(self, tx, ty, DamageType.FIRE, dam) + local act = game.level.map(tx, ty, engine.Map.ACTOR) + if act then + self:incPsi(-dam/mast) end - end end - - -- Randomly take targets - local tg = {type="hit", range=1, talent=t} - for i = 1, 10 do - if #tgts <= 0 then break end - local a, id = rng.table(tgts) - table.remove(tgts, id) - self:project(tg, a.x, a.y, DamageType.FIRE, dam) - --game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(a.x-self.x), math.abs(a.y-self.y)), "lightning", {tx=a.x-self.x, ty=a.y-self.y}) - self:incPsi(-dam/mast) - end - + end) end, activate = function(self, t) if self:isTalentActive(self.T_KINETIC_AURA) and self:isTalentActive(self.T_CHARGED_AURA) then @@ -254,14 +321,14 @@ end, deactivate = function(self, t, p) local dam = 50 + 0.4 * t.getAuraStrength(self, t)*t.getAuraStrength(self, t) - local cost = t.sustain_psi - 2*getGemLevel(self) + local cost = t.getSpikeCost(self, t) --if self:isTalentActive(self.T_CONDUIT) then return true end if self:getPsi() <= cost then game.logPlayer(self, "The aura dissipates without producing a spike.") return true end - local tg = {type="cone", range=1, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = t.getSpikedTarget(self, t) local x, y = self:getTarget(tg) if not x or not y then return nil end local actor = game.level.map(x, y, Map.ACTOR) @@ -279,7 +346,7 @@ local rad = self:getTalentRange(t) local spikedam = 50 + 0.4 * dam * dam local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) - local spikecost = t.sustain_psi - 2*getGemLevel(self) + local spikecost = t.getSpikeCost(self, t) return ([[Fills the air around you with reactive currents of furnace-like heat that do %d fire damage to all who approach. All damage done by the aura will drain one point of energy per %0.2f points of damage dealt. When deactivated, if you have at least %d energy, a massive spike of thermal energy is released as a conical blast (radius %d) of superheated air. Anybody caught in it will suffer %d fire damage. Telekinetically wielding a gem instead of a weapon will result in improved spike efficiency. The damage will increase with the Willpower stat. @@ -300,14 +367,44 @@ return 15 - (self:getTalentLevelRaw(self.T_AURA_DISCIPLINE) or 0) end, tactical = { ATTACKAREA = 2 }, - range = function(self, t) + range = aura_range, + radius = aura_radius, + target = aura_target, + getSpikedRange = function(self, t) local r = 6 local gem_level = getGemLevel(self) local mult = (1 + 0.02*gem_level*(self:getTalentLevel(self.T_REACH))) r = math.floor(r*mult) return math.min(r, 10) end, - direct_hit = true, + getNormalRange = function(self, t) + return 0 + end, + getSpikedRadius = function(self, t) + return 10 + end, + getNormalRadius = function(self, t) + return 1 + end, + getSpikedTarget = function(self, t) + -- Use the nb_foes_seen + return + end, + getNormalTarget = function(self, t) + return {type="ball", range=t.getNormalRange(self, t), radius=t.getNormalRadius(self, t), selffire=false} + end, + requires_target = function(self, t) + -- Spiked ability + if self:isTalentActive(t.id) and self:getPsi() > t.getSpikeCost(self, t) then + return true + -- Normal ability + else + return false + end + end, + getSpikeCost = function(self, t) + return t.sustain_psi - 2*getGemLevel(self) + end, getAuraStrength = function(self, t) local add = 0 if self:knowTalent(self.T_FOCUSED_CHANNELING) then @@ -319,25 +416,14 @@ do_chargedaura = function(self, t) local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) local dam = t.getAuraStrength(self, t) - local tgts = {} - local grids = core.fov.circle_grids(self.x, self.y, 1, true) - for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do - local a = game.level.map(x, y, Map.ACTOR) - if a and self:reactionToward(a) < 0 then - tgts[#tgts+1] = a + local tg = t.getNormalTarget(self, t) + self:project(tg, self.x, self.y, function(tx, ty) + DamageType:get(DamageType.LIGHTNING).projector(self, tx, ty, DamageType.LIGHTNING, dam) + local act = game.level.map(tx, ty, engine.Map.ACTOR) + if act then + self:incPsi(-dam/mast) end - end end - - -- Randomly take targets - local tg = {type="hit", range=1, talent=t} - for i = 1, 10 do - if #tgts <= 0 then break end - local a, id = rng.table(tgts) - table.remove(tgts, id) - self:project(tg, a.x, a.y, DamageType.LIGHTNING, dam) - --game.level.map:particleEmitter(self.x, self.y, math.max(math.abs(a.x-self.x), math.abs(a.y-self.y)), "lightning", {tx=a.x-self.x, ty=a.y-self.y}) - self:incPsi(-dam/mast) - end + end) end, activate = function(self, t) if self:isTalentActive(self.T_THERMAL_AURA) and self:isTalentActive(self.T_KINETIC_AURA) then @@ -349,7 +435,7 @@ end, deactivate = function(self, t, p) local dam = 50 + 0.4 * t.getAuraStrength(self, t)*t.getAuraStrength(self, t) - local cost = t.sustain_psi - 2*getGemLevel(self) + local cost = t.getSpikeCost(self, t) --if self:isTalentActive(self.T_CONDUIT) then return true end if self:getPsi() <= cost then game.logPlayer(self, "The aura dissipates without producing a spike.") @@ -413,7 +499,7 @@ local dam = t.getAuraStrength(self, t) local spikedam = 50 + 0.4 * dam * dam local mast = 5 + (self:getTalentLevel(self.T_AURA_DISCIPLINE) or 0) + getGemLevel(self) - local spikecost = t.sustain_psi - 2*getGemLevel(self) + local spikecost = t.getSpikeCost(self, t) local nb = 3 + self:getTalentLevelRaw(t) return ([[Fills the air around you with crackling energy, doing %d lightning damage to all who stand nearby. All damage done by the aura will drain one point of energy per %0.2f points of damage dealt. When deactivated, if you have at least %d energy, a massive spike of electrical energy jumps between up to %d nearby targets, doing %d lightning damage to each. Telekinetically wielding a gem instead of a weapon will result in improved spike efficiency. Index: game/modules/tome/data/talents/cursed/force-of-will.lua =================================================================== --- game/modules/tome/data/talents/cursed/force-of-will.lua (revision 2714) +++ game/modules/tome/data/talents/cursed/force-of-will.lua (working copy) @@ -209,13 +209,13 @@ points = 5, random_ego = "attack", cooldown = 10, - tactical = { ATTACK = 2 }, + tactical = { ATTACKAREA = 2 }, requires_target = true, hate = 1.5, range = function(self, t) return 4 end, - getRadius = function(self, t) + radius = function(self, t) return math.floor(2 + self:getTalentLevel(t) / 3) end, getDamage = function(self, t) @@ -224,13 +224,16 @@ getKnockback = function(self, t) return 2 + math.floor(self:getTalentLevel(t)) end, + target = function(self, t) + return {type="ball", nolock=true, pass_terrain=false, friendly_fire=false, nowarning=true, range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) local range = self:getTalentRange(t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) local knockback = t.getKnockback(self, t) - local tg = {type="ball", nolock=true, pass_terrain=false, friendly_fire=false, nowarning=true, range=range, radius=radius, talent=t} + local tg = self:getTalentTarget(t) local blastX, blastY = self:getTarget(tg) if not blastX or not blastY or core.fov.distance(self.x, self.y, blastX, blastY) > range then return nil end @@ -254,7 +257,7 @@ return true end, info = function(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) local knockback = t.getKnockback(self, t) return ([[You rage coalesces at a single point and then explodes outward blasting enemies within a radius of %d in all directions. The blast causes %d damage and %d knockback at the center that decreases with distance. Index: game/modules/tome/data/talents/cursed/darkness.lua =================================================================== --- game/modules/tome/data/talents/cursed/darkness.lua (revision 2714) +++ game/modules/tome/data/talents/cursed/darkness.lua (working copy) @@ -147,6 +147,7 @@ cooldown = 20, hate = 1.5, range = 5, + radius = 3, tactical = { ATTACK = 1, DISABLE = 2 }, requires_target = true, @@ -271,9 +272,6 @@ end end, - getRadius = function(self, t) - return 3 - end, getDarkCount = function(self, t) return 2 + math.floor(self:getTalentLevel(t)) end, @@ -282,7 +280,7 @@ end, action = function(self, t) local range = self:getTalentRange(t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) local darkCount = t.getDarkCount(self, t) @@ -323,7 +321,7 @@ return true end, info = function(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) local darkCount = t.getDarkCount(self, t) return ([[Creeping dark slowly spreads from %d spots in a radius of %d around the targeted location. The dark deals %d damage and blocks the sight of any who do not possess Dark Vision or some other magical means of seeing. Index: game/modules/tome/data/talents/cursed/gloom.lua =================================================================== --- game/modules/tome/data/talents/cursed/gloom.lua (revision 2714) +++ game/modules/tome/data/talents/cursed/gloom.lua (working copy) @@ -156,7 +156,7 @@ resetTorment = true local attackStrength = 0.3 + self:getTalentLevel(tTorment) * 0.12 if checkWillFailure(self, target, 30, 95, attackStrength) then - local tg = {type="hit", friendlyfire=false, talent=tTorment} + local tg = {type="hit", selffire=false, talent=tTorment} local damage = (30 + self:getWil() * 0.4 * self:getTalentLevel(tTorment)) * getHateMultiplier(self, 0.5, 1.5) local grids = self:project(tg, target.x, target.y, DamageType.DARKNESS, damage, {type="slime"}) --game:playSoundNear(self, "talents/spell_generic") Index: game/modules/tome/data/talents/corruptions/blood.lua =================================================================== --- game/modules/tome/data/talents/corruptions/blood.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/blood.lua (working copy) @@ -25,11 +25,13 @@ cooldown = 7, vim = 24, tactical = { ATTACKAREA = 2 }, - range = function(self, t) return math.ceil(3 + self:getTalentLevel(t)) end, + radius = function(self, t) + return math.ceil(3 + self:getTalentLevel(t)) + end, direct_hit = true, requires_target = true, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), talent=t} + local tg = {type="cone", range=0, radius=self:getTalentRadius(t), talent=t} local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.CORRUPTED_BLOOD, { @@ -83,10 +85,12 @@ cooldown = 12, vim = 30, tactical = { ATTACKAREA = 2, DISABLE = 2 }, - range = function(self, t) return 2 + self:getTalentLevelRaw(t) end, + radius = function(self, t) + return 2 + self:getTalentLevelRaw(t) + end, requires_target = true, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = {type="ball", range=0, radius=self:getTalentRadius(t), selffire=false, talent=t} local grids = self:project(tg, self.x, self.y, DamageType.BLOOD_BOIL, self:spellCrit(self:combatTalentSpellDamage(t, 28, 190))) game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_blood", {radius=tg.radius}) game:playSoundNear(self, "talents/slime") Index: game/modules/tome/data/talents/corruptions/bone.lua =================================================================== --- game/modules/tome/data/talents/corruptions/bone.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/bone.lua (working copy) @@ -29,8 +29,11 @@ tactical = { ATTACK = 2 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, action = function(self, t) - 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 self:project(tg, x, y, DamageType.PHYSICAL, self:spellCrit(self:combatTalentSpellDamage(t, 20, 200)), {type="bones"}) @@ -97,9 +100,14 @@ cooldown = 12, tactical = { ATTACKAREA = 2 }, random_ego = "attack", - range = function(self, t) return self:getTalentLevelRaw(t) end, + radius = function(self, t) + return self:getTalentLevelRaw(t) + end, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), selffire=false} + end, action = function(self, t) - local tg = {type="ball", radius=self:getTalentRange(t), friendlyfire=false} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, DamageType.PHYSICAL, self:combatTalentSpellDamage(t, 8, 180), {type="bones"}) game:playSoundNear(self, "talents/arcane") return true Index: game/modules/tome/data/talents/corruptions/scourge.lua =================================================================== --- game/modules/tome/data/talents/corruptions/scourge.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/scourge.lua (working copy) @@ -101,9 +101,14 @@ points = 5, vim = 18, cooldown = 12, - range = 1, + range = 0, + radius = 1, requires_target = true, tactical = { ATTACK = 2, DISABLE = 1 }, + target = function(self, t) + -- Tries to simulate the acid splash + return {type="ballbolt", range=1, radius=self:getTalentRadius(t), selffire=false, talent=t} + end, action = function(self, t) local weapon, offweapon = self:hasDualWeapon() if not weapon then @@ -121,7 +126,9 @@ -- Acid splash ! if hit1 or hit2 then - local tg = {type="ball", range=0, radius=1, friendlyfire=false, talent=t, x=target.x, y=target.y} + local tg = self:getTalentTarget(t) + tg.x = target.x + tg.y = target.y self:project(tg, target.x, target.y, DamageType.ACID, self:spellCrit(self:combatTalentSpellDamage(t, 10, 130))) end Index: game/modules/tome/data/talents/corruptions/blight.lua =================================================================== --- game/modules/tome/data/talents/corruptions/blight.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/blight.lua (working copy) @@ -52,10 +52,14 @@ cooldown = 10, vim = 30, range = 10, + radius = 3, tactical = { DISABLE = 2 }, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", radius=3, 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 = self:spellCrit(self:combatTalentSpellDamage(t, 28, 120)) @@ -140,10 +144,15 @@ points = 5, vim = 36, cooldown = 30, + range = 0, + radius = 4, tactical = { ATTACKAREA = 2 }, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) local duration = 5 + self:getTalentLevel(t) - local radius = 4 + local radius = self:getTalentRadius(t) local dam = self:combatTalentSpellDamage(t, 12, 130) -- Add a lasting map effect game.level.map:addEffect(self, @@ -163,8 +172,8 @@ return true end, info = function(self, t) - return ([[A furious poison storm rages around the caster, poisoning all creatures inside for doing %0.2f nature damage in 6 turns in a radius of 4 for %d turns. + return ([[A furious poison storm rages around the caster, poisoning all creatures inside for doing %0.2f nature damage in 6 turns in a radius of %d for %d turns. Poisoning is cumulative, the longer they stay in they higher the poison they take. - The damage will increase with the Magic stat]]):format(damDesc(self, DamageType.NATURE, self:combatTalentSpellDamage(t, 12, 130)), 5 + self:getTalentLevel(t)) + The damage will increase with the Magic stat]]):format(damDesc(self, DamageType.NATURE, self:combatTalentSpellDamage(t, 12, 130)), self:getTalentRadius(t), 5 + self:getTalentLevel(t)) end, } Index: game/modules/tome/data/talents/corruptions/shadowflame.lua =================================================================== --- game/modules/tome/data/talents/corruptions/shadowflame.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/shadowflame.lua (working copy) @@ -46,12 +46,18 @@ vim = 20, requires_target = true, range = 6, + radius = function(self, t) + return 1 + self:getTalentLevelRaw(t) + end, proj_speed = 4, tactical = { ATTACKAREA = 2 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=set:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t, display={particle="bolt_fire", trail="firetrail"}} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), friendlyfire=self:spellFriendlyFire(), talent=t, display={particle="bolt_fire", trail="firetrail"}} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:projectile(tg, x, y, DamageType.SHADOWFLAME, self:spellCrit(self:combatTalentSpellDamage(t, 28, 220)), function(self, tg, x, y, grids) @@ -66,7 +72,7 @@ The damage will increase with the Magic stat]]):format( damDesc(self, DamageType.FIRE, self:combatTalentSpellDamage(t, 28, 220) / 2), damDesc(self, DamageType.DARKNESS, self:combatTalentSpellDamage(t, 28, 220) / 2), - 1 + self:getTalentLevelRaw(t) + self:getTalentRadius(t) ) end, } Index: game/modules/tome/data/talents/corruptions/hexes.lua =================================================================== --- game/modules/tome/data/talents/corruptions/hexes.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/hexes.lua (working copy) @@ -25,11 +25,15 @@ cooldown = 20, vim = 30, range = 10, + radius = 2, tactical = { DISABLE = 2 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=2, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(tx, ty) @@ -56,11 +60,15 @@ cooldown = 20, vim = 30, range = 10, + radius = 2, tactical = { DISABLE = 2 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=2, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(tx, ty) @@ -87,11 +95,15 @@ cooldown = 20, vim = 30, range = 10, + radius = 2, tactical = { DISABLE = 2 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=2, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(tx, ty) @@ -121,8 +133,11 @@ no_npc_use = true, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="hit", range=self:getTalentRange(t), talent=t} + end, action = function(self, t) - local tg = {type="hit", 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 self:project(tg, x, y, function(tx, ty) Index: game/modules/tome/data/talents/corruptions/plague.lua =================================================================== --- game/modules/tome/data/talents/corruptions/plague.lua (revision 2714) +++ game/modules/tome/data/talents/corruptions/plague.lua (working copy) @@ -66,8 +66,15 @@ vim = 18, cooldown = 9, range = 7, + radius = function(self, t) + return 1 + math.floor(self:getTalentLevelRaw(t) / 2) + end, tactical = { ATTACK = 1 }, requires_target = true, + target = function(self, t) + -- Target trying to combine the bolt and the ball disease spread + return {type="ballbolt", radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, action = function(self, t) local tg = {type="bolt", range=self:getTalentRange(t)} local x, y = self:getTarget(tg) @@ -97,12 +104,12 @@ end) if #diseases > 0 then - self:project({type="ball", radius=1 + math.floor(self:getTalentLevelRaw(t) / 2), range=self:getTalentRange(t)}, x, y, function(px, py) + self:project({type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)}, x, y, function(px, py) local target = game.level.map(px, py, engine.Map.ACTOR) if not target or target == source or target == self or (self:reactionToward(target) >= 0) then return end local disease = rng.table(diseases) - target:setEffect(disease.id, 6, {src=self, dam=disease.params.dam, str=disease.params.str, dex=disease.params.dex, con=disease.params.con}) + target:setEffect(disease.id, 6, {src=self, dam=disease.params.dam, str=disease.params.str, dex=disease.params.dex, con=disease.params.con, heal_factor=disease.params.heal_factor}) game.level.map:particleEmitter(px, py, 1, "slime") end) end @@ -114,7 +121,7 @@ return ([[Make your target's diseases burst, doing %0.2f blight damage for each disease it is infected with. This will also spread a random disease to any nearby foes in a radius of %d. The damage will increase with your Magic stat.]]): - format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 15, 85)), 1 + math.floor(self:getTalentLevelRaw(t) / 2)) + format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 15, 85)), self:getTalentRadius(t)) end, } @@ -126,11 +133,15 @@ vim = 35, cooldown = 15, range = 6, + radius = 2, tactical = { DISABLE = 1 }, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=2} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end @@ -180,6 +191,7 @@ vim = 20, cooldown = 13, range = 6, + radius = 2, tactical = { ATTACK = 2 }, requires_target = true, do_spread = function(self, t, carrier) @@ -193,12 +205,14 @@ end if #diseases == 0 then return end - self:project({type="ball", radius=2}, carrier.x, carrier.y, function(px, py) + self:project({type="ball", radius=self:getTalentRadius(t)}, carrier.x, carrier.y, function(px, py) local target = game.level.map(px, py, engine.Map.ACTOR) if not target or target == carrier or target == self then return end local disease = rng.table(diseases) - target:setEffect(disease.id, 6, {src=self, dam=disease.params.dam, str=disease.params.str, dex=disease.params.dex, con=disease.params.con}) + local params = disease.params + params.src = self + target:setEffect(disease.id, 6, {src=self, dam=disease.params.dam, str=disease.params.str, dex=disease.params.dex, con=disease.params.con, heal_factor=disease.params.heal_factor}) game.level.map:particleEmitter(px, py, 1, "slime") end) end, @@ -224,7 +238,7 @@ end, info = function(self, t) return ([[Infects the target with a very contagious disease doing %0.2f damage per turn for 6 turns. - If any blight damage from non-diseases hits the target, the epidemic will activate and spread a random disease to nearby targets. + If any blight damage from non-diseases hits the target, the epidemic may activate and spread a random disease to nearby targets. Creatures suffering from that disease will also suffer healing reduction (%d%%). The damage will increase with your Magic stat.]]): format(damDesc(self, DamageType.BLIGHT, self:combatTalentSpellDamage(t, 15, 50)), 40 + self:getTalentLevel(t) * 4) Index: game/modules/tome/data/talents/techniques/dualweapon.lua =================================================================== --- game/modules/tome/data/talents/techniques/dualweapon.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/dualweapon.lua (working copy) @@ -251,6 +251,11 @@ stamina = 30, require = techs_dex_req4, tactical = { ATTACKAREA = 2 }, + range = 0, + radius = 1, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, on_pre_use = function(self, t, silent) if not self:hasDualWeapon() then if not silent then game.logPlayer(self, "You require a two weapons to use this talent.") end return false end return true end, action = function(self, t) local weapon, offweapon = self:hasDualWeapon() Index: game/modules/tome/data/talents/techniques/warcries.lua =================================================================== --- game/modules/tome/data/talents/techniques/warcries.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/warcries.lua (working copy) @@ -26,11 +26,17 @@ random_ego = "attack", cooldown = 7, stamina = 20, - range = 4, + range = 0, + radius = function(self, t) + return 3 + self:getTalentLevelRaw(t) + end, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, requires_target = true, tactical = { ATTACKAREA = 2 }, action = function(self, t) - local tg = {type="cone", range=0, radius=3 + self:getTalentLevelRaw(t), friendlyfire=false} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.PHYSICAL, (50 + self:getTalentLevel(t) * self:getStr()) / 2.3, {type="flame"}) @@ -86,11 +92,17 @@ random_ego = "attack", cooldown = 30, stamina = 40, - range = 4, + range = 0, + radius = function(self, t) + return 3 + self:getTalentLevelRaw(t) + end, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, requires_target = true, tactical = { DISABLE = 2 }, action = function(self, t) - local tg = {type="cone", range=0, radius=3 + self:getTalentLevelRaw(t), friendlyfire=false} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(px, py) Index: game/modules/tome/data/talents/techniques/weaponshield.lua =================================================================== --- game/modules/tome/data/talents/techniques/weaponshield.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/weaponshield.lua (working copy) @@ -179,6 +179,11 @@ random_ego = "attack", cooldown = 10, stamina = 30, + range = 0, + radius = 1, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, tactical = { ESCAPE = 2, DEFEND = 0.5 }, on_pre_use = function(self, t, silent) if not self:hasShield() then if not silent then game.logPlayer(self, "You require a weapon and a shield to use this talent.") end return false end return true end, action = function(self, t) Index: game/modules/tome/data/talents/techniques/2hweapon.lua =================================================================== --- game/modules/tome/data/talents/techniques/2hweapon.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/2hweapon.lua (working copy) @@ -27,6 +27,11 @@ cooldown = 10, stamina = 30, tactical = { ATTACKAREA = 3 }, + range = 0, + radius = 1, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, on_pre_use = function(self, t, silent) if not self:hasTwoHandedWeapon() then if not silent then game.logPlayer(self, "You require a two handed weapon to use this talent.") end return false end return true end, action = function(self, t) local weapon = self:hasTwoHandedWeapon() @@ -107,8 +112,14 @@ stamina = 30, cooldown = 18, tactical = { ATTACKAREA = 1, DISABLE = 3 }, - range = 1, + range = 0, + radius = function(self, t) + return 3 + self:getTalentLevelRaw(t) + end, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false} + end, on_pre_use = function(self, t, silent) if not self:hasTwoHandedWeapon() then if not silent then game.logPlayer(self, "You require a two handed weapon to use this talent.") end return false end return true end, action = function(self, t) local weapon = self:hasTwoHandedWeapon() @@ -117,7 +128,7 @@ return nil end - local tg = {type="cone", range=0, radius=3 + self:getTalentLevelRaw(t), friendlyfire=false} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.CONFUSION, { Index: game/modules/tome/data/talents/techniques/bow.lua =================================================================== --- game/modules/tome/data/talents/techniques/bow.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/bow.lua (working copy) @@ -62,13 +62,17 @@ stamina = 15, require = techs_dex_req3, range = archery_range, + radius = 1, tactical = { ATTACKAREA = 1 }, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon("bow") then if not silent then game.logPlayer(self, "You require a bow for this talent.") end return false end return true end, action = function(self, t) if not self:hasArcheryWeapon("bow") then game.logPlayer(self, "You must wield a bow!") return nil end - local tg = {type="ball", radius=1} + local tg = self:getTalentTarget(t) local targets = self:archeryAcquireTargets(tg, {limit_shots=2}) if not targets then return end self:archeryShoot(targets, t, nil, {mult=self:combatTalentWeaponDamage(t, 1.2, 1.7)}) @@ -88,17 +92,23 @@ stamina = 35, require = techs_dex_req4, range = archery_range, + radius = function(self, t) + return 2 + self:getTalentLevel(t)/3 + end, direct_hit = true, tactical = { ATTACKAREA = 2 }, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t), selffire=false} + end, on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon("bow") then if not silent then game.logPlayer(self, "You require a bow for this talent.") end return false end return true end, action = function(self, t) if not self:hasArcheryWeapon("bow") then game.logPlayer(self, "You must wield a bow!") return nil end - local tg = {type="ball", radius=2 + self:getTalentLevel(t)/3, friendlyfire=false} + local tg = self:getTalentTarget(t) local targets = self:archeryAcquireTargets(tg) if not targets then return end - self:archeryShoot(targets, t, {type="bolt",friendlyfire=false}, {mult=self:combatTalentWeaponDamage(t, 0.6, 1.3)}) + self:archeryShoot(targets, t, {type="bolt", selffire=false}, {mult=self:combatTalentWeaponDamage(t, 0.6, 1.3)}) return true end, info = function(self, t) Index: game/modules/tome/data/talents/techniques/archery.lua =================================================================== --- game/modules/tome/data/talents/techniques/archery.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/archery.lua (working copy) @@ -179,18 +179,24 @@ cooldown = 15, stamina = 15, range = archery_range, + radius = function(self, t) + local rad = 1 + if self:getTalentLevel(t) >= 3 then rad = rad + 1 end + if self:getTalentLevel(t) >= 5 then rad = rad + 1 end + return rad + end, require = techs_dex_req1, tactical = { ATTACKAREA = 2, DISABLE = 2 }, on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon() then if not silent then game.logPlayer(self, "You require a bow or sling for this talent.") end return false end return true end, requires_target = true, + target = function(self, t) + return {type="ball", x=x, y=y, radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, archery_onreach = function(self, t, x, y) - local rad = 1 - if self:getTalentLevel(t) >= 3 then rad = rad + 1 end - if self:getTalentLevel(t) >= 5 then rad = rad + 1 end - local tg = {type="ball", x=x, y=y, radius=rad} + local tg = self:getTalentTarget(t) self:project(tg, x, y, DamageType.LITE, 1) if self:getTalentLevel(t) >= 3 then - tg.friendlyfire = false + tg.selffire= false self:project(tg, self.x, self.y, DamageType.BLINDPHYSICAL, 3) end game.level.map:particleEmitter(x, y, tg.radius, "ball_light", {radius=tg.radius}) @@ -286,8 +292,14 @@ stamina = 15, require = techs_dex_req4, range = archery_range, + radius = function(self, t) + return 1 + self:getTalentLevel(t) / 3 + end, tactical = { ATTACKAREA = 2, DISABLE = 3 }, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), range=self:getTalentRange(t)} + end, on_pre_use = function(self, t, silent) if not self:hasArcheryWeapon() then if not silent then game.logPlayer(self, "You require a bow or sling for this talent.") end return false end return true end, archery_onhit = function(self, t, target, x, y) if target:checkHit(self:combatAttackDex(), target:combatPhysicalResist(), 0, 95, 10) and target:canBe("stun") then @@ -297,7 +309,7 @@ end end, action = function(self, t) - local tg = {type="ball", radius=1 + self:getTalentLevel(t) / 3} + local tg = self:getTalentTarget(t) local targets = self:archeryAcquireTargets(tg, {one_shot=true}) if not targets then return end self:archeryShoot(targets, t, tg, {mult=self:combatTalentWeaponDamage(t, 0.5, 1.5)}) Index: game/modules/tome/data/talents/techniques/superiority.lua =================================================================== --- game/modules/tome/data/talents/techniques/superiority.lua (revision 2714) +++ game/modules/tome/data/talents/techniques/superiority.lua (working copy) @@ -74,9 +74,15 @@ cooldown = 10, stamina = 30, tactical = { CLOSEIN = 2 }, - range = function(self, t) return 2 + self:getTalentLevel(t) end, + range = 0, + radius = function(self, t) + return 2 + self:getTalentLevel(t) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), friendlyfire=false, radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=0, friendlyfire=false, radius=self:getTalentRange(t), talent=t} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, function(px, py) local target = game.level.map(px, py, Map.ACTOR) if not target then return end Index: game/modules/tome/data/talents/misc/npcs.lua =================================================================== --- game/modules/tome/data/talents/misc/npcs.lua (revision 2714) +++ game/modules/tome/data/talents/misc/npcs.lua (working copy) @@ -579,20 +579,30 @@ ATTACKAREA = 10, DEFEND = 5, }, - range = 4, + range = 0, + radius = function(self, t) + return 4 + self:getTalentLevelRaw(t) + end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRadius(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, + getDuration = function(self, t) + return 2 + self:getTalentLevelRaw(t) + end, tactical = { DISABLE = 2 }, action = function(self, t) - local tg = {type="cone", range=0, radius=4 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end - self:project(tg, x, y, DamageType.BLINDING_INK, 2+self:getTalentLevelRaw(t), {type="dark"}) + self:project(tg, x, y, DamageType.BLINDING_INK, t.getDuration(self, t), {type="dark"}) game:playSoundNear(self, "talents/breath") return true end, info = function(self, t) - return ([[You project thick black ink, blinding your targets for %d turns.]]):format(2+self:getTalentLevelRaw(t)) + local duration = t.getDuration(self, t) + return ([[You project thick black ink, blinding your targets for %d turns.]]):format(duration) end, } @@ -705,11 +715,15 @@ ATTACK = 10, }, range = 10, + radius = 2, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, tactical = { ATTACK = 2 }, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=2} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.BLEED, 20 + (self:getStr() * self:getTalentLevel(t)) * 0.8, {type="archery"}) @@ -774,12 +788,18 @@ tactical = { ATTACK = 10, }, - range = 10, + range = 0, + radius = function(self, t) + return 2 + self:getTalentLevelRaw(t) / 1.5 + end, direct_hit = true, tactical = { DISABLE = 3 }, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=0, radius=2 + self:getTalentLevelRaw(t) / 1.5, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, function(px, py) @@ -808,11 +828,15 @@ ATTACK = 10, }, range = 10, + radius = 1, direct_hit = true, tactical = { DISABLE = 3, ATTACK = 2, ESCAPE = 2 }, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=1, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.PHYSKNOCKBACK, {dist=3+self:getTalentLevelRaw(t), dam=self:spellCrit(12 + self:getStr(50) * self:getTalentLevel(t))}, {type="archery"}) @@ -942,9 +966,12 @@ range = 7, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, tactical = { ATTACK = 3 }, action = function(self, t) - 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 self:project(tg, x, y, DamageType.MIND, self:spellCrit(self:combatTalentMindDamage(t, 10, 370)), {type="mind"}) @@ -989,9 +1016,12 @@ range = 7, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, tactical = { ATTACK = 3 }, action = function(self, t) - 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 self:project(tg, x, y, DamageType.MINDKNOCKBACK, self:spellCrit(self:combatTalentMindDamage(t, 10, 170)), {type="mind"}) @@ -1011,14 +1041,17 @@ cooldown = 13, vim = 27, range = 10, + radius = 4, direct_hit = true, requires_target = true, - tactical = { ATTACK = 2 }, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, + tactical = { ATTACK = 2, ATTACKAREA = 2 }, action = function(self, t) local duration = self:getTalentLevel(t) + 2 - local radius = 4 local dam = self:combatTalentSpellDamage(t, 4, 65) - local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -1026,7 +1059,7 @@ game.level.map:addEffect(self, x, y, duration, DamageType.BLIGHT, dam, - radius, + self:getTalentRadius(t), 5, nil, {type="blightzone"}, nil, self:spellFriendlyFire() @@ -1189,9 +1222,13 @@ BUFF = 10, }, direct_hit = true, - range = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=true, talent=t} + end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=true, talent=t} + local tg = self:getTalentTarget(t) local grids = self:project(tg, self.x, self.y, DamageType.DREDGE_FRENZY) game.level.map:particleEmitter(self.x, self.y, tg.radius, "ball_light", {radius=tg.radius}) game:playSoundNear(self, "talents/arcane") @@ -1201,4 +1238,4 @@ return ([[Speeds up nearby Dredges. ]]):format() end, -} \ No newline at end of file +} Index: game/modules/tome/data/talents/misc/inscriptions.lua =================================================================== --- game/modules/tome/data/talents/misc/inscriptions.lua (revision 2714) +++ game/modules/tome/data/talents/misc/inscriptions.lua (working copy) @@ -170,8 +170,8 @@ tactical = { BUFF = 2 }, action = function(self, t) local data = self:getInscriptionData(t.short_name) - self:project({type="ball", range=0, friendlyfire=true, radius=data.range + data.inc_stat}, self.x, self.y, engine.DamageType.LITE, 1) - self:project({type="ball", range=0, friendlyfire=true, radius=data.range + data.inc_stat}, self.x, self.y, engine.DamageType.BREAK_STEALTH, 1) + self:project({type="ball", range=0, selffire=true, radius=data.range + data.inc_stat}, self.x, self.y, engine.DamageType.LITE, 1) + self:project({type="ball", range=0, selffire=true, radius=data.range + data.inc_stat}, self.x, self.y, engine.DamageType.BREAK_STEALTH, 1) return true end, info = function(self, t) @@ -515,13 +515,14 @@ tactical = { ATTACKAREA = 1 }, requires_target = true, direct_hit = true, - range = function(self, t) + range = 0, + radius = function(self, t) local data = self:getInscriptionData(t.short_name) return data.range end, action = function(self, t) local data = self:getInscriptionData(t.short_name) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=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") Index: game/modules/tome/data/talents/gifts/summon-utility.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-utility.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/summon-utility.lua (working copy) @@ -23,13 +23,14 @@ points = 1, cooldown = 5, requires_target = false, - tactical = { PROTECT = 2 }, - range = function(self, t) return 3 + self:getTalentLevelRaw(t) end, + tactical = { SURROUNDED = 2 }, + range = 0, + radius = function(self, t) return 3 + self:getTalentLevelRaw(t) end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t} self:project(tg, self.x, self.y, function(tx, ty) local a = game.level.map(tx, ty, Map.ACTOR) - if a and self:reactionToward(a) < 0 then + if a then a:setTarget(self) end end) @@ -120,7 +121,8 @@ name = "turtle", faction = self.faction, desc = [[]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"default", stats = { con=15 + self:getWil() * self:getTalentLevel(t) / 5 + self:getTalentLevelRaw(self.T_RESILIENCE)*2, wil=18, dex=10 + self:getTalentLevel(t) * 2, }, level_range = {self.level, self.level}, exp_worth = 0, @@ -192,7 +194,8 @@ name = "giant spider", faction = self.faction, desc = [[]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"ranged", stats = { dex=15 + self:getWil() * self:getTalentLevel(t) / 5, wil=18, str=10 + self:getTalentLevel(t) * 2, con=10 + self:getTalentLevelRaw(self.T_RESILIENCE)*2 }, level_range = {self.level, self.level}, exp_worth = 0, @@ -241,7 +244,7 @@ tactical = { DISABLE = 0.2 }, action = function(self, t) local dur = math.floor(5 + self:getTalentLevel(t)) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=true, talent=t} + local tg = {type="ball", range=0, radius=self:getTalentRange(t), selffire=true, talent=t} self:project(tg, self.x, self.y, function(px, py) local target = game.level.map(px, py, Map.ACTOR) if not target then return end Index: game/modules/tome/data/talents/gifts/cold-drake.lua =================================================================== --- game/modules/tome/data/talents/gifts/cold-drake.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/cold-drake.lua (working copy) @@ -129,11 +129,15 @@ cooldown = 12, message = "@Source@ breathes ice!", tactical = { ATTACKAREA = 2, DISABLE = 1 }, - range = function(self, t) return 4 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 4 + self:getTalentLevelRaw(t) end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRange(t), selffire=false, talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.ICE, self:combatTalentStatDamage(t, "str", 30, 430)) Index: game/modules/tome/data/talents/gifts/summon-distance.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-distance.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/summon-distance.lua (working copy) @@ -49,11 +49,15 @@ equilibrium = 10, cooldown = 8, message = "@Source@ breathes acid!", - tactical = { ATTACKAREA = 2 }, - range = 5, + tactical = { ATTACKAREA = 2}, + range = 0, + radius = 5, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.ACID, self:combatTalentStatDamage(t, "wil", 30, 430)) @@ -76,10 +80,14 @@ cooldown = 8, message = "@Source@ breathes lightning!", tactical = { ATTACKAREA = 2 }, - range = 5, + range = 0, + radius = 5, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, 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 = self:combatTalentStatDamage(t, "wil", 30, 500) @@ -107,10 +115,14 @@ cooldown = 8, message = "@Source@ breathes poison!", tactical = { ATTACKAREA = 2 }, - range = 5, + range = 0, + radius = 5, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.POISON, self:combatTalentStatDamage(t, "wil", 30, 460)) @@ -160,7 +172,8 @@ name = "ritch flamespitter", faction = self.faction, desc = [[]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"ranged", stats = { mag=15 + self:getWil() * self:getTalentLevel(t) / 5, wil=10 + self:getTalentLevel(t) * 2, con=10+ self:getTalentLevelRaw(self.T_RESILIENCE)*2, }, level_range = {self.level, self.level}, exp_worth = 0, @@ -234,7 +247,9 @@ name = "3-headed hydra", faction = self.faction, desc = [[A strange reptilian creature with three smouldering heads.]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"melee", + stats = { wil=15 + self:getWil() * self:getTalentLevel(t) / 5, str=18, con=10 + self:getTalentLevel(t) * 2 + self:getTalentLevelRaw(self.T_RESILIENCE)*2}, level_range = {self.level, self.level}, exp_worth = 0, @@ -309,7 +324,8 @@ name = "warper", faction = self.faction, desc = [[It looks like a hole in reality. The Warper disrupts the normal flow of space and time.]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"ranged", stats = { mag=15 + self:getWil() * self:getTalentLevel(t) / 5, wil=10 + self:getTalentLevel(t) * 2, con=10+self:getTalentLevelRaw(self.T_RESILIENCE) * 2, }, level_range = {self.level, self.level}, exp_worth = 0, @@ -384,7 +400,8 @@ name = "fire drake", faction = self.faction, desc = [[A mighty fire drake, an Uruloki.]], autolevel = "none", - ai = "summoned", ai_real = "dumb_talented_simple", ai_state = { talent_in=1, }, + ai = "summoned", ai_real = "tactical", ai_state = { talent_in=1, ally_compassion=10}, + ai_tactic = resolvers.tactic"melee", stats = { str=15 + self:getWil() * self:getTalentLevel(t) / 5, wil=38, con=20 + self:getTalentLevel(t) * 3 + self:getTalentLevelRaw(self.T_RESILIENCE) * 2, }, level_range = {self.level, self.level}, exp_worth = 0, Index: game/modules/tome/data/talents/gifts/summon-augmentation.lua =================================================================== --- game/modules/tome/data/talents/gifts/summon-augmentation.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/summon-augmentation.lua (working copy) @@ -47,20 +47,29 @@ equilibrium = 5, cooldown = 25, range = 10, + radius = function(self, t) + return 1 + self:getTalentLevelRaw(t) + end, requires_target = true, - np_npc_use = true, + no_npc_use = true, + getRitchDamage = function(self, t) + return self:combatTalentStatDamage(t, "wil", 30, 400) + end, + getJellyDamage = function(self, t) + return self:combatTalentStatDamage(t, "wil", 30, 300) + end, action = function(self, t) local tg = {type="hit", range=self:getTalentRange(t), talent=t, first_target="friend"} local tx, ty, target = self:getTarget(tg) if not tx or not ty or not target or not target.summoner or not target.summoner == self or not target.wild_gift_summon then return nil end if target.name == "ritch flamespitter" then - local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), talent=t} - target:project(tg, target.x, target.y, DamageType.FIRE, self:combatTalentStatDamage(t, "wil", 30, 400), {type="flame"}) + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + target:project(tg, target.x, target.y, DamageType.FIRE, t.getRitchDamage(self, t), {type="flame"}) target:die() elseif target.name == "black jelly" then - local tg = {type="ball", range=self:getTalentRange(t), radius=1 + self:getTalentLevelRaw(t), talent=t} - target:project(tg, target.x, target.y, DamageType.SLIME, self:combatTalentStatDamage(t, "wil", 30, 300), {type="slime"}) + local tg = {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t} + target:project(tg, target.x, target.y, DamageType.SLIME, t.getJellyDamage(self, t), {type="slime"}) target:die() else game.logPlayer("You may not detonate this summon.") @@ -70,11 +79,14 @@ return true end, info = function(self, t) + local radius = self:getTalentRadius(t) + local ritch_damage = t.getRitchDamage(self, t) + local jelly_damage = t.getJellyDamage(self, t) return ([[Destroys one of your summons, make it detonate in radius of %d. Only some summons can be detonated: - Ritch Flamespitter: Explodes into a fireball doing %0.2f fire damage - Jelly: Explodes into a ball of slowing slime doing %0.2f damage and slowing for 3 turns for 30%% - The effects improves with your Willpower.]]):format(1 + self:getTalentLevelRaw(t),damDesc(self, DamageType.FIRE, self:combatTalentStatDamage(t, "wil", 30, 400)),damDesc(self, DamageType.SLIME, self:combatTalentStatDamage(t, "wil", 30, 300))) + The effects improves with your Willpower.]]):format(radius, damDesc(self, DamageType.FIRE, ritch_damage), damDesc(self, DamageType.SLIME, jelly_damage)) end, } Index: game/modules/tome/data/talents/gifts/storm-drake.lua =================================================================== --- game/modules/tome/data/talents/gifts/storm-drake.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/storm-drake.lua (working copy) @@ -47,11 +47,18 @@ points = 5, equilibrium = 20, cooldown = 20, - range = 1, + range = 0, + radius = 1, tactical = { ATTACKAREA = 5 }, requires_target = true, + target = function(self, t) + return {type="ball", radius=self:getTalentRadius(t), selffire=false, talent=t} + end, + getPercent = function(self, t) + return self:combatTalentMindDamage(t, 10, 45) + end, action = function(self, t) - local tg = {type="ball", radius=1, friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, function(px, py) local target = game.level.map(px, py, Map.ACTOR) if not target then return end @@ -60,7 +67,7 @@ return end game.logSeen(target, "%s is caught in the static field!", target.name:capitalize()) - local dam = target.life * self:combatTalentMindDamage(t, 10, 45) / 100 + local dam = target.life * t.getPercent(self, t) / 100 if target.life - dam < 0 then dam = target.life end target:takeHit(dam, self) end, nil, {type="lightning_explosion"}) @@ -68,9 +75,10 @@ return true end, info = function(self, t) + local percent = t.getPercent(self, t) return ([[Generate an electrical field around you in a radius of 1. Any foe caught inside will lose %d%% of its current life. This effect can not kill creatures. - Life loss will increase with the Willpower stat.]]):format(self:combatTalentMindDamage(t, 10, 45)) + Life loss will increase with the Willpower stat.]]):format(percent) end, } @@ -157,24 +165,32 @@ cooldown = 12, message = "@Source@ breathes lightning!", tactical = { ATTACKAREA = 2 }, - range = function(self, t) return 4 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 4 + self:getTalentLevelRaw(t) end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, + getDamage = function(self, t) + return self:combatTalentStatDamage(t, "str", 30, 500) + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, 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 = self:combatTalentStatDamage(t, "str", 30, 500) + local dam = t.getDamage(self, t) self:project(tg, x, y, DamageType.LIGHTNING_DAZE, rng.avg(dam / 3, dam, 3)) game.level.map:particleEmitter(self.x, self.y, tg.radius, "breath_lightning", {radius=tg.radius, tx=x-self.x, ty=y-self.y}) game:playSoundNear(self, "talents/breath") return true end, info = function(self, t) + local damage = t.getDamage(self, t) return ([[You breathe lightning in a frontal cone. Any target caught in the area will take %0.2f to %0.2f lightning damage and can be dazed for 3 turns. The damage will increase with the Strength stat]]):format( - damDesc(self, DamageType.LIGHTNING, self:combatTalentStatDamage(t, "str", 30, 500)) / 3, - damDesc(self, DamageType.LIGHTNING, self:combatTalentStatDamage(t, "str", 30, 500)) + damDesc(self, DamageType.LIGHTNING, damage / 3, + damDesc(self, DamageType.LIGHTNING, damage)) ) end, } Index: game/modules/tome/data/talents/gifts/fire-drake.lua =================================================================== --- game/modules/tome/data/talents/gifts/fire-drake.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/fire-drake.lua (working copy) @@ -26,15 +26,22 @@ message = "@Source@ roars!", equilibrium = 3, cooldown = 20, - range = 5, + range = 0, + radius = function(self, t) + return 2 + self:getTalentLevelRaw(t) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, tactical = { DEFEND = 1, DISABLE = 3 }, action = function(self, t) - local tg = {type="ball", range=0, radius=2 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, DamageType.CONFUSION, {dur=3, dam=40 + 6 * self:getTalentLevel(t)}, {type="flame"}) return true end, info = function(self, t) - return ([[You let out a powerful roar that sends your foes into utter confusion for 3 turns in a radius of %d.]]):format(2 + self:getTalentLevelRaw(t)) + local radius = self:getTalentRadius(t) + return ([[You let out a powerful roar that sends your foes into utter confusion for 3 turns in a radius of %d.]]):format(radius) end, } @@ -46,12 +53,18 @@ random_ego = "attack", equilibrium = 7, cooldown = 10, - range = 5, + range = 0, + radius = function(self, t) + return 4 + self:getTalentLevelRaw(t) + end, direct_hit = true, tactical = { DEFEND = 1, DISABLE = 2, ESCAPE = 1 }, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=4 + self:getTalentLevelRaw(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.PHYSKNOCKBACK, {dam=self:combatTalentStatDamage(t, "str", 15, 90), dist=4}) @@ -74,13 +87,23 @@ cooldown = 35, tactical = { ATTACKAREA = 2 }, range = 10, + radius = 2, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, + getDamage = function(self, t) + return self:combatTalentStatDamage(t, "wil", 15, 120) + end, + getDuration = function(self, t) + return 2 + self:getTalentLevelRaw(t) + end, action = function(self, t) - local duration = 2 + self:getTalentLevelRaw(t) - local radius = 2 - local dam = self:combatTalentStatDamage(t, "wil", 15, 120) - local tg = {type="ball", range=self:getTalentRange(t), radius=radius} + local duration = t.getDuration(self, t) + local radius = self:getTalentRadius(t) + local dam = t.getDamage(self, t) + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -97,8 +120,11 @@ return true end, info = function(self, t) - return ([[Spit a cloud of flames doing %0.2f fire damage in a radius of 2 each turn for %d turns. - The damage will increase with the Willpower stat]]):format(damDesc(self, DamageType.FIRE, self:combatTalentStatDamage(t, "wil", 15, 120)), 2 + self:getTalentLevelRaw(t)) + local dam = t.getDamage(self, t) + local radius = self:getTalentRadius(t) + local duration = t.getDuration(self, t) + return ([[Spit a cloud of flames doing %0.2f fire damage in a radius of %d each turn for %d turns. + The damage will increase with the Willpower stat]]):format(damDesc(self, DamageType.FIRE, dam), radius, duration) end, } @@ -112,11 +138,15 @@ cooldown = 12, message = "@Source@ breathes fire!", tactical = { ATTACKAREA = 2 }, - range = function(self, t) return 4 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 4 + self:getTalentLevelRaw(t) end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end self:project(tg, x, y, DamageType.FIREBURN, self:combatTalentStatDamage(t, "str", 30, 450)) Index: game/modules/tome/data/talents/gifts/sand-drake.lua =================================================================== --- game/modules/tome/data/talents/gifts/sand-drake.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/sand-drake.lua (working copy) @@ -69,16 +69,20 @@ cooldown = 30, tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 10, + radius = function(self, t) + return 2 + self:getTalentLevel(t) / 2 + end, no_npc_use = true, action = function(self, t) - local tg = {type="ball", range=0, friendlyfire=false, radius=2 + self:getTalentLevel(t) / 2, talent=t, no_restrict=true} + local tg = {type="ball", range=0, selffire=false, radius=self:getTalentRadius(t), talent=t, no_restrict=true} self:project(tg, self.x, self.y, DamageType.PHYSKNOCKBACK, {dam=self:combatDamage() * 0.8, dist=4}) self:doQuake(tg, self.x, self.y) return true end, info = function(self, t) + local radius = self:getTalentRadius(t) return ([[You slam your foot onto the ground, shaking the area around you in a radius of %d, damaging them for %d and knocking back up to 4 titles away. - The damage will increase with the Strength stat]]):format(2 + self:getTalentLevel(t) / 2, self:combatDamage() * 0.8) + The damage will increase with the Strength stat]]):format(radius, self:combatDamage() * 0.8) end, } @@ -110,20 +114,32 @@ cooldown = 12, message = "@Source@ breathes sand!", tactical = { ATTACKAREA = 2, DISABLE = 2 }, - range = function(self, t) return 4 + self:getTalentLevelRaw(t) end, + range = 0, + radius = function(self, t) return 4 + self:getTalentLevelRaw(t) end, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="cone", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t} + end, + getDamage = function(self, t) + return self:combatTalentStatDamage(t, "str", 30, 400) + end, + getDuration = function(self, t) + return 2+self:getTalentLevelRaw(t) + end, action = function(self, t) - local tg = {type="cone", range=0, radius=self:getTalentRange(t), friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end - self:project(tg, x, y, DamageType.SAND, {dur=2+self:getTalentLevelRaw(t), dam=self:combatTalentStatDamage(t, "str", 30, 400)}) + self:project(tg, x, y, DamageType.SAND, {dur=t.getDuration(self, t), dam=t.getDamage(self, t)}) game.level.map:particleEmitter(self.x, self.y, tg.radius, "breath_earth", {radius=tg.radius, tx=x-self.x, ty=y-self.y}) game:playSoundNear(self, "talents/breath") return true end, info = function(self, t) + local damage = t.getDamage(self, t) + local duration = t.getDuration(self, t) return ([[You breathe sand in a frontal cone. Any target caught in the area will take %0.2f physical damage and be blinded for %d turns. - The damage will increase with the Strength stat]]):format(damDesc(self, DamageType.PHYSICAL, self:combatTalentStatDamage(t, "str", 30, 400)), 2+self:getTalentLevelRaw(t)) + The damage will increase with the Strength stat]]):format(damDesc(self, DamageType.PHYSICAL, damage), duration) end, } Index: game/modules/tome/data/talents/gifts/slime.lua =================================================================== --- game/modules/tome/data/talents/gifts/slime.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/slime.lua (working copy) @@ -108,24 +108,35 @@ cooldown = 20, tactical = { CLOSEIN = 2 }, requires_target = true, - range = 10, + range = function(self, t) + return 20 + self:getTalentLevel(t) + end, + radius = function(self, t) + return 7 - self:getTalentLevel(t) + end, + getDuration = function(self, t) + return util.bound(5 - self:getTalentLevel(t) / 2, 2, 7) + end, action = function(self, t) - local x, y = self:getTarget{type="ball", range=20 + self:getTalentLevel(t), radius=math.min(0, 5 - self:getTalentLevel(t))} + local x, y = self:getTarget{type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} if not x then return nil end -- Target code does not restrict the self coordinates to the range, it lets the project function do it -- but we cant ... local _ _, x, y = self:canProject(tg, x, y) game.level.map:particleEmitter(self.x, self.y, 1, "slime") - self:teleportRandom(x, y, 7 - self:getTalentLevel(t)) + self:teleportRandom(x, y, self:getTalentRadius(t)) game.level.map:particleEmitter(self.x, self.y, 1, "slime") -- Stunned! - self:setEffect(self.EFF_STUNNED, util.bound(5 - self:getTalentLevel(t) / 2, 2, 7), {}) + self:setEffect(self.EFF_STUNNED, t.getDuration(self, t), {}) game:playSoundNear(self, "talents/slime") return true end, info = function(self, t) + local range = self:getTalentRange(t) + local radius = self:getTalentRadius(t) + local duration = t.getDuration(self, t) return ([[You extend slimy roots into the ground, follow them, and re-appear somewhere else in a range of %d with error margin of %d. - The process is quite a strain on your body and you will be stunned for %d turns.]]):format(20 + self:getTalentLevel(t),7 - self:getTalentLevel(t), util.bound(5 - self:getTalentLevel(t) / 2, 2, 7)) + The process is quite a strain on your body and you will be stunned for %d turns.]]):format(range, radius, duration) end, } Index: game/modules/tome/data/talents/gifts/call.lua =================================================================== --- game/modules/tome/data/talents/gifts/call.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/call.lua (working copy) @@ -99,10 +99,11 @@ equilibrium = 3, cooldown = 10, range = 100, + radius = function(self, t) return math.ceil(3 + self:getTalentLevel(t)) end, requires_target = true, no_npc_use = true, action = function(self, t) - local x, y = self:getTarget{type="ball", nolock=true, no_restrict=true, nowarning=true, range=100, radius=math.ceil(3 + self:getTalentLevel(t))} + local x, y = self:getTarget{type="ball", nolock=true, no_restrict=true, nowarning=true, range=100, radius=self:getTalentRadius(t)} if not x then return nil end self:magicMap(math.ceil(3 + self:getTalentLevel(t)), x, y) @@ -110,8 +111,9 @@ return true end, info = function(self, t) + local radius = self:getTalentRadius(t) return ([[Using your connection to Nature you can see remote areas in a radius of %d.]]): - format(math.ceil(3 + self:getTalentLevel(t))) + format(radius) end, } Index: game/modules/tome/data/talents/gifts/antimagic.lua =================================================================== --- game/modules/tome/data/talents/gifts/antimagic.lua (revision 2714) +++ game/modules/tome/data/talents/gifts/antimagic.lua (working copy) @@ -56,9 +56,12 @@ equilibrium = 20, cooldown = 10, tactical = { DISABLE = 4 }, - range = function(self, t) return 4 + self:getTalentLevel(t) * 1.5 end, + radius = function(self, t) return 4 + self:getTalentLevel(t) * 1.5 end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=true, talent=t} + end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), friendlyfire=true, talent=t} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, DamageType.SILENCE, 3 + math.floor(self:getTalentLevel(t) / 2)) return true end, Index: game/modules/tome/data/talents/divine/circles.lua =================================================================== --- game/modules/tome/data/talents/divine/circles.lua (revision 2714) +++ game/modules/tome/data/talents/divine/circles.lua (working copy) @@ -25,16 +25,22 @@ points = 5, cooldown = 20, negative = 20, - tactical = { DEFEND = 2, ATTACK = 1 }, + tactical = { DEFEND = 2, ATTACKAREA = 1 }, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 4, 30) end, getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end, - getRadius = function(self, t) return 2 + math.floor(self:getTalentLevelRaw(t)/2) end, + range = 0, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevelRaw(t)/2) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) -- Add a lasting map effect game.level.map:addEffect(self, self.x, self.y, t.getDuration(self, t), DamageType.SHIFTINGSHADOWS, t.getDamage(self, t), - t.getRadius(self, t), + self:getTalentRadius(t), 5, nil, engine.Entity.new{alpha=75, display='', color_br=60, color_bg=10, color_bb=60}, nil, self:spellFriendlyFire(true) @@ -45,7 +51,7 @@ info = function(self, t) local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Creates a circle of radius %d at your feet, it increase your defense by %d and deals %0.2f darkness damage per turn to everyone else with in its radius. The circle lasts %d turns. The damage will increase with the Magic stat.]]): format(radius, damage, (damDesc (self, DamageType.DARKNESS, damage)), duration) @@ -59,13 +65,19 @@ points = 5, cooldown = 20, positive = 20, - tactical = { DEFEND = 2, ATTACK = 1 }, + tactical = { DEFEND = 2, ATTACKAREA = 1 }, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 2, 15) end, getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end, - getRadius = function(self, t) return 2 + math.floor(self:getTalentLevelRaw(t)/2) end, + range = 0, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevelRaw(t)/2) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) - local radius = t.getRadius(self, t) - local tg = {type="ball", range=0, friendlyfire=true, radius=radius, talent=t} + local radius = self:getTalentRadius(t) + local tg = {type="ball", range=0, selffire=true, radius=radius, talent=t} self:project(tg, self.x, self.y, DamageType.LITE, 1) -- Add a lasting map effect game.level.map:addEffect(self, @@ -82,7 +94,7 @@ info = function(self, t) local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Creates a circle of radius %d at your feet, it lights up affected tiles, increases your positive energy by %d each turn, and deals %0.2f light damage and %0.2f fire damage per turn to everyone else within its radius. The circle lasts %d turns. The damage will increase with the Magic stat.]]): format(radius, 1 + (damage / 4), (damDesc (self, DamageType.LIGHT, damage)), (damDesc (self, DamageType.FIRE, damage)), duration) @@ -97,15 +109,21 @@ cooldown = 20, positive = 20, negative = 20, - tactical = { DEFEND = 2, ATTACK = 1 }, + tactical = { DEFEND = 2, ATTACKAREA = 1 }, getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end, - getRadius = function(self, t) return 2 + math.floor(self:getTalentLevelRaw(t)/2) end, + range = 0, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevelRaw(t)/2) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, action = function(self, t) -- Add a lasting map effect game.level.map:addEffect(self, self.x, self.y, t.getDuration(self, t), DamageType.SANCTITY, 1, - t.getRadius(self, t), + self:getTalentRadius(t), 5, nil, engine.Entity.new{alpha=75, display='', color_br=150, color_bg=10, color_bb=200}, nil, self:spellFriendlyFire(true) @@ -115,7 +133,7 @@ end, info = function(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Creates a circle of radius %d at your feet, it protects you from silence effects while you remain in its radius and silences everyone else who enters. The circle lasts %d turns.]]): format(radius, duration) end, @@ -129,16 +147,22 @@ cooldown = 20, positive = 20, negative = 20, - tactical = { DEFEND = 2, ATTACK = 1 }, + tactical = { DEFEND = 2, ATTACKAREA = 1 }, getDuration = function(self, t) return 3 + math.ceil(self:getTalentLevel(t)) end, - getRadius = function(self, t) return 2 + math.floor(self:getTalentLevelRaw(t)/2) end, + range = 0, + radius = function(self, t) + return 2 + math.floor(self:getTalentLevelRaw(t)/2) + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 2, 20) end, action = function(self, t) -- Add a lasting map effect game.level.map:addEffect(self, self.x, self.y, t.getDuration(self, t), DamageType.WARDING, t.getDamage(self, t), - t.getRadius(self, t), + self:getTalentRadius(t), 5, nil, engine.Entity.new{alpha=75, display='', color_br=200, color_bg=200, color_bb=200}, nil, self:spellFriendlyFire(true) @@ -149,7 +173,7 @@ info = function(self, t) local damage = t.getDamage(self, t) local duration = t.getDuration(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Creates a circle of radius %d at your feet, it slows incoming projectiles %d%% and attempts to push all creatures other then yourself out of its radius, inflicting %0.2f light damage and %0.2f darkness damage per turn as it does so. The circle lasts %d turns. The slow effect and damage will increase with the Magic stat.]]): format(radius, damage, (damDesc (self, DamageType.LIGHT, damage)), (damDesc (self, DamageType.DARKNESS, damage)), duration) Index: game/modules/tome/data/talents/divine/eclipse.lua =================================================================== --- game/modules/tome/data/talents/divine/eclipse.lua (revision 2714) +++ game/modules/tome/data/talents/divine/eclipse.lua (working copy) @@ -158,9 +158,9 @@ self:removeTemporaryValue("invisible", p.invisible) self:removeTemporaryValue("positive_regen", p.fill) self:removeTemporaryValue("negative_regen", p.drain) - local tg = {type="ball", range=0, friendlyfire=true, radius= t.getRadius(self, t), talent=t} + local tg = {type="ball", range=0, selffire=true, radius= t.getRadius(self, t), talent=t} self:project(tg, self.x, self.y, DamageType.LITE, 1) - tg.friendlyfire = false + tg.selffire = false local grids = self:project(tg, self.x, self.y, DamageType.LIGHT, self:spellCrit(t.getDamage(self, t) + self.positive)) game.level.map:particleEmitter(self.x, self.y, tg.radius, "sunburst", {radius=tg.radius, grids=grids, tx=self.x, ty=self.y, max_alpha=80}) game:playSoundNear(self, "talents/flame") Index: game/modules/tome/data/talents/divine/sun.lua =================================================================== --- game/modules/tome/data/talents/divine/sun.lua (revision 2714) +++ game/modules/tome/data/talents/divine/sun.lua (working copy) @@ -74,13 +74,22 @@ positive = -15, tactical = { ATTACKAREA = 1, DISABLE = 2 }, direct_hit = true, + range = 0, + radius = function(self, t) + return 2 + self:getTalentLevel(t) / 2 + end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), selffire=false, radius=self:getTalentRadius(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 4, 80) end, - range = function(self, t) return 2 + self:getTalentLevel(t) / 2 end, + getDuration = function(self, t) return 3 + self:getTalentLevel(t) end, action = function(self, t) - local tg = {type="ball", range=0, friendlyfire=true, radius=self:getTalentRange(t), talent=t} + local tg = self:getTalentTarget(t) + -- Temporarily turn on "friendlyfire" to lite all tiles + tg.friendlyfire = true self:project(tg, self.x, self.y, DamageType.LITE, 1) tg.friendlyfire = false - local grids = self:project(tg, self.x, self.y, DamageType.BLIND, 3 + self:getTalentLevel(t)) + local grids = self:project(tg, self.x, self.y, DamageType.BLIND, t.getDuration(self, t)) if self:getTalentLevel(t) >= 3 then self:project(tg, self.x, self.y, DamageType.LIGHT, t.getDamage(self, t)) end @@ -89,12 +98,13 @@ return true end, info = function(self, t) - local radius = self:getTalentRange(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) + local duration = t.getDuration(self, t) return ([[Invokes Sun flare with radius of %d, blinding your foes for %d turns and lighting up your immediate area. At level 3 it will start dealing %0.2f light damage. The damage will increase with the Magic stat.]]): - format(2 + self:getTalentLevel(t) / 2, 3 + self:getTalentLevel(t),damDesc(self, DamageType.LIGHT, self:combatTalentSpellDamage(t, 4, 80))) + format(radius, duration, damDesc(self, DamageType.LIGHT, damage)) end, } @@ -110,9 +120,12 @@ range = 7, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 200) end, action = function(self, t) - 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 self:project(tg, x, y, DamageType.FIRE, self:spellCrit(t.getDamage(self, t))) @@ -139,11 +152,15 @@ cooldown = 15, positive = -20, tactical = { ATTACKAREA = 2 }, - range = 3, + range = 0, + radius = 3, direct_hit = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), friendlyfire=false, talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 160) end, action = function(self, t) - local tg = {type="ball", range=0, radius=3, friendlyfire=false, talent=t} + local tg = self:getTalentTarget(t) local grids = self:project(tg, self.x, self.y, DamageType.LIGHT, self:spellCrit(t.getDamage(self, t))) game.level.map:particleEmitter(self.x, self.y, tg.radius, "sunburst", {radius=tg.radius, grids=grids, tx=self.x, ty=self.y}) @@ -152,8 +169,9 @@ return true end, info = function(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) - return ([[Conjures a furious burst of Sunlight, dealing %0.2f light damage to all those around you in a radius of 3. - The damage will increase with the Magic stat.]]):format(damDesc(self, DamageType.LIGHT, damage)) + return ([[Conjures a furious burst of Sunlight, dealing %0.2f light damage to all those around you in a radius of %d. + The damage will increase with the Magic stat.]]):format(damDesc(self, DamageType.LIGHT, damage), radius) end, } Index: game/modules/tome/data/talents/divine/light.lua =================================================================== --- game/modules/tome/data/talents/divine/light.lua (revision 2714) +++ game/modules/tome/data/talents/divine/light.lua (working copy) @@ -49,15 +49,19 @@ cooldown = 10, positive = -20, tactical = { HEAL = 3 }, + range = 0, + radius = 3, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t)} + end, getHeal = function(self, t) return self:combatTalentSpellDamage(t, 4, 30) end, getDuration = function(self, t) return self:getTalentLevel(t) + 2 end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=3} -- Add a lasting map effect game.level.map:addEffect(self, self.x, self.y, t.getDuration(self, t), DamageType.HEALING_POWER, t.getHeal(self, t), - 3, + self:getTalentRadius(t), 5, nil, {type="healing_vapour"}, nil, true @@ -66,11 +70,12 @@ return true end, info = function(self, t) + local radius = self:getTalentRadius(t) local heal = t.getHeal(self, t) local duration = t.getDuration(self, t) - return ([[A magical zone of Sunlight appears around you, healing all within a radius of 3 for %0.2f per turn and increasing healing effects on those within by %d%%. The effect lasts %d turns. + return ([[A magical zone of Sunlight appears around you, healing all within a radius of %d for %0.2f per turn and increasing healing effects on those within by %d%%. The effect lasts %d turns. The life healed will increase with the Magic stat]]): - format(heal, heal, duration) + format(radius, heal, heal, duration) end, } Index: game/modules/tome/data/talents/divine/guardian.lua =================================================================== --- game/modules/tome/data/talents/divine/guardian.lua (revision 2714) +++ game/modules/tome/data/talents/divine/guardian.lua (working copy) @@ -64,7 +64,9 @@ getWeaponDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.3) end, getShieldDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.3, self:getTalentLevel(self.T_SHIELD_EXPERTISE)) end, getLightDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 150) end, - getRadius = function(self, t) return 2 + self:getTalentLevel(t) / 2 end, + radius = function(self, t) + return 2 + self:getTalentLevel(t) / 2 + end, action = function(self, t) local shield = self:hasShield() if not shield then @@ -84,9 +86,9 @@ -- Light Burst if hit then - local tg = {type="ball", range=1, friendlyfire=true, radius=t.getRadius(self, t), talent=t} + local tg = {type="ball", range=1, selffire=true, radius=self:getTalentRadius(t), talent=t} self:project(tg, x, y, DamageType.LITE, 1) - tg.friendlyfire = false + tg.selffire = false local grids = self:project(tg, x, y, DamageType.LIGHT, t.getLightDamage(self, t)) game.level.map:particleEmitter(x, y, tg.radius, "sunburst", {radius=tg.radius, grids=grids, tx=x, ty=y, max_alpha=80}) game:playSoundNear(self, "talents/flame") @@ -98,7 +100,7 @@ local weapondamage = t.getWeaponDamage(self, t) local shielddamage = t.getShieldDamage(self, t) local lightdamage = t.getLightDamage(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) return ([[Hits the target with your weapon doing %d%% damage and a shield strike doing %d%% damage. If the shield strike hits your shield will explode in a burst of light, inflicting %0.2f light damage on all within a radius of %d of the target, lighting up the affected grids. Light damage will increase with your Magic stat.]]): format(100 * weapondamage, 100 * shielddamage, damDesc(self, DamageType.LIGHT, lightdamage), radius) Index: game/modules/tome/data/talents/divine/twilight.lua =================================================================== --- game/modules/tome/data/talents/divine/twilight.lua (revision 2714) +++ game/modules/tome/data/talents/divine/twilight.lua (working copy) @@ -151,13 +151,16 @@ cooldown = 15, negative = 15, tactical = { DISABLE = 3 }, - range = 3, + radius = 3, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, selffire=false} + end, getConfuseDuration = function(self, t) return math.floor(self:getTalentLevel(t) + self:getCun(5)) + 2 end, getConfuseEfficency = function(self, t) return 50 + self:getTalentLevelRaw(t)*10 end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), talent=t, friendlyfire=false} + local tg = self:getTalentTarget(t) self:project(tg, self.x, self.y, DamageType.CONFUSION, { dur = t.getConfuseDuration(self, t), dam = t.getConfuseEfficency(self, t) @@ -169,7 +172,7 @@ local duration = t.getConfuseDuration(self, t) return ([[Let out a mental cry that shatters the will of your targets, confusing them for %d turns. The duration will improve with the Cunning stat.]]): - format(math.floor(self:getTalentLevel(t) + self:getCun(5)) + 2) + format(duration) end, } Index: game/modules/tome/data/talents/divine/star-fury.lua =================================================================== --- game/modules/tome/data/talents/divine/star-fury.lua (revision 2714) +++ game/modules/tome/data/talents/divine/star-fury.lua (working copy) @@ -30,9 +30,12 @@ direct_hit = true, reflectable = true, requires_target = true, + target = function(self, t) + return {type="beam", range=self:getTalentRange(t), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 14, 230) end, action = function(self, t) - 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 self:project(tg, x, y, DamageType.DARKNESS, self:spellCrit(t.getDamage(self, t))) @@ -59,13 +62,17 @@ negative = 15, tactical = { ATTACKAREA = 2 }, range = 5, + radius = 3, direct_hit = true, requires_target = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire()} + end, getDamageOnSpot = function(self, t) return self:combatTalentSpellDamage(t, 4, 50) end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 5, 120) end, getDuration = function(self, t) return self:getTalentLevel(t) + 2 end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=3, friendlyfire=self:spellFriendlyFire()} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local _ _, x, y = self:canProject(tg, x, y) @@ -74,7 +81,7 @@ game.level.map:addEffect(self, x, y, t.getDuration(self, t), DamageType.DARKNESS, t.getDamageOnSpot(self, t), - 3, + self:getTalentRadius(t), 5, nil, {type="shadow_zone"}, nil, self:spellFriendlyFire() @@ -105,12 +112,16 @@ negative = -20, positive = -10, tactical = { ATTACKAREA = 1 }, - range = 2, + range = 0, + radius = 2, direct_hit = true, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), talent=t, friendlyfire=false} + end, getLightDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:getTalentLevel(t) end, getDarknessDamage = function(self, t) return 10 + self:combatSpellpower(0.2) * self:getTalentLevel(t) end, action = function(self, t) - local tg = {type="ball", range=0, radius=self:getTalentRange(t), talent=t, friendlyfire=false} + local tg = self:getTalentTarget(t) local grids = self:project(tg, self.x, self.y, DamageType.LIGHT, self:spellCrit(t.getLightDamage(self, t))) self:project(tg, self.x, self.y, DamageType.DARKNESS, self:spellCrit(t.getDarknessDamage(self, t))) game.level.map:particleEmitter(self.x, self.y, tg.radius, "shadow_flash", {radius=tg.radius, grids=grids, tx=self.x, ty=self.y}) @@ -138,12 +149,17 @@ negative = 20, tactical = { ATTACKAREA = 2, DISABLE = 2 }, range = 6, + radius = function(self, t) + return 1 + math.floor(self:getTalentLevelRaw(t) / 3) + end, direct_hit = true, requires_target = true, - getRadius = function(self, t) return 1 + math.floor(self:getTalentLevelRaw(t) / 3) end, + target = function(self, t) + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=self:spellFriendlyFire(), talent=t} + end, getDamage = function(self, t) return self:combatTalentSpellDamage(t, 28, 170) end, action = function(self, t) - local tg = {type="ball", range=self:getTalentRange(t), radius=t.getRadius(self, t), friendlyfire=self:spellFriendlyFire(), talent=t} + local tg = self:getTalentTarget(t) local x, y = self:getTarget(tg) if not x or not y then return nil end local grids = self:project(tg, x, y, DamageType.DARKSTUN, self:spellCrit(t.getDamage(self, t))) @@ -154,7 +170,7 @@ return true end, info = function(self, t) - local radius = t.getRadius(self, t) + local radius = self:getTalentRadius(t) local damage = t.getDamage(self, t) return ([[A star falls into area of radius %d, stunning all for 4 turns and doing %0.2f darkness damage. The damage will increase with the Magic stat.]]): Index: game/modules/tome/data/general/npcs/cold-drake.lua =================================================================== --- game/modules/tome/data/general/npcs/cold-drake.lua (revision 2714) +++ game/modules/tome/data/general/npcs/cold-drake.lua (working copy) @@ -108,7 +108,8 @@ }, ai = "tactical", - + ai_status = {ally_compassion = 0}, + resolvers.talents{ [Talents.T_SUMMON]=1, [Talents.T_ICE_CLAW]=5, Index: game/modules/tome/data/general/npcs/multihued-drake.lua =================================================================== --- game/modules/tome/data/general/npcs/multihued-drake.lua (revision 2714) +++ game/modules/tome/data/general/npcs/multihued-drake.lua (working copy) @@ -111,7 +111,8 @@ resists = { [DamageType.PHYSICAL] = 40, [DamageType.FIRE] = 40, [DamageType.COLD] = 40, [DamageType.ACID] = 40, [DamageType.LIGHTNING] = 40, }, ai = "tactical", - + ai_status = {ally_compassion = 0}, + summon = { {type="dragon", name="multi-hued drake", number=1, hasxp=false}, -- {type="dragon", name="greater multi-hued wyrm", number=1, hasxp=false}, @@ -150,7 +151,8 @@ ai = "tactical", ai_tactic = resolvers.tactic"ranged", - + ai_status = {ally_compassion = 0}, + no_auto_resists = true, color_switch = 2, resists = { all=50, [DamageType.FIRE] = 100, [DamageType.COLD] = -100 }, Index: game/modules/tome/data/general/npcs/fire-drake.lua =================================================================== --- game/modules/tome/data/general/npcs/fire-drake.lua (revision 2714) +++ game/modules/tome/data/general/npcs/fire-drake.lua (working copy) @@ -97,7 +97,8 @@ ai = "tactical", ai_tactic = resolvers.tactic"melee", - + ai_status = {ally_compassion = 0}, + summon = { {type="dragon", name="fire drake", number=1, hasxp=false}, -- {type="dragon", name="fire wyrm", number=1, hasxp=false}, Index: game/modules/tome/data/general/npcs/storm-drake.lua =================================================================== --- game/modules/tome/data/general/npcs/storm-drake.lua (revision 2714) +++ game/modules/tome/data/general/npcs/storm-drake.lua (working copy) @@ -97,6 +97,7 @@ ai = "tactical", ai_tactic = resolvers.tactic"melee", + ai_status = {ally_compassion = 0}, summon = { {type="dragon", name="storm drake", number=1, hasxp=false}, Index: game/modules/tome/data/general/objects/world-artifacts.lua =================================================================== --- game/modules/tome/data/general/objects/world-artifacts.lua (revision 2714) +++ game/modules/tome/data/general/objects/world-artifacts.lua (working copy) @@ -213,11 +213,11 @@ max_power = 300, power_regen = 1, use_power = { name = "unleash a destructive wail", power = 300, use = function(self, who) - who:project({type="ball", range=0, friendlyfire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) - who:project({type="ball", range=0, friendlyfire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) - who:project({type="ball", range=0, friendlyfire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) - who:project({type="ball", range=0, friendlyfire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) - who:project({type="ball", range=0, friendlyfire=false, radius=3}, who.x, who.y, engine.DamageType.PHYSICAL, 100 + who:getMag() * 2) + who:project({type="ball", range=0, selffire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) + who:project({type="ball", range=0, selffire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) + who:project({type="ball", range=0, selffire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) + who:project({type="ball", range=0, selffire=false, radius=3}, who.x, who.y, engine.DamageType.DIG, 1) + who:project({type="ball", range=0, selffire=false, radius=3}, who.x, who.y, engine.DamageType.PHYSICAL, 100 + who:getMag() * 2) game.logSeen(who, "%s uses the %s!", who.name:capitalize(), self:getName()) end }, Index: game/modules/tome/data/general/objects/egos/wands.lua =================================================================== --- game/modules/tome/data/general/objects/egos/wands.lua (revision 2714) +++ game/modules/tome/data/general/objects/egos/wands.lua (working copy) @@ -61,7 +61,7 @@ cost_per_charge = 0.4, use_power = { name = "light the area", power = 3, use = function(self, who) - who:project({type="ball", range=0, friendlyfire=true, radius=15}, who.x, who.y, engine.DamageType.LITE, 1) + who:project({type="ball", range=0, selffire=true, radius=15}, who.x, who.y, engine.DamageType.LITE, 1) game.logSeen(who, "%s uses %s!", who.name:capitalize(), self:getName{no_count=true}) return nil, true end} Index: game/modules/tome/data/general/objects/boss-artifacts.lua =================================================================== --- game/modules/tome/data/general/objects/boss-artifacts.lua (revision 2714) +++ game/modules/tome/data/general/objects/boss-artifacts.lua (working copy) @@ -50,7 +50,7 @@ max_power = 18, power_regen = 1, use_power = { name = "generate a burst of ice", power = 8, use = function(self, who) - local tg = {type="ball", range=0, radius=4, friendlyfire=false} + local tg = {type="ball", range=0, radius=4, selffire=false} who:project(tg, who.x, who.y, engine.DamageType.ICE, 10 + (who:getMag() + who:getWil()) / 2, {type="freeze"}) game:playSoundNear(who, "talents/ice") game.logSeen(who, "%s invokes the power of %s!", who.name:capitalize(), self.name)