diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua index bdbd691c76f14c60fa13804f58a6a60220c4f806..4204465f559d66907d02a0e3a809f25c0255b34c 100644 --- a/game/engines/default/engine/utils.lua +++ b/game/engines/default/engine/utils.lua @@ -34,6 +34,13 @@ function math.round(v, mult, num) return v >= 0 and math.floor((v + mult/2)/mult) * mult/num or math.ceil((v - mult/2)/mult) * mult/num end +function math.scale(i, imin, imax, dmin, dmax) + local bi = i - imin + local bm = imax - imin + local dm = dmax - dmin + return bi * dm / bm + dmin +end + function lpeg.anywhere (p) return lpeg.P{ p + 1 * lpeg.V(1) } end diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index 3785bc27d2d3395f3dbe00e3931b0219f5cc3fd2..db94931708950cabf627c4e49988d9e3d280c67d 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -400,7 +400,7 @@ function _M:attackTargetWith(target, weapon, damtype, mult, force_dam) elseif self:checkEvasion(target) then evaded = true self:logCombat(target, "#Target# evades #Source#.") - elseif self.turn_procs.auto_melee_hit or (self:checkHit(atk, def) and (self:canSee(target) or self:attr("blind_fight") or rng.chance(3))) then + elseif self.turn_procs.auto_melee_hit or (self:checkHit(atk, def) and (self:canSee(target) or self:attr("blind_fight") or target:attr("blind_fighted") or rng.chance(3))) then local pres = util.bound(target:combatArmorHardiness() / 100, 0, 1) if target.knowTalent and target:hasEffect(target.EFF_DUAL_WEAPON_DEFENSE) then local deflect = math.min(dam, target:callTalent(target.T_DUAL_WEAPON_DEFENSE, "doDeflect")) diff --git a/game/modules/tome/data/gfx/effects/light_burst_speed.png b/game/modules/tome/data/gfx/effects/light_burst_speed.png new file mode 100644 index 0000000000000000000000000000000000000000..691ab7f0de6f207874ad056beaff8c04ff31633d Binary files /dev/null and b/game/modules/tome/data/gfx/effects/light_burst_speed.png differ diff --git a/game/modules/tome/data/gfx/talents/hurricane_throw.png b/game/modules/tome/data/gfx/talents/hurricane_throw.png new file mode 100644 index 0000000000000000000000000000000000000000..a61f6a5de149cc3180dda2e3605deb77eb5b070e Binary files /dev/null and b/game/modules/tome/data/gfx/talents/hurricane_throw.png differ diff --git a/game/modules/tome/data/gfx/talents/illumination.png b/game/modules/tome/data/gfx/talents/illumination.png new file mode 100644 index 0000000000000000000000000000000000000000..655ea852a57f2d7e98c4751361c785cfc04589ce Binary files /dev/null and b/game/modules/tome/data/gfx/talents/illumination.png differ diff --git a/game/modules/tome/data/gfx/talents/light_burst.png b/game/modules/tome/data/gfx/talents/light_burst.png new file mode 100644 index 0000000000000000000000000000000000000000..83f53cfbd4d8e8567e6806ab9e4055eaa4ac7dda Binary files /dev/null and b/game/modules/tome/data/gfx/talents/light_burst.png differ diff --git a/game/modules/tome/data/gfx/talents/radiance.png b/game/modules/tome/data/gfx/talents/radiance.png new file mode 100644 index 0000000000000000000000000000000000000000..d36dbf1f7683b263a57e6c6b00ab6360e7c14a16 Binary files /dev/null and b/game/modules/tome/data/gfx/talents/radiance.png differ diff --git a/game/modules/tome/data/gfx/talents/searing_sight.png b/game/modules/tome/data/gfx/talents/searing_sight.png new file mode 100644 index 0000000000000000000000000000000000000000..343cf41f2c41b21cf8dee47e0720d645a286952d Binary files /dev/null and b/game/modules/tome/data/gfx/talents/searing_sight.png differ diff --git a/game/modules/tome/data/talents/celestial/crusader.lua b/game/modules/tome/data/talents/celestial/crusader.lua index 55ddc5b87a8fcd3048694c31427ac900b0459b0d..b67d5612fd890ff93d15f05aef3d96d33800abb3 100644 --- a/game/modules/tome/data/talents/celestial/crusader.lua +++ b/game/modules/tome/data/talents/celestial/crusader.lua @@ -112,7 +112,7 @@ newTalent{ return ([[While wielding a two handed weapon, your critical strike chance is increased by %d%%, and your melee criticals instill you with righteous strength, increasing all physical and light damage you deal by %d%%, stacking up to 3 times. In addition, your melee critical strikes leave a lasting lightburn on the target, dealing %0.2f light damage over 5 turns and reducing opponents armour by %d. The damage increase with your Spellpower.]]): - format(t.getCrit(self, t), t.getPower(self, t), t.getDamage(self, t), t.getArmor(self, t)) + format(t.getCrit(self, t), t.getPower(self, t), damDesc(self, DamageType.LIGHT, t.getDamage(self, t)), t.getArmor(self, t)) end, } diff --git a/game/modules/tome/data/talents/celestial/glyphs.lua b/game/modules/tome/data/talents/celestial/glyphs.lua index a02c203c0fb9c0029093e7bb0c0b1377e140e5cb..06d1748b3c7a2e9f0423640ba19104ea4733dd0c 100644 --- a/game/modules/tome/data/talents/celestial/glyphs.lua +++ b/game/modules/tome/data/talents/celestial/glyphs.lua @@ -165,7 +165,7 @@ newTalent{ return ([[You bind light in a glyph on the floor. All targets walking over the glyph will be hit by a blast that knocks them back and does %0.2f physical damage. The glyph is a hidden trap (%d detection and %d disarm power based on your Magic) and lasts for %d turns. The damage will increase with your Spellpower.]]): - format(damDesc(self, DamageType.SPELLKNOCKBACK, damage), t.trapPower(self, t)*0.8, t.trapPower(self, t), duration) + format(damDesc(self, DamageType.PHYSICAL, damage), t.trapPower(self, t)*0.8, t.trapPower(self, t), duration) end, } diff --git a/game/modules/tome/data/talents/celestial/radiance.lua b/game/modules/tome/data/talents/celestial/radiance.lua index caaa3e1b7ddc7136451d61676236650d225dfa70..9284ff378a8bb8a487c57052089dbb39e82180b6 100644 --- a/game/modules/tome/data/talents/celestial/radiance.lua +++ b/game/modules/tome/data/talents/celestial/radiance.lua @@ -17,6 +17,10 @@ -- Nicolas Casalini "DarkGod" -- darkgod@te4.org +function radianceRadius(self) + return self:getTalentRadius(self:getTalentFromId(self.T_RADIANCE)) +end + newTalent{ name = "Radiance", type = {"celestial/radiance", 1}, @@ -26,7 +30,7 @@ newTalent{ radius = function(self, t) return self:combatTalentScale(t, 3, 7) end, getResist = function(self, t) return math.min(100, self:combatTalentScale(t, 20, 90)) end, passives = function(self, t, p) - self:talentTemporaryValue(p, "radiance_aura", self:getTalentRadius(t)) + self:talentTemporaryValue(p, "radiance_aura", radianceRadius(self)) self:talentTemporaryValue(p, "blind_immune", t.getResist(self, t) / 100) end, info = function(self, t) @@ -34,7 +38,7 @@ newTalent{ The light protects your eyes, giving %d%% blindness resistance. The light radius overrides your normal light if it is bigger (it does not stack). ]]): - format(self:getTalentRadius(t), t.getResist(self, t)) + format(radianceRadius(self), t.getResist(self, t)) end, } @@ -43,65 +47,62 @@ newTalent{ type = {"celestial/radiance", 2}, require = divi_req2, points = 5, - random_ego = "attack", - cooldown = 22, - positive = 25, - tactical = { DISABLE = 2 }, - range = 6, - reflectable = true, - requires_target = true, - getReturnDamage = function(self, t) return self:combatLimit(self:getTalentLevel(t)^.5, 100, 15, 1, 40, 2.24) end, -- Limit <100% - action = function(self, t) - local tg = {type="bolt", range=self:getTalentRange(t), talent=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) - game:playSoundNear(self, "talents/spell_generic") - local target = game.level.map(x, y, Map.ACTOR) - if target then - target:setEffect(self.EFF_MARTYRDOM, 10, {src = self, power=t.getReturnDamage(self, t), apply_power=self:combatSpellpower()}) - else - return - end - return true + mode = "passive", + getPower = function(self, t) return 15 + self:combatTalentSpellDamage(t, 1, 100) end, + getDef = function(self, t) return 5 + self:combatTalentSpellDamage(t, 1, 35) end, + callbackOnActBase = function(self, t) + local radius = radianceRadius(self) + local grids = core.fov.circle_grids(self.x, self.y, radius, true) + for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local target = game.level.map(x, y, Map.ACTOR) if target and self ~= target then + target:setEffect(target.EFF_ILLUMINATION, 1, {power=t.getPower(self, t), def=t.getDef(self, t)}) + local ss = self:isTalentActive(self.T_SEARING_SIGHT) + if ss then + local dist = core.fov.distance(self.x, self.y, target.x, target.y) - 1 + local coeff = math.scale(radius - dist, 1, radius, 0.1, 1) + local realdam = DamageType:get(DamageType.LIGHT).projector(self, target.x, target.y, DamageType.LIGHT, ss.dam * coeff) + if ss.daze and rng.percent(ss.daze) and target:canBe("stun") then + target:setEffect(target.EFF_DAZED, 3, {apply_power=self:combatSpellpower()}) + end + + if realdam and realdam > 0 and self:hasEffect(self.EFF_LIGHT_BURST) then + self:setEffect(self.EFF_LIGHT_BURST_SPEED, 4, {}) + end + end + end end end end, info = function(self, t) - local returndamage = t.getReturnDamage(self, t) - return ([[Designate a target as a martyr for 10 turns. When the martyr deals damage, it also damages itself for %d%% of the damage dealt.]]): - format(returndamage) + return ([[The light of your Radiance allows you to see that which would normally be unseen. + All actors in your Radiance aura have their invisibility and stealth power reduced by %d. + In addition, all actors affected by illumination are easier to see and therefore hit; their defense is reduced by %d and all evasion bonuses from being unseen are negated. + The effects increase with your Spellpower.]]): + format(t.getPower(self, t), t.getDef(self, t)) end, } newTalent{ - name = "Searing Ray", + name = "Searing Sight", type = {"celestial/radiance",3}, require = divi_req3, + mode = "sustained", points = 5, - random_ego = "attack", - cooldown = 6, - positive = 10, - tactical = { ATTACK = 2 }, - requires_target = true, - range = function(self, t) return 2 + math.max(0, self:combatStatScale("str", 0.8, 8)) end, - getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 1.1, 1.9) end, - action = function(self, t) - local tg = {type="bolt", range=self:getTalentRange(t), talent=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) - local target = game.level.map(x, y, Map.ACTOR) - if target then - self:attackTarget(target, nil, t.getDamage(self, t), true) - else - return - end - return true + cooldown = 15, + range = function(self) return radianceRadius(self) end, + tactical = { ATTACKAREA = {LIGHT=1} }, + sustain_positive = 40, + getDamage = function(self, t) return self:combatTalentSpellDamage(t, 1, 90) end, + getDaze = function(self, t) return self:combatTalentLimit(t, 35, 5, 20) end, + activate = function(self, t) + local daze = nil + if self:getTalentLevel(t) >= 4 then daze = t.getDaze(self, t) end + return {dam=t.getDamage(self, t), daze=daze} + end, + deactivate = function(self, t, p) end, info = function(self, t) - local damage = t.getDamage(self, t) - return ([[In a pure display of power, you project a melee attack, doing %d%% damage. - The range will increase with your Strength.]]): - format(100 * damage) + return ([[Your Radiance is so powerful it burns all foes caught in it, doing up to %0.2f light damage (reduced with distance) to all foes caught inside. + At level 4 the light is so bright it has %d%% chances to daze them for 3 turns. + The damage increase with your Spellpower.]]): + format(damDesc(self, DamageType.LIGHT, t.getDamage(self, t)), t.getDaze(self, t)) end, } @@ -109,27 +110,30 @@ newTalent{ name = "Light Burst", type = {"celestial/radiance", 4}, require = divi_req4, - random_ego = "attack", points = 5, - cooldown = 10, - positive = 10, - tactical = { ATTACK = {LIGHT = 2} }, - range = 1, + cooldown = 25, + positive = 15, + tactical = { DISABLE = {blind=1} }, + range = function(self) return radianceRadius(self) end, requires_target = true, - getDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.8, 1.6) end, + getDur = function(self, t) return self:combatTalentLimit(t, 9, 2, 6) end, + getMax = function(self, t) return math.floor(self:combatTalentScale(t, 2, 8)) end, action = function(self, t) - local tg = {type="hit", range=self:getTalentRange(t)} - local x, y, target = self:getTarget(tg) - if not x or not y or not target then return nil end - if core.fov.distance(self.x, self.y, x, y) > 1 then return nil end - self:attackTarget(target, DamageType.LIGHT, t.getDamage(self, t), true) - self:attackTarget(target, DamageType.LIGHT, t.getDamage(self, t), true) + local radius = radianceRadius(self) + local grids = core.fov.circle_grids(self.x, self.y, radius, true) + for x, yy in pairs(grids) do for y, _ in pairs(grids[x]) do local target = game.level.map(x, y, Map.ACTOR) if target and self ~= target then + if target:canBe("blind") then + target:setEffect(target.EFF_BLINDED, 4, {apply_power=self:combatSpellpower()}) + end + end end end + + self:setEffect(self.EFF_LIGHT_BURST, t.getDur(self, t), {max=t.getMax(self, t)}) return true end, info = function(self, t) - local damage = t.getDamage(self, t) - return ([[Concentrate the power of the Sun into two blows; each blow does %d%% of your weapon damage as light damage.]]): - format(100 * damage) + return ([[Concentrate your Radiance in a blinding flash of light. All foes caught inside will be blinded for 3 turns. + In addition for %d turns each time your Searing Sight damages a foe you gain a movement bonus of 10%%, stacking up to %d times.]]): + format(t.getDur(self, t), t.getMax(self, t)) end, } diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua index 2ee4c973d6448d3d2b7e649addf4dc82af8c176f..8241a0677284878aa87d4c0d6e2851615f8955a9 100644 --- a/game/modules/tome/data/timed_effects/magical.lua +++ b/game/modules/tome/data/timed_effects/magical.lua @@ -2580,3 +2580,62 @@ newEffect{ DamageType:get(DamageType.LIGHT).projector(eff.src, self.x, self.y, DamageType.LIGHT, eff.dam) end, } + +newEffect{ + name = "ILLUMINATION", + desc = "Illumination ", image = "talents/illumination.png", + long_desc = function(self, eff) return ("The target glows in the light, reducing its stealth and invisibility power by %d, defense by %d and looses all evasion bonus from being unseen."):format(eff.power, eff.def) end, + type = "physical", + subtype = { sun=true }, + status = "detrimental", + parameters = { power=20, def=20 }, + on_gain = function(self, err) return nil, "+Illumination" end, + on_lose = function(self, err) return nil, "-Illumination" end, + activate = function(self, eff) + self:effectTemporaryValue(eff, "inc_stealth", -eff.power) + if self:attr("invisible") then self:effectTemporaryValue(eff, "invisible", -eff.power) end + self:effectTemporaryValue(eff, "combat_def", -eff.def) + self:effectTemporaryValue(eff, "blind_fighted", 1) + end, +} + +newEffect{ + name = "LIGHT_BURST", + desc = "Light Burst ", image = "talents/light_burst.png", + long_desc = function(self, eff) return ("The is invigorated when dealing damage with Searing Sight."):format() end, + type = "physical", + subtype = { sun=true }, + status = "beneficial", + parameters = { max=1 }, + on_gain = function(self, err) return nil, "+Light Burst" end, + on_lose = function(self, err) return nil, "-Light Burst" end, +} + +newEffect{ + name = "LIGHT_BURST_SPEED", + desc = "Light Burst Speed ", image = "effects/light_burst_speed.png", + long_desc = function(self, eff) return ("The is invigorated from Searing Sight, increasing movement speed by %d%%."):format(eff.charges * 10) end, + type = "physical", + subtype = { sun=true }, + status = "beneficial", + parameters = {}, + charges = function(self, eff) return eff.charges end, + on_gain = function(self, err) return nil, "+Light Burst Speed" end, + on_lose = function(self, err) return nil, "-Light Burst Speed" end, + on_merge = function(self, old_eff, new_eff) + local p = self:hasEffect(self.EFF_LIGHT_BURST) + if not p then p = {max=1} end + + new_eff.charges = math.min(old_eff.charges + 1, p.max) + self:removeTemporaryValue("movement_speed", old_eff.tmpid) + new_eff.tmpid = self:addTemporaryValue("movement_speed", new_eff.charges * 0.1) + return new_eff + end, + activate = function(self, eff) + eff.charges = 1 + eff.tmpid = self:addTemporaryValue("movement_speed", eff.charges * 0.1) + end, + deactivate = function(self, eff) + self:removeTemporaryValue("movement_speed", eff.tmpid) + end, +}