black-sun.lua 10.29 KiB
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009 - 2019 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
local Object = require "mod.class.Object"
newTalent{
name = "Collapse",
type = {"celestial/black-sun", 1},
require = divi_str_req_high1,
points = 5,
cooldown = 12,
positive = -15,
range = 7,
direct_hit = true,
requires_target = true,
target = function(self, t) return {type="hit", nolock=true, range=self:getTalentRange(t)} end,
getDamage = function(self, t) return self:combatTalentSpellDamage(t, 20, 75) end,
getDuration = function(self, t) return math.floor(self:combatTalentScale(t, 3, 5.6)) end,
getMaxRadius = function(self, t) return math.max(1, math.floor(self:combatTalentLimit(t, 5, 1, 3))) end,
action = function(self, t)
local tg = self:getTalentTarget(t)
local x, y, target = self:getTarget(tg)
if not x or not y then return nil end
local _ _, px, py = self:canProject(tg, x, y)
local dam = t.getDamage(self, t)
local dur = t.getDuration(self, t)
local rad = 1
local max_radius = t.getMaxRadius(self, t)
dam = self:spellCrit(dam)
local oe = game.level.map(px, py, Map.TERRAIN+1)
if (oe and oe.is_maelstrom) or game.level.map:checkEntity(x, y, Map.TERRAIN, "block_move") then return nil end
local e = Object.new{
old_feat = oe,
type = "void", subtype = "black hole",
name = self.name:capitalize().. "'s black hole",
display = ' ',
tooltip = mod.class.Grid.tooltip,
always_remember = true,
temporary = dur,
is_maelstrom = true,
x = px, y = py,
canAct = false,
dam = dam,
radius = rad,
max_radius = max_radius,
rebuild_particles = function(self)
if self.particles then game.level.map:removeParticleEmitter(self.particles) end
if self.particles2 then game.level.map:removeParticleEmitter(self.particles2) end
local particle = engine.Particles.new("generic_vortex", self.radius, {radius=self.radius, rm=255, rM=255, gm=180, gM=255, bm=180, bM=255, am=35, aM=90})
local particle2 = engine.Particles.new("image", self.radius, {size=64*self.radius, image="particles_images/breach"}) particle2.zdepth = 4
if core.shader.allow("distort") then particle:setSub("vortex_distort", self.radius, {radius=self.radius}) end
self.particles2 = game.level.map:addParticleEmitter(particle2, self.x, self.y)
self.particles = game.level.map:addParticleEmitter(particle, self.x, self.y)
game:shakeScreen(10, 3)
end,
act = function(self)
local tgts = {}
local Map = require "engine.Map"
local DamageType = require "engine.DamageType"
if self.radius < self.max_radius then
self.radius = math.min(self.max_radius, (self.radius + 1))
self:rebuild_particles()
end
local grids = core.fov.circle_grids(self.x, self.y, self.radius, true)
for x, yy in pairs(grids) do
for y, _ in pairs(grids[x]) do
local Map = require "engine.Map"
local target = game.level.map(x, y, Map.ACTOR)
local friendlyfire = false
if target and not (friendlyfire == false and self.summoner:reactionToward(target) >= 0) then
tgts[#tgts+1] = {actor=target, sqdist=core.fov.distance(self.x, self.y, x, y)}
end
end
end
table.sort(tgts, "sqdist")
for i, target in ipairs(tgts) do
local old_source = self.summoner.__project_source
self.summoner.__project_source = self
DamageType:get(DamageType.BLACK_HOLE_GRAVITY).projector(self.summoner, target.actor.x, target.actor.y, DamageType.BLACK_HOLE_GRAVITY, self.dam)
self.summoner.__project_source = old_source
end
self:useEnergy()
self.temporary = self.temporary - 1
if self.temporary <= 0 then
game.level.map:removeParticleEmitter(self.particles)
game.level.map:removeParticleEmitter(self.particles2)
if self.old_feat then game.level.map(self.x, self.y, engine.Map.TERRAIN+1, self.old_feat)
else game.level.map:remove(self.x, self.y, engine.Map.TERRAIN+1) end
game.level:removeEntity(self)
game.level.map:updateMap(self.x, self.y)
game.nicer_tiles:updateAround(game.level, self.x, self.y)
end
end,
summoner_gain_exp = true,
summoner = self,
}
e:rebuild_particles()
game:playSoundNear(self, "talents/fallen_brokenglass")
game.level:addEntity(e)
game.level.map(x, y, Map.TERRAIN+1, e)
game.level.map:updateMap(x, y)
return true
end,
info = function(self, t)
local rad = t.getMaxRadius(self,t)
local dam = t.getDamage(self,t)/2
local dur = t.getDuration(self,t)
local entropy = 0
return ([[Open a radius 1 rift in spacetime at the targeted location for %d turns, increasing in radius by 1 each turn to a maximum of %d.
All caught within the rift are pulled towards the center and take %0.2f gravity damage.
The damage will increase with your Spellpower.]]):
tformat(dur, rad, damDesc(self, DamageType.PHYSICAL, dam))
end,
}
newTalent{
name = "Devourer Stance",
type = {"celestial/black-sun", 2},
require = divi_str_req_high2,
points = 5,
cooldown = 15,
positive = 10,
getDuration = function(self,t) return math.floor(self:combatTalentScale(t, 3, 7)) end,
getOnhit = function(self,t) return self:combatTalentSpellDamage(t, 10, 50) end,
action = function(self, t)
self:setEffect(self.EFF_DEVOURER_STANCE, t.getDuration(self,t), {gravity=t.getOnhit(self,t)})
return true
end,
info = function(self, t)
return ([[Attune yourself to the endless hunger of distant dead suns. For the next %d turns, your attacks will inflict an additional %0.2f gravity damage and attempt to pull enemies closer. After three turns, you will recover half of all damage taken during this effect.
The damage will increase with your Spellpower.]]):tformat(t.getDuration(self,t), damDesc(self, DamageType.PHSYICAL, t.getOnhit(self,t)))
end,
}
newTalent{
name = "Singularity Armor",
type = {"celestial/black-sun", 3},
require = divi_str_req_high3,
points = 5,
mode = "sustained",
sustain_positive = 20,
cooldown = 10,
tactical = { BUFF = 2 },
points = 5,
getSlow = function(self, t) return self:combatTalentLimit(t, 80, 10, 50) end,
getConversion= function(self, t) return self:combatTalentLimit(t, 80, 10, 40) end,
activate = function(self, t)
game:playSoundNear(self, "talents/heal")
local particle = Particles.new("ultrashield", 1, {rm=204, rM=220, gm=102, gM=120, bm=0, bM=0, am=15, aM=60, radius=0.5, density=10, life=28, instop=100})
return {
converttype = self:addTemporaryValue("all_damage_convert", DamageType.PHYSICAL),
convertamount = self:addTemporaryValue("all_damage_convert_percent", t.getConversion(self, t)),
proj = self:addTemporaryValue("slow_projectiles", t.getSlow(self, t)),
particle = self:addParticles(particle)
}
end,
deactivate = function(self, t, p)
self:removeTemporaryValue("all_damage_convert", p.converttype)
self:removeTemporaryValue("all_damage_convert_percent", p.convertamount)
self:removeTemporaryValue("slow_projectiles", p.proj)
self:removeParticles(p.particle)
return true
end,
info = function(self, t)
local conv = t.getConversion(self, t)
local proj = t.getSlow(self, t)
return ([[Create a gravity field around you that converts %d%% of all damage you deal into physical damage, slows incoming projectiles by %d%%, and causes your gravity damage to reduce the target's knockback resistance by half for two turns.]]):tformat(conv, proj)
end,
}
newTalent{
name = "Doom Spiral",
type = {"celestial/black-sun", 4},
require = divi_str_req_high4,
points = 5,
random_ego = "attack",
cooldown = 9,
positive = 15,
tactical = { ATTACKAREA = {LIGHT = 2} },
range = 0,
radius = 2,
requires_target = true,
target = function(self, t)
return {type="ball", range=self:getTalentRange(t), selffire=false, radius=self:getTalentRadius(t)}
end,
getOuterDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.5, 1.3) end,
getInnerDamage = function(self, t) return self:combatTalentWeaponDamage(t, 0.3, 1.5) end,
getShield = function(self, t) return self:combatTalentSpellDamage(t, 35, 220) end,
action = function(self, t)
local tg1 = self:getTalentTarget(t) tg1.radius = 1
local tg2 = self:getTalentTarget(t)
-- Gravity pull
self:addParticles(Particles.new("meleestorm", 2, {radius=2, img="spinningwinds_black"}))
self:project(tg2, self.x, self.y, function(px, py, tg, self)
local target = game.level.map(px, py, Map.ACTOR)
if target and target ~= self then
self:attackTarget(target, DamageType.BLACK_HOLE_GRAVITY, t.getOuterDamage(self, t), true)
end
end)
-- Physical hit
local absorbed = 0
self:addParticles(Particles.new("meleestorm", 1, {img="spinningwinds_red"}))
self:project(tg1, self.x, self.y, function(px, py, tg, self)
local target = game.level.map(px, py, Map.ACTOR)
if target and target ~= self then
hitted = self:attackTarget(target, nil, t.getInnerDamage(self, t), true)
if hitted then absorbed = absorbed + 1 end
end
end)
--Shield
local multShield = 2-0.5^absorbed
self:setEffect(self.EFF_DAMAGE_SHIELD, 2, {color={0xff/255, 0x3b/255, 0x3f/255}, power=self:spellCrit(t.getShield(self, t)*multShield)})
return true
end,
info = function(self, t)
return ([[Infuse your weapon with overwhelming gravitational power while spinning around.
All creatures within radius 2 take %d%% weapon damage as physical (gravity) and are pulled closer.
Then, all adjacent creatures take %d%% weapon damage. This second strike shields you for between %d and %d, increasing with more enemies hit. The shield lasts for 2 turns.
The shield strength will increase with your Spellpower.]]):
tformat(t.getOuterDamage(self, t) * 100,
t.getInnerDamage(self, t) * 100,
t.getShield(self, t), t.getShield(self, t)*2)
end,
}