diff --git a/arena.lua b/arena.lua index 2b74564..e0cb96d 100644 --- a/arena.lua +++ b/arena.lua @@ -53,6 +53,8 @@ function Arena:on_enter(from, level, units, passives, shop_level, shop_xp, lock) self.main:enable_trigger_between('projectile', 'enemy') self.main:enable_trigger_between('enemy_projectile', 'player') self.main:enable_trigger_between('player', 'enemy_projectile') + self.main:enable_trigger_between('enemy_projectile', 'enemy') + self.main:enable_trigger_between('enemy', 'enemy_projectile') self.main:enable_trigger_between('player', 'ghost') self.main:enable_trigger_between('ghost', 'player') @@ -407,7 +409,7 @@ function Arena:update(dt) main:add(BuyScreen'buy_screen') locked_state = nil system.save_run() - main:go_to('buy_screen', 0, {}, passives, 1, 0) + main:go_to('buy_screen', 1, {}, passives, 1, 0) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} end} @@ -595,7 +597,7 @@ function Arena:update(dt) main:add(BuyScreen'buy_screen') locked_state = nil system.save_run() - main:go_to('buy_screen', 0, {}, passives, 1, 0) + main:go_to('buy_screen', 1, {}, passives, 1, 0) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} end @@ -863,8 +865,16 @@ function Arena:quit() trigger:tween(1, _G, {slow_amount = 0}, math.linear, function() slow_amount = 0 end, 'slow_amount') trigger:tween(4, camera, {x = gw/2, y = gh/2, r = 0}, math.linear, function() camera.x, camera.y, camera.r = gw/2, gh/2, 0 end) self:set_passives() - RerollButton{group = main.current.ui, x = 40, y = 40, parent = self, force_update = true} + RerollButton{group = main.current.ui, x = gw - 40, y = 40, parent = self, force_update = true} self.shop_text = Text({{text = '[wavy_mid, fg]gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}, global_text_tags) + + self.build_text = Text2{group = self.ui, x = 40, y = 20, force_update = true, lines = {{text = "[wavy_mid, fg]your build", font = pixul_font, alignment = 'center'}}} + for i, unit in ipairs(self.units) do + CharacterPart{group = self.ui, x = 20, y = 40 + (i-1)*19, character = unit.character, level = unit.level, force_update = true, cant_click = true, parent = self} + Text2{group = self.ui, x = 20 + 14 + pixul_font:get_text_width(unit.character)/2, y = 40 + (i-1)*19, force_update = true, lines = { + {text = '[' .. character_color_strings[unit.character] .. ']' .. unit.character, font = pixul_font, alignment = 'left'} + }} + end else self:transition() end @@ -890,15 +900,15 @@ function Arena:set_passives(from_reroll) local passive_2 = random:table_remove(run_passive_pool) local passive_3 = random:table_remove(run_passive_pool) if passive_1 then - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 0*(card_w + 20) + card_w/2, y = gh/2 - 6, w = card_w, h = card_h, card_i = 1, arena = self, passive = passive_1, force_update = true}) + table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 0*(card_w + 20) + card_w/2 + 45, y = gh/2 - 6 + 10, w = card_w, h = card_h, card_i = 1, arena = self, passive = passive_1, force_update = true}) end if passive_2 then - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 1*(card_w + 20) + card_w/2, y = gh/2 - 6, w = card_w, h = card_h, card_i = 2, arena = self, passive = passive_2, force_update = true}) + table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 1*(card_w + 20) + card_w/2 + 45, y = gh/2 - 6 + 10, w = card_w, h = card_h, card_i = 2, arena = self, passive = passive_2, force_update = true}) end if passive_3 then - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 2*(card_w + 20) + card_w/2, y = gh/2 - 6, w = card_w, h = card_h, card_i = 3, arena = self, passive = passive_3, force_update = true}) + table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 2*(card_w + 20) + card_w/2 + 45, y = gh/2 - 6 + 10, w = card_w, h = card_h, card_i = 3, arena = self, passive = passive_3, force_update = true}) end - self.passive_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 65, lines = {{text = '[fg, wavy]choose one', font = fat_font, alignment = 'center'}}} + self.passive_text = Text2{group = self.ui, x = gw/2 + 45, y = gh/2 - 65 + 10, lines = {{text = '[fg, wavy]choose one', font = fat_font, alignment = 'center'}}} if not passive_1 and not passive_2 and not passive_3 then self:transition() end @@ -965,7 +975,7 @@ function Arena:draw() if self.choosing_passives or self.won or self.paused or self.died then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end self.ui:draw() - if self.shop_text then self.shop_text:draw(40, 20) end + if self.shop_text then self.shop_text:draw(gw - 40, 20) end if self.in_credits then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent_2) end self.credits:draw() @@ -1007,7 +1017,7 @@ function Arena:die() max_units = 7 + current_new_game_plus main:add(BuyScreen'buy_screen') system.save_run() - main:go_to('buy_screen', 0, {}, passives, 1, 0) + main:go_to('buy_screen', 1, {}, passives, 1, 0) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} end} end) @@ -1078,7 +1088,7 @@ end function Arena:gain_gold() local merchant = self.player:get_unit'merchant' self.gold_gained = random:int(level_to_gold_gained[self.level][1], level_to_gold_gained[self.level][2]) - self.interest = math.min(math.floor(gold/5), 5) + (merchant and math.floor(gold/10) or 0) + self.interest = math.min(math.floor(gold/5), 5) + math.min((merchant and math.floor(gold/10) or 0), 10) gold = gold + self.gold_gained + self.gold_picked_up + self.interest end @@ -1103,8 +1113,8 @@ function Arena:transition() end slow_amount = 1 main:add(BuyScreen'buy_screen') - system.save_run(self.level, gold, self.units, self.passives, self.shop_level, self.shop_xp, run_passive_pool, locked_state) - main:go_to('buy_screen', self.level, self.units, self.passives, self.shop_level, self.shop_xp) + system.save_run(self.level+1, gold, self.units, self.passives, self.shop_level, self.shop_xp, run_passive_pool, locked_state) + main:go_to('buy_screen', self.level+1, self.units, self.passives, self.shop_level, self.shop_xp) t.t:after(0.1, function() t.text:set_text({ {text = '[nudge_down, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']gold gained: ' .. tostring(self.gold_gained or 0) .. ' + ' .. tostring(self.gold_picked_up or 0), font = pixul_font, diff --git a/assets/sounds/Weapon Swap 2.ogg b/assets/sounds/Weapon Swap 2.ogg new file mode 100644 index 0000000..37ab3b8 Binary files /dev/null and b/assets/sounds/Weapon Swap 2.ogg differ diff --git a/buy_screen.lua b/buy_screen.lua index 3a40652..b514cc1 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -48,10 +48,7 @@ function BuyScreen:on_enter(from, level, units, passives, shop_level, shop_xp) input:set_mouse_visible(true) - if self.level == 0 then - main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5} - self.level = 1 - self.first_screen = true + if self.level == 1 then end steam.friends.setRichPresence('steam_display', '#StatusFull') @@ -79,9 +76,9 @@ function BuyScreen:on_enter(from, level, units, passives, shop_level, shop_xp) elseif lvl % 3 == 0 then return ' (hard)' else return '' end end - self.level_text = Text({{text = '[fg]Lv.' .. tostring(level == 0 and 1 or self.level+1) .. get_elite_str(self.level+1), font = pixul_font, alignment = 'center'}}, global_text_tags) + self.level_text = Text({{text = '[fg]Lv.' .. tostring(self.level) .. get_elite_str(self.level), font = pixul_font, alignment = 'center'}}, global_text_tags) - if not self.first_screen then RerollButton{group = self.main, x = 150, y = 18, parent = self} end + RerollButton{group = self.main, x = 150, y = 18, parent = self} GoButton{group = self.main, x = gw - 90, y = gh - 20, parent = self} LevelButton{group = self.main, x = gw/2, y = 18, parent = self} self.tutorial_button = Button{group = self.main, x = gw/2 + 134, y = 18, button_text = '?', fg_color = 'bg10', bg_color = 'bg', action = function() @@ -152,7 +149,7 @@ function BuyScreen:on_enter(from, level, units, passives, shop_level, shop_xp) max_units = 7 + current_new_game_plus main:add(BuyScreen'buy_screen') system.save_run() - main:go_to('buy_screen', 0, {}, passives, 1, 0) + main:go_to('buy_screen', 1, {}, passives, 1, 0) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} end, mouse_enter = function(b) b.info_text = InfoText{group = main.current.ui, force_update = true} @@ -177,6 +174,9 @@ function BuyScreen:on_enter(from, level, units, passives, shop_level, shop_xp) self.t:tween(0.2, self.screen_text, {sy = 0}, math.linear, function() self.screen_text.sy = 0 end) end) end + + locked_state = {locked = self.locked, cards = {self.cards[1] and self.cards[1].unit, self.cards[2] and self.cards[2].unit, self.cards[3] and self.cards[3].unit}} + system.save_run(self.level, gold, self.units, self.passives, self.shop_level, self.shop_xp, run_passive_pool, locked_state) end @@ -345,7 +345,7 @@ function BuyScreen:set_cards(shop_level, dont_spawn_effect, first_call) unit_3 = random:table(tier_to_characters[random:weighted_pick(unpack(tier_weights))]) all_units = {unit_1, unit_2, unit_3} until not table.all(all_units, function(v) return table.any(non_attacking_characters, function(u) return v == u end) end) - if first_call and self.locked then + if first_call and locked_state then if locked_state.cards[1] then self.cards[1] = ShopCard{group = self.main, x = 60, y = 75, w = 80, h = 90, unit = locked_state.cards[1], parent = self, i = 1} end if locked_state.cards[2] then self.cards[2] = ShopCard{group = self.main, x = 140, y = 75, w = 80, h = 90, unit = locked_state.cards[2], parent = self, i = 2} end if locked_state.cards[3] then self.cards[3] = ShopCard{group = self.main, x = 220, y = 75, w = 80, h = 90, unit = locked_state.cards[3], parent = self, i = 3} end @@ -539,7 +539,7 @@ function RestartButton:update(dt) system.save_state() main:add(BuyScreen'buy_screen') system.save_run() - main:go_to('buy_screen', 0, {}, passives, 1, 0) + main:go_to('buy_screen', 1, {}, passives, 1, 0) end, text = Text({{text = '[wavy, ' .. tostring(state.dark_transitions and 'fg' or 'bg') .. ']restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} end end @@ -685,11 +685,11 @@ function GoButton:update(dt) ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} ui_transition1:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.transitioning = true - system.save_run(self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) TransitionEffect{group = main.transitions, x = self.x, y = self.y, color = state.dark_transitions and bg[-2] or character_colors[random:table(self.parent.units).character], transition_action = function() main:add(Arena'arena') - main:go_to('arena', ((self.parent.first_screen and 1) or (self.parent.level + 1)), 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 ' .. ((self.parent.first_screen and 1) or (self.parent.level + 1)) .. '/25', font = pixul_font, alignment = 'center'}}, global_text_tags)} + main:go_to('arena', self.parent.level, 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) .. '/25', font = pixul_font, alignment = 'center'}}, global_text_tags)} end end end @@ -739,7 +739,7 @@ function LockButton:update(dt) if not self.parent.locked then locked_state = nil end if self.parent.locked then locked_state = {locked = true, cards = {self.parent.cards[1] and self.parent.cards[1].unit, self.parent.cards[2] and self.parent.cards[2].unit, self.parent.cards[3] and self.parent.cards[3].unit}} - system.save_run(self.parent.level == 1 and 0 or self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) end ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.selected = true @@ -820,7 +820,7 @@ function LevelButton:update(dt) gold = gold - 5 self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} self.text = Text({{text = '[bg10]' .. tostring(self.parent.shop_level), font = pixul_font, alignment = 'center'}}, global_text_tags) - system.save_run(self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) end end end @@ -950,7 +950,7 @@ function RerollButton:update(dt) self.spring:pull(0.2, 200, 10) gold = gold - 2 self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} - system.save_run(self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) end elseif self.parent:is(Arena) then if gold < 10 and not self.free_reroll then @@ -1154,12 +1154,14 @@ function CharacterPart:update(dt) self:die() self.parent:set_party_and_sets() self.parent:refresh_cards() + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) else self.parent.parent:gain_gold(self:get_sale_price()) self.parent.parent.units[self.i].reserve[self.level] = self.parent.parent.units[self.i].reserve[self.level] - 1 self:die() self.parent.parent:set_party_and_sets() self.parent.parent:refresh_cards() + system.save_run(self.parent.parent.level, gold, self.parent.parent.units, self.parent.parent.passives, self.parent.parent.shop_level, self.parent.parent.shop_xp, run_passive_pool, locked_state) end end @@ -1330,7 +1332,7 @@ function PassiveCard:on_mouse_enter() self.info_text:activate({ {text = self.passive_description, font = pixul_font, alignment = 'center', height_multiplier = 1.25}, }, nil, nil, nil, nil, 16, 4, nil, 2) - self.info_text.x, self.info_text.y = gw/2, gh/2 + gh/4 + 12 + self.info_text.x, self.info_text.y = gw/2, gh/2 + gh/4 + 22 end @@ -1399,7 +1401,7 @@ function ItemCard:update(dt) self.selected = true self.spring:pull(0.2, 200, 10) gold = gold - 5 - for _, passive in ipairs(passives) do + for _, passive in ipairs(self.parent.passives) do if passive.passive == self.passive then passive.level = self.level passive.xp = self.xp @@ -1407,7 +1409,7 @@ function ItemCard:update(dt) end self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} self.text = Text({{text = '[bg10]' .. tostring(self.parent.shop_level), font = pixul_font, alignment = 'center'}}, global_text_tags) - system.save_run(self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) end end end @@ -1543,7 +1545,8 @@ function ShopCard:update(dt) self:die() self.parent.cards[self.i] = nil self.parent:refresh_cards() - system.save_run(self.parent.level == 1 and 0 or self.parent.level, gold, self.parent.units, passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) + locked_state = {locked = self.parent.locked, cards = {self.parent.cards[1] and self.parent.cards[1].unit, self.parent.cards[2] and self.parent.cards[2].unit, self.parent.cards[3] and self.parent.cards[3].unit}} + system.save_run(self.parent.level, gold, self.parent.units, self.parent.passives, self.parent.shop_level, self.parent.shop_xp, run_passive_pool, locked_state) else error1:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.spring:pull(0.2, 200, 10) diff --git a/enemies.lua b/enemies.lua index 2be1706..0af918d 100644 --- a/enemies.lua +++ b/enemies.lua @@ -225,7 +225,7 @@ function Seeker:init(args) local n = math.remap(current_new_game_plus, 0, 5, 1, 0.5) self.t:after({2*n, 4*n}, function() self.shooting = true - self.t:every({3, 5}, function() + self.t:every({4, 6}, 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() @@ -233,8 +233,8 @@ function Seeker:init(args) self.hfx:use('hit', 0.25, 200, 10, 0.1) local r = self.r HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r), y = self.y + 0.8*self.shape.w*math.sin(r), rs = 6} - EnemyProjectile{group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), color = fg[0], r = r, v = 140 + 5*self.level + 4*current_new_game_plus, - dmg = (current_new_game_plus*0.1 + 1)*self.dmg} + EnemyProjectile{group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), color = fg[0], r = r, v = 140 + 3.5*self.level + 2*current_new_game_plus, + dmg = (current_new_game_plus*0.1 + 1)*self.dmg, source = 'shooter'} end) end end, nil, nil, 'shooter') @@ -473,7 +473,7 @@ function Seeker:hit(damage, projectile, dot) _G[random:table{'enemy_die1', 'enemy_die2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.5} if main.current.mercenary_level > 0 then - if random:bool((main.current.mercenary_level == 2 and 20) or (main.current.mercenary_level == 1 and 10) or 0) then + if random:bool((main.current.mercenary_level == 2 and 16) or (main.current.mercenary_level == 1 and 8) or 0) then trigger:after(0.01, function() Gold{group = main.current.main, x = self.x, y = self.y} end) @@ -500,12 +500,9 @@ function Seeker:hit(damage, projectile, dot) if self.exploder then if self.silenced then return end - shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.4} + mine1:play{pitch = random:float(0.95, 1.05), volume = 0.5} trigger:after(0.01, function() - local n = math.floor(8 + current_new_game_plus*1.5) - for i = 1, n do - EnemyProjectile{group = main.current.main, x = self.x, y = self.y, color = blue[0], r = (i-1)*math.pi/(n/2), v = 120 + 5*self.level, dmg = 1.5*self.dmg} - end + ExploderMine{group = main.current.main, x = self.x, y = self.y, color = blue[0], parent = self} end) end @@ -573,8 +570,9 @@ end function Seeker:push(f, r, push_invulnerable) local n = 1 - if self.tank then n = 0.4 - 0.01*self.level end - if self.boss then n = 0.1 end + if self.tank then n = 0.7 end + if self.boss then n = 0.2 end + if self.level == 25 and self.boss then n = 0.7 end self.push_invulnerable = push_invulnerable self.push_force = n*f self.being_pushed = true @@ -672,6 +670,50 @@ function Seeker:apply_dot(dmg, duration) end +ExploderMine = Object:extend() +ExploderMine:implement(GameObject) +function ExploderMine:init(args) + self:init_game_object(args) + self.hfx:add('hit', 1) + self.vr = 0 + self.dvr = random:float(-math.pi/4, math.pi/4) + self.rs = 0 + self.t:tween(0.05, self, {rs = args.rs}, math.cubic_in_out, function() + self.spring:pull(0.15) + self.t:every(0.8 - current_new_game_plus*0.1, function() + mine1:play{pitch = 1 + self.t:get_every_iteration'mine_count'*0.1, volume = 0.5} + self.spring:pull(0.5, 200, 10) + self.hfx:use('hit', 0.5, 200, 10, 0.2) + end, 3, function() + shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.4} + cannoneer1:play{pitch = random:float(0.95, 1.05), volume = 0.4} + for i = 1, 4 do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end + HitCircle{group = main.current.effects, x = self.x, y = self.y} + local n = math.floor(8 + current_new_game_plus*1.5) + for i = 1, n do + EnemyProjectile{group = main.current.main, x = self.x, y = self.y, color = blue[0], r = (i-1)*math.pi/(n/2), v = 120 + 5*self.parent.level, dmg = 1.5*self.parent.dmg} + end + self.dead = true + end, 'mine_count') + end) + --[[ + ]]-- +end + + +function ExploderMine:update(dt) + self:update_game_object(dt) + self.vr = self.vr + self.dvr*dt +end + + +function ExploderMine:draw() + graphics.push(self.x, self.y, 0, self.spring.x, self.spring.x) + graphics.circle(self.x, self.y, 2.5, self.hfx.hit.f and fg[0] or self.color) + graphics.pop() +end + + EnemyCritter = Object:extend() @@ -930,5 +972,11 @@ function EnemyProjectile:on_trigger_enter(other, contact) self:die(self.x, self.y, nil, random:int(2, 3)) other:hit(1000) end + + elseif other:is(Seeker) or other:is(EnemyCritter) then + if self.source == 'shooter' then + self:die(self.x, self.y, nil, random:int(2, 3)) + other:hit(0.5*self.dmg) + end end end diff --git a/main.lua b/main.lua index 96bd7bc..4cd504a 100644 --- a/main.lua +++ b/main.lua @@ -18,6 +18,7 @@ function init() input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'}) local s = {tags = {sfx}} + mine1 = Sound('Weapon Swap 2.ogg', s) level_up1 = Sound('Buff 4.ogg', s) unlock1 = Sound('Unlock 3.ogg', s) gambler1 = Sound('Collect 5.ogg', s) @@ -565,8 +566,8 @@ function init() ['lich'] = function(lvl) return '[fg]launches a slow projectile that jumps [yellow]7[fg] times, dealing [yellow]' .. 2*get_character_stat('lich', lvl, 'dmg') .. '[fg] damage per hit' end, ['cryomancer'] = function(lvl) return '[fg]nearby enemies take [yellow]' .. get_character_stat('cryomancer', lvl, 'dmg') .. '[fg] damage per second' end, ['pyromancer'] = function(lvl) return '[fg]nearby enemies take [yellow]' .. get_character_stat('pyromancer', lvl, 'dmg') .. '[fg] damage per second' end, - ['corruptor'] = function(lvl) return '[fg]spawn [yellow]3[fg] small critters if the corruptor kills an enemy' end, - ['beastmaster'] = function(lvl) return '[fg]spawn [yellow]2[fg] small critters if the beastmaster crits' end, + ['corruptor'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('corruptor', lvl, 'dmg') .. '[fg] damage, spawn [yellow]3[fg] critters if it kills' end, + ['beastmaster'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. get_character_stat('beastmaster', lvl, 'dmg') .. '[fg] damage, spawn [yellow]2[fg] critters if it 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]6[fg] nearby enemies for [yellow]6[fg] seconds, they will explode into [yellow]4[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]' .. @@ -589,7 +590,7 @@ function init() ['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') .. ' AoE[fg] damage' end, ['miner'] = function(lvl) return '[fg]picking up gold releases [yellow]4[fg] homing projectiles that each deal [yellow]' .. get_character_stat('miner', lvl, 'dmg') .. ' [fg]damage' end, - ['merchant'] = function(lvl) return '[fg]gain [yellow]+1[fg] interest for every [yellow]10[fg] gold' end, + ['merchant'] = function(lvl) return '[fg]gain [yellow]+1[fg] interest for every [yellow]10[fg] gold, up to a max of [yellow]+10[fg] from the merchant' end, ['usurer'] = function(lvl) return '[fg]curses [yellow]3[fg] nearby enemies indefinitely with debt, dealing [yellow]' .. get_character_stat('usurer', lvl, 'dmg') .. '[fg] damage per second' end, ['gambler'] = function(lvl) return '[fg]deal [yellow]2X[fg] damage to a single random enemy where X is how much gold you have' end, ['thief'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. 2*get_character_stat('thief', lvl, 'dmg') .. '[fg] damage and chains [yellow]5[fg] times' end, @@ -737,8 +738,8 @@ function init() ['lich'] = function() return '[fg]chain frost slows enemies hit by [yellow]80%[fg] for [yellow]2[fg] seconds and chains [yellow]+7[fg] times' end, ['cryomancer'] = function() return '[fg]enemies are also slowed by [yellow]60%[fg] while in the area' end, ['pyromancer'] = function() return '[fg]enemies killed by the pyromancer explode, dealing [yellow]' .. get_character_stat('pyromancer', 3, 'dmg') .. '[fg] AoE damage' end, - ['corruptor'] = function() return '[fg]spawn [yellow]3[fg] small critters if the corruptor hits an enemy' end, - ['beastmaster'] = function() return '[fg]spawn [yellow]2[fg] small critters if the beastmaster gets hit' end, + ['corruptor'] = function() return '[fg]spawn [yellow]2[fg] small critters if the corruptor hits an enemy' end, + ['beastmaster'] = function() return '[fg]spawn [yellow]4[fg] small critters if the beastmaster gets hit' end, ['launcher'] = function() return '[fg]enemies launched take [yellow]300%[fg] more damage when they hit walls' end, ['jester'] = function() return '[fg]all knives seek enemies and pierce [yellow]2[fg] times' end, ['assassin'] = function() return '[fg]poison inflicted from crits deals [yellow]8x[fg] damage' end, @@ -794,8 +795,8 @@ function init() ['lich'] = function() return '[light_bg]chain frost slows enemies hit by 80% for 2 seconds and chains +7 times' end, ['cryomancer'] = function() return '[light_bg]enemies are also slowed by 60% while in the area' end, ['pyromancer'] = function() return '[light_bg]enemies killed by the pyromancer explode, dealing ' .. get_character_stat('pyromancer', 3, 'dmg') .. ' AoE damage' end, - ['corruptor'] = function() return '[light_bg]spawn 3 small critters if the corruptor hits an enemy' end, - ['beastmaster'] = function() return '[light_bg]spawn 2 small critters if the beastmaster gets hit' end, + ['corruptor'] = function() return '[light_bg]spawn 2 small critters if the corruptor hits an enemy' end, + ['beastmaster'] = function() return '[light_bg]spawn 4 small critters if the beastmaster gets hit' end, ['launcher'] = function() return '[light_bg]enemies launched take 300% more damage when they hit walls' end, ['jester'] = function() return '[light_bg]curses 6 enemies and all knives seek enemies and pierce 2 times' end, ['assassin'] = function() return '[light_bg]poison inflicted from crits deals 8x damage' end, @@ -935,12 +936,12 @@ function init() return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4[light_bg]/[' .. ylb3(lvl) .. ']6 [fg]- sorcerers repeat their attacks once every [' .. ylb1(lvl) .. ']4[light_bg]/[' .. ylb2(lvl) .. ']3[light_bg]/[' .. ylb3(lvl) .. ']2[fg] attacks' end, - ['mercenary'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+10%[light_bg]/[' .. ylb2(lvl) .. ']+20% [fg]chance for enemies to drop gold on death' end, + ['mercenary'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+8%[light_bg]/[' .. ylb2(lvl) .. ']+16% [fg]chance for enemies to drop gold on death' end, } tier_to_characters = { - [1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist', 'miner'}, - [2] = {'wizard', 'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw', 'merchant'}, + [1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist', 'merchant'}, + [2] = {'wizard', 'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw', 'miner'}, [3] = {'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'host', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant', 'illusionist', 'usurer', 'gambler'}, [4] = {'priest', 'highlander', 'psykino', 'fairy', 'blade', 'plague_doctor', 'cannoneer', 'vulcanist', 'warden', 'corruptor', 'thief'}, } @@ -998,8 +999,8 @@ function init() ['vulcanist'] = 4, ['warden'] = 4, ['psychic'] = 2, - ['miner'] = 1, - ['merchant'] = 2, + ['miner'] = 2, + ['merchant'] = 1, ['usurer'] = 3, ['gambler'] = 3, ['thief'] = 4, @@ -1493,22 +1494,27 @@ function init() main = Main() - 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, run.shop_level or 1, run.shop_xp or 0) + main:go_to('buy_screen', run.level or 1, run.units or {}, passives, run.shop_level or 1, run.shop_xp or 0) -- main:go_to('buy_screen', 7, run.units or {}, {'unleash'}) --[[ main:add(Arena'arena') main:go_to('arena', 3, { - {character = 'merchant', level = 1}, - {character = 'miner', level = 1}, - {character = 'thief', level = 1}, - {character = 'gambler', level = 1}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, + {character = 'vulcanist', level = 3}, }, passives) ]]-- diff --git a/media.lua b/media.lua index 1d52128..4948673 100644 --- a/media.lua +++ b/media.lua @@ -11,10 +11,10 @@ function Media:on_enter(from) self.effects = Group() self.ui = Group() - graphics.set_background_color(yellow2[0]) + graphics.set_background_color(blue[0]) Text2{group = self.ui, x = gw/2, y = gh/2, lines = { {text = '[fg]SNKRX', font = fat_font, alignment = 'center', height_offset = -15}, - {text = '[fg]mercenary update', font = pixul_font, alignment = 'center'}, + {text = '[fg]item update', font = pixul_font, alignment = 'center'}, }} end diff --git a/objects.lua b/objects.lua index 3fe99ee..81b45ed 100644 --- a/objects.lua +++ b/objects.lua @@ -250,7 +250,7 @@ function Unit:calculate_stats(first_run) else if self.boss then local x = self.level - local y = {0, 0, 3, 0, 0, 6, 0, 0, 9, 0, 0, 12, 0, 0, 18, 0, 0, 40, 0, 0, 32, 0, 0, 64, 84} + local y = {0, 0, 3, 0, 0, 6, 0, 0, 9, 0, 0, 12, 0, 0, 18, 0, 0, 40, 0, 0, 32, 0, 0, 64, 90} self.base_hp = 100 + (current_new_game_plus*5) + (90 + current_new_game_plus*10)*y[x] self.base_dmg = (12 + current_new_game_plus*2) + (2 + current_new_game_plus)*y[x] self.base_mvspd = 35 + 1.5*y[x] diff --git a/player.lua b/player.lua index 258f531..07dda38 100644 --- a/player.lua +++ b/player.lua @@ -158,14 +158,14 @@ function Player:init(args) 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() 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}) + self:shoot(self:angle_to_object(closest_enemy), {pierce = 10000, 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_repeat() self.sorcerer_count = 0 self.t:after(0.25, function() - self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000, v = 40}) + self:shoot(self:angle_to_object(closest_enemy), {pierce = 10000, v = 40}) end) end end @@ -469,7 +469,7 @@ 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), {spawn_critters_on_kill = 3, spawn_critters_on_hit = (self.level == 3 and 3 or nil)}) + self:shoot(self:angle_to_object(closest_enemy), {spawn_critters_on_kill = 3, spawn_critters_on_hit = (self.level == 3 and 2 or nil)}) end end, nil, nil, 'shoot') @@ -1404,7 +1404,7 @@ function Player:hit(damage, from_undead) if self.character == 'beastmaster' and self.level == 3 then critter1:play{pitch = random:float(0.95, 1.05), volume = 0.5} trigger:after(0.01, function() - for i = 1, 2 do + for i = 1, 4 do Critter{group = main.current.main, x = self.x, y = self.y, color = orange[0], r = random:float(0, 2*math.pi), v = 20, dmg = self.dmg, parent = self} end end) @@ -1508,7 +1508,7 @@ function Player:hit(damage, from_undead) end if self.insurance then - if random:bool(4*((main.current.mercenary_level == 2 and 20) or (main.current.mercenary_level == 1 and 10) or 0)) then + if random:bool(4*((main.current.mercenary_level == 2 and 16) or (main.current.mercenary_level == 1 and 8) or 0)) then main.current.t:after(0.01, function() Gold{group = main.current.main, x = self.x, y = self.y} Gold{group = main.current.main, x = self.x, y = self.y} @@ -1879,7 +1879,7 @@ function Projectile:init(args) arcane2:play{pitch = random:float(0.7, 1.3), volume = 0.15} self.hfx:use('hit', 0.5) local r = self:angle_to_object(enemy) - local t = {group = main.current.main, x = self.x + 8*math.cos(r), y = self.y + 8*math.sin(r), v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, pierce = 1000, character = 'arcanist_projectile', + local t = {group = main.current.main, x = self.x + 8*math.cos(r), y = self.y + 8*math.sin(r), v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, pierce = 2, character = 'arcanist_projectile', parent = self.parent, level = self.parent.level} local check_circle = Circle(t.x, t.y, 2) local objects = main.current.main:get_objects_in_shape(check_circle, {Player, Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) @@ -2778,9 +2778,8 @@ function Volcano:draw() if self.hidden then return end if not self.hfx.hit 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.push(self.x, self.y, -math.pi/2, self.spring.x, self.spring.x) + graphics.triangle_equilateral(self.x, self.y, 1.5*self.shape.w, self.hfx.hit.f and fg[0] or self.color, 3) graphics.pop() graphics.push(self.x, self.y, self.r + self.vr, self.spring.x, self.spring.x) diff --git a/todo b/todo index 4708c52..620a64e 100644 --- a/todo +++ b/todo @@ -1,7 +1,7 @@ Item Update New mechanics * Spend gold to level items up - Block levelling for unlevellable items + * Block levelling for unlevellable items Items General: * Centipede - +10/20/30% movement speed @@ -84,37 +84,29 @@ Item Update * Blessing * Immolation Balance - * Changed voider DoT damage bonus to 20/40% (from 15/25%) + * Increased voider DoT damage bonus to 20/40% (from 15/25%) * Decreased shop reroll cost to 10 - Decrease mercenary gold drop chance to 8/16% (from 10/20%) + * Decreased mercenary gold drop chance to 8/16% (from 10/20%) + * Changed Merchant to tier 1 + * Changed Merchant interest to cap at 10 (having more than 100 gold won't generate more interest from the merchant) + * Changed Miner to tier 2 + * Changed Arcanist projectiles to pierce once (from infinite) + * Changed Exploder to create a mine on death, it will explode into projectiles after a delay (this delay is smaller on higher NG+ difficulties) + * Decreased Shooter projectile fire rate, speed, and now the projectiles can also be blocked by enemies + * Decreased Tank knockback resistance + * Decreased level 25 elite knockback resistance + * Changed Beastmaster's Lv.3 effect to spawn 4 small critters when it gets hit (from 2) + * Changed Corruptor's Lv.3 effect to spawn 2 small critters on hit (from 3) QoL - Current snake/items visible on item selection screen - Volume slider - Add visuals for defensive ouroboros, divine intervention, fairy buff - Options menu from buy screen - https://i.imgur.com/JJUddT3.png - https://i.imgur.com/R3YgUqk.png - Improve volcano to not look like spawn marker - https://i.imgur.com/HuS15HG.png - Add option for mouse cursor to always be visible - Add main menu - Soundtrack button - Arena run button - Options button - Quit button + * Added snake to the passive selection screen + * Changed Volcano's icon to be a triangle instead of X so it isn't confused with a spawn marker + * Improved Beastmaster and Corruptor description with text describing their attack and how much damage it deals + * Added visual effect for when defensive ouroboros is active * Added an option to force all screen transitions to be dark * Added tier text to characters on the shop screen * Added shop unit highlights/markers to make it easier to tell when you already own something * Added unit names to the "your build" section of the end game screen - Bug fixes - Fix fullscreen with different resolutions that don't scale properly - https://steamcommunity.com/app/915310/discussions/0/3106901665841020282/ - Fix enemies still spawning after arena clear (this happens with the extra enemy spawns that were blocked earlier) - Kill enemies that go outside play area - https://i.imgur.com/QPgZbve.png - https://i.imgur.com/lCdPFZx.png - https://i.imgur.com/1CwmFYX.png - https://i.imgur.com/qrExpq5.png - https://i.imgur.com/DNHUST1.png - Fixed multiple bugs related to locking the shop and quitting * Fixed ouroboros technique passives not working with mouse controls * Fixed mouse not showing up on death * Fixed NG+5 achievement not triggering (this happened only between last Sunday night and Monday morning due to a small update I pushed breaking it) @@ -124,6 +116,7 @@ Item Update * Fixed a bug where the shop would be rerolled after quitting in the arena * Fixed a bug where units could be duplicated in the shop by locking and quitting the game at certain steps * Fixed a bug where quitting on level 2 would go back to level 1 shop (again) + * Fixed multiple bugs related to locking the shop and quitting * Fixed a bug where mouse cursor wasn't visible on death * Fixed a bug where NG+ level wasn't increased when the game is beaten but only when the NG+ button was clicked * Fixed a bug where level 2 and level 3 achievements (win with only level 2/3 units) were not triggering correctly sometimes @@ -145,6 +138,23 @@ Endless Update Units die permanently when they die Slower scaling with less individually threatening units Max snake size goes up every 10 levels + QoL + Volume slider + Add visuals divine intervention, fairy buff + Options menu from buy screen + https://i.imgur.com/JJUddT3.png + Add option for mouse cursor to always be visible + Add main menu + Soundtrack button + Arena run button + Options button + Quit button + Bug fixes + Fix fullscreen with different resolutions that don't scale properly - https://steamcommunity.com/app/915310/discussions/0/3106901665841020282/ + Fix enemies still spawning after arena clear (this happens with the extra enemy spawns that were blocked earlier) + Kill enemies that go outside play area - https://i.imgur.com/QPgZbve.png + https://i.imgur.com/lCdPFZx.png + https://i.imgur.com/qrExpq5.png --- @@ -152,6 +162,8 @@ Future updates: Chaos related classes Invoker - shoots a projectile with random properties, Lv.3 effect - ??? Trappers: + Traps - map modifier + turrets attached to walls shoot single, slow moving projectiles in a predictable pattern that deal lots of damage 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