diff --git a/arena.lua b/arena.lua index e9275cc..02907e8 100644 --- a/arena.lua +++ b/arena.lua @@ -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') diff --git a/assets/sounds/Earth Bolt 1.ogg b/assets/sounds/Earth Bolt 1.ogg new file mode 100644 index 0000000..d51cf25 Binary files /dev/null and b/assets/sounds/Earth Bolt 1.ogg differ diff --git a/assets/sounds/Earth Bolt 14.ogg b/assets/sounds/Earth Bolt 14.ogg new file mode 100644 index 0000000..e2a3042 Binary files /dev/null and b/assets/sounds/Earth Bolt 14.ogg differ diff --git a/assets/sounds/Earth Bolt 20.ogg b/assets/sounds/Earth Bolt 20.ogg new file mode 100644 index 0000000..8b6816a Binary files /dev/null and b/assets/sounds/Earth Bolt 20.ogg differ diff --git a/assets/sounds/Fire bolt 3.ogg b/assets/sounds/Fire bolt 3.ogg new file mode 100644 index 0000000..7f307c3 Binary files /dev/null and b/assets/sounds/Fire bolt 3.ogg differ diff --git a/assets/sounds/Magical Impact 13.ogg b/assets/sounds/Magical Impact 13.ogg new file mode 100644 index 0000000..c13864d Binary files /dev/null and b/assets/sounds/Magical Impact 13.ogg differ diff --git a/buy_screen.lua b/buy_screen.lua index 80eee09..240365b 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -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() diff --git a/enemies.lua b/enemies.lua index 19d2a06..47b984c 100644 --- a/enemies.lua +++ b/enemies.lua @@ -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 diff --git a/main.lua b/main.lua index f96dd62..7a93d50 100644 --- a/main.lua +++ b/main.lua @@ -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 diff --git a/player.lua b/player.lua index f2ca948..cb59c8c 100644 --- a/player.lua +++ b/player.lua @@ -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() diff --git a/shared.lua b/shared.lua index 05d271c..b1ae221 100644 --- a/shared.lua +++ b/shared.lua @@ -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}, diff --git a/todo b/todo index 4f2029a..a72606f 100644 --- a/todo +++ b/todo @@ -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)