Sorcerer update 2/4

master
a327ex 2021-06-03 17:02:04 -03:00
parent cea71538b2
commit f3997b08a7
12 changed files with 522 additions and 98 deletions

View File

@ -20,7 +20,7 @@ function Arena:on_enter(from, level, units, passives)
steam.friends.setRichPresence('text', 'Arena - Level ' .. self.level) steam.friends.setRichPresence('text', 'Arena - Level ' .. self.level)
self.floor = Group() self.floor = Group()
self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'}) self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile', 'force_field'})
self.post_main = Group() self.post_main = Group()
self.effects = Group() self.effects = Group()
self.ui = Group() self.ui = Group()
@ -33,6 +33,8 @@ function Arena:on_enter(from, level, units, passives)
self.main:disable_collision_between('projectile', 'enemy') self.main:disable_collision_between('projectile', 'enemy')
self.main:disable_collision_between('enemy_projectile', 'enemy') self.main:disable_collision_between('enemy_projectile', 'enemy')
self.main:disable_collision_between('enemy_projectile', 'enemy_projectile') self.main:disable_collision_between('enemy_projectile', 'enemy_projectile')
self.main:disable_collision_between('player', 'force_field')
self.main:disable_collision_between('projectile', 'force_field')
self.main:enable_trigger_between('projectile', 'enemy') self.main:enable_trigger_between('projectile', 'enemy')
self.main:enable_trigger_between('enemy_projectile', 'player') self.main:enable_trigger_between('enemy_projectile', 'player')
self.main:enable_trigger_between('player', 'enemy_projectile') self.main:enable_trigger_between('player', 'enemy_projectile')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1323,6 +1323,7 @@ function CharacterIcon:init(args)
self:init_game_object(args) self:init_game_object(args)
self.shape = Rectangle(self.x, self.y, 40, 20) self.shape = Rectangle(self.x, self.y, 40, 20)
self.interact_with_mouse = true self.interact_with_mouse = true
print(character_color_strings[self.character])
self.character_text = Text({{text = '[' .. character_color_strings[self.character] .. ']' .. string.lower(character_names[self.character]), font = pixul_font, alignment = 'center'}}, global_text_tags) self.character_text = Text({{text = '[' .. character_color_strings[self.character] .. ']' .. string.lower(character_names[self.character]), font = pixul_font, alignment = 'center'}}, global_text_tags)
end end
@ -1394,12 +1395,12 @@ end
function TutorialClassIcon:draw() function TutorialClassIcon:draw()
graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x) graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x)
local i, j, n = class_set_numbers[self.class](self.units) local i, j, k, n = class_set_numbers[self.class](self.units)
graphics.rectangle(self.x, self.y, 16, 24, 4, 4, self.highlighted and fg[0] or ((n >= i) and class_colors[self.class] or bg[3])) graphics.rectangle(self.x, self.y, 16, 24, 4, 4, self.highlighted and fg[0] or ((n >= i) and class_colors[self.class] or bg[3]))
_G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, self.highlighted and fg[-5] or ((n >= i) and _G[class_color_strings[self.class]][-5] or bg[10])) _G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, self.highlighted and fg[-5] or ((n >= i) and _G[class_color_strings[self.class]][-5] or bg[10]))
graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, self.highlighted and fg[0] or bg[3]) graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, self.highlighted and fg[0] or bg[3])
if i == 2 then if i == 2 and not k then
if self.highlighted then if self.highlighted then
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and fg[-5] or fg[-10], 3) graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and fg[-5] or fg[-10], 3)
graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and fg[-5] or fg[-10], 3) graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and fg[-5] or fg[-10], 3)
@ -1435,7 +1436,7 @@ end
function TutorialClassIcon:on_mouse_enter() function TutorialClassIcon:on_mouse_enter()
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
self.spring:pull(0.2, 200, 10) self.spring:pull(0.2, 200, 10)
local i, j, owned = class_set_numbers[self.class](self.units) local i, j, k, owned = class_set_numbers[self.class](self.units)
self.info_text = InfoText{group = main.current.tutorial} self.info_text = InfoText{group = main.current.tutorial}
self.info_text:activate({ self.info_text:activate({
{text = '[' .. class_color_strings[self.class] .. ']' .. self.class:capitalize() .. '[fg] - owned: [yellow]' .. owned, font = pixul_font, alignment = 'center', height_multiplier = 1.25}, {text = '[' .. class_color_strings[self.class] .. ']' .. self.class:capitalize() .. '[fg] - owned: [yellow]' .. owned, font = pixul_font, alignment = 'center', height_multiplier = 1.25},
@ -1474,7 +1475,7 @@ end
function ClassIcon:draw() function ClassIcon:draw()
graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x) graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x)
local i, j, n = class_set_numbers[self.class](self.units) local i, j, k, n = class_set_numbers[self.class](self.units)
local next_n local next_n
if self.parent:is(ShopCard) then if self.parent:is(ShopCard) then
next_n = n+1 next_n = n+1
@ -1485,7 +1486,7 @@ function ClassIcon:draw()
graphics.rectangle(self.x, self.y, 16, 24, 4, 4, self.highlighted and fg[0] or ((n >= i) and class_colors[self.class] or bg[3])) graphics.rectangle(self.x, self.y, 16, 24, 4, 4, self.highlighted and fg[0] or ((n >= i) and class_colors[self.class] or bg[3]))
_G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, self.highlighted and fg[-5] or ((n >= i) and _G[class_color_strings[self.class]][-5] or bg[10])) _G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, self.highlighted and fg[-5] or ((n >= i) and _G[class_color_strings[self.class]][-5] or bg[10]))
graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, self.highlighted and fg[0] or bg[3]) graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, self.highlighted and fg[0] or bg[3])
if i == 2 then if i == 2 and not k then
if self.highlighted then if self.highlighted then
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and fg[-5] or fg[-10], 3) graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and fg[-5] or fg[-10], 3)
graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and fg[-5] or fg[-10], 3) graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and fg[-5] or fg[-10], 3)
@ -1508,6 +1509,38 @@ function ClassIcon:draw()
graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, self.flash and class_colors[self.class] or bg[10], 3) graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, self.flash and class_colors[self.class] or bg[10], 3)
end end
end end
elseif i == 2 and k == 6 then
if self.highlighted then
graphics.line(self.x - 5, self.y + 21, self.x - 5, self.y + 24, (n >= 1) and fg[-5] or fg[-10], 3)
graphics.line(self.x - 5, self.y + 28, self.x - 5, self.y + 31, (n >= 2) and fg[-5] or fg[-10], 3)
graphics.line(self.x + 0, self.y + 21, self.x + 0, self.y + 24, (n >= 3) and fg[-5] or fg[-10], 3)
graphics.line(self.x + 0, self.y + 28, self.x + 0, self.y + 31, (n >= 4) and fg[-5] or fg[-10], 3)
graphics.line(self.x + 5, self.y + 21, self.x + 5, self.y + 24, (n >= 5) and fg[-5] or fg[-10], 3)
graphics.line(self.x + 5, self.y + 28, self.x + 5, self.y + 31, (n >= 6) and fg[-5] or fg[-10], 3)
else
graphics.line(self.x - 5, self.y + 21, self.x - 5, self.y + 24, (n >= 1) and class_colors[self.class] or bg[10], 3)
graphics.line(self.x - 5, self.y + 28, self.x - 5, self.y + 31, (n >= 2) and class_colors[self.class] or bg[10], 3)
graphics.line(self.x + 0, self.y + 21, self.x + 0, self.y + 24, (n >= 3) and class_colors[self.class] or bg[10], 3)
graphics.line(self.x + 0, self.y + 28, self.x + 0, self.y + 31, (n >= 4) and class_colors[self.class] or bg[10], 3)
graphics.line(self.x + 5, self.y + 21, self.x + 5, self.y + 24, (n >= 5) and class_colors[self.class] or bg[10], 3)
graphics.line(self.x + 5, self.y + 28, self.x + 5, self.y + 31, (n >= 6) and class_colors[self.class] or bg[10], 3)
end
if next_n then
if next_n == 1 then
graphics.line(self.x - 5, self.y + 21, self.x - 5, self.y + 24, self.flash and class_colors[self.class] or bg[10], 3)
elseif next_n == 2 then
graphics.line(self.x - 5, self.y + 28, self.x - 5, self.y + 31, self.flash and class_colors[self.class] or bg[10], 3)
elseif next_n == 3 then
graphics.line(self.x + 0, self.y + 21, self.x + 0, self.y + 24, self.flash and class_colors[self.class] or bg[10], 3)
elseif next_n == 4 then
graphics.line(self.x + 0, self.y + 28, self.x + 0, self.y + 31, self.flash and class_colors[self.class] or bg[10], 3)
elseif next_n == 5 then
graphics.line(self.x + 5, self.y + 21, self.x + 5, self.y + 24, self.flash and class_colors[self.class] or bg[10], 3)
elseif next_n == 6 then
graphics.line(self.x + 5, self.y + 28, self.x + 5, self.y + 31, self.flash and class_colors[self.class] or bg[10], 3)
end
end
elseif i == 3 then elseif i == 3 then
if self.highlighted then if self.highlighted then
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and fg[-5] or fg[-10], 3) graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and fg[-5] or fg[-10], 3)
@ -1547,11 +1580,11 @@ end
function ClassIcon:on_mouse_enter() function ClassIcon:on_mouse_enter()
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
self.spring:pull(0.2, 200, 10) self.spring:pull(0.2, 200, 10)
local i, j, owned = class_set_numbers[self.class](self.units) local i, j, k, owned = class_set_numbers[self.class](self.units)
self.info_text = InfoText{group = main.current.ui} self.info_text = InfoText{group = main.current.ui}
self.info_text:activate({ self.info_text:activate({
{text = '[' .. class_color_strings[self.class] .. ']' .. self.class:capitalize() .. '[fg] - owned: [yellow]' .. owned, font = pixul_font, alignment = 'center', height_multiplier = 1.25}, {text = '[' .. class_color_strings[self.class] .. ']' .. self.class:capitalize() .. '[fg] - owned: [yellow]' .. owned, font = pixul_font, alignment = 'center', height_multiplier = 1.25},
{text = class_descriptions[self.class]((owned >= j and 2) or (owned >= i and 1) or 0), font = pixul_font, alignment = 'center'}, {text = class_descriptions[self.class]((k and (owned >= k and 3)) or (owned >= j and 2) or (owned >= i and 1) or 0), font = pixul_font, alignment = 'center'},
}, nil, nil, nil, nil, 16, 4, nil, 2) }, nil, nil, nil, nil, 16, 4, nil, 2)
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10 self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
@ -1584,7 +1617,7 @@ end
function ClassIcon:die(dont_spawn_effect) function ClassIcon:die(dont_spawn_effect)
self.dead = true self.dead = true
local i, j, n = class_set_numbers[self.class](self.units) local i, j, k, n = class_set_numbers[self.class](self.units)
if not dont_spawn_effect then SpawnEffect{group = main.current.effects, x = self.x, y = self.y + 4, color = (n >= i) and class_colors[self.class] or bg[3]} end if not dont_spawn_effect then SpawnEffect{group = main.current.effects, x = self.x, y = self.y + 4, color = (n >= i) and class_colors[self.class] or bg[3]} end
if self.info_text then if self.info_text then
self.info_text:deactivate() self.info_text:deactivate()

View File

@ -16,6 +16,7 @@ function Seeker:init(args)
if self.boss == 'speed_booster' then if self.boss == 'speed_booster' then
self.color = green[0]:clone() self.color = green[0]:clone()
self.t:every(8, function() self.t:every(8, function()
if self.silenced then return end
local enemies = table.head(self:get_objects_in_shape(Circle(self.x, self.y, 128), main.current.enemies), 4) local enemies = table.head(self:get_objects_in_shape(Circle(self.x, self.y, 128), main.current.enemies), 4)
if #enemies > 0 then if #enemies > 0 then
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -30,6 +31,7 @@ function Seeker:init(args)
elseif self.boss == 'forcer' then elseif self.boss == 'forcer' then
self.color = yellow[0]:clone() self.color = yellow[0]:clone()
self.t:every(6, function() self.t:every(6, function()
if self.silenced then return end
local enemies = main.current.main:get_objects_by_classes(main.current.enemies) local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
local x, y = 0, 0 local x, y = 0, 0
if #enemies > 0 then if #enemies > 0 then
@ -74,6 +76,7 @@ function Seeker:init(args)
elseif self.boss == 'swarmer' then elseif self.boss == 'swarmer' then
self.color = purple[0]:clone() self.color = purple[0]:clone()
self.t:every(4, function() self.t:every(4, function()
if self.silenced then return end
local enemies = table.select(main.current.main:get_objects_by_classes(main.current.enemies), function(v) return v.id ~= self.id and v:is(Seeker) end) local enemies = table.select(main.current.main:get_objects_by_classes(main.current.enemies), function(v) return v.id ~= self.id and v:is(Seeker) end)
local enemy = random:table(enemies) local enemy = random:table(enemies)
if enemy then if enemy then
@ -89,6 +92,7 @@ function Seeker:init(args)
elseif self.boss == 'exploder' then elseif self.boss == 'exploder' then
self.color = blue[0]:clone() self.color = blue[0]:clone()
self.t:every(4, function() self.t:every(4, function()
if self.silenced then return end
local enemies = table.select(main.current.main:get_objects_by_classes(main.current.enemies), function(v) return v.id ~= self.id and v:is(Seeker) end) local enemies = table.select(main.current.main:get_objects_by_classes(main.current.enemies), function(v) return v.id ~= self.id and v:is(Seeker) end)
local enemy = random:table(enemies) local enemy = random:table(enemies)
if enemy then if enemy then
@ -104,6 +108,7 @@ function Seeker:init(args)
elseif self.boss == 'randomizer' then elseif self.boss == 'randomizer' then
self.t:every_immediate(0.07, function() self.color = _G[random:table{'green', 'purple', 'yellow', 'blue'}][0]:clone() end) self.t:every_immediate(0.07, function() self.color = _G[random:table{'green', 'purple', 'yellow', 'blue'}][0]:clone() end)
self.t:every(6, function() self.t:every(6, function()
if self.silenced then return end
local attack = random:table{'explode', 'swarm', 'force', 'speed_boost'} local attack = random:table{'explode', 'swarm', 'force', 'speed_boost'}
if attack == 'explode' then if attack == 'explode' then
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 128), {Seeker}) local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 128), {Seeker})
@ -182,6 +187,7 @@ function Seeker:init(args)
self.last_headbutt_time = 0 self.last_headbutt_time = 0
local n = math.remap(current_new_game_plus, 0, 5, 1, 0.5) local n = math.remap(current_new_game_plus, 0, 5, 1, 0.5)
self.t:every(function() return math.distance(self.x, self.y, main.current.player.x, main.current.player.y) < 64 and love.timer.getTime() - self.last_headbutt_time > 10*n end, function() self.t:every(function() return math.distance(self.x, self.y, main.current.player.x, main.current.player.y) < 64 and love.timer.getTime() - self.last_headbutt_time > 10*n end, function()
if self.silenced then return end
if self.headbutt_charging or self.headbutting then return end if self.headbutt_charging or self.headbutting then return end
self.headbutt_charging = true self.headbutt_charging = true
self.t:tween(2, self.color, {r = fg[0].r, b = fg[0].b, g = fg[0].g}, math.cubic_in_out, function() self.t:tween(2, self.color, {r = fg[0].r, b = fg[0].b, g = fg[0].g}, math.cubic_in_out, function()
@ -208,6 +214,7 @@ function Seeker:init(args)
self.t:after({2*n, 4*n}, function() self.t:after({2*n, 4*n}, function()
self.shooting = true self.shooting = true
self.t:every({3, 5}, function() self.t:every({3, 5}, function()
if self.silenced then return end
for i = 1, 3 do for i = 1, 3 do
self.t:after((1 - self.level*0.01)*0.15*(i-1), function() self.t:after((1 - self.level*0.01)*0.15*(i-1), function()
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.1} shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.1}
@ -420,6 +427,7 @@ function Seeker:hit(damage, projectile)
end end
if self.speed_booster then if self.speed_booster then
if self.silenced then return end
local enemies = self:get_objects_in_shape(self.area_sensor, main.current.enemies) local enemies = self:get_objects_in_shape(self.area_sensor, main.current.enemies)
if #enemies > 0 then if #enemies > 0 then
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -432,6 +440,7 @@ function Seeker:hit(damage, projectile)
end end
if self.exploder then if self.exploder then
if self.silenced then return end
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.4} shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.4}
trigger:after(0.01, function() trigger:after(0.01, function()
local n = 8 + current_new_game_plus*2 local n = 8 + current_new_game_plus*2
@ -442,6 +451,7 @@ function Seeker:hit(damage, projectile)
end end
if self.spawner then if self.spawner then
if self.silenced then return end
critter1:play{pitch = random:float(0.95, 1.05), volume = 0.35} critter1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
trigger:after(0.01, function() trigger:after(0.01, function()
for i = 1, random:int(5, 8) do for i = 1, random:int(5, 8) do
@ -565,6 +575,9 @@ function Seeker:curse(curse, duration, arg1, arg2, arg3)
self.infested_dmg = arg2 self.infested_dmg = arg2
self.infested_ref = arg3 self.infested_ref = arg3
self.t:after(duration*curse_m, function() self.infested = false end, 'infestor_curse') self.t:after(duration*curse_m, function() self.infested = false end, 'infestor_curse')
elseif curse == 'silencer' then
self.silenced = true
self.t:after(duration*curse_m, function() self.silenced = false end, 'silencer_curse')
end end
end end
@ -745,6 +758,9 @@ function EnemyCritter:curse(curse, duration, arg1, arg2, arg3)
self.infested_dmg = arg2 self.infested_dmg = arg2
self.infested_ref = arg3 self.infested_ref = arg3
self.t:after(duration*curse_m, function() self.infested = false end, 'infestor_curse') self.t:after(duration*curse_m, function() self.infested = false end, 'infestor_curse')
elseif curse == 'silencer' then
self.silenced = true
self.t:after(duration*curse_m, function() self.silenced = false end, 'silencer_curse')
end end
end end

121
main.lua
View File

@ -18,6 +18,13 @@ function init()
input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'}) input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'})
local s = {tags = {sfx}} local s = {tags = {sfx}}
psychic1 = Sound('Magical Impact 13.ogg', s)
fire1 = Sound('Fire bolt 3.ogg', s)
fire2 = Sound('Fire bolt 5.ogg', s)
fire3 = Sound('Fire bolt 10.ogg', s)
earth1 = Sound('Earth Bolt 1.ogg', s)
earth2 = Sound('Earth Bolt 14.ogg', s)
earth3 = Sound('Earth Bolt 20.ogg', s)
illusion1 = Sound('Buff 5.ogg', s) illusion1 = Sound('Buff 5.ogg', s)
thunder1 = Sound('399656__bajko__sfx-thunder-blast.ogg', s) thunder1 = Sound('399656__bajko__sfx-thunder-blast.ogg', s)
flagellant1 = Sound('Whipping Horse 3.ogg', s) flagellant1 = Sound('Whipping Horse 3.ogg', s)
@ -211,6 +218,7 @@ function init()
['vagrant'] = 'Vagrant', ['vagrant'] = 'Vagrant',
['swordsman'] = 'Swordsman', ['swordsman'] = 'Swordsman',
['wizard'] = 'Wizard', ['wizard'] = 'Wizard',
['magician'] = 'Magician',
['archer'] = 'Archer', ['archer'] = 'Archer',
['scout'] = 'Scout', ['scout'] = 'Scout',
['cleric'] = 'Cleric', ['cleric'] = 'Cleric',
@ -262,6 +270,7 @@ function init()
['vagrant'] = fg[0], ['vagrant'] = fg[0],
['swordsman'] = yellow[0], ['swordsman'] = yellow[0],
['wizard'] = blue[0], ['wizard'] = blue[0],
['magician'] = blue[0],
['archer'] = green[0], ['archer'] = green[0],
['scout'] = red[0], ['scout'] = red[0],
['cleric'] = green[0], ['cleric'] = green[0],
@ -313,6 +322,7 @@ function init()
['vagrant'] = 'fg', ['vagrant'] = 'fg',
['swordsman'] = 'yellow', ['swordsman'] = 'yellow',
['wizard'] = 'blue', ['wizard'] = 'blue',
['magician'] = 'blue',
['archer'] = 'green', ['archer'] = 'green',
['scout'] = 'red', ['scout'] = 'red',
['cleric'] = 'green', ['cleric'] = 'green',
@ -363,7 +373,8 @@ function init()
character_classes = { character_classes = {
['vagrant'] = {'psyker', 'ranger', 'warrior'}, ['vagrant'] = {'psyker', 'ranger', 'warrior'},
['swordsman'] = {'warrior'}, ['swordsman'] = {'warrior'},
['wizard'] = {'mage'}, ['wizard'] = {'mage', 'nuker'},
['magician'] = {'mage'},
['archer'] = {'ranger'}, ['archer'] = {'ranger'},
['scout'] = {'rogue'}, ['scout'] = {'rogue'},
['cleric'] = {'healer'}, ['cleric'] = {'healer'},
@ -372,7 +383,7 @@ function init()
['elementor'] = {'mage', 'nuker'}, ['elementor'] = {'mage', 'nuker'},
['saboteur'] = {'rogue', 'conjurer', 'nuker'}, ['saboteur'] = {'rogue', 'conjurer', 'nuker'},
['stormweaver'] = {'enchanter'}, ['stormweaver'] = {'enchanter'},
['sage'] = {'nuker'}, ['sage'] = {'forcer', 'nuker'},
['squire'] = {'warrior', 'enchanter'}, ['squire'] = {'warrior', 'enchanter'},
['cannoneer'] = {'ranger', 'nuker'}, ['cannoneer'] = {'ranger', 'nuker'},
['dual_gunner'] = {'ranger', 'rogue'}, ['dual_gunner'] = {'ranger', 'rogue'},
@ -414,7 +425,8 @@ function init()
character_class_strings = { character_class_strings = {
['vagrant'] = '[fg]Psyker, [green]Ranger, [yellow]Warrior', ['vagrant'] = '[fg]Psyker, [green]Ranger, [yellow]Warrior',
['swordsman'] = '[yellow]Warrior', ['swordsman'] = '[yellow]Warrior',
['wizard'] = '[blue]Mage', ['wizard'] = '[blue]Mage, [red]Nuker',
['magician'] = '[blue]Mage',
['archer'] = '[green]Ranger', ['archer'] = '[green]Ranger',
['scout'] = '[red]Rogue', ['scout'] = '[red]Rogue',
['cleric'] = '[green]Healer', ['cleric'] = '[green]Healer',
@ -482,6 +494,7 @@ function init()
['swordsman'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('swordsman', lvl, 'dmg') .. '[fg] damage in an area, deals extra [yellow]' .. ['swordsman'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('swordsman', lvl, 'dmg') .. '[fg] damage in an area, deals extra [yellow]' ..
math.round(get_character_stat('swordsman', lvl, 'dmg')*0.15, 2) .. '[fg] damage per unit hit' end, math.round(get_character_stat('swordsman', lvl, 'dmg')*0.15, 2) .. '[fg] damage per unit hit' end,
['wizard'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('wizard', lvl, 'dmg') .. ' AoE[fg] damage' end, ['wizard'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('wizard', lvl, 'dmg') .. ' AoE[fg] damage' end,
['magician'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. get_character_stat('magician', lvl, 'dmg') .. 'AoE[fg] damage' end,
['archer'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('archer', lvl, 'dmg') .. '[fg] damage and pierces' end, ['archer'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('archer', lvl, 'dmg') .. '[fg] damage and pierces' end,
['scout'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. get_character_stat('scout', lvl, 'dmg') .. '[fg] damage and chains [yellow]3[fg] times' end, ['scout'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. get_character_stat('scout', lvl, 'dmg') .. '[fg] damage and chains [yellow]3[fg] times' end,
['cleric'] = function(lvl) return '[fg]heals a unit for [yellow]20%[fg] of its max hp when it drops below [yellow]50%[fg] max hp' end, ['cleric'] = function(lvl) return '[fg]heals a unit for [yellow]20%[fg] of its max hp when it drops below [yellow]50%[fg] max hp' end,
@ -508,32 +521,33 @@ function init()
['corruptor'] = function(lvl) return '[fg]spawn [yellow]3[fg] small critters if the corruptor kills an enemy' end, ['corruptor'] = function(lvl) return '[fg]spawn [yellow]3[fg] small critters if the corruptor kills an enemy' end,
['beastmaster'] = function(lvl) return '[fg]spawn [yellow]2[fg] small critters if the beastmaster crits' end, ['beastmaster'] = function(lvl) return '[fg]spawn [yellow]2[fg] small critters if the beastmaster crits' end,
['launcher'] = function(lvl) return '[fg]all nearby enemies are pushed after [yellow]4[fg] seconds, taking [yellow]' .. 2*get_character_stat('launcher', lvl, 'dmg') .. '[fg] damage on wall hit' end, ['launcher'] = function(lvl) return '[fg]all nearby enemies are pushed after [yellow]4[fg] seconds, taking [yellow]' .. 2*get_character_stat('launcher', lvl, 'dmg') .. '[fg] damage on wall hit' end,
['jester'] = function(lvl) return "[fg]curses [yellow]4[fg] nearby enemies for [yellow]6[fg] seconds, they will explode into [yellow]3[fg] knives on death" end, ['jester'] = function(lvl) return "[fg]curses [yellow]6[fg] nearby enemies for [yellow]6[fg] seconds, they will explode into [yellow]3[fg] knives on death" end,
['assassin'] = function(lvl) return '[fg]throws a piercing knife that deals [yellow]' .. get_character_stat('assassin', lvl, 'dmg') .. '[fg] damage + [yellow]' .. ['assassin'] = function(lvl) return '[fg]throws a piercing knife that deals [yellow]' .. get_character_stat('assassin', lvl, 'dmg') .. '[fg] damage + [yellow]' ..
get_character_stat('assassin', lvl, 'dmg')/2 .. '[fg] damage per second' end, get_character_stat('assassin', lvl, 'dmg')/2 .. '[fg] damage per second' end,
['host'] = function(lvl) return '[fg]periodically spawn [yellow]1[fg] small critter' end, ['host'] = function(lvl) return '[fg]periodically spawn [yellow]1[fg] small critter' end,
['carver'] = function(lvl) return '[fg]carves a statue that periodically heals [yellow]1[fg] unit for [yellow]20%[fg] max HP if in range' end, ['carver'] = function(lvl) return '[fg]carves a statue that periodically heals [yellow]1[fg] unit for [yellow]20%[fg] max HP if in range' end,
['bane'] = function(lvl) return '[fg]curses [yellow]5[fg] nearby enemies for [yellow]6[fg] seconds, they will create small void rifts on death' end, ['bane'] = function(lvl) return '[fg]curses [yellow]6[fg] nearby enemies for [yellow]6[fg] seconds, they will create small void rifts on death' end,
['psykino'] = function(lvl) return '[fg]pulls enemies together for [yellow]2[fg] seconds' end, ['psykino'] = function(lvl) return '[fg]pulls enemies together for [yellow]2[fg] seconds' end,
['barrager'] = function(lvl) return '[fg]shoots a barrage of [yellow]3[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end, ['barrager'] = function(lvl) return '[fg]shoots a barrage of [yellow]3[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end,
['highlander'] = function(lvl) return '[fg]deals [yellow]' .. 5*get_character_stat('highlander', lvl, 'dmg') .. '[fg] AoE damage' end, ['highlander'] = function(lvl) return '[fg]deals [yellow]' .. 5*get_character_stat('highlander', lvl, 'dmg') .. '[fg] AoE damage' end,
['fairy'] = function(lvl) return '[fg]periodically heals [yellow]1[fg] unit at random and grants it [yellow]+100%[fg] attack speed for [yellow]6[fg] seconds' end, ['fairy'] = function(lvl) return '[fg]periodically heals [yellow]1[fg] unit at random and grants it [yellow]+100%[fg] attack speed for [yellow]6[fg] seconds' end,
['priest'] = function(lvl) return '[fg]heals all allies for [yellow]20%[fg] their max HP' end, ['priest'] = function(lvl) return '[fg]heals all allies for [yellow]20%[fg] their max HP' end,
['infestor'] = function(lvl) return '[fg]curses all nearby enemies for [yellow]6[fg] seconds, they will release [yellow]2[fg] critters on death' end, ['infestor'] = function(lvl) return '[fg]curses [yellow]8[fg] nearby enemies for [yellow]6[fg] seconds, they will release [yellow]2[fg] critters on death' end,
['flagellant'] = function(lvl) return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', lvl, 'dmg') .. '[fg] damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end, ['flagellant'] = function(lvl) return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', lvl, 'dmg') .. '[fg] damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end,
['arcanist'] = function(lvl) return '[fg]launches a slow moving orb that launches projectiles, each dealing [yellow]' .. get_character_stat('arcanist', lvl, 'dmg') .. '[fg] damage' end, ['arcanist'] = function(lvl) return '[fg]launches a slow moving orb that launches projectiles, each dealing [yellow]' .. get_character_stat('arcanist', lvl, 'dmg') .. '[fg] damage' end,
['illusionist'] = function(lvl) return '[fg]launches a projectile that deals [yellow]' .. get_character_stat('illusionist', lvl, 'dmg') .. '[fg] damage and creates copies that do the same' end, ['illusionist'] = function(lvl) return '[fg]launches a projectile that deals [yellow]' .. get_character_stat('illusionist', lvl, 'dmg') .. '[fg] damage and creates copies that do the same' end,
['witch'] = function(lvl) return '[fg]creates an area that ricochets around the arena and deals [yellow]' .. get_character_stat('witch', lvl, 'dmg') .. '[fg] damage per second' end, ['witch'] = function(lvl) return '[fg]creates an area that ricochets around the arena and deals [yellow]' .. get_character_stat('witch', lvl, 'dmg') .. '[fg] damage per second' end,
['silencer'] = function(lvl) return '[fg]curses [yellow]5[fg] nearby enemies for [yellow]6[fg] seconds, preventing them from using special attacks' end, ['silencer'] = function(lvl) return '[fg]curses [yellow]5[fg] nearby enemies for [yellow]6[fg] seconds, preventing them from using special attacks' end,
['vulcanist'] = function(lvl) return '[fg]creates a volcano that explodes the nearby area [yellow]5[fg] times, dealing [yellow]' .. get_character_stat('vulcanist', lvl, 'dmg') .. 'AoE [fg]damage' end, ['vulcanist'] = function(lvl) return '[fg]creates a volcano that explodes the nearby area [yellow]4[fg] times, dealing [yellow]' .. get_character_stat('vulcanist', lvl, 'dmg') .. 'AoE [fg]damage' end,
['warden'] = function(lvl) return '[fg]creates a force field around a random unit that prevents enemies from entering' end, ['warden'] = function(lvl) return '[fg]creates a force field around a random unit that prevents enemies from entering' end,
['psychic'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. get_character_stat('psychic', lvl, 'dmg') .. '[fg] damage' end, ['psychic'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. get_character_stat('psychic', lvl, 'dmg') .. 'AoE[fg] damage' end,
} }
character_effect_names = { character_effect_names = {
['vagrant'] = '[fg]Champion', ['vagrant'] = '[fg]Champion',
['swordsman'] = '[yellow]Cleave', ['swordsman'] = '[yellow]Cleave',
['wizard'] = '[blue]Magic Missile', ['wizard'] = '[blue]Magic Missile',
['magician'] = '[blue]Teleportation',
['archer'] = '[green]Bounce Shot', ['archer'] = '[green]Bounce Shot',
['scout'] = '[red]Dagger Resonance', ['scout'] = '[red]Dagger Resonance',
['cleric'] = '[green]Mass Heal ', ['cleric'] = '[green]Mass Heal ',
@ -585,6 +599,7 @@ function init()
['vagrant'] = '[light_bg]Champion', ['vagrant'] = '[light_bg]Champion',
['swordsman'] = '[light_bg]Cleave', ['swordsman'] = '[light_bg]Cleave',
['wizard'] = '[light_bg]Magic Missile', ['wizard'] = '[light_bg]Magic Missile',
['magician'] = '[light_bg]Teleportation',
['archer'] = '[light_bg]Bounce Shot', ['archer'] = '[light_bg]Bounce Shot',
['scout'] = '[light_bg]Dagger Resonance', ['scout'] = '[light_bg]Dagger Resonance',
['cleric'] = '[light_bg]Mass Heal ', ['cleric'] = '[light_bg]Mass Heal ',
@ -635,12 +650,13 @@ function init()
character_effect_descriptions = { character_effect_descriptions = {
['vagrant'] = function() return '[yellow]+10%[fg] damage and [yellow]+10%[fg] attack speed per active set' end, ['vagrant'] = function() return '[yellow]+10%[fg] damage and [yellow]+10%[fg] attack speed per active set' end,
['swordsman'] = function() return "[fg]the swordsman's damage is [yellow]doubled" end, ['swordsman'] = function() return "[fg]the swordsman's damage is [yellow]doubled" end,
['wizard'] = function() return '[fg]the projectile chains [yellow]3[fg] times' end, ['wizard'] = function() return '[fg]the projectile chains [yellow]2[fg] times' end,
['magician'] = function() return '[fg]the magician becomes invulnerable for [yellow]6[fg] seconds' end,
['archer'] = function() return '[fg]the arrow ricochets off walls [yellow]3[fg] times' end, ['archer'] = function() return '[fg]the arrow ricochets off walls [yellow]3[fg] times' end,
['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end, ['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end,
['cleric'] = function() return '[fg]heals all units' end, ['cleric'] = function() return '[fg]heals all units' end,
['outlaw'] = function() return "[yellow]+50%[fg] outlaw attack speed and his knives seek enemies" end, ['outlaw'] = function() return "[yellow]+50%[fg] outlaw attack speed and his knives seek enemies" end,
['blade'] = function() return '[fg]deal additional [yellow]' .. get_character_stat('blade', 3, 'dmg')/3 .. '[fg] damage per enemy hit' end, ['blade'] = function() return '[fg]deal additional [yellow]' .. math.round(get_character_stat('blade', 3, 'dmg')/3, 2) .. '[fg] damage per enemy hit' end,
['elementor'] = function() return '[fg]slows enemies by [yellow]60%[fg] for [yellow]6[fg] seconds on hit' end, ['elementor'] = function() return '[fg]slows enemies by [yellow]60%[fg] for [yellow]6[fg] seconds on hit' end,
['saboteur'] = function() return '[fg]the explosion has [yellow]50%[fg] chance to crit, increasing in size and dealing [yellow]2x[fg] damage' end, ['saboteur'] = function() return '[fg]the explosion has [yellow]50%[fg] chance to crit, increasing in size and dealing [yellow]2x[fg] damage' end,
['stormweaver'] = function() return "[fg]chain lightning's trigger area of effect and number of units hit is [yellow]doubled" end, ['stormweaver'] = function() return "[fg]chain lightning's trigger area of effect and number of units hit is [yellow]doubled" end,
@ -674,12 +690,12 @@ function init()
['priest'] = function() return '[fg]picks [yellow]3[fg] units at random and grants them a buff that prevents death once' end, ['priest'] = function() return '[fg]picks [yellow]3[fg] units at random and grants them a buff that prevents death once' end,
['infestor'] = function() return '[fg][yellow]triples[fg] the number of critters released' end, ['infestor'] = function() return '[fg][yellow]triples[fg] the number of critters released' end,
['flagellant'] = function() return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', 3, 'dmg') .. '[fg] damage to all allies and grants [yellow]+12%[fg] damage to all allies per cast' end, ['flagellant'] = function() return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', 3, 'dmg') .. '[fg] damage to all allies and grants [yellow]+12%[fg] damage to all allies per cast' end,
['arcanist'] = function() return '[yellow]100%[fg] increased attack speed for the orb and [yellow]2[fg] projectiles are released per cast' end, ['arcanist'] = function() return '[yellow]+100%[fg] attack speed for the orb and [yellow]2[fg] projectiles are released per cast' end,
['illusionist'] = function() return '[yellow]doubles[fg] the number of copies created and they release [yellow]12[fg] projectiles on death that pierce and ricochet once' end, ['illusionist'] = function() return '[yellow]doubles[fg] the number of copies created and they release [yellow]12[fg] projectiles on death that pierce and ricochet once' end,
['witch'] = function() return '[fg]the area periodically releases projectiles, each dealing [yellow]' .. get_character_stat('witch', 3, 'dmg') .. '[fg] damage and chaining once' end, ['witch'] = function() return '[fg]the area periodically releases projectiles, each dealing [yellow]' .. get_character_stat('witch', 3, 'dmg') .. '[fg] damage and chaining once' end,
['silencer'] = function() return '[fg]the curse also deals [yellow]' .. get_character_stat('silencer', 3, 'dmg') .. '[fg] damage per second' end, ['silencer'] = function() return '[fg]the curse also deals [yellow]' .. get_character_stat('silencer', 3, 'dmg') .. '[fg] damage per second' end,
['vulcanist'] = function() return '[fg]the volcano spawn also deals [yellow]' .. get_character_stat('vulcanist', 3, 'dmg') .. 'AoE [fg] damage and [yellow]doubles[fg] the number of explosions' end, ['vulcanist'] = function() return '[fg]the number and speed of explosions is [yellow]doubled[fg]' end,
['warden'] = function() return '[fg]creates the force field around [yellow]2[fg] additional random units' end, ['warden'] = function() return '[fg]creates the force field around [yellow]2[fg] units, and they are always the [yellow]head[fg] and [yellow]tail[fg] of the snake' end,
['psychic'] = function() return '[fg]the attack can happen from any distance and deals [yellow]double[fg] damage' end, ['psychic'] = function() return '[fg]the attack can happen from any distance and deals [yellow]double[fg] damage' end,
} }
@ -687,11 +703,12 @@ function init()
['vagrant'] = function() return '[light_bg]+10% damage and +10% attack speed per active set' end, ['vagrant'] = function() return '[light_bg]+10% damage and +10% attack speed per active set' end,
['swordsman'] = function() return "[light_bg]the swordsman's damage is doubled" end, ['swordsman'] = function() return "[light_bg]the swordsman's damage is doubled" end,
['wizard'] = function() return '[light_bg]the projectile chains 3 times' end, ['wizard'] = function() return '[light_bg]the projectile chains 3 times' end,
['magician'] = function() return '[light_bg]the magician becomes invulnerable for 6 seconds' end,
['archer'] = function() return '[light_bg]the arrow ricochets off walls 3 times' end, ['archer'] = function() return '[light_bg]the arrow ricochets off walls 3 times' end,
['scout'] = function() return '[light_bg]+25% damage per chain and +3 chains' end, ['scout'] = function() return '[light_bg]+25% damage per chain and +3 chains' end,
['cleric'] = function() return '[light_bg]heals all units' end, ['cleric'] = function() return '[light_bg]heals all units' end,
['outlaw'] = function() return "[light_bg]+50% outlaw attack speed and his knives seek enemies" end, ['outlaw'] = function() return "[light_bg]+50% outlaw attack speed and his knives seek enemies" end,
['blade'] = function() return '[light_bg]deal additional ' .. get_character_stat('blade', 3, 'dmg')/2 .. ' damage per enemy hit' end, ['blade'] = function() return '[light_bg]deal additional ' .. math.round(get_character_stat('blade', 3, 'dmg')/2, 2) .. ' damage per enemy hit' end,
['elementor'] = function() return '[light_bg]slows enemies by 60% for 6 seconds on hit' end, ['elementor'] = function() return '[light_bg]slows enemies by 60% for 6 seconds on hit' end,
['saboteur'] = function() return '[light_bg]the explosion has 50% chance to crit, increasing in size and dealing 2x damage' end, ['saboteur'] = function() return '[light_bg]the explosion has 50% chance to crit, increasing in size and dealing 2x damage' end,
['stormweaver'] = function() return "[light_bg]chain lightning's trigger area of effect and number of units hit is doubled" end, ['stormweaver'] = function() return "[light_bg]chain lightning's trigger area of effect and number of units hit is doubled" end,
@ -725,12 +742,12 @@ function init()
['priest'] = function() return '[light_bg]picks 3 units at random and grants them a buff that prevents death once' end, ['priest'] = function() return '[light_bg]picks 3 units at random and grants them a buff that prevents death once' end,
['infestor'] = function() return '[light_bg]triples the number of critters released' end, ['infestor'] = function() return '[light_bg]triples the number of critters released' end,
['flagellant'] = function() return '[light_bg]deals ' .. 2*get_character_stat('flagellant', 3, 'dmg') .. ' damage to all allies and grants +12% damage to all allies per cast' end, ['flagellant'] = function() return '[light_bg]deals ' .. 2*get_character_stat('flagellant', 3, 'dmg') .. ' damage to all allies and grants +12% damage to all allies per cast' end,
['arcanist'] = function() return '[light_bg]100% increased attack speed for the orb and 2 projectiles are released per cast' end, ['arcanist'] = function() return '[light_bg]+100% attack speed for the orb and 2 projectiles are released per cast' end,
['illusionist'] = function() return '[light_bg]doubles the number of copies created and they release 12 projectiles on death' end, ['illusionist'] = function() return '[light_bg]doubles the number of copies created and they release 12 projectiles on death that pierce and ricochet once' end,
['witch'] = function() return '[light_bg]the area periodically releases projectiles, each dealing ' .. get_character_stat('witch', 3, 'dmg') .. ' damage and chaining once' end, ['witch'] = function() return '[light_bg]the area periodically releases projectiles, each dealing ' .. get_character_stat('witch', 3, 'dmg') .. ' damage and chaining once' end,
['silencer'] = function() return '[light_bg]the curse also deals ' .. get_character_stat('silencer', 3, 'dmg') .. ' damage per second' end, ['silencer'] = function() return '[light_bg]the curse also deals ' .. get_character_stat('silencer', 3, 'dmg') .. ' damage per second' end,
['vulcanist'] = function() return '[light_bg]the volcano spawn also deals ' .. get_character_stat('vulcanist', 3, 'dmg') .. 'AoE damage and doubles the number of explosions' end, ['vulcanist'] = function() return '[light_bg]the number and speed of explosions is doubled' end,
['warden'] = function() return '[light_bg]creates the force field around 2 additional random units' end, ['warden'] = function() return '[light_bg]creates the force field around 2 units, and they are always the head and tail of the snake' end,
['psychic'] = function() return '[light_bg]the attack can happen from any distance and deals double damage' end, ['psychic'] = function() return '[light_bg]the attack can happen from any distance and deals double damage' end,
} }
@ -738,6 +755,7 @@ function init()
['vagrant'] = function(lvl) return get_character_stat_string('vagrant', lvl) end, ['vagrant'] = function(lvl) return get_character_stat_string('vagrant', lvl) end,
['swordsman'] = function(lvl) return get_character_stat_string('swordsman', lvl) end, ['swordsman'] = function(lvl) return get_character_stat_string('swordsman', lvl) end,
['wizard'] = function(lvl) return get_character_stat_string('wizard', lvl) end, ['wizard'] = function(lvl) return get_character_stat_string('wizard', lvl) end,
['magician'] = function(lvl) return get_character_stat_string('magician', lvl) end,
['archer'] = function(lvl) return get_character_stat_string('archer', lvl) end, ['archer'] = function(lvl) return get_character_stat_string('archer', lvl) end,
['scout'] = function(lvl) return get_character_stat_string('scout', lvl) end, ['scout'] = function(lvl) return get_character_stat_string('scout', lvl) end,
['cleric'] = function(lvl) return get_character_stat_string('cleric', lvl) end, ['cleric'] = function(lvl) return get_character_stat_string('cleric', lvl) end,
@ -797,7 +815,7 @@ function init()
['psyker'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.5, mvspd = 1}, ['psyker'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.5, mvspd = 1},
['curser'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 1}, ['curser'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 1},
['forcer'] = {hp = 1.25, dmg = 1.1, aspd = 0.9, area_dmg = 0.75, area_size = 0.75, def = 1.2, mvspd = 1}, ['forcer'] = {hp = 1.25, dmg = 1.1, aspd = 0.9, area_dmg = 0.75, area_size = 0.75, def = 1.2, mvspd = 1},
['swarmer'] = {hp = 1.2, dmg = 1, aspd = 1.25, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 0.5}, ['swarmer'] = {hp = 1.2, dmg = 1, aspd = 1.25, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 0.75},
['voider'] = {hp = 0.75, dmg = 1.3, aspd = 1, area_dmg = 0.8, area_size = 0.75, def = 0.6, mvspd = 0.8}, ['voider'] = {hp = 0.75, dmg = 1.3, aspd = 1, area_dmg = 0.8, area_size = 0.75, def = 0.6, mvspd = 0.8},
['sorcerer'] = {hp = 0.8, dmg = 1.3, aspd = 1, area_dmg = 1.2, area_size = 1, def = 0.8, mvspd = 1}, ['sorcerer'] = {hp = 0.8, dmg = 1.3, aspd = 1, area_dmg = 1.2, area_size = 1, def = 0.8, mvspd = 1},
['seeker'] = {hp = 0.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.3}, ['seeker'] = {hp = 0.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.3},
@ -836,15 +854,15 @@ function init()
['swarmer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+1[' .. ylb2(lvl) .. ']/+3 [fg]hits to critters' end, ['swarmer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+1[' .. ylb2(lvl) .. ']/+3 [fg]hits to critters' end,
['voider'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+15%[' .. ylb2(lvl) .. ']/+25% [fg]damage over time to allied voiders' end, ['voider'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+15%[' .. ylb2(lvl) .. ']/+25% [fg]damage over time to allied voiders' end,
['sorcerer'] = function(lvl) ['sorcerer'] = function(lvl)
return '[' .. ybl1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4[' .. ylb3(lvl) .. '/6 [fg]- sorcerers repeat their attacks once every [' .. ylb1(lvl) .. ']4/[' .. ylb2(lvl) .. ']3/[' .. ylb3(lvl) .. ']2[fg] attacks' return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4[' .. ylb3(lvl) .. ']/6 [fg]- sorcerers repeat their attacks once every [' .. ylb1(lvl) .. ']4/[' .. ylb2(lvl) .. ']3/[' .. ylb3(lvl) .. ']2[fg] attacks'
end, end,
} }
tier_to_characters = { tier_to_characters = {
[1] = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'}, [1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist'},
[2] = {'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'launcher', 'jester', 'carver'}, [2] = {'wizard', 'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'launcher', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw'},
[3] = {'outlaw', 'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'corruptor', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant'}, [3] = {'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'host', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant', 'illusionist'},
[4] = {'priest', 'highlander', 'psykino', 'lich', 'host', 'fairy', 'blade', 'plague_doctor', 'cannoneer'}, [4] = {'priest', 'highlander', 'psykino', 'fairy', 'blade', 'plague_doctor', 'cannoneer', 'vulcanist', 'warden', 'corruptor'},
} }
non_attacking_characters = {'cleric', 'stormweaver', 'squire', 'chronomancer', 'sage', 'psykeeper', 'bane', 'carver', 'fairy', 'priest', 'flagellant'} non_attacking_characters = {'cleric', 'stormweaver', 'squire', 'chronomancer', 'sage', 'psykeeper', 'bane', 'carver', 'fairy', 'priest', 'flagellant'}
@ -853,14 +871,16 @@ function init()
character_tiers = { character_tiers = {
['vagrant'] = 1, ['vagrant'] = 1,
['swordsman'] = 1, ['swordsman'] = 1,
['wizard'] = 1, ['magician'] = 1,
['archer'] = 1, ['archer'] = 1,
['scout'] = 1, ['scout'] = 1,
['cleric'] = 1, ['cleric'] = 1,
['outlaw'] = 3, ['arcanist'] = 1,
['outlaw'] = 2,
['blade'] = 4, ['blade'] = 4,
['elementor'] = 3, ['elementor'] = 3,
['saboteur'] = 2, ['saboteur'] = 2,
['wizard'] = 2,
['stormweaver'] = 3, ['stormweaver'] = 3,
['sage'] = 2, ['sage'] = 2,
['squire'] = 2, ['squire'] = 2,
@ -874,15 +894,15 @@ function init()
['plague_doctor'] = 4, ['plague_doctor'] = 4,
['barbarian'] = 2, ['barbarian'] = 2,
['juggernaut'] = 3, ['juggernaut'] = 3,
['lich'] = 4, -- ['lich'] = 4,
['cryomancer'] = 2, ['cryomancer'] = 2,
['pyromancer'] = 3, ['pyromancer'] = 3,
['corruptor'] = 3, ['corruptor'] = 4,
['beastmaster'] = 2, ['beastmaster'] = 2,
['launcher'] = 2, ['launcher'] = 2,
['jester'] = 2, ['jester'] = 2,
['assassin'] = 3, ['assassin'] = 3,
['host'] = 4, ['host'] = 3,
['carver'] = 2, ['carver'] = 2,
['bane'] = 3, ['bane'] = 3,
['psykino'] = 4, ['psykino'] = 4,
@ -892,6 +912,12 @@ function init()
['priest'] = 4, ['priest'] = 4,
['infestor'] = 3, ['infestor'] = 3,
['flagellant'] = 3, ['flagellant'] = 3,
['psychic'] = 2,
['witch'] = 2,
['silencer'] = 2,
['illusionist'] = 3,
['warden'] = 4,
['vulcanist'] = 4,
} }
get_number_of_units_per_class = function(units) get_number_of_units_per_class = function(units)
@ -976,19 +1002,20 @@ function init()
end end
class_set_numbers = { class_set_numbers = {
['ranger'] = function(units) return 3, 6, get_number_of_units_per_class(units).ranger end, ['ranger'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).ranger end,
['warrior'] = function(units) return 3, 6, get_number_of_units_per_class(units).warrior end, ['warrior'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).warrior end,
['mage'] = function(units) return 3, 6, get_number_of_units_per_class(units).mage end, ['mage'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).mage end,
['nuker'] = function(units) return 3, 6, get_number_of_units_per_class(units).nuker end, ['nuker'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).nuker end,
['rogue'] = function(units) return 3, 6, get_number_of_units_per_class(units).rogue end, ['rogue'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).rogue end,
['healer'] = function(units) return 2, 4, get_number_of_units_per_class(units).healer end, ['healer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).healer end,
['conjurer'] = function(units) return 2, 4, get_number_of_units_per_class(units).conjurer end, ['conjurer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).conjurer end,
['enchanter'] = function(units) return 2, 4, get_number_of_units_per_class(units).enchanter end, ['enchanter'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).enchanter end,
['psyker'] = function(units) return 2, 4, get_number_of_units_per_class(units).psyker end, ['psyker'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).psyker end,
['curser'] = function(units) return 2, 4, get_number_of_units_per_class(units).curser end, ['curser'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).curser end,
['forcer'] = function(units) return 2, 4, get_number_of_units_per_class(units).forcer end, ['forcer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).forcer end,
['swarmer'] = function(units) return 2, 4, get_number_of_units_per_class(units).swarmer end, ['swarmer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).swarmer end,
['voider'] = function(units) return 2, 4, get_number_of_units_per_class(units).voider end, ['voider'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).voider end,
['sorcerer'] = function(units) return 2, 4, 6, get_number_of_units_per_class(units).sorcerer end,
} }
passive_names = { passive_names = {
@ -1288,17 +1315,17 @@ function init()
if run.level and run.level > 0 then if run.level and run.level > 0 then
main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5} main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5}
end end
main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5} -- main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5}
--[[
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')
main:go_to('buy_screen', run.level or 0, run.units or {}, passives) main:go_to('buy_screen', run.level or 0, run.units or {}, passives)
]]--
--[[
main:add(Arena'arena') main:add(Arena'arena')
main:go_to('arena', 16, { main:go_to('arena', 14, {
{character = 'witch', level = 3}, {character = 'magician', level = 3},
}, passives) }, passives)
]]--
trigger:every(2, function() trigger:every(2, function()
if debugging_memory then if debugging_memory then

View File

@ -34,10 +34,26 @@ function Player:init(args)
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies) local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then if closest_enemy then
self:shoot(self:angle_to_object(closest_enemy), {chain = (self.level == 3 and 3 or 0)}) self:shoot(self:angle_to_object(closest_enemy), {chain = (self.level == 3 and 2 or 0)})
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'magician' then
self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local enemy = self:get_random_object_in_shape(self.attack_sensor, main.current.enemies)
if enemy then
self:attack(32, {x = enemy.x, y = enemy.y})
end
end, nil, nil, 'attack')
if self.level == 3 then
self.t:every(12, function()
self.magician_invulnerable = true
self.t:after(6, function() self.magician_invulnerable = false end, 'magician_invulnerable')
end)
end
elseif self.character == 'archer' then elseif self.character == 'archer' then
self.attack_sensor = Circle(self.x, self.y, 160) self.attack_sensor = Circle(self.x, self.y, 160)
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
@ -57,11 +73,10 @@ function Player:init(args)
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'cleric' then elseif self.character == 'cleric' then
self.last_heal_time = love.timer.getTime() self.t:every(6, function()
self.t:every(2, function()
local all_units = self:get_all_units() local all_units = self:get_all_units()
local unit_index = table.contains(all_units, function(v) return v.hp <= 0.5*v.max_hp end) local unit_index = table.contains(all_units, function(v) return v.hp <= 0.5*v.max_hp end)
if unit_index and love.timer.getTime() - self.last_heal_time > 6 then if unit_index then
local unit = all_units[unit_index] local unit = all_units[unit_index]
self.last_heal_time = love.timer.getTime() self.last_heal_time = love.timer.getTime()
if self.level == 3 then if self.level == 3 then
@ -74,20 +89,40 @@ function Player:init(args)
end, nil, nil, 'heal') end, nil, nil, 'heal')
elseif self.character == 'arcanist' then elseif self.character == 'arcanist' then
self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, 128) self.attack_sensor = Circle(self.x, self.y, 128)
self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies) local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then if closest_enemy then
self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000, v = 40}) self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000, v = 40})
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.25, function()
self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000, v = 40})
end)
end
end
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'illusionist' then elseif self.character == 'illusionist' then
self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, 96) self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies) local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then if closest_enemy then
self:shoot(self:angle_to_object(closest_enemy)) self:shoot(self:angle_to_object(closest_enemy))
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.25, function()
self:shoot(self:angle_to_object(closest_enemy))
end)
end
end
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
self.t:every(8, function() self.t:every(8, function()
@ -96,6 +131,18 @@ function Player:init(args)
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5} illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
Illusion{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1, crit = (self.level == 3) and random:bool(50)} Illusion{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1, crit = (self.level == 3) and random:bool(50)}
end} end}
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.25, function()
SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y)
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
Illusion{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1, crit = (self.level == 3) and random:bool(50)}
end}
end)
end
end
end, self.level == 3 and 2 or 1) end, self.level == 3 and 2 or 1)
end) end)
@ -123,6 +170,38 @@ function Player:init(args)
end end
end, nil, nil, 'attack') end, nil, nil, 'attack')
elseif self.character == 'psychic' then
self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, self.level == 3 and 512 or 64)
self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local strike = function()
local enemy = self:get_random_object_in_shape(self.attack_sensor, main.current.enemies)
if enemy then
if self.level == 3 then
self:attack(32, {x = enemy.x, y = enemy.y})
self.t:after(0.5, function()
local enemy = self:get_random_object_in_shape(self.attack_sensor, main.current.enemies)
if enemy then
self:attack(32, {x = enemy.x, y = enemy.y})
end
end)
else
self:attack(32, {x = enemy.x, y = enemy.y})
end
end
end
strike()
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.1, function()
strike()
end)
end
end
end, nil, nil, 'attack')
elseif self.character == 'saboteur' then elseif self.character == 'saboteur' then
self.t:every(8, function() self.t:every(8, function()
self.t:every(0.25, function() self.t:every(0.25, function()
@ -159,6 +238,38 @@ function Player:init(args)
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'vulcanist' then
self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, 128)
self.t:every(12, function()
local volcano = function()
local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
local x, y = 0, 0
if enemies and #enemies > 0 then
for _, enemy in ipairs(enemies) do
x = x + enemy.x
y = y + enemy.y
end
x = x/#enemies
y = y/#enemies
end
if x == 0 and y == 0 then x, y = gw/2, gh/2 end
x, y = x + self.x, y + self.y
x, y = x/2, y/2
Volcano{group = main.current.main, x = x, y = y, color = self.color, parent = self, rs = 24, level = self.level}
end
volcano()
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.5, function()
volcano()
end)
end
end
end, nil, nil, 'attack')
elseif self.character == 'dual_gunner' then elseif self.character == 'dual_gunner' then
self.dg_counter = 0 self.dg_counter = 0
self.attack_sensor = Circle(self.x, self.y, 96) self.attack_sensor = Circle(self.x, self.y, 96)
@ -229,8 +340,18 @@ function Player:init(args)
end end
elseif self.character == 'witch' then elseif self.character == 'witch' then
self.t:every(6, function() self.sorcerer_count = 0
self:dot_attack(24, {duration = random:float(12, 16), homing = true}) self.t:every(4, function()
self:dot_attack(42, {duration = random:float(12, 16)})
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.25, function()
self:dot_attack(42, {duration = random:float(12, 16)})
end)
end
end
end, nil, nil, 'attack') end, nil, nil, 'attack')
elseif self.character == 'barbarian' then elseif self.character == 'barbarian' then
@ -281,7 +402,8 @@ function Player:init(args)
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'launcher' then elseif self.character == 'launcher' then
self.t:every({6, 10}, function() self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5} buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
local enemies = main.current.main:get_objects_by_classes(main.current.enemies) local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
for _, enemy in ipairs(enemies) do for _, enemy in ipairs(enemies) do
@ -296,9 +418,10 @@ function Player:init(args)
end, nil, nil, 'attack') end, nil, nil, 'attack')
elseif self.character == 'jester' then elseif self.character == 'jester' then
self.t:every({6, 10}, function() self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5} buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), self.level == 3 and 8 or 4) local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), 6)
for _, enemy in ipairs(enemies) do for _, enemy in ipairs(enemies) do
if self:distance_to_object(enemy) < 128 then if self:distance_to_object(enemy) < 128 then
enemy:curse('jester', 6*(self.hex_duration_m or 1), self.level == 3, self) enemy:curse('jester', 6*(self.hex_duration_m or 1), self.level == 3, self)
@ -308,6 +431,40 @@ function Player:init(args)
end end
end, nil, nil, 'attack') end, nil, nil, 'attack')
elseif self.character == 'silencer' then
self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
local curse = function()
buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), 6)
for _, enemy in ipairs(enemies) do
if self:distance_to_object(enemy) < 128 then
enemy:curse('silencer', 6*(self.hex_duration_m or 1), self.level == 3, self)
if self.level == 3 then
local curse_m = 1
if main.current.curser_level == 2 then curse_m = 1.5
elseif main.current.curser_level == 1 then curse_m = 1.25
else curse_m = 1 end
enemy:apply_dot(self.dmg*(self.dot_dmg_m or 1)*(main.current.chronomancer_dot or 1), 6*(self.hex_duration_m or 1)*(curse_m or 1))
end
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = blue2[0], duration = 0.1}
LightningLine{group = main.current.effects, src = self, dst = enemy, color = blue2[0]}
end
end
end
curse()
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.5, function()
curse()
end)
end
end
end, nil, nil, 'attack')
elseif self.character == 'assassin' then elseif self.character == 'assassin' then
self.attack_sensor = Circle(self.x, self.y, 64) self.attack_sensor = Circle(self.x, self.y, 64)
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
@ -338,9 +495,10 @@ function Player:init(args)
end, nil, nil, 'spawn') end, nil, nil, 'spawn')
elseif self.character == 'bane' then elseif self.character == 'bane' then
self.t:every({6, 10}, function() self.attack_sensor = Circle(self.x, self.y, 96)
self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5} buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), 5) local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), 6)
for _, enemy in ipairs(enemies) do for _, enemy in ipairs(enemies) do
if self:distance_to_object(enemy) < 128 then if self:distance_to_object(enemy) < 128 then
enemy:curse('bane', 6*(self.hex_duration_m or 1), self.level == 3, self) enemy:curse('bane', 6*(self.hex_duration_m or 1), self.level == 3, self)
@ -399,24 +557,66 @@ function Player:init(args)
local units = self:get_all_units() local units = self:get_all_units()
local unit_1 = random:table_remove(units) local unit_1 = random:table_remove(units)
local unit_2 = random:table_remove(units) local unit_2 = random:table_remove(units)
unit_1:heal(0.2*unit_1.max_hp*(self.heal_effect_m or 1)) if unit_1 then
unit_1.fairy_aspd_m = 3 unit_1:heal(0.2*unit_1.max_hp*(self.heal_effect_m or 1))
unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1 end) unit_1.fairy_aspd_m = 3
unit_2:heal(0.2*unit_2.max_hp*(self.heal_effect_m or 1)) unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1 end)
unit_2.fairy_aspd_m = 3 end
unit_2.t:after(5.98, function() unit_2.fairy_aspd_m = 1 end) if unit_2 then
unit_2:heal(0.2*unit_2.max_hp*(self.heal_effect_m or 1))
unit_2.fairy_aspd_m = 3
unit_2.t:after(5.98, function() unit_2.fairy_aspd_m = 1 end)
end
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
else else
local unit = random:table(self:get_all_units()) local unit = random:table(self:get_all_units())
unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1)) if unit then
unit.fairy_aspd_m = 2 unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1))
unit.t:after(5.98, function() unit.fairy_aspd_m = 1 end) unit.fairy_aspd_m = 2
unit.t:after(5.98, function() unit.fairy_aspd_m = 1 end)
end
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end end
end, nil, nil, 'heal') end, nil, nil, 'heal')
elseif self.character == 'warden' then
self.sorcerer_count = 0
self.t:every(12, function()
local ward = function()
if self.level == 3 then
local units = self:get_all_units()
local unit_1 = random:table_remove(units)
local unit_2 = random:table_remove(units)
if unit_1 then
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ForceField{group = main.current.main, x = unit_1.x, y = unit_1.y, parent = unit_1}
end
if unit_2 then
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ForceField{group = main.current.main, x = unit_2.x, y = unit_2.y, parent = unit_2}
end
else
local unit = random:table(self:get_all_units())
if unit then
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ForceField{group = main.current.main, x = unit.x, y = unit.y, parent = unit}
end
end
end
ward()
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self.sorcerer_count = 0
self.t:after(0.5, function()
ward()
end)
end
end
end, nil, nil, 'buff')
elseif self.character == 'priest' then elseif self.character == 'priest' then
if self.level == 3 then if self.level == 3 then
self.t:after(0.01, function() self.t:after(0.01, function()
@ -437,9 +637,10 @@ function Player:init(args)
end, nil, nil, 'heal') end, nil, nil, 'heal')
elseif self.character == 'infestor' then elseif self.character == 'infestor' then
self.t:every({6, 10}, function() self.attack_sensor = Circle(self.x, self.y, 128)
self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5} buff1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
local enemies = main.current.main:get_objects_by_classes(main.current.enemies) local enemies = table.first(table.shuffle(main.current.main:get_objects_by_classes(main.current.enemies)), 8)
for _, enemy in ipairs(enemies) do for _, enemy in ipairs(enemies) do
if self:distance_to_object(enemy) < 128 then if self:distance_to_object(enemy) < 128 then
enemy:curse('infestor', 6*(self.hex_duration_m or 1), (self.level == 3 and 6 or 2), self.dmg, self) enemy:curse('infestor', 6*(self.hex_duration_m or 1), (self.level == 3 and 6 or 2), self.dmg, self)
@ -873,7 +1074,11 @@ end
function Player:draw() function Player:draw()
graphics.push(self.x, self.y, self.r, self.hfx.hit.x*self.hfx.shoot.x, self.hfx.hit.x*self.hfx.shoot.x) graphics.push(self.x, self.y, self.r, self.hfx.hit.x*self.hfx.shoot.x, self.hfx.hit.x*self.hfx.shoot.x)
if self.visual_shape == 'rectangle' then if self.visual_shape == 'rectangle' then
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, (self.hfx.hit.f or self.hfx.shoot.f) and fg[0] or self.color) if self.magician_invulnerable then
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, blue_transparent)
else
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, (self.hfx.hit.f or self.hfx.shoot.f) and fg[0] or self.color)
end
end end
graphics.pop() graphics.pop()
end end
@ -939,6 +1144,7 @@ end
function Player:hit(damage) function Player:hit(damage)
if self.dead then return end if self.dead then return end
if self.magician_invulnerable then return end
self.hfx:use('hit', 0.25, 200, 10) self.hfx:use('hit', 0.25, 200, 10)
self:show_hp() self:show_hp()
@ -1182,14 +1388,14 @@ function Player:shoot(r, mods)
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
end end
if self.character == 'vagrant' then if self.character == 'vagrant' or self.character == 'illusionist' then
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2} shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2}
elseif self.character == 'dual_gunner' then elseif self.character == 'dual_gunner' then
dual_gunner1:play{pitch = random:float(0.95, 1.05), volume = 0.3} dual_gunner1:play{pitch = random:float(0.95, 1.05), volume = 0.3}
dual_gunner2:play{pitch = random:float(0.95, 1.05), volume = 0.3} dual_gunner2:play{pitch = random:float(0.95, 1.05), volume = 0.3}
elseif self.character == 'archer' or self.character == 'hunter' or self.character == 'barrager' or self.character == 'corruptor' then elseif self.character == 'archer' or self.character == 'hunter' or self.character == 'barrager' or self.character == 'corruptor' then
archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35} archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' or self.character == 'illusionist' then elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' then
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.15} wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
elseif self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'spellblade' or self.character == 'jester' or self.character == 'assassin' or self.character == 'beastmaster' then elseif self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'spellblade' or self.character == 'jester' or self.character == 'assassin' or self.character == 'beastmaster' then
_G[random:table{'scout1', 'scout2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35} _G[random:table{'scout1', 'scout2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35}
@ -1226,6 +1432,8 @@ function Player:attack(area, mods)
_G[random:table{'swordsman1', 'swordsman2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.75} _G[random:table{'swordsman1', 'swordsman2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.75}
elseif self.character == 'elementor' then elseif self.character == 'elementor' then
elementor1:play{pitch = random:float(0.9, 1.1), volume = 0.5} elementor1:play{pitch = random:float(0.9, 1.1), volume = 0.5}
elseif self.character == 'psychic' then
psychic1:play{pitch = random:float(0.9, 1.1), volume = 0.4}
elseif self.character == 'launcher' then elseif self.character == 'launcher' then
buff1:play{pitch == random:float(0.9, 1.1), volume = 0.5} buff1:play{pitch == random:float(0.9, 1.1), volume = 0.5}
end end
@ -1500,7 +1708,7 @@ function Projectile:on_collision_enter(other, contact)
self.ricochet = self.ricochet - 1 self.ricochet = self.ricochet - 1
end end
_G[random:table{'arrow_hit_wall1', 'arrow_hit_wall2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.2} _G[random:table{'arrow_hit_wall1', 'arrow_hit_wall2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.2}
elseif self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'spellblade' or self.character == 'jester' or self.character == 'beastmaster' then elseif self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'spellblade' or self.character == 'jester' or self.character == 'beastmaster' or self.character == 'witch' then
self:die(x, y, r, 0) self:die(x, y, r, 0)
knife_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2} knife_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2}
local r = Unit.bounce(self, nx, ny) local r = Unit.bounce(self, nx, ny)
@ -1519,7 +1727,7 @@ function Projectile:on_collision_enter(other, contact)
self.r = r self.r = r
self.ricochet = self.ricochet - 1 self.ricochet = self.ricochet - 1
end end
elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' or self.character == 'arcanist_projectile' or self.character == 'illusionist' or self.character == 'witch' then elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' or self.character == 'arcanist_projectile' or self.character == 'witch' then
self:die(x, y, r, random:int(2, 3)) self:die(x, y, r, random:int(2, 3))
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
elseif self.character == 'cannoneer' then elseif self.character == 'cannoneer' then
@ -1574,12 +1782,12 @@ function Projectile:on_trigger_enter(other, contact)
end end
if self.character == 'archer' or self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'hunter' or self.character == 'spellblade' or self.character == 'engineer' or if self.character == 'archer' or self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'hunter' or self.character == 'spellblade' or self.character == 'engineer' or
self.character == 'jester' or self.character == 'assassin' or self.character == 'barrager' or self.character == 'beastmaster' then self.character == 'jester' or self.character == 'assassin' or self.character == 'barrager' or self.character == 'beastmaster' or self.character == 'witch' then
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
if self.character == 'spellblade' then if self.character == 'spellblade' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
end end
elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' or self.character == 'illusionist' or self.character == 'illusionist_death' or self.character == 'witch' then elseif self.character == 'wizard' or self.character == 'lich' or self.character == 'arcanist' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
elseif self.character == 'arcanist_projectile' then elseif self.character == 'arcanist_projectile' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
@ -1702,7 +1910,7 @@ function Area:init(args)
HitCircle{group = main.current.effects, x = enemy.x, y = enemy.y, rs = 6, color = fg[0], duration = 0.1} HitCircle{group = main.current.effects, x = enemy.x, y = enemy.y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 1 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = self.color} end for i = 1, 1 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = self.color} end
for i = 1, 1 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = enemy.color} end for i = 1, 1 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = enemy.color} end
if self.character == 'wizard' or self.character == 'elementor' then if self.character == 'wizard' or self.character == 'magician' or self.character == 'elementor' or self.character == 'psychic' then
magic_hit1:play{pitch = random:float(0.95, 1.05), volume = 0.5} magic_hit1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
elseif self.character == 'swordsman' or self.character == 'barbarian' or self.character == 'juggernaut' or self.character == 'highlander' then elseif self.character == 'swordsman' or self.character == 'barbarian' or self.character == 'juggernaut' or self.character == 'highlander' then
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
@ -1889,11 +2097,12 @@ function DotArea:init(args)
self.t:every(1, function() self.t:every(1, function()
local enemies = main.current.main:get_objects_in_shape(self.closest_sensor, main.current.enemies) local enemies = main.current.main:get_objects_in_shape(self.closest_sensor, main.current.enemies)
if enemies and #enemies > 0 then if enemies and #enemies > 0 then
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.05}
local r = self:angle_to_object(enemies[1]) local r = self:angle_to_object(enemies[1])
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6} HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6}
local t = {group = main.current.main, x = self.x, y = self.y, v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, character = 'witch', parent = self.parent, level = self.parent.level} local t = {group = main.current.main, x = self.x, y = self.y, v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, character = 'witch', parent = self.parent, level = self.parent.level}
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
_G[random:table{'scout1', 'scout2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35}
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
end end
end) end)
end end
@ -2103,6 +2312,122 @@ end
ForceField = Object:extend()
ForceField:implement(GameObject)
ForceField:implement(Physics)
function ForceField:init(args)
self:init_game_object(args)
self:set_as_circle(12, 'static', 'force_field')
self.hfx:add('hit', 1)
self.color = fg[0]
self.color_transparent = Color(yellow[0].r, yellow[0].g, yellow[0].b, 0.08)
self.rs = 0
self.hidden = false
self.t:tween(0.05, self, {rs = args.rs}, math.cubic_in_out, function() self.spring:pull(0.15) end)
self.t:after(0.2, function() self.color = yellow[0] end)
self.t:after(6, function()
self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function() self.dead = true end)
dot1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end)
end
function ForceField:update(dt)
self:update_game_object(dt)
if not self.parent then self.dead = true; return end
if self.parent and self.parent.dead then self.dead = true; return end
self:set_position(self.parent.x, self.parent.y)
end
function ForceField:draw()
if self.hidden then return end
graphics.push(self.x, self.y, 0, self.spring.x*self.hfx.hit.x, self.spring.x*self.hfx.hit.x)
graphics.circle(self.x, self.y, self.shape.rs, self.hfx.hit.f and fg[0] or self.color, 2)
graphics.circle(self.x, self.y, self.shape.rs, self.hfx.hit.f and fg_transparent[0] or self.color_transparent)
graphics.pop()
end
function ForceField:on_collision_enter(other, contact)
local x, y = contact:getPositions()
if table.any(main.current.enemies, function(v) return other:is(v) end) then
other:push(random:float(15, 20)*(self.parent.knockback_m or 1), self.parent:angle_to_object(other))
other:hit(0)
HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = other.color} end
self.hfx:use('hit', 0.2)
dot1:play{pitch = random:float(0.95, 1.05), volume = 0.3}
end
end
Volcano = Object:extend()
Volcano:implement(GameObject)
Volcano:implement(Physics)
function Volcano:init(args)
self:init_game_object(args)
self:set_as_rectangle(9, 9, 'static', 'player')
self:set_restitution(0.5)
self.hfx:add('hit', 1)
self.color = orange[0]
self.attack_sensor = Circle(self.x, self.y, 256)
self.vr = 0
self.dvr = random:float(-math.pi/4, math.pi/4)
self.color = fg[0]
self.color_transparent = Color(args.color.r, args.color.g, args.color.b, 0.08)
self.rs = 0
self.hidden = false
self.t:tween(0.05, self, {rs = args.rs}, math.cubic_in_out, function() self.spring:pull(0.15) end)
self.t:after(0.2, function() self.color = args.color end)
camera:shake(6, 1)
earth1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
fire1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.t:every(self.level == 3 and 0.5 or 1, function()
camera:shake(4, 0.5)
_G[random:table{'earth1', 'earth2', 'earth3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.25}
_G[random:table{'fire1', 'fire2', 'fire3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.25}
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*72, r = random:float(0, 2*math.pi), color = self.color, dmg = (self.parent.area_dmg_m or 1)*self.parent.dmg,
character = self.parent.character, level = self.parent.level, parent = self, void_rift = self.parent.void_rift, echo_barrage = self.parent.echo_barrage}
end, self.level == 3 and 8 or 4)
self.t:after(4, function()
self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function() self.dead = true end)
end)
end
function Volcano:update(dt)
self:update_game_object(dt)
self.vr = self.vr + self.dvr*dt
end
function Volcano:draw()
if self.hidden then return end
graphics.push(self.x, self.y, math.pi/4, self.spring.x, self.spring.x)
graphics.rectangle(self.x, self.y, 1.5*self.shape.w, 4, 2, 2, self.hfx.hit.f and fg[0] or self.color)
graphics.rectangle(self.x, self.y, 4, 1.5*self.shape.h, 2, 2, self.hfx.hit.f and fg[0] or self.color)
graphics.pop()
graphics.push(self.x, self.y, self.r + self.vr, self.spring.x, self.spring.x)
-- graphics.circle(self.x, self.y, self.shape.rs + random:float(-1, 1), self.color, 2)
graphics.circle(self.x, self.y, 24, self.color_transparent)
local lw = 2
for i = 1, 4 do graphics.arc('open', self.x, self.y, 24, (i-1)*math.pi/2 + math.pi/4 - math.pi/8, (i-1)*math.pi/2 + math.pi/4 + math.pi/8, self.color, lw) end
graphics.pop()
end
Turret = Object:extend() Turret = Object:extend()
Turret:implement(GameObject) Turret:implement(GameObject)
@ -2375,12 +2700,12 @@ function Illusion:update(dt)
self:seek_point(gw/2, gh/2) self:seek_point(gw/2, gh/2)
self:wander(50, 200, 50) self:wander(50, 200, 50)
self:rotate_towards_velocity(1) self:rotate_towards_velocity(1)
self:steering_separate(32, {Illusion, Seeker, Player}) self:steering_separate(32, {Illusion, Seeker})
else else
self:seek_point(self.target.x, self.target.y) self:seek_point(self.target.x, self.target.y)
self:wander(50, 200, 50) self:wander(50, 200, 50)
self:rotate_towards_velocity(1) self:rotate_towards_velocity(1)
self:steering_separate(32, {Illusion, Seeker, Player}) self:steering_separate(32, {Illusion, Seeker})
end end
self.r = self:get_angle() self.r = self:get_angle()

View File

@ -497,6 +497,7 @@ global_text_tags = {
green = TextTag{draw = function(c, i, text) graphics.set_color(green[0]) end}, green = TextTag{draw = function(c, i, text) graphics.set_color(green[0]) end},
purple = TextTag{draw = function(c, i, text) graphics.set_color(purple[0]) end}, purple = TextTag{draw = function(c, i, text) graphics.set_color(purple[0]) end},
blue = TextTag{draw = function(c, i, text) graphics.set_color(blue[0]) end}, blue = TextTag{draw = function(c, i, text) graphics.set_color(blue[0]) end},
blue2 = TextTag{draw = function(c, i, text) graphics.set_color(blue2[0]) end},
bg = TextTag{draw = function(c, i, text) graphics.set_color(bg[0]) end}, bg = TextTag{draw = function(c, i, text) graphics.set_color(bg[0]) end},
bg3 = TextTag{draw = function(c, i, text) graphics.set_color(bg[3]) end}, bg3 = TextTag{draw = function(c, i, text) graphics.set_color(bg[3]) end},
bg10 = TextTag{draw = function(c, i, text) graphics.set_color(bg[10]) end}, bg10 = TextTag{draw = function(c, i, text) graphics.set_color(bg[10]) end},
@ -508,6 +509,8 @@ global_text_tags = {
green5 = TextTag{draw = function(c, i, text) graphics.set_color(green[5]) end}, green5 = TextTag{draw = function(c, i, text) graphics.set_color(green[5]) end},
blue5 = TextTag{draw = function(c, i, text) graphics.set_color(blue[5]) end}, blue5 = TextTag{draw = function(c, i, text) graphics.set_color(blue[5]) end},
bluem5 = TextTag{draw = function(c, i, text) graphics.set_color(blue[-5]) end}, bluem5 = TextTag{draw = function(c, i, text) graphics.set_color(blue[-5]) end},
blue25 = TextTag{draw = function(c, i, text) graphics.set_color(blue2[5]) end},
blue2m5 = TextTag{draw = function(c, i, text) graphics.set_color(blue2[-5]) end},
redm5 = TextTag{draw = function(c, i, text) graphics.set_color(red[-5]) end}, redm5 = TextTag{draw = function(c, i, text) graphics.set_color(red[-5]) end},
orangem5 = TextTag{draw = function(c, i, text) graphics.set_color(orange[-5]) end}, orangem5 = TextTag{draw = function(c, i, text) graphics.set_color(orange[-5]) end},
purplem5 = TextTag{draw = function(c, i, text) graphics.set_color(purple[-5]) end}, purplem5 = TextTag{draw = function(c, i, text) graphics.set_color(purple[-5]) end},

36
todo
View File

@ -8,7 +8,6 @@ Sorcerer update
QoL QoL
Item reroll for 15 gold Item reroll for 15 gold
Fix highlight colors and highlight reserve Fix highlight colors and highlight reserve
Change cursers to trigger only near enemies
Rename tutorial to guide or manual Rename tutorial to guide or manual
Add visuals for defensive ouroboros Add visuals for defensive ouroboros
Unlock automatically on shop enter Unlock automatically on shop enter
@ -23,21 +22,24 @@ Sorcerer update
Fix lock bug after death/win - https://i.imgur.com/iUyOtLk.png Fix lock bug after death/win - https://i.imgur.com/iUyOtLk.png
Fix enemies still spawning after arena clear (this happens with the extra enemy spawns that were blocked earlier) Fix enemies still spawning after arena clear (this happens with the extra enemy spawns that were blocked earlier)
Fix death + win at the same time bug Fix death + win at the same time bug
Fix leader distance being off on certain speeds
Balance Balance
Buff tanks, maybe add a simple forcer ability to them Buff tanks, maybe add a simple forcer ability to them
Buff 24/25 HP again Buff 24/25 HP again
Buff headbutter (+ trigger range) Buff headbutter (+ trigger range)
New * New
Sorcerer = sorcerers repeat their attacks once every 4/3/2 attacks * Sorcerer = sorcerers repeat their attacks once every 4/3/2 attacks
* Arcanist (tier 1 sorcerer) - launches a slow piercing orb that launches other piercing projectiles, Lv.3 effect - 50% increased attack speed for the orb and 2 projectiles are released per cast * Arcanist (tier 1 sorcerer) - launches a slow piercing orb that launches other piercing projectiles, Lv.3 effect - 50% increased attack speed for the orb and 2 projectiles are released per cast
* Sorcerer + Conjurer = Illusionist - launches a projectile that deals X damage and creates copies that do the same, Lv.3 effect - doubles the number of copies created and they release additional projectiles on death * Sorcerer + Conjurer = Illusionist - launches a projectile that deals X damage and creates copies that do the same, Lv.3 effect - doubles the number of copies created and they release 12 projectiles on death that pierce and ricochet once
* Sorcerer + Voider = Witch - creates an area that ricochets around the arena and deals X damage over time, Lv.3 effect - the area periodically releases projectiles that chains once * Sorcerer + Voider = Witch - creates an area that ricochets around the arena and deals X damage over time, Lv.3 effect - the area periodically releases projectiles that chain once
Sorcerer + Curser = Silencer - curses 5 nearby enemies for 6 seconds, preventing them from using special attacks, Lv.3 effect - the curse also deals X damage over time * Sorcerer + Curser = Silencer - curses 6 nearby enemies for 6 seconds, preventing them from using special attacks, Lv.3 effect - the curse also deals X damage over time
Sorcerer + Nuker = Vulcanist - creates a volcano that explodes the nearby area 5 times, Lv.3 effect - the volcano spawn also deals damage and doubles the number of explosions * Sorcerer + Nuker = Vulcanist - creates a volcano that explodes the nearby area 4 times, Lv.3 effect - the number and speed of explosions is doubled
Sorcerer + Forcer = Warden - creates a force field around a random unit that prevents enemies from entering, Lv.3 effect - creates the force field around 2 other random units * Sorcerer + Forcer = Warden - creates a force field around a random unit that prevents enemies from entering, Lv.3 effect - creates the force field around 2 units instead
Sorcerer + Psyker = Psychic - creates a small area that deals X damage, Lv.3 effect - the attack can happen from any distance and repeats twice * Sorcerer + Psyker = Psychic - creates a small area that deals X damage, Lv.3 effect - the attack can happen from any distance and repeats twice
* Magician (tier 1 mage) - creates a small area that deals X damage, Lv.3 effect - the magician becomes invulnerable for 6 seconds
Sorcerer update patch notes Sorcerer update patch notes
Changed cursers to trigger only when near enemies
Decreased projectile speed for the exploder (blue enemy) Decreased projectile speed for the exploder (blue enemy)
Changed shooters (white enemy) to scale with NG+ difficulty Changed shooters (white enemy) to scale with NG+ difficulty
Increased damage and movement speed for enemy swarmers (small purple enemies) Increased damage and movement speed for enemy swarmers (small purple enemies)
@ -47,6 +49,18 @@ Sorcerer update patch notes
Removed cooldown visuals on snake for units that don't have cooldowns (Squire, Chronomancer and Psykeeper) Removed cooldown visuals on snake for units that don't have cooldowns (Squire, Chronomancer and Psykeeper)
Slightly decreased base game's difficulty Slightly decreased base game's difficulty
Fixed NG+ difficulty only being able to be lowered, now you can lower or increase it (up to your maximum acquired value) Fixed NG+ difficulty only being able to be lowered, now you can lower or increase it (up to your maximum acquired value)
Buffed swarmer movement speed
Fixed a visual bug with the cleric, its cooldown was showing as faster than it actually was and thus gave the impression of not healing when it should
Changed Corruptor to tier 4
Changed Host to tier 3
Changed Wizard to tier 2
Removed Lich (will come back in future update)
Added Magician (tier 1 mage)
Change Outlaw to tier 2
Added Forcer class to Sage
Added Nuker class to Wizard
Change Wizard's Lv.3 effect's chain to 2 (from 3)
Fixed Blade's Lv.3 effect's damage text not being rounded
--- ---
@ -55,6 +69,9 @@ Chaos related classes
Invoker - shoots a projectile with random properties, Lv.3 effect - ??? Invoker - shoots a projectile with random properties, Lv.3 effect - ???
Trappers: Trappers:
Triangler - drops a trap and the 3rd trap will trigger the area, dealing X AoE damage 2-3 times Triangler - drops a trap and the 3rd trap will trigger the area, dealing X AoE damage 2-3 times
Brawlers: units focused on crashing on enemies
https://i.imgur.com/5YubukS.png - unit idea
Hexblaster? - curser that consumes curses to deal damage
Bench? - https://i.imgur.com/B1gNVKk.png Bench? - https://i.imgur.com/B1gNVKk.png
Balance option for when there are more sets - https://i.imgur.com/JMynwbL.png Balance option for when there are more sets - https://i.imgur.com/JMynwbL.png
Negative effect: colliding with yourself kills one of your units Negative effect: colliding with yourself kills one of your units
@ -62,6 +79,7 @@ Go through this later https://i.imgur.com/4t7NA32.png <- lots of good improvemen
Remove level 3 units from rotation Remove level 3 units from rotation
Hide cursor during waves Hide cursor during waves
Mouse follow control? Mouse follow control?
Visuals for divine intervertion, fairy buff
Roguelite update: Roguelite update:
Slay the Spire-like node selection map (copy code from SHOOTRX repo as this is already implemented there) Slay the Spire-like node selection map (copy code from SHOOTRX repo as this is already implemented there)