From ef194d54761dd4a7a31319762e68ac27d5444719 Mon Sep 17 00:00:00 2001 From: a327ex Date: Wed, 14 Apr 2021 21:02:57 -0300 Subject: [PATCH] Day 57 --- assets/sounds/Whipping Horse 3.ogg | Bin 0 -> 18802 bytes devlog.md | 36 +++++ enemies.lua | 27 +++- main.lua | 56 +++---- player.lua | 230 ++++++++++++++++++++++++----- todo | 46 +++--- 6 files changed, 300 insertions(+), 95 deletions(-) create mode 100644 assets/sounds/Whipping Horse 3.ogg diff --git a/assets/sounds/Whipping Horse 3.ogg b/assets/sounds/Whipping Horse 3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..71bf944eb58d5bff284b7871e0c1814100577ec4 GIT binary patch literal 18802 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 E0Z$amGXMYp literal 0 HcmV?d00001 diff --git a/devlog.md b/devlog.md index abdc094..5469737 100644 --- a/devlog.md +++ b/devlog.md @@ -923,3 +923,39 @@ Still slow... But I got something done :) | Bane | Nightmare | the area also deals X damage per second and slows enemies by 50% | | Psykino | Magnetic Force | enemies take 4X damage and are pushed away when the area expires | | Barrager | Barrage | every 3rd attack the barrage shoots 15 projectiles and they push harder | + +# Day 57 - 14/04/21 + +Finished remaining 5 characters and revised all class bonuses. So 40/40 characters and 13/13 classes done. Now the only thing left are items and then all content will be done. + +| Character | Classes | Description | +| --- | --- | --- | +| Highlander | warrior | deals 5X AoE damage | +| Fairy | enchanter, healer | periodically heals 1 unit at random and grants it +100% attack speed for 6 seconds | +| Priest | healer | heals all allies for 20% their max HP | +| Infestor | curser, swarmer | curses nearby enemies for 6 seconds, they will release 2 critters on death | +| Flagellant | enchanter, psyker | deals 2X damage to self and grants +4% damage to all allies per cast | + +| Character | Lv.3 Effect Name | Lv.3 Effect Description | +| --- | --- | --- | +| Highlander | Moulinet | quickly repeats the attack 3 times | +| Fairy | Whimsy | heals 2 units instead and grants them an additional 100% attack speed | +| Priest | Divine Intervention | at the start of the round pick 3 units at random and grants them a buff that prevents death once | +| Infestor | Infestation | triples the number of critters released | +| Flagellant | Zealotry | deals 2X damage to all allies and grants +12% damage to all allies per cast | + +| Class | Set Color | Set Numbers | Total Units | Set Effect | +| --- | --- | --- | --- | --- | +| Ranger | green | 3/6 | 7 | +10/20% chance to release a barrage to allied rangers | +| Warrior | yellow | 3/6 | 8 | +25/50 defense to allied warriors | +| Mage | blue | 3/6 | 8 | -15/30 enemy defense | +| Rogue | red | 3/6 | 8 | +10/20% chance to crit to allied rogues, dealing 4x damage | +| Healer | green | 2/4 | 5 | +15/30% healing effectiveness | +| Enchanter | blue/red | 2/4 | 5 | +15/25% damage to all allies | +| Nuker | blue/purple | 3/6 | 7 | +15/25% area damage and size to allied nukers | +| Conjurer | orange | 2/4 | 4 | +25/50% summon damage and duration | +| Psyker | white | 2/4 | 4 | +5/10% damage and attack speed per active set to allied psykers | +| Curser | purple | 2/4 | 5 | +25/50% curse dueration | +| Forcer | yellow | 2/4 | 5 | +25/50% knockback force to all allies | +| Swarmer | orange | 2/4 | 4 | +1/3 health to critters | +| Voider | purple | 2/4 | 5 | +15/25% DoT to allied voiders | diff --git a/enemies.lua b/enemies.lua index 6d68200..9ba005a 100644 --- a/enemies.lua +++ b/enemies.lua @@ -430,6 +430,15 @@ function Seeker:hit(damage, projectile) end end) end + + if self.infested then + critter1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + trigger:after(0.01, function() + for i = 1, self.infested do + Critter{group = main.current.main, x = self.x, y = self.y, color = orange[0], r = random:float(0, 2*math.pi), v = 10, dmg = self.infested_dmg} + end + end) + end end end @@ -461,17 +470,27 @@ function Seeker:slow(amount, duration) end -function Seeker:curse(curse, duration, arg1) +function Seeker:curse(curse, duration, arg1, arg2) + 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 + if curse == 'launcher' then - self.t:after(duration, function() + self.t:after(duration*curse_m, function() self.launcher_push = arg1 - self:push(random:float(50, 75), random:table{0, math.pi, math.pi/2, -math.pi/2}) + self.launcher = arg2 + self:push(random:float(50, 75)*self.launcher.knockback_m, random:table{0, math.pi, math.pi/2, -math.pi/2}) end, 'launcher_curse') elseif curse == 'bard' then self.bard_cursed = true elseif curse == 'bane' then self.baned = true - self.t:after(duration, function() self.baned = false end, 'bane_curse') + self.t:after(duration*curse_m, function() self.baned = false end, 'bane_curse') + elseif curse == 'infestor' then + self.infested = arg1 + self.infested_dmg = arg2 + self.t:after(duration*curse_m, function() self.infested = false end, 'infestor_curse') end end diff --git a/main.lua b/main.lua index f4df4e2..42819ba 100644 --- a/main.lua +++ b/main.lua @@ -19,6 +19,7 @@ function init() music.volume = 0 local s = {tags = {sfx}} + flagellant1 = Sound('Whipping Horse 3.ogg', s) bard2 = Sound('376532__womb-affliction__flute-trill.ogg', s) bard1 = Sound('Magical Impact 12.ogg', s) frost1 = Sound('Frost Bolt 20.ogg', s) @@ -184,7 +185,7 @@ function init() ['psykino'] = fg[0], ['barrager'] = green[0], ['highlander'] = yellow[0], - ['sapper'] = blue[0], + ['fairy'] = green[0], ['priest'] = green[0], ['infestor'] = orange[0], ['flagellant'] = fg[0], @@ -228,7 +229,7 @@ function init() ['psykino'] = 'fg', ['barrager'] = 'green', ['highlander'] = 'yellow', - ['sapper'] = 'blue', + ['fairy'] = 'green', ['priest'] = 'green', ['infestor'] = 'orange', ['flagellant'] = 'fg', @@ -272,7 +273,7 @@ function init() ['psykino'] = {'mage', 'psyker', 'forcer'}, ['barrager'] = {'ranger', 'forcer'}, ['highlander'] = {'warrior'}, - ['sapper'] = {'enchanter', 'voider', 'healer'}, + ['fairy'] = {'enchanter', 'healer'}, ['priest'] = {'healer'}, ['infestor'] = {'curser', 'swarmer'}, ['flagellant'] = {'psyker', 'enchanter'}, @@ -316,7 +317,7 @@ function init() ['psykino'] = '[blue]Mage, [fg]Psyker, [yellow]Forcer', ['barrager'] = '[green]Ranger, [yellow]Forcer', ['highlander'] = '[yellow]Warrior', - ['sapper'] = '[blue]Enchanter, [purple]Voider, [green]Healer', + ['fairy'] = '[blue]Enchanter, [green]Healer', ['priest'] = '[green]Healer', ['infestor'] = '[purple]Curser, [orange]Swarmer', ['flagellant'] = '[fg]Psyker, [blue]Enchanter', @@ -376,11 +377,11 @@ function init() ['bane'] = function(lvl) return '[fg]creates a large area that curses enemies to take [yellow]+50%[fg] damage' 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]5[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end, - ['highlander'] = function(lvl) return '[fg]deals [yellow]' .. 6*get_character_stat('highlander', lvl, 'dmg') .. '[fg] AoE damage' end, - ['sapper'] = function(lvl) return '[fg]periodically steals [yellow]5%[fg] max HP per second from nearby enemies and gain 25% increased movement speed' 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 enemies in an area for [yellow]6[fg] seconds, they will release multiple critters on death' end, - ['flagellant'] = function(lvl) return '[fg]deals damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end, + ['infestor'] = function(lvl) return '[fg]curses 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, } character_effect_names = { @@ -420,8 +421,8 @@ function init() ['bane'] = '[purple]Nightmare', ['psykino'] = '[fg]Magnetic Force', ['barrager'] = '[green]Barrage', - ['highlander'] = '[yellow]Crosscut', - ['sapper'] = '[blue]Enduring Sap', + ['highlander'] = '[yellow]Moulinet', + ['fairy'] = '[green]Whimsy', ['priest'] = '[green]Divine Intervention', ['infestor'] = '[orange]Infestation', ['flagellant'] = '[red]Zealotry', @@ -449,23 +450,23 @@ function init() ['psykeeper'] = '[light_bg]Crucio', ['engineer'] = '[light_bg]Upgrade', ['plague_doctor'] = '[light_bg]Black Death Steam', - ['fisherman'] = '[light_bg]Electric Net', + ['barbarian'] = '[light_bg]Seism', ['juggernaut'] = '[light_bg]Brutal Impact', - ['lich'] = '[light_bg]Piercing Frost', + ['lich'] = '[light_bg]Chain Frost', ['cryomancer'] = '[light_bg]Frostbite', ['pyromancer'] = '[light_bg]Ignite', ['corruptor'] = '[light_bg]Corruption', ['beastmaster'] = '[light_bg]Call of the Wild', ['launcher'] = '[light_bg]Kineticism', - ['spiker'] = '[light_bg]Caltrops', + ['bard'] = "[red]The Bard'light_bgSong", ['assassin'] = '[light_bg]Toxic Delivery', ['host'] = '[light_bg]Invasion', ['carver'] = '[light_bg]World Tree', - ['bane'] = '[light_bg]Baneling Swarm', + ['bane'] = '[light_bg]Nightmare', ['psykino'] = '[light_bg]Magnetic Force', - ['barrager'] = '[light_bg]Ballista Sinitra', - ['barbarian'] = '[light_bg]Berserk', - ['sapper'] = '[light_bg]Chain Reaction', + ['barrager'] = '[light_bg]Barrage', + ['highlander'] = '[light_bg]Moulinet', + ['fairy'] = '[light_bg]Whimsy', ['priest'] = '[light_bg]Divine Intervention', ['infestor'] = '[light_bg]Infestation', ['flagellant'] = '[light_bg]Zealotry', @@ -508,11 +509,11 @@ function init() ['bane'] = function() return '[fg]the area also deals [yellow]' .. get_character_stat('bane', 3, 'dmg') .. '[fg] damage per second and slows enemies by [yellow]50%[fg]' end, ['psykino'] = function() return '[fg]enemies take [yellow]' .. 4*get_character_stat('psykino', 3, 'dmg') .. '[fg] damage and are pushed away when the area expires' end, ['barrager'] = function() return '[fg]every 3rd attack the barrage shoots [yellow]15[fg] projectiles and they push harder' end, - ['crosscut'] = function() return '[fg]two crosscutting areas of +100% size are created instead' end, - ['sapper'] = function() return '[fg]sapped enemies permanently take [yellow]' .. get_character_stat('sapper', 3, 'dmg') .. '[fg] damage per second' end, + ['highlander'] = function() return '[fg]quickly repeats the attack [yellow]3[fg] times' end, + ['fairy'] = function() return '[fg]heals [yellow]2[fg] units instead and grants them an additional [yellow]100%[fg] attack speed' end, ['priest'] = function() return '[fg]at the start of the round pick [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 damage to all allies instead and grants stacking [yellow]+10%[fg] damage to all allies per cast' end, + ['flagellant'] = function() return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', 3, 'dmg') .. '[fg] damage to all allies and grants [yellow]+12%[fg] damage to all allies per cast' end, } character_stats = { @@ -553,7 +554,7 @@ function init() ['psykino'] = function(lvl) return get_character_stat_string('psykino', lvl) end, ['barrager'] = function(lvl) return get_character_stat_string('barrager', lvl) end, ['highlander'] = function(lvl) return get_character_stat_string('highlander', lvl) end, - ['sapper'] = function(lvl) return get_character_stat_string('sapper', lvl) end, + ['fairy'] = function(lvl) return get_character_stat_string('fairy', lvl) end, ['priest'] = function(lvl) return get_character_stat_string('priest', lvl) end, ['infestor'] = function(lvl) return get_character_stat_string('infestor', lvl) end, ['flagellant'] = function(lvl) return get_character_stat_string('flagellant', lvl) end, @@ -577,7 +578,6 @@ function init() ['mini_boss'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.3}, ['enemy_critter'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.5}, ['saboteur'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 1.4}, - ['overlord'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.5}, } local ylb1 = function(lvl) return lvl >= 2 and 'fg' or (lvl >= 1 and 'yellow' or 'light_bg') end @@ -591,8 +591,8 @@ function init() ['enchanter'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+15%[' .. ylb2(lvl) .. ']/+25% [fg]damage to all allies' end, ['nuker'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[' .. ylb2(lvl) .. ']/6 [fg]- [' .. ylb1(lvl) .. ']+15%[' .. ylb2(lvl) .. ']/+25% [fg]area damage and size to allied nukers' end, ['conjurer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+25%[' .. ylb2(lvl) .. ']/+50% [fg]summon damage and duration' end, - ['psyker'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+5%[' .. ylb2(lvl) .. ']/+10% [fg]damage and health per active set to allied psykers' end, - ['curser'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+25%[' .. ylb2(lvl) .. ']/+50% [fg]curse effectiveness and duration' end, + ['psyker'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+5%[' .. ylb2(lvl) .. ']/+10% [fg]damage and attack speed per active set to allied psykers' end, + ['curser'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+25%[' .. ylb2(lvl) .. ']/+50% [fg]curse duration' end, ['forcer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+25%[' .. ylb2(lvl) .. ']/+50% [fg]knockback force to all allies' end, ['swarmer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+1[' .. ylb2(lvl) .. ']/+3 [fg]hits to critters' end, ['voider'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[' .. ylb2(lvl) .. ']/4 [fg]- [' .. ylb1(lvl) .. ']+15%[' .. ylb2(lvl) .. ']/+25% [fg]damage over time to allied voiders' end, @@ -602,7 +602,7 @@ function init() [1] = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'}, [2] = {'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'launcher', 'bard', 'carver'}, [3] = {'outlaw', 'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'corruptor', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant'}, - [4] = {'priest', 'highlander', 'psykino', 'lich', 'host', 'sapper', 'blade', 'plague_doctor', 'cannoneer'}, + [4] = {'priest', 'highlander', 'psykino', 'lich', 'host', 'fairy', 'blade', 'plague_doctor', 'cannoneer'}, } non_attacking_characters = {'cleric', 'stormweaver', 'squire', 'chronomancer', 'sage'} @@ -645,7 +645,7 @@ function init() ['psykino'] = 4, ['barrager'] = 3, ['highlander'] = 4, - ['sapper'] = 4, + ['fairy'] = 4, ['priest'] = 4, ['infestor'] = 3, ['flagellant'] = 3, @@ -809,7 +809,9 @@ function init() main = Main() main:add(BuyScreen'buy_screen') main:go_to('buy_screen', 22, { - {character = 'barrager', level = 3}, + {character = 'flagellant', level = 3}, + {character = 'scout', level = 3}, + {character = 'archer', level = 3}, }) --[[ main:add(Arena'arena') diff --git a/player.lua b/player.lua index b0b718b..e582588 100644 --- a/player.lua +++ b/player.lua @@ -321,6 +321,106 @@ function Player:init(args) end end end) + + elseif self.character == 'highlander' then + self.attack_sensor = Circle(self.x, self.y, 64) + self.t:cooldown(4, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() + if self.level == 3 then + self.t:every(0.25, function() + self:attack(48) + end, 3) + else + self:attack(48) + end + end, nil, nil, 'attack') + + elseif self.character == 'fairy' then + self.t:every(6, 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) + 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) + 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) + 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) + + elseif self.character == 'priest' then + if self.level == 3 then + self.t:after(0.01, function() + local all_units = self:get_all_units() + local unit_1 = random:table_remove(all_units) + local unit_2 = random:table_remove(all_units) + local unit_3 = random:table_remove(all_units) + if unit_1 then unit_1.divined = true end + if unit_2 then unit_2.divined = true end + if unit_3 then unit_3.divined = true end + end) + end + + self.t:every(10, function() + local all_units = self:get_all_units() + for _, unit in ipairs(all_units) do unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1)) end + heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + end) + + elseif self.character == 'infestor' then + self.t:every(8, function() + local enemies = main.current.main:get_objects_by_classes(main.current.enemies) + for _, enemy in ipairs(enemies) do + if self:distance_to_object(enemy) < 128 then + enemy:curse('infestor', 6, (self.level == 3 and 6 or 2), self.dmg) + HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = orange[0], duration = 0.1} + LightningLine{group = main.current.effects, src = self, dst = enemy, color = orange[0]} + end + end + end) + + elseif self.character == 'flagellant' then + self.t:every(8, function() + if self.level == 3 then + flagellant1:play{pitch = random:float(0.95, 1.05), volume = 0.4} + buff1:play{pitch = random:float(0.95, 1.05), volume = 0.3} + local all_units = self:get_all_units() + local dmg = self.dmg + for _, unit in ipairs(all_units) do + hit2:play{pitch = random:float(0.95, 1.05), volume = 0.4} + unit:hit(2*dmg) + if not unit.flagellant_dmg_m then + unit.flagellant_dmg_m = 1 + end + unit.flagellant_dmg_m = unit.flagellant_dmg_m + 0.12 + end + + else + buff1:play{pitch = random:float(0.95, 1.05), volume = 0.3} + flagellant1:play{pitch = random:float(0.95, 1.05), volume = 0.4} + local all_units = self:get_all_units() + for _, unit in ipairs(all_units) do + if unit.character == 'flagellant' then + hit2:play{pitch = random:float(0.95, 1.05), volume = 0.4} + unit:hit(2*unit.dmg) + end + if not unit.flagellant_dmg_m then + unit.flagellant_dmg_m = 1 + end + unit.flagellant_dmg_m = unit.flagellant_dmg_m + 0.04 + end + end + end) end self:calculate_stats(true) @@ -333,6 +433,8 @@ function Player:init(args) if #self.previous_positions > 256 then self.previous_positions[257] = nil end end) end + + self.first_frame_calculate_stats = true end @@ -391,10 +493,9 @@ function Player:update(dt) elseif main.current.warrior_level == 0 then self.warrior_def_a = 0 end end - if table.any(self.classes, function(v) return v == 'healer' end) then - if main.current.healer_level == 1 then self.heal_effect_m = 1.25 - else self.heal_effect_m = 1 end - end + if main.current.healer_level == 2 then self.heal_effect_m = 1.3 + elseif main.current.healer_level == 1 then self.heal_effect_m = 1.15 + else self.heal_effect_m = 1 end if table.any(self.classes, function(v) return v == 'nuker' end) then if main.current.nuker_level == 2 then self.nuker_area_size_m = 1.25; self.nuker_area_dmg_m = 1.25 @@ -402,10 +503,9 @@ function Player:update(dt) elseif main.current.nuker_level == 0 then self.nuker_area_size_m = 1; self.nuker_area_dmg_m = 1 end end - if table.any(self.classes, function(v) return v == 'conjurer' end) then - if main.current.conjurer_level == 1 then self.conjurer_buff_m = 1.25 - else self.conjurer_buff_m = 1 end - end + if main.current.conjurer_level == 2 then self.conjurer_buff_m = 1.5 + elseif main.current.conjurer_level == 1 then self.conjurer_buff_m = 1.25 + else self.conjurer_buff_m = 1 end if table.any(self.classes, function(v) return v == 'rogue' end) then if main.current.rogue_level == 2 then self.chance_to_crit = 20 @@ -413,14 +513,50 @@ function Player:update(dt) elseif main.current.rogue_level == 0 then self.chance_to_crit = 0 end end - if table.any(self.classes, function(v) return v == 'enchanter' end) then - if main.current.enchanter_level == 1 then self.enchanter_dmg_m = 1.25 - else self.enchanter_dmg_m = 1 end + if main.current.enchanter_level == 2 then self.enchanter_dmg_m = 1.25 + elseif main.current.enchanter_level == 1 then self.enchanter_dmg_m = 1.15 + else self.enchanter_dmg_m = 1 end + + if table.any(self.classes, function(v) return v == 'psyker' end) then + local class_levels = get_class_levels(self:get_all_units()) + local number_of_active_sets = 0 + if class_levels.ranger >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.warrior >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.mage >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.rogue >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.healer >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.conjurer >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.enchanter >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.psyker >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.curser >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.forcer >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.swarmer >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if class_levels.voider >= 1 then number_of_active_sets = number_of_active_sets + 1 end + if main.current.psyker_level == 2 then + self.psyker_dmg_m = 1 + 0.1*number_of_active_sets + self.psyker_aspd_m = 1 + 0.1*number_of_active_sets + elseif main.current.psyker_level == 1 then + self.psyker_dmg_m = 1 + 0.05*number_of_active_sets + self.psyker_aspd_m = 1 + 0.05*number_of_active_sets + else + self.psyker_dmg_m = 1 + self.psyker_aspd_m = 1 + end + end + + if main.current.forcer_level == 2 then self.knockback_m = 1.5 + elseif main.current.forcer_level == 1 then self.knockback_m = 1.25 + else self.knockback_m = 1 end + + if table.any(self.classes, function(v) return v == 'voider' end) then + if main.current.voider_level == 2 then self.dot_dmg_m = 1.25 + elseif main.current.voider_level == 1 then self.dot_dmg_m = 1.15 + else self.dot_dmg_m = 1 end end self.buff_def_a = (self.warrior_def_a or 0) - self.buff_aspd_m = (self.chronomancer_aspd_m or 1)*(self.vagrant_aspd_m or 1)*(self.outlaw_aspd_m or 1) - self.buff_dmg_m = (self.squire_dmg_m or 1)*(self.vagrant_dmg_m or 1)*(main.current.enchanter_dmg_m or 1)*(self.swordsman_dmg_m or 1) + self.buff_aspd_m = (self.chronomancer_aspd_m or 1)*(self.vagrant_aspd_m or 1)*(self.outlaw_aspd_m or 1)*(self.fairy_aspd_m or 1)*(self.psyker_aspd_m or 1) + self.buff_dmg_m = (self.squire_dmg_m or 1)*(self.vagrant_dmg_m or 1)*(self.enchanter_dmg_m or 1)*(self.swordsman_dmg_m or 1)*(self.flagellant_dmg_m or 1)*(self.psyker_dmg_m or 1) self.buff_def_m = (self.squire_def_m or 1) self.buff_area_size_m = (self.nuker_area_size_m or 1) self.buff_area_dmg_m = (self.nuker_area_dmg_m or 1) @@ -516,7 +652,7 @@ function Player:on_collision_enter(other, contact) end elseif table.any(main.current.enemies, function(v) return other:is(v) end) then - other:push(random:float(25, 35), self:angle_to_object(other)) + other:push(random:float(25, 35)*self.knockback_m, self:angle_to_object(other)) if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(2*self.dmg) else other:hit(self.dmg) end if other.headbutting then @@ -573,19 +709,29 @@ function Player:hit(damage) end if self.hp <= 0 then - hit4:play{pitch = random:float(0.95, 1.05), volume = 0.5} - slow(0.25, 1) - self.dead = true - for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end - HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color) - if self.leader and #self.followers == 0 then - main.current:die() - else - if self.leader then self:recalculate_followers() - else self.parent:recalculate_followers() end - end + if self.divined then + self:heal(self.max_hp) + heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end + HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color) + self.divined = false - if self.dot_area then self.dot_area.dead = true; self.dot_area = nil end + else + hit4:play{pitch = random:float(0.95, 1.05), volume = 0.5} + slow(0.25, 1) + self.dead = true + for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end + HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color) + if self.leader and #self.followers == 0 then + main.current:die() + else + if self.leader then self:recalculate_followers() + else self.parent:recalculate_followers() end + end + + if self.dot_area then self.dot_area.dead = true; self.dot_area = nil end + end end end @@ -790,7 +936,7 @@ function Player:attack(area, mods) character = self.character, level = self.level, parent = self} Area(table.merge(t, mods)) - if self.character == 'swordsman' or self.character == 'barbarian' or self.character == 'juggernaut' then + if self.character == 'swordsman' or self.character == 'barbarian' or self.character == 'juggernaut' or self.character == 'highlander' then _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} @@ -1110,7 +1256,7 @@ function Projectile:on_trigger_enter(other, contact) end if self.character == 'assassin' then - other:apply_dot(self.crit and 4*self.dmg or self.dmg/2, 3) + other:apply_dot((self.crit and 4*self.dmg or self.dmg/2)*self.dot_dmg_m*(main.current.chronomancer_dot), 3) end if self.parent.chain_infused then @@ -1145,7 +1291,7 @@ function Projectile:on_trigger_enter(other, contact) end if self.knockback then - other:push(self.knockback, self.r) + other:push(self.knockback*self.knockback_m, self.r) end end end @@ -1169,8 +1315,10 @@ function Area:init(args) enemy:hit(self.dmg + self.dmg*0.33*#enemies) elseif self.character == 'blade' and self.level == 3 then enemy:hit(self.dmg + self.dmg*0.5*#enemies) + elseif self.character == 'highlander' then + enemy:hit(6*self.dmg) elseif self.character == 'launcher' then - enemy:curse('launcher', 4, (self.level == 3 and 6*self.dmg or 2*self.dmg)) + enemy:curse('launcher', 4, (self.level == 3 and 6*self.dmg or 2*self.dmg), self.parent) else enemy:hit(self.dmg) end @@ -1179,7 +1327,7 @@ function Area:init(args) 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 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' then + elseif self.character == 'swordsman' or self.character == 'barbarian' or self.character == 'juggernaut' or self.character == 'highlander' then hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} elseif self.character == 'blade' then blade_hit1:play{pitch = random:float(0.9, 1.1), volume = 0.35} @@ -1199,7 +1347,7 @@ function Area:init(args) if self.juggernaut_push then local r = self.parent:angle_to_object(enemy) - enemy:push(random:float(75, 100), r) + enemy:push(random:float(75, 100)*self.knockback_m, r) enemy.juggernaut_push = 3*self.dmg end end @@ -1256,7 +1404,7 @@ function DotArea:init(args) pyro1:play{pitch = random:float(1.5, 1.8), volume = 0.1} enemy.pyrod = self end - enemy:hit(self.dmg/5) + enemy:hit(self.dot_dmg_m*self.dmg/5) 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 @@ -1274,7 +1422,7 @@ function DotArea:init(args) if self.level == 3 then enemy:slow(0.4, 4) end - enemy:hit(2*self.dmg) + enemy:hit(self.dot_dmg_m*2*self.dmg) 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 @@ -1293,7 +1441,7 @@ function DotArea:init(args) enemy:curse('bane', 0.5) if self.level == 3 then enemy:slow(0.5, 0.5) - enemy:hit(self.dmg/2) + enemy:hit(self.dot_dmg_m*self.dmg/2) 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 @@ -1383,7 +1531,7 @@ function ForceArea:init(args) local enemies = main.current.main:get_objects_in_shape(self.shape, main.current.enemies) for _, enemy in ipairs(enemies) do enemy:hit(4*self.parent.dmg) - enemy:push(50, self:angle_to_object(enemy)) + enemy:push(50*self.knockback_m, self:angle_to_object(enemy)) end end end) @@ -1615,7 +1763,7 @@ function Pet:on_trigger_enter(other) if self.pierce <= 0 then camera:shake(2, 0.5) other:hit(self.parent.dmg*(self.conjurer_buff_m or 1)) - other:push(35, self:angle_to_object(other)) + other:push(35*self.knockback_m, self:angle_to_object(other)) self.dead = true local n = random:int(3, 4) for i = 1, n do HitParticle{group = main.current.effects, x = x, y = y, r = random:float(0, 2*math.pi), color = self.color} end @@ -1623,7 +1771,7 @@ function Pet:on_trigger_enter(other) else camera:shake(2, 0.5) other:hit(self.parent.dmg*(self.conjurer_buff_m or 1)) - other:push(35, self:angle_to_object(other)) + other:push(35*self.knockback_m, self:angle_to_object(other)) self.pierce = self.pierce - 1 end hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} @@ -1717,8 +1865,8 @@ function Critter:init(args) self.invulnerable = true self.t:after(0.5, function() self.invulnerable = false end) - self.dmg = self.parent.dmg - self.hp = 1 + self.dmg = args.dmg or self.parent.dmg + self.hp = 1 + ((main.current.swarmer_level == 2 and 3) or (main.current.swarmer_level == 1 and 1) or 0) end @@ -1762,7 +1910,7 @@ end function Critter:hit(damage) if self.dead or self.invulnerable then return end self.hfx:use('hit', 0.25, 200, 10) - self.hp = self.hp - damage + self.hp = self.hp - 1 -- self:show_hp() if self.hp <= 0 then self:die() end end diff --git a/todo b/todo index 9347148..151a677 100644 --- a/todo +++ b/todo @@ -23,23 +23,23 @@ * Randomizer - randomly does the 4 ones above Orbitter - spawns shooters that orbit the boss -8. Additional characters and classes -9. Lv.3 effects for every character - Classes - Ranger: chance to release a barrage on attack - Warrior: increased defense - Mage: decreased enemy defense - Nuker: increased area damage and size - Rogue: chance to crit - Healer: increased healing effectiveness - Enchanter: increased damage - Conjurer: increased summon damage and duration - Psyker: increased damage and health based on number of active sets - Curser: increased curse effect and duration - Forcer: increased knockback force - Swarmer: increased critter health - Voider: increased damage over time - Characters +* 8. Additional characters and classes +* 9. Lv.3 effects for every character + * Classes + * Ranger: chance to release a barrage on attack + * Warrior: increased defense + * Mage: decreased enemy defense + * Nuker: increased area damage and size + * Rogue: chance to crit + * Healer: increased healing effectiveness + * Enchanter: increased damage + * Conjurer: increased summon damage and duration + * Psyker: increased damage and health based on number of active sets + * Curser: increased curse effect and duration + * Forcer: increased knockback force + * Swarmer: increased critter health + * Voider: increased damage over time + * Characters * Vagrant [psyker, ranger, warrior]: shoots a projectile - Lv.3: Champion - gains increased damage and attack speed based on number of active sets * Swordsman [warrior]: deals AoE damage, deals extra damage for each unit hit - Lv.3: Cleave - damage is doubled * Wizard [mage]: shoots a projectile that deals AoE damage - Lv.3: Magic Missile - the projectile chains 5 times, each dealing AoE damage on impact @@ -76,12 +76,12 @@ * Bane [curser, voider]: creates a large area that curses enemies to take increased damage - Lv.3: Nightmare - the area also deals DoT and slows enemies * Psykino [mage, psyker, forcer]: quickly pulls enemies together and then releases them with a force - Lv.3: Magnetic Force - enemies pulled together are forced to collide with each other before being released * Barrager [ranger, forcer]: shoots a barrage of 5 arrows that knocks enemies back - Lv.3: every 3rd attack the barrage shoots 15 projectiles and they push harder - Highlander [warrior]: creates a small area that deals massive damage - Lv.3: Crosscut - two crosscutting areas of larger size are created instead - Sapper [enchanter, voider, healer]: periodically steals health from nearby enemies and gain increased movement speed - Lv.3: Enduring Sap - sapped enemies permanently take damage over time, even outside the sapper's area of effect - Priest [healer]: heals all units periodically - Lv.3: Divine Intervention - at the start of the round pick 3 units at random and grants them a buff that prevents them from dying once - Infestor [curser, swarmer]: curses nearby enemies for 6 seconds, they will release multiple critters on death - Lv.3: Infestation - triples the number of critters released - Flagellant [psyker, enchanter]: periodically deals damage to self and grants a damage buff to all allies - Lv.3: Zealotry - deals damage to all allies instead and also grants a massive damage buff - Sets + * Highlander [warrior]: creates a small area that deals massive damage - Lv.3: Crosscut - two crosscutting areas of larger size are created instead + * Fairy [enchanter, healer]: periodically heals 1 random unit that has less than 100% HP and grants it +200% attack speed for 6 seconds - Lv.3: heals and buffs 2 units instead + * Priest [healer]: heals all units periodically - Lv.3: Divine Intervention - at the start of the round pick 3 units at random and grants them a buff that prevents them from dying once + * Infestor [curser, swarmer]: curses nearby enemies for 6 seconds, they will release multiple critters on death - Lv.3: Infestation - triples the number of critters released + * Flagellant [psyker, enchanter]: periodically deals damage to self and grants a damage buff to all allies - Lv.3: Zealotry - deals damage to all allies instead and also grants a massive damage buff + * Sets Ranger = 8/8 Warrior = 8/8 Mage = 8/8