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)
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.effects = 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('enemy_projectile', 'enemy')
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('enemy_projectile', 'player')
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.shape = Rectangle(self.x, self.y, 40, 20)
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)
end
@ -1394,12 +1395,12 @@ end
function TutorialClassIcon:draw()
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]))
_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])
if i == 2 then
if i == 2 and not k 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 + 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()
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
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:activate({
{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()
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
if self.parent:is(ShopCard) then
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]))
_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])
if i == 2 then
if i == 2 and not k 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 + 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)
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
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)
@ -1547,11 +1580,11 @@ end
function ClassIcon:on_mouse_enter()
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
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: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_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)
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
@ -1584,7 +1617,7 @@ end
function ClassIcon:die(dont_spawn_effect)
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 self.info_text then
self.info_text:deactivate()

View File

@ -16,6 +16,7 @@ function Seeker:init(args)
if self.boss == 'speed_booster' then
self.color = green[0]:clone()
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)
if #enemies > 0 then
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
self.color = yellow[0]:clone()
self.t:every(6, function()
if self.silenced then return end
local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
local x, y = 0, 0
if #enemies > 0 then
@ -74,6 +76,7 @@ function Seeker:init(args)
elseif self.boss == 'swarmer' then
self.color = purple[0]:clone()
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 enemy = random:table(enemies)
if enemy then
@ -89,6 +92,7 @@ function Seeker:init(args)
elseif self.boss == 'exploder' then
self.color = blue[0]:clone()
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 enemy = random:table(enemies)
if enemy then
@ -104,6 +108,7 @@ function Seeker:init(args)
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(6, function()
if self.silenced then return end
local attack = random:table{'explode', 'swarm', 'force', 'speed_boost'}
if attack == 'explode' then
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
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()
if self.silenced then return end
if self.headbutt_charging or self.headbutting then return end
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()
@ -208,6 +214,7 @@ function Seeker:init(args)
self.t:after({2*n, 4*n}, function()
self.shooting = true
self.t:every({3, 5}, function()
if self.silenced then return end
for i = 1, 3 do
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}
@ -420,6 +427,7 @@ function Seeker:hit(damage, projectile)
end
if self.speed_booster then
if self.silenced then return end
local enemies = self:get_objects_in_shape(self.area_sensor, main.current.enemies)
if #enemies > 0 then
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -432,6 +440,7 @@ function Seeker:hit(damage, projectile)
end
if self.exploder then
if self.silenced then return end
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.4}
trigger:after(0.01, function()
local n = 8 + current_new_game_plus*2
@ -442,6 +451,7 @@ function Seeker:hit(damage, projectile)
end
if self.spawner then
if self.silenced then return end
critter1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
trigger:after(0.01, function()
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_ref = arg3
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
@ -745,6 +758,9 @@ function EnemyCritter:curse(curse, duration, arg1, arg2, arg3)
self.infested_dmg = arg2
self.infested_ref = arg3
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

121
main.lua
View File

@ -18,6 +18,13 @@ function init()
input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'})
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)
thunder1 = Sound('399656__bajko__sfx-thunder-blast.ogg', s)
flagellant1 = Sound('Whipping Horse 3.ogg', s)
@ -211,6 +218,7 @@ function init()
['vagrant'] = 'Vagrant',
['swordsman'] = 'Swordsman',
['wizard'] = 'Wizard',
['magician'] = 'Magician',
['archer'] = 'Archer',
['scout'] = 'Scout',
['cleric'] = 'Cleric',
@ -262,6 +270,7 @@ function init()
['vagrant'] = fg[0],
['swordsman'] = yellow[0],
['wizard'] = blue[0],
['magician'] = blue[0],
['archer'] = green[0],
['scout'] = red[0],
['cleric'] = green[0],
@ -313,6 +322,7 @@ function init()
['vagrant'] = 'fg',
['swordsman'] = 'yellow',
['wizard'] = 'blue',
['magician'] = 'blue',
['archer'] = 'green',
['scout'] = 'red',
['cleric'] = 'green',
@ -363,7 +373,8 @@ function init()
character_classes = {
['vagrant'] = {'psyker', 'ranger', 'warrior'},
['swordsman'] = {'warrior'},
['wizard'] = {'mage'},
['wizard'] = {'mage', 'nuker'},
['magician'] = {'mage'},
['archer'] = {'ranger'},
['scout'] = {'rogue'},
['cleric'] = {'healer'},
@ -372,7 +383,7 @@ function init()
['elementor'] = {'mage', 'nuker'},
['saboteur'] = {'rogue', 'conjurer', 'nuker'},
['stormweaver'] = {'enchanter'},
['sage'] = {'nuker'},
['sage'] = {'forcer', 'nuker'},
['squire'] = {'warrior', 'enchanter'},
['cannoneer'] = {'ranger', 'nuker'},
['dual_gunner'] = {'ranger', 'rogue'},
@ -414,7 +425,8 @@ function init()
character_class_strings = {
['vagrant'] = '[fg]Psyker, [green]Ranger, [yellow]Warrior',
['swordsman'] = '[yellow]Warrior',
['wizard'] = '[blue]Mage',
['wizard'] = '[blue]Mage, [red]Nuker',
['magician'] = '[blue]Mage',
['archer'] = '[green]Ranger',
['scout'] = '[red]Rogue',
['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]' ..
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,
['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,
['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,
@ -508,32 +521,33 @@ function init()
['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,
['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]' ..
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,
['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,
['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,
['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,
['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,
['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,
['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,
['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,
['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 = {
['vagrant'] = '[fg]Champion',
['swordsman'] = '[yellow]Cleave',
['wizard'] = '[blue]Magic Missile',
['magician'] = '[blue]Teleportation',
['archer'] = '[green]Bounce Shot',
['scout'] = '[red]Dagger Resonance',
['cleric'] = '[green]Mass Heal ',
@ -585,6 +599,7 @@ function init()
['vagrant'] = '[light_bg]Champion',
['swordsman'] = '[light_bg]Cleave',
['wizard'] = '[light_bg]Magic Missile',
['magician'] = '[light_bg]Teleportation',
['archer'] = '[light_bg]Bounce Shot',
['scout'] = '[light_bg]Dagger Resonance',
['cleric'] = '[light_bg]Mass Heal ',
@ -635,12 +650,13 @@ function init()
character_effect_descriptions = {
['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,
['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,
['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end,
['cleric'] = function() return '[fg]heals all units' 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,
['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,
@ -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,
['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,
['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,
['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,
['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,
['warden'] = function() return '[fg]creates the force field around [yellow]2[fg] additional random units' 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] 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,
}
@ -687,11 +703,12 @@ function init()
['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,
['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,
['scout'] = function() return '[light_bg]+25% damage per chain and +3 chains' 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,
['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,
['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,
@ -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,
['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,
['arcanist'] = function() return '[light_bg]100% increased 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,
['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 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,
['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,
['warden'] = function() return '[light_bg]creates the force field around 2 additional random units' 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 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,
}
@ -738,6 +755,7 @@ function init()
['vagrant'] = function(lvl) return get_character_stat_string('vagrant', lvl) end,
['swordsman'] = function(lvl) return get_character_stat_string('swordsman', 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,
['scout'] = function(lvl) return get_character_stat_string('scout', 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},
['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},
['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},
['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},
@ -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,
['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)
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,
}
tier_to_characters = {
[1] = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'},
[2] = {'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'launcher', 'jester', 'carver'},
[3] = {'outlaw', 'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'corruptor', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant'},
[4] = {'priest', 'highlander', 'psykino', 'lich', 'host', 'fairy', 'blade', 'plague_doctor', 'cannoneer'},
[1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist'},
[2] = {'wizard', 'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'launcher', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw'},
[3] = {'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'host', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant', 'illusionist'},
[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'}
@ -853,14 +871,16 @@ function init()
character_tiers = {
['vagrant'] = 1,
['swordsman'] = 1,
['wizard'] = 1,
['magician'] = 1,
['archer'] = 1,
['scout'] = 1,
['cleric'] = 1,
['outlaw'] = 3,
['arcanist'] = 1,
['outlaw'] = 2,
['blade'] = 4,
['elementor'] = 3,
['saboteur'] = 2,
['wizard'] = 2,
['stormweaver'] = 3,
['sage'] = 2,
['squire'] = 2,
@ -874,15 +894,15 @@ function init()
['plague_doctor'] = 4,
['barbarian'] = 2,
['juggernaut'] = 3,
['lich'] = 4,
-- ['lich'] = 4,
['cryomancer'] = 2,
['pyromancer'] = 3,
['corruptor'] = 3,
['corruptor'] = 4,
['beastmaster'] = 2,
['launcher'] = 2,
['jester'] = 2,
['assassin'] = 3,
['host'] = 4,
['host'] = 3,
['carver'] = 2,
['bane'] = 3,
['psykino'] = 4,
@ -892,6 +912,12 @@ function init()
['priest'] = 4,
['infestor'] = 3,
['flagellant'] = 3,
['psychic'] = 2,
['witch'] = 2,
['silencer'] = 2,
['illusionist'] = 3,
['warden'] = 4,
['vulcanist'] = 4,
}
get_number_of_units_per_class = function(units)
@ -976,19 +1002,20 @@ function init()
end
class_set_numbers = {
['ranger'] = function(units) return 3, 6, get_number_of_units_per_class(units).ranger end,
['warrior'] = function(units) return 3, 6, get_number_of_units_per_class(units).warrior end,
['mage'] = function(units) return 3, 6, get_number_of_units_per_class(units).mage end,
['nuker'] = function(units) return 3, 6, get_number_of_units_per_class(units).nuker end,
['rogue'] = function(units) return 3, 6, get_number_of_units_per_class(units).rogue end,
['healer'] = function(units) return 2, 4, get_number_of_units_per_class(units).healer end,
['conjurer'] = function(units) return 2, 4, get_number_of_units_per_class(units).conjurer end,
['enchanter'] = function(units) return 2, 4, get_number_of_units_per_class(units).enchanter end,
['psyker'] = function(units) return 2, 4, get_number_of_units_per_class(units).psyker end,
['curser'] = function(units) return 2, 4, get_number_of_units_per_class(units).curser end,
['forcer'] = function(units) return 2, 4, get_number_of_units_per_class(units).forcer end,
['swarmer'] = function(units) return 2, 4, get_number_of_units_per_class(units).swarmer end,
['voider'] = function(units) return 2, 4, get_number_of_units_per_class(units).voider end,
['ranger'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).ranger end,
['warrior'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).warrior end,
['mage'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).mage end,
['nuker'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).nuker end,
['rogue'] = function(units) return 3, 6, nil, get_number_of_units_per_class(units).rogue end,
['healer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).healer end,
['conjurer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).conjurer end,
['enchanter'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).enchanter end,
['psyker'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).psyker end,
['curser'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).curser end,
['forcer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).forcer end,
['swarmer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).swarmer 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 = {
@ -1288,17 +1315,17 @@ function init()
if run.level and run.level > 0 then
main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5}
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:go_to('buy_screen', run.level or 0, run.units or {}, passives)
]]--
--[[
main:add(Arena'arena')
main:go_to('arena', 16, {
{character = 'witch', level = 3},
main:go_to('arena', 14, {
{character = 'magician', level = 3},
}, passives)
]]--
trigger:every(2, function()
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()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
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, 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
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()
@ -57,11 +73,10 @@ function Player:init(args)
end, nil, nil, 'shoot')
elseif self.character == 'cleric' then
self.last_heal_time = love.timer.getTime()
self.t:every(2, function()
self.t:every(6, function()
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)
if unit_index and love.timer.getTime() - self.last_heal_time > 6 then
if unit_index then
local unit = all_units[unit_index]
self.last_heal_time = love.timer.getTime()
if self.level == 3 then
@ -74,20 +89,40 @@ function Player:init(args)
end, nil, nil, 'heal')
elseif self.character == 'arcanist' then
self.sorcerer_count = 0
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()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then
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, nil, nil, 'shoot')
elseif self.character == 'illusionist' then
self.sorcerer_count = 0
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 closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then
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, nil, nil, 'shoot')
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}
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}
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)
@ -123,6 +170,38 @@ function Player:init(args)
end
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
self.t:every(8, function()
self.t:every(0.25, function()
@ -159,6 +238,38 @@ function Player:init(args)
end
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
self.dg_counter = 0
self.attack_sensor = Circle(self.x, self.y, 96)
@ -229,8 +340,18 @@ function Player:init(args)
end
elseif self.character == 'witch' then
self.t:every(6, function()
self:dot_attack(24, {duration = random:float(12, 16), homing = true})
self.sorcerer_count = 0
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')
elseif self.character == 'barbarian' then
@ -281,7 +402,8 @@ function Player:init(args)
end, nil, nil, 'shoot')
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}
local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
for _, enemy in ipairs(enemies) do
@ -296,9 +418,10 @@ function Player:init(args)
end, nil, nil, 'attack')
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}
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
if self:distance_to_object(enemy) < 128 then
enemy:curse('jester', 6*(self.hex_duration_m or 1), self.level == 3, self)
@ -308,6 +431,40 @@ function Player:init(args)
end
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
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()
@ -338,9 +495,10 @@ function Player:init(args)
end, nil, nil, 'spawn')
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}
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
if self:distance_to_object(enemy) < 128 then
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 unit_1 = 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))
unit_1.fairy_aspd_m = 3
unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1 end)
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)
if unit_1 then
unit_1:heal(0.2*unit_1.max_hp*(self.heal_effect_m or 1))
unit_1.fairy_aspd_m = 3
unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1 end)
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}
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
else
local unit = random:table(self:get_all_units())
unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1))
unit.fairy_aspd_m = 2
unit.t:after(5.98, function() unit.fairy_aspd_m = 1 end)
if unit then
unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1))
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}
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end
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
if self.level == 3 then
self.t:after(0.01, function()
@ -437,9 +637,10 @@ function Player:init(args)
end, nil, nil, 'heal')
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}
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
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)
@ -873,7 +1074,11 @@ end
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)
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
graphics.pop()
end
@ -939,6 +1144,7 @@ end
function Player:hit(damage)
if self.dead then return end
if self.magician_invulnerable then return end
self.hfx:use('hit', 0.25, 200, 10)
self:show_hp()
@ -1182,14 +1388,14 @@ function Player:shoot(r, mods)
Projectile(table.merge(t, mods or {}))
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}
elseif self.character == 'dual_gunner' then
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}
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}
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}
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}
@ -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}
elseif self.character == 'elementor' then
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
buff1:play{pitch == random:float(0.9, 1.1), volume = 0.5}
end
@ -1500,7 +1708,7 @@ function Projectile:on_collision_enter(other, contact)
self.ricochet = self.ricochet - 1
end
_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)
knife_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2}
local r = Unit.bounce(self, nx, ny)
@ -1519,7 +1727,7 @@ function Projectile:on_collision_enter(other, contact)
self.r = r
self.ricochet = self.ricochet - 1
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))
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
elseif self.character == 'cannoneer' then
@ -1574,12 +1782,12 @@ function Projectile:on_trigger_enter(other, contact)
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
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}
if self.character == 'spellblade' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
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}
elseif self.character == 'arcanist_projectile' then
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}
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
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}
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}
@ -1889,11 +2097,12 @@ function DotArea:init(args)
self.t:every(1, function()
local enemies = main.current.main:get_objects_in_shape(self.closest_sensor, main.current.enemies)
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])
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}
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
@ -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:implement(GameObject)
@ -2375,12 +2700,12 @@ function Illusion:update(dt)
self:seek_point(gw/2, gh/2)
self:wander(50, 200, 50)
self:rotate_towards_velocity(1)
self:steering_separate(32, {Illusion, Seeker, Player})
self:steering_separate(32, {Illusion, Seeker})
else
self:seek_point(self.target.x, self.target.y)
self:wander(50, 200, 50)
self:rotate_towards_velocity(1)
self:steering_separate(32, {Illusion, Seeker, Player})
self:steering_separate(32, {Illusion, Seeker})
end
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},
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},
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},
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},
@ -508,6 +509,8 @@ global_text_tags = {
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},
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},
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},

36
todo
View File

@ -8,7 +8,6 @@ Sorcerer update
QoL
Item reroll for 15 gold
Fix highlight colors and highlight reserve
Change cursers to trigger only near enemies
Rename tutorial to guide or manual
Add visuals for defensive ouroboros
Unlock automatically on shop enter
@ -23,21 +22,24 @@ Sorcerer update
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 death + win at the same time bug
Fix leader distance being off on certain speeds
Balance
Buff tanks, maybe add a simple forcer ability to them
Buff 24/25 HP again
Buff headbutter (+ trigger range)
New
Sorcerer = sorcerers repeat their attacks once every 4/3/2 attacks
* New
* 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
* 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 + 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 + 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 + 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 + 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 + Psyker = Psychic - creates a small area that deals X damage, Lv.3 effect - the attack can happen from any distance and repeats twice
* 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 chain once
* 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 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 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
* 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
Changed cursers to trigger only when near enemies
Decreased projectile speed for the exploder (blue enemy)
Changed shooters (white enemy) to scale with NG+ difficulty
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)
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)
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 - ???
Trappers:
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
Balance option for when there are more sets - https://i.imgur.com/JMynwbL.png
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
Hide cursor during waves
Mouse follow control?
Visuals for divine intervertion, fairy buff
Roguelite update:
Slay the Spire-like node selection map (copy code from SHOOTRX repo as this is already implemented there)