diff --git a/arena.lua b/arena.lua index 1652c67..4113d89 100644 --- a/arena.lua +++ b/arena.lua @@ -943,7 +943,7 @@ function Arena:create_credits() open_url(b, 'https://freesound.org/people/benzix2/sounds/467951/') end} Button{group = self.credits, x = 204, y = 160, button_text = 'lord', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b) open_url(b, 'https://store.steampowered.com/developer/T_TGames') end} - Button{group = self.credits, x = 254, y = 160, button_text = 'InspectorJ', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b) + Button{group = self.credits, x = 262, y = 160, button_text = 'InspectorJ', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b) open_url(b, 'https://freesound.org/people/InspectorJ/sounds/458586/') end} Text2{group = self.credits, x = 70, y = 190, lines = {{text = '[red]playtesters: ', font = pixul_font}}} Button{group = self.credits, x = 130, y = 190, button_text = 'Jofer', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b) @@ -962,8 +962,8 @@ function Arena:create_credits() open_url(b, 'https://twitter.com/Ge0forceBE') end} Button{group = self.credits, x = 193, y = 210, button_text = 'Vlad', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b) open_url(b, 'https://twitter.com/thecryru') end} - Button{group = self.credits, x = 223, y = 210, button_text = 'F', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b) - open_url(b, 'https://twitter.com/notyps') end} + Button{group = self.credits, x = 258, y = 210, button_text = 'Yongmin Park', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b) + open_url(b, 'https://twitter.com/yongminparks') end} end diff --git a/buy_screen.lua b/buy_screen.lua index 9d66e8a..3548461 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -46,6 +46,7 @@ function BuyScreen:on_enter(from, level, loop, units, passives, shop_level, shop self.shop_level = shop_level self.shop_xp = shop_xp camera.x, camera.y = gw/2, gh/2 + max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) input:set_mouse_visible(true) @@ -698,7 +699,7 @@ end function GoButton:update(dt) self:update_game_object(dt) - if self.selected and input.m1.pressed and not self.transitioning then + if ((self.selected and input.m1.pressed) or input.enter.pressed) and not self.transitioning then if #self.parent.units == 0 then if not self.info_text then error1:play{pitch = random:float(0.95, 1.05), volume = 0.5} @@ -724,6 +725,8 @@ function GoButton:update(dt) main:go_to('arena', self.parent.level, self.parent.loop, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, self.parent.locked) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']level ' .. tostring(self.parent.level) .. '/' .. tostring(25*(self.parent.loop+1)), font = pixul_font, alignment = 'center'}}, global_text_tags)} end + + if input.enter.pressed then self.selected = false end end end @@ -998,7 +1001,7 @@ end function RerollButton:update(dt) self:update_game_object(dt) - if self.selected and input.m1.pressed then + if (self.selected and input.m1.pressed) or input.r.pressed then if self.parent:is(BuyScreen) then if gold < 2 then self.spring:pull(0.2, 200, 10) @@ -1045,6 +1048,8 @@ function RerollButton:update(dt) self.text = Text({{text = '[bg10]reroll: [yellow]5', font = pixul_font, alignment = 'center'}}, global_text_tags) end end + + if input.r.pressed then self.selected = false end end end @@ -1372,7 +1377,7 @@ function PassiveCard:update(dt) self:update_game_object(dt) self.passive_name:update(dt) - if self.selected and input.m1.pressed and self.arena.choosing_passives then + if ((self.selected and input.m1.pressed) or input[tostring(self.card_i)].pressed) and self.arena.choosing_passives then self.arena.choosing_passives = false table.insert(self.arena.passives, {passive = self.passive, level = 1, xp = 0}) self.arena:restore_passives_to_pool(self.card_i) @@ -1621,7 +1626,7 @@ end function ShopCard:update(dt) self:update_game_object(dt) - if self.selected and input.m1.pressed then + if (self.selected and input.m1.pressed) or input[tostring(self.i)].pressed then if self.parent:buy(self.unit, self.i) then ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} diff --git a/enemies.lua b/enemies.lua index 5eca980..22053b5 100644 --- a/enemies.lua +++ b/enemies.lua @@ -595,6 +595,7 @@ function Seeker:hit(damage, projectile, dot, from_enemy) if self.silenced or self.barbarian_stunned then return end critter1:play{pitch = random:float(0.95, 1.05), volume = 0.35} trigger:after(0.01, function() + if not main.current.main.world then return end for i = 1, random:int(5, 8) do EnemyCritter{group = main.current.main, x = self.x, y = self.y, color = purple[0], r = random:float(0, 2*math.pi), v = 10 + 0.1*self.level, dmg = 2*self.dmg, projectile = projectile} end @@ -645,7 +646,7 @@ function Seeker:hit(damage, projectile, dot, from_enemy) if self.bane_cursed then trigger:after(0.01, function() - DotArea{group = main.current.effects, x = self.x, y = self.y, rs = (self.bane_ref.level == 3 and 2 or 1)*self.bane_ref.area_size_m*18, color = purple[0], + DotArea{group = main.current.effects, x = self.x, y = self.y, rs = (self.bane_ref.level == 3 and 2 or 1)*self.bane_ref.area_size_m*27, color = purple[0], dmg = self.bane_ref.area_dmg_m*self.bane_ref.dmg*(self.bane_ref.dot_dmg_m or 1), void_rift = true, duration = 1} end) end diff --git a/main.lua b/main.lua index 3d9e853..384f3e1 100644 --- a/main.lua +++ b/main.lua @@ -615,7 +615,7 @@ function init() ['chronomancer'] = function(lvl) return '[yellow]+20%[fg] attack speed to all allies' end, ['spellblade'] = function(lvl) return '[fg]throws knives that deal [yellow]' .. get_character_stat('spellblade', lvl, 'dmg') .. '[fg] damage, pierce and spiral outwards' end, ['psykeeper'] = function(lvl) return '[fg]creates [yellow]3[fg] healing orbs every time the psykeeper takes [yellow]25%[fg] of its max HP in damage' end, - ['engineer'] = function(lvl) return '[fg]drops sentries that shoot bursts of projectiles, each dealing [yellow]' .. get_character_stat('engineer', lvl, 'dmg') .. '[fg] damage' end, + ['engineer'] = function(lvl) return '[fg]drops turrets that shoot bursts of projectiles, each dealing [yellow]' .. get_character_stat('engineer', lvl, 'dmg') .. '[fg] damage' end, ['plague_doctor'] = function(lvl) return '[fg]creates an area that deals [yellow]' .. get_character_stat('plague_doctor', lvl, 'dmg') .. '[fg] damage per second' end, ['barbarian'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('barbarian', lvl, 'dmg') .. '[fg] AoE damage and stuns enemies hit for [yellow]4[fg] seconds' end, ['juggernaut'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('juggernaut', lvl, 'dmg') .. '[fg] AoE damage and pushes enemies away with a strong force' end, @@ -657,7 +657,7 @@ function init() ['vagrant'] = '[fg]Experience', ['swordsman'] = '[yellow]Cleave', ['wizard'] = '[blue]Magic Missile', - ['magician'] = '[blue]Ethereal Form', + ['magician'] = '[blue]Quick Cast', ['archer'] = '[green]Bounce Shot', ['scout'] = '[red]Dagger Resonance', ['cleric'] = '[green]Mass Heal', @@ -717,7 +717,7 @@ function init() ['vagrant'] = '[light_bg]Experience', ['swordsman'] = '[light_bg]Cleave', ['wizard'] = '[light_bg]Magic Missile', - ['magician'] = '[light_bg]Ethereal Form', + ['magician'] = '[light_bg]Quick Cast', ['archer'] = '[light_bg]Bounce Shot', ['scout'] = '[light_bg]Dagger Resonance', ['cleric'] = '[light_bg]Mass Heal ', @@ -777,7 +777,7 @@ function init() ['vagrant'] = function() return '[yellow]+15%[fg] attack speed and damage per active class' end, ['swordsman'] = function() return "[fg]the swordsman's damage is [yellow]doubled" 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 but also cannot attack' end, + ['magician'] = function() return '[yellow]+50%[[fg] attack speed every [yellow]12[fg] seconds 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]creates [yellow]4[fg] healing orbs every [yellow]8[fg] seconds' end, @@ -792,7 +792,7 @@ function init() ['cannoneer'] = function() return '[fg]showers the hit area in [yellow]7[fg] additional cannon shots that deal [yellow]' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. '[fg] AoE damage' end, ['dual_gunner'] = function() return '[fg]every 5th attack shoot in rapid succession for [yellow]2[fg] seconds' end, ['hunter'] = function() return '[fg]summons [yellow]3[fg] pets and the pets ricochet off walls once' end, - ['sentry'] = function() return '[yellow]+50%[fg] sentry attack speed and the projectiles ricochet [yellow]twice[fg]' end, + ['sentry'] = function() return '[yellow]+50%[fg] sentry turret attack speed and the projectiles ricochet [yellow]twice[fg]' end, ['chronomancer'] = function() return '[fg]enemies take damage over time [yellow]50%[fg] faster' end, ['spellblade'] = function() return '[fg]faster projectile speed and tighter turns' end, ['psykeeper'] = function() return '[fg]deal [yellow]double[fg] the damage taken by the psykeeper to all enemies' end, @@ -837,7 +837,7 @@ function init() ['vagrant'] = function() return '[light_bg]+15% attack speed and damage per active class' 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 but also cannot attack' end, + ['magician'] = function() return '[light_bg]+50% attack speed every 12 seconds 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]creates 4 healing orbs' end, @@ -852,7 +852,7 @@ function init() ['cannoneer'] = function() return '[light_bg]showers the hit area in 7 additional cannon shots that deal ' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. ' AoE damage' end, ['dual_gunner'] = function() return '[light_bg]every 5th attack shoot in rapid succession for 2 seconds' end, ['hunter'] = function() return '[light_bg]summons 3 pets and the pets ricochet off walls once' end, - ['sentry'] = function() return '[light_bg]+50% attack speed and the projectiles ricochet twice' end, + ['sentry'] = function() return '[light_bg]+50% sentry turret attack speed and the projectiles ricochet twice' end, ['chronomancer'] = function() return '[light_bg]enemies take damage over time 50% faster' end, ['spellblade'] = function() return '[light_bg]faster projectile speed and tighter turns' end, ['psykeeper'] = function() return '[light_bg]deal double the damage taken by the psykeeper to all enemies' end, @@ -1731,15 +1731,10 @@ function init() 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', 'kinetic_strike', } main:add(Arena'arena') - main:go_to('arena', 7, 0, { - {character = 'arcanist', level = 1}, - {character = 'artificer', level = 1}, - {character = 'witch', level = 1}, - {character = 'warden', level = 3}, - {character = 'psychic', level = 1}, - {character = 'vulcanist', level = 1}, + main:go_to('arena', 21, 0, { + {character = 'magician', level = 3}, }, { - {passive = 'magnify', level = 3}, + {passive = 'awakening', level = 3}, }) ]]-- diff --git a/player.lua b/player.lua index 27d097c..b397a03 100644 --- a/player.lua +++ b/player.lua @@ -49,8 +49,8 @@ function Player:init(args) 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') + self.magician_aspd_m = 1.5 + self.t:after(6, function() self.magician_aspd_m = 1 end, 'magician_aspd_m') end) end @@ -230,7 +230,7 @@ function Player:init(args) end) end end - end) + end, nil, nil, 'spawn') elseif self.character == 'outlaw' then self.attack_sensor = Circle(self.x, self.y, 96) @@ -411,7 +411,7 @@ function Player:init(args) SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = orange[0], action = function(x, y) Turret{group = main.current.main, x = x, y = y, parent = self} end} - end) + end, nil, nil, 'spawn') if self.level == 3 then self.t:every(24, function() @@ -480,7 +480,7 @@ function Player:init(args) elseif self.character == 'cryomancer' then self.t:after(0.01, function() - self.dot_area = DotArea{group = main.current.effects, x = self.x, y = self.y, rs = self.area_size_m*48, color = self.color, dmg = self.area_dmg_m*self.dmg, character = self.character, level = self.level, parent = self} + self.dot_area = DotArea{group = main.current.effects, x = self.x, y = self.y, rs = self.area_size_m*72, color = self.color, dmg = self.area_dmg_m*self.dmg, character = self.character, level = self.level, parent = self} end) elseif self.character == 'pyromancer' then @@ -679,8 +679,12 @@ function Player:init(args) 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) + local unit_1 = random:table(units) + local runs = 0 + while table.any(non_attacking_characters, function(v) return v == unit_1 end) and runs < 1000 do unit_1 = random:table(units); runs = runs + 1 end + local unit_2 = random:table(units) + local runs = 0 + while table.any(non_attacking_characters, function(v) return v == unit_2 end) and runs < 1000 do unit_2 = random:table(units); runs = runs + 1 end if unit_1 then unit_1.fairy_aspd_m = 3 unit_1.fairyd = true @@ -711,6 +715,8 @@ function Player:init(args) else local unit = random:table(self:get_all_units()) + local runs = 0 + while table.any(non_attacking_characters, function(v) return v == unit end) and runs < 1000 do unit = random:table(self:get_all_units()); runs = runs + 1 end if unit then unit.fairyd = true unit.fairy_aspd_m = 2 @@ -918,6 +924,8 @@ function Player:init(args) end end local mage = random:table(mages) + local runs = 0 + while table.any(non_attacking_characters, function(v) return v == mage end) and runs < 1000 do mage = random:table(mages); runs = runs + 1 end if mage then mage.awakening_aspd_m = (self.awakening == 1 and 1.5) or (self.awakening == 2 and 1.75) or (self.awakening == 3 and 2) mage.awakening_dmg_m = (self.awakening == 1 and 1.5) or (self.awakening == 2 and 1.75) or (self.awakening == 3 and 2) @@ -1002,6 +1010,8 @@ function Player:init(args) if enchanter_amount >= 2 then local unit = random:table(units) + local runs = 0 + while table.any(non_attacking_characters, function(v) return v == unit end) and runs < 1000 do unit = random:table(units); runs = runs + 1 end unit.enchanted_aspd_m = (self.enchanted == 1 and 1.33) or (self.enchanted == 2 and 1.66) or (self.enchanted == 3 and 1.99) end end) @@ -1317,7 +1327,7 @@ function Player:update(dt) 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.fairy_aspd_m or 1)*(self.psyker_aspd_m or 1)*(self.chronomancy_aspd_m or 1)*(self.awakening_aspd_m or 1)*(self.berserking_aspd_m or 1)*(self.reinforce_aspd_m or 1)*(self.squire_aspd_m or 1)*(self.speed_3_aspd_m or 1)*(self.last_stand_aspd_m or 1)*(self.enchanted_aspd_m or 1)*(self.explorer_aspd_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.chronomancy_aspd_m or 1)*(self.awakening_aspd_m or 1)*(self.berserking_aspd_m or 1)*(self.reinforce_aspd_m or 1)*(self.squire_aspd_m or 1)*(self.speed_3_aspd_m or 1)*(self.last_stand_aspd_m or 1)*(self.enchanted_aspd_m or 1)*(self.explorer_aspd_m or 1)*(self.magician_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.ballista_dmg_m or 1)*(self.awakening_dmg_m or 1)*(self.reinforce_dmg_m or 1)*(self.payback_dmg_m or 1)*(self.immolation_dmg_m or 1)*(self.damage_4_dmg_m or 1)*(self.offensive_stance_dmg_m or 1)*(self.last_stand_dmg_m or 1)*(self.dividends_dmg_m or 1)*(self.explorer_dmg_m or 1) self.buff_def_m = (self.squire_def_m or 1)*(self.ouroboros_def_m or 1)*(self.unwavering_stance_def_m or 1)*(self.reinforce_def_m or 1)*(self.defensive_stance_def_m or 1)*(self.last_stand_def_m or 1)*(self.unrelenting_stance_def_m or 1)*(self.hardening_def_m or 1) self.buff_area_size_m = (self.nuker_area_size_m or 1)*(self.magnify_area_size_m or 1)*(self.unleash_area_size_m or 1)*(self.last_stand_area_size_m or 1) @@ -1689,7 +1699,7 @@ function Player:sorcerer_repeat() if self.freezing_field then frost1:play{pitch = random:float(0.8, 1.2), volume = 0.3} elementor1:play{pitch = random:float(0.9, 1.1), volume = 0.3} - Area{group = main.current.effects, x = enemy.x, y = enemy.y, w = self.area_size_m*36, color = fg[0], character = 'freezing_field', parent = self} + Area{group = main.current.effects, x = enemy.x, y = enemy.y, w = self.area_size_m*36, color = blue[0], character = 'freezing_field', parent = self} end end end @@ -1779,6 +1789,7 @@ function Player:shoot(r, mods) local dmg_m = 1 local crit = false + if self.character == 'beastmaster' then crit = random:bool(10) end if self.chance_to_crit and random:bool(self.chance_to_crit) then dmg_m = ((self.assassination == 1 and 8) or (self.assassination == 2 and 10) or (self.assassination == 3 and 12) or 4); crit = true end if self.assassination and table.any(self.classes, function(v) return v == 'rogue' end) then if not crit then diff --git a/todo b/todo index d691617..111ec18 100644 --- a/todo +++ b/todo @@ -1,5 +1,28 @@ Weekly maintenance updates: +#3 + + * Fixed a bug that would cause incorrect party size after loading a looped run (thanks ArnaudOechslin https://github.com/a327ex/SNKRX/pull/15) + * Fixed a rare crash due to enemy critters being spawned during a level transition + * Improved descriptions for engineer and sentry to avoid confusion + * Fixed engineer's and artificer's cooldown not being displayed properly + * Changed freezing field's color to blue for better visual clarity + * Increased cryomancer's area of effect by 50% + * Increased bane's void rift's size by 50% + * Beastmaster now has 10% crit chance by default + * The fairy will no longer buff non-attacking units + * Awakening and enchanted items will no longer buff non-attacking units + * Changed magician's Lv.3 effect to "+50% attack speed every 12 seconds for 6 seconds" + Added the following keyboard shortcuts: + While in the shop: + * R rerolls units + * 1, 2, 3 buys units + * Enter/space starts the round + While in the item selection screen: + * R rerolls items + * 1, 2, 3, 4 buys items + * Credit yongminparks + #2 * Fixed a bug where NG+5 difficulty would go down to NG+4 after looping