diff --git a/arena.lua b/arena.lua index c3d6592..02ee34f 100644 --- a/arena.lua +++ b/arena.lua @@ -113,6 +113,7 @@ function Arena:on_enter(from, level, units) self.enemies_killed = 0 self.enemies_to_kill = self.level_to_enemies_to_kill[self.level] self.enemy_spawn_delay = 8 + self.enemies_spawned = 0 self.start_time = 3 self.t:after(1, function() self.t:every(1, function() @@ -171,7 +172,7 @@ function Arena:on_enter(from, level, units) if self.level == 1 then local t1 = Text2{group = self.floor, x = gw/2, y = gh/2 + 2, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]<- or a -> or d', font = fat_font, alignment = 'center'}}} local t2 = Text2{group = self.floor, x = gw/2, y = gh/2 + 18, lines = {{text = '[light_bg]turn left turn right', font = pixul_font, alignment = 'center'}}} - local t3 = Text2{group = self.floor, x = gw/2, y = gh/2 + 46, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]n - mute sfx', font = fat_font, alignment = 'center'}}} + local t3 = Text2{group = self.floor, x = gw/2, y = gh/2 + 46, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]s - mute sfx', font = fat_font, alignment = 'center'}}} local t4 = Text2{group = self.floor, x = gw/2, y = gh/2 + 68, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]m - mute music', font = fat_font, alignment = 'center'}}} t1.t:after(8, function() t1.t:tween(0.2, t1, {sy = 0}, math.linear, function() t1.sy = 0 end) end) t2.t:after(8, function() t2.t:tween(0.2, t2, {sy = 0}, math.linear, function() t2.sy = 0 end) end) @@ -233,7 +234,76 @@ end function Arena:update(dt) + if input.escape.pressed and not self.transitioning then + if not self.paused then + trigger:tween(0.25, _G, {slow_amount = 0}, math.linear, function() + slow_amount = 0 + self.paused = true + self.paused_t1 = Text2{group = self.ui, x = gw/2, y = gh/2 - 68, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]<- or a -> or d', font = fat_font, alignment = 'center'}}} + self.paused_t2 = Text2{group = self.ui, x = gw/2, y = gh/2 - 52, lines = {{text = '[bg10]turn left turn right', font = pixul_font, alignment = 'center'}}} + self.paused_t3 = Text2{group = self.ui, x = gw/2, y = gh/2 - 22, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]s - mute sfx', font = fat_font, alignment = 'center'}}} + self.paused_t4 = Text2{group = self.ui, x = gw/2, y = gh/2 + 0, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]m - mute music', font = fat_font, alignment = 'center'}}} + self.paused_t5 = Text2{group = self.ui, x = gw/2, y = gh/2 + 22, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]esc - resume game', font = fat_font, alignment = 'center'}}} + self.paused_t6 = Text2{group = self.ui, x = gw/2, y = gh/2 + 44, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]r - restart run', font = fat_font, alignment = 'center'}}} + self.paused_t7 = Text2{group = self.ui, x = gw/2, y = gh/2 + 68, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]w - wishlist on steam', font = fat_font, alignment = 'center'}}} + end, 'pause') + else + trigger:tween(0.25, _G, {slow_amount = 1}, math.linear, function() + slow_amount = 1 + self.paused = false + self.paused_t1.dead = true + self.paused_t2.dead = true + self.paused_t3.dead = true + self.paused_t4.dead = true + self.paused_t5.dead = true + self.paused_t6.dead = true + self.paused_t7.dead = true + self.paused_t1 = nil + self.paused_t2 = nil + self.paused_t3 = nil + self.paused_t4 = nil + self.paused_t5 = nil + self.paused_t6 = nil + self.paused_t7 = nil + end, 'pause') + end + end + + if self.paused or self.died and not self.transitioning then + if input.r.pressed then + self.transitioning = true + ui_transition2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = fg[0], transition_action = function() + slow_amount = 1 + gold = 2 + cascade_instance:stop() + main:add(BuyScreen'buy_screen') + main:go_to('buy_screen', 0, {}) + end, text = Text({{text = '[wavy, bg]restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)} + end + + if input.w.pressed then + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + system.open_url'https://store.steampowered.com/app/915310/SNKRX/' + end + end + + if input.w.pressed and self.won then + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + system.open_url'https://store.steampowered.com/app/915310/SNKRX/' + end + self:update_game_object(dt*slow_amount) + cascade_instance.pitch = math.clamp(slow_amount*self.main_slow_amount, 0.05, 1) + + if input.k.pressed then + local enemies = self.main:get_objects_by_classes(self.enemies) + for _, enemy in ipairs(enemies) do enemy:hit(1000000000000) end + end if self.enchanter_level == 1 then self.enchanter_dmg_m = 1.25 else self.enchanter_dmg_m = 1 end @@ -248,44 +318,62 @@ function Arena:update(dt) self.can_quit = false self.transitioning = true local gold_gained = random:int(level_to_gold_gained[self.level][1], level_to_gold_gained[self.level][2]) - print(gold_gained) gold = gold + gold_gained - if not self.arena_clear_text then self.arena_clear_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 48, lines = {{text = '[wavy_mid, cbyc]arena clear!', font = fat_font, alignment = 'center'}}} end - self.t:after(3, function() - ui_transition2:play{pitch = random:float(0.95, 1.05), volume = 0.5} - TransitionEffect{group = main.transitions, x = self.player.x, y = self.player.y, color = self.color, transition_action = function(t) - main:add(BuyScreen'buy_screen') - main:go_to('buy_screen', self.level, self.units) - t.t:after(0.1, function() - t.text:set_text({ - {text = '[nudge_down, bg]gold gained: ' .. tostring(gold_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]damage taken: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]damage dealt: 0', font = pixul_font, alignment = 'center'} - }) - _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} - t.t:after(0.2, function() + + if self.level == 25 then + if not self.win_text and not self.win_text2 then + self.won = true + camera.x, camera.y = gw/2, gh/2 + self.win_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 64, lines = {{text = '[wavy_mid, cbyc2]congratulations!', font = fat_font, alignment = 'center'}}} + self.t:after(2.5, function() + self.win_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 16, lines = { + {text = "[fg]you've beaten the demo!", font = pixul_font, alignment = 'center', height_multiplier = 1.2}, + {text = "[fg]the game's full version is coming in a few weeks,", font = pixul_font, alignment = 'center', height_multiplier = 1.2}, + {text = "[fg]so if you liked the game, make sure to wishlist it!", font = pixul_font, alignment = 'center', height_multiplier = 5}, + {text = "[wavy_mid, fg]thanks for playing!", font = pixul_font, alignment = 'center'}, + }} + WishlistButton{group = self.ui, x = gw/2, y = gh/2 + 30, w_to_wishlist = true} + end) + end + + else + if not self.arena_clear_text then self.arena_clear_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 48, lines = {{text = '[wavy_mid, cbyc]arena clear!', font = fat_font, alignment = 'center'}}} end + self.t:after(3, function() + ui_transition2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + TransitionEffect{group = main.transitions, x = self.player.x, y = self.player.y, color = self.color, transition_action = function(t) + main:add(BuyScreen'buy_screen') + main:go_to('buy_screen', self.level, self.units) + t.t:after(0.1, function() t.text:set_text({ - {text = '[wavy_lower, bg]gold gained: ' .. tostring(gold_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[nudge_down, bg]damage taken: ' .. tostring(math.round(self.damage_taken, 0)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[nudge_down, bg]gold gained: ' .. tostring(gold_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[wavy_lower, bg]damage taken: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, {text = '[wavy_lower, bg]damage dealt: 0', font = pixul_font, alignment = 'center'} }) _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} t.t:after(0.2, function() t.text:set_text({ {text = '[wavy_lower, bg]gold gained: ' .. tostring(gold_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]damage taken: ' .. tostring(math.round(self.damage_taken, 0)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[nudge_down, bg]damage dealt: ' .. tostring(math.round(self.damage_dealt, 0)), font = pixul_font, alignment = 'center'} + {text = '[nudge_down, bg]damage taken: ' .. tostring(math.round(self.damage_taken, 0)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[wavy_lower, bg]damage dealt: 0', font = pixul_font, alignment = 'center'} }) _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} + t.t:after(0.2, function() + t.text:set_text({ + {text = '[wavy_lower, bg]gold gained: ' .. tostring(gold_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[wavy_lower, bg]damage taken: ' .. tostring(math.round(self.damage_taken, 0)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[nudge_down, bg]damage dealt: ' .. tostring(math.round(self.damage_dealt, 0)), font = pixul_font, alignment = 'center'} + }) + _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} + end) end) end) - end) - end, text = Text({ - {text = '[wavy_lower, bg]gold gained: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]damage taken: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]damage dealt: 0', font = pixul_font, alignment = 'center'} - }, global_text_tags)} - end, 'transition') + end, text = Text({ + {text = '[wavy_lower, bg]gold gained: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[wavy_lower, bg]damage taken: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, + {text = '[wavy_lower, bg]damage dealt: 0', font = pixul_font, alignment = 'center'} + }, global_text_tags)} + end, 'transition') + end end end @@ -339,14 +427,14 @@ end function Arena:die() - if not self.died_text then + if not self.died_text and not self.won then self.died = true self.t:tween(2, self, {main_slow_amount = 0}, math.linear, function() self.main_slow_amount = 0 end) self.died_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 32, lines = { {text = '[wavy_mid, cbyc]you died...', font = fat_font, alignment = 'center', height_multiplier = 1.25}, }} self.t:after(2, function() - self.death_info_text = Text2{group = self.ui, x = gw/2, y = gh/2 + 16, sx = 0.7, sy = 0.7, lines = { + self.death_info_text = Text2{group = self.ui, x = gw/2, y = gh/2 + 24, sx = 0.7, sy = 0.7, lines = { {text = '[wavy_mid, light_bg]level reached: [wavy_mid, yellow]' .. self.level, font = fat_font, alignment = 'center'}, {text = '[wavy_mid, light_bg]r - start new run', font = fat_font, alignment = 'center'}, {text = '[wavy_mid, light_bg]w - wishlist on steam', font = fat_font, alignment = 'center'}, @@ -411,6 +499,10 @@ function Arena:spawn_n_enemies(p, j, n) n = n or 4 self.last_spawn_enemy_time = love.timer.getTime() self.t:every(0.1, function() + if self.win_condition == 'enemy_kill' then + if self.enemies_spawned >= math.floor(1.4*self.enemies_to_kill) then return end + self.enemies_spawned = self.enemies_spawned + 1 + end local o = self.spawn_offsets[(self.t:get_every_iteration('spawn_enemies_' .. j) % 5) + 1] SpawnEffect{group = self.effects, x = p.x + o.x, y = p.y + o.y, action = function(x, y) spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15} diff --git a/assets/sounds/Kick 16.ogg b/assets/sounds/Kick 16_1.ogg similarity index 100% rename from assets/sounds/Kick 16.ogg rename to assets/sounds/Kick 16_1.ogg diff --git a/assets/sounds/Kick 16_2.ogg b/assets/sounds/Kick 16_2.ogg new file mode 100644 index 0000000..affdf1e Binary files /dev/null and b/assets/sounds/Kick 16_2.ogg differ diff --git a/assets/sounds/Kubbi - Ember - 04 Cascade.ogg b/assets/sounds/Kubbi - Ember - 04 Cascade.ogg new file mode 100644 index 0000000..7257704 Binary files /dev/null and b/assets/sounds/Kubbi - Ember - 04 Cascade.ogg differ diff --git a/buy_screen.lua b/buy_screen.lua index c9e88e8..31b2317 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -32,6 +32,7 @@ function BuyScreen:on_enter(from, level, units) camera.x, camera.y = gw/2, gh/2 if self.level == 0 then + cascade_instance = cascade:play{volume = 0.5, loop = true} self.level = 1 self.first_screen = true end @@ -60,6 +61,8 @@ end function BuyScreen:update(dt) self:update_game_object(dt*slow_amount) + cascade_instance.pitch = 1 + self.main:update(dt*slow_amount) self.effects:update(dt*slow_amount) self.ui:update(dt*slow_amount) @@ -180,9 +183,14 @@ WishlistButton = Object:extend() WishlistButton:implement(GameObject) function WishlistButton:init(args) self:init_game_object(args) - self.shape = Rectangle(self.x, self.y, 110, 18) self.interact_with_mouse = true - self.text = Text({{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}}, global_text_tags) + if self.w_to_wishlist then + self.shape = Rectangle(self.x, self.y, 85, 18) + self.text = Text({{text = '[bg10]w to wishlist', font = pixul_font, alignment = 'center'}}, global_text_tags) + else + self.shape = Rectangle(self.x, self.y, 110, 18) + self.text = Text({{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}}, global_text_tags) + end end @@ -194,7 +202,7 @@ function WishlistButton:update(dt) self.spring:pull(0.2, 200, 10) self.selected = true ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - system.open_url'https://store.steampowered.com/app/760330/BYTEPATH/' + system.open_url'https://store.steampowered.com/app/915310/SNKRX/' end end @@ -211,13 +219,21 @@ function WishlistButton:on_mouse_enter() ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.selected = true - self.text:set_text{{text = '[fgm5]wishlist on steam', font = pixul_font, alignment = 'center'}} + if self.w_to_wishlist then + self.text:set_text{{text = '[fgm5]w to wishlist', font = pixul_font, alignment = 'center'}} + else + self.text:set_text{{text = '[fgm5]wishlist on steam', font = pixul_font, alignment = 'center'}} + end self.spring:pull(0.2, 200, 10) end function WishlistButton:on_mouse_exit() - self.text:set_text{{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}} + if self.w_to_wishlist then + self.text:set_text{{text = '[bg10]w to wishlist', font = pixul_font, alignment = 'center'}} + else + self.text:set_text{{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}} + end self.selected = false end diff --git a/devlog.md b/devlog.md index c3c804d..a872cb4 100644 --- a/devlog.md +++ b/devlog.md @@ -406,4 +406,10 @@ Mostly done with balance tuning. Now all that's left are some final details: * Win screen * W to wishlist * R to restart -* Unit death sound +* Allied unit death sound + +# Day 28 - 16/03/21 + +The demo is finally 100% complete. Now tomorrow I'll spend some time recording gameplay and hopefully finishing the trailer. After that I can start working on the steam page. +If I have it done by tomorrow and Valve takes 5 business days to approve the store page I should have everything ready by the 25th. And then I can release the game 14 days after that, which would be the 8th of April. +I definitely want to release it around that time, before the 15th because then I will have completed the game in less than 60 days which is my limit, although I should probably aim for 40 days going forward. diff --git a/enemies.lua b/enemies.lua index 12c9bb7..76c7d4e 100644 --- a/enemies.lua +++ b/enemies.lua @@ -58,8 +58,8 @@ function Seeker:on_collision_enter(other, contact) elseif table.any(main.current.enemies, function(v) return other:is(v) end) then if self.being_pushed and math.length(self:get_velocity()) > 60 then - other:hit(5) - self:hit(10) + other:hit(math.floor(self.dmg/2)) + self:hit(self.dmg) other:push(random:float(10, 15), other:angle_to_object(self)) HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1} for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end diff --git a/main.lua b/main.lua index e6e9ce3..c114b70 100644 --- a/main.lua +++ b/main.lua @@ -37,7 +37,8 @@ function init() arrow_hit_wall2 = Sound('Arrow Impact wood 1.ogg', s) hit1 = Sound('Player Takes Damage 17.ogg', s) hit2 = Sound('Body Head (Headshot) 1.ogg', s) - hit3 = Sound('Kick 16.ogg', s) + hit3 = Sound('Kick 16_1.ogg', s) + hit4 = Sound('Kick 16_2.ogg', s) proj_hit_wall1 = Sound('Player Takes Damage 2.ogg', s) enemy_die1 = Sound('Bloody punches 7.ogg', s) enemy_die2 = Sound('Bloody punches 10.ogg', s) @@ -77,6 +78,7 @@ function init() turret_deploy = Sound('321215__hybrid-v__sci-fi-weapons-deploy.ogg', s) rogue_crit1 = Sound('Dagger Stab (Flesh) 4.ogg', s) rogue_crit2 = Sound('Sword hits another sword 6.ogg', s) + cascade = Sound('Kubbi - Ember - 04 Cascade.ogg', {tags = {music}}) warrior = Image('warrior') ranger = Image('ranger') @@ -376,29 +378,29 @@ function init() level_to_gold_gained = { [1] = {2, 2}, [2] = {2, 2}, - [3] = {2, 3}, + [3] = {4, 6}, [4] = {2, 3}, [5] = {3, 5}, - [6] = {3, 5}, + [6] = {6, 10}, [7] = {4, 7}, [8] = {4, 7}, - [9] = {5, 8}, + [9] = {10, 16}, [10] = {5, 8}, [11] = {5, 8}, - [12] = {6, 10}, + [12] = {12, 20}, [13] = {6, 10}, [14] = {6, 10}, - [15] = {7, 11}, + [15] = {14, 22}, [16] = {8, 12}, [17] = {8, 12}, - [18] = {8, 12}, + [18] = {16, 24}, [19] = {8, 12}, [20] = {10, 14}, - [21] = {10, 14}, + [21] = {20, 28}, [22] = {11, 15}, [23] = {11, 15}, - [24] = {12, 18}, - [25] = {12, 18}, + [24] = {24, 36}, + [25] = {100, 100}, } gold = 2 @@ -411,6 +413,23 @@ end function update(dt) main:update(dt) + + if input.s.pressed then + if sfx.volume == 0.5 then + sfx.volume = 0 + elseif sfx.volume == 0 then + sfx.volume = 0.5 + end + end + + if input.m.pressed then + print(music.volume) + if music.volume == 0.5 then + music.volume = 0 + elseif music.volume == 0 then + music.volume = 0.5 + end + end end diff --git a/objects.lua b/objects.lua index d981955..88e6608 100644 --- a/objects.lua +++ b/objects.lua @@ -204,9 +204,9 @@ function Unit:calculate_stats(first_run) elseif self:is(Seeker) then local x = self.level local y = {0, 1, 4, 2, 3, 6, 3, 5, 9, 4, 6, 11, 7, 9, 15, 8, 10, 18, 9, 11, 21, 14, 15, 24, 25} - self.base_hp = 50 + 60*y[x] - self.base_dmg = 10 + 40*y[x] - self.base_mvspd = 70 + 10*y[x] + self.base_hp = 50 + 55*y[x] + self.base_dmg = 10 + 3*y[x] + self.base_mvspd = 70 + 3*y[x] elseif self:is(Saboteur) then self.base_hp = 100*math.pow(2, self.level-1) self.base_dmg = 10*math.pow(2, self.level-1) diff --git a/player.lua b/player.lua index 1134b88..295abab 100644 --- a/player.lua +++ b/player.lua @@ -188,8 +188,8 @@ function Player:init(args) local followers local leader = (self.leader and self) or self.parent if self.leader then followers = self.followers else followers = self.parent.followers end - local next_character = followers[self.follower_index + 1] - local previous_character = followers[self.follower_index - 1] + local next_character = followers[(self.follower_index or 0) + 1] + local previous_character = followers[(self.follower_index or 0) - 1] if next_character then next_character:squire_buff(8) end if previous_character then previous_character:squire_buff(8) end self.t:after(8, function() self.applying_buff = false end, 'squire_buff_apply') @@ -250,8 +250,8 @@ function Player:init(args) local followers local leader = (self.leader and self) or self.parent if self.leader then followers = self.followers else followers = self.parent.followers end - local next_character = followers[self.follower_index + 1] - local previous_character = followers[self.follower_index - 1] + local next_character = followers[(self.follower_index or 0) + 1] + local previous_character = followers[(self.follower_index or 0) - 1] if next_character then next_character:chronomancer_buff(2) end if previous_character then previous_character:chronomancer_buff(2) end end) @@ -320,8 +320,8 @@ function Player:update(dt) local followers local leader = (self.leader and self) or self.parent if self.leader then followers = self.followers else followers = self.parent.followers end - local next_character = followers[self.follower_index + 1] - local previous_character = followers[self.follower_index - 1] + local next_character = followers[(self.follower_index or 0) + 1] + local previous_character = followers[(self.follower_index or 0) - 1] if self.applying_buff then if next_character then next_character.squire_dmg_a = 10 @@ -346,8 +346,8 @@ function Player:update(dt) local followers local leader = (self.leader and self) or self.parent if self.leader then followers = self.followers else followers = self.parent.followers end - local next_character = followers[self.follower_index + 1] - local previous_character = followers[self.follower_index - 1] + local next_character = followers[(self.follower_index or 0) + 1] + local previous_character = followers[(self.follower_index or 0) - 1] if next_character then next_character.chronomancer_aspd_m = 1.25 end if previous_character then previous_character.chronomancer_aspd_m = 1.25 end end @@ -409,21 +409,23 @@ function Player:update(dt) if input.move_right.down then self.r = self.r + 1.66*math.pi*dt end self:set_velocity(self.v*math.cos(self.r), self.v*math.sin(self.r)) - local vx, vy = self:get_velocity() - local hd = math.remap(math.abs(self.x - gw/2), 0, 192, 1, 0) - local vd = math.remap(math.abs(self.y - gh/2), 0, 108, 1, 0) - camera.x = camera.x + math.remap(vx, -100, 100, -24*hd, 24*hd)*dt - camera.y = camera.y + math.remap(vy, -100, 100, -8*vd, 8*vd)*dt - if input.move_right.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, math.pi/256) - elseif input.move_left.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, -math.pi/256) - elseif input.move_down.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, math.pi/256) - elseif input.move_up.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, -math.pi/256) - else camera.r = math.lerp_angle_dt(0.005, dt, camera.r, 0) end + if not main.current.won then + local vx, vy = self:get_velocity() + local hd = math.remap(math.abs(self.x - gw/2), 0, 192, 1, 0) + local vd = math.remap(math.abs(self.y - gh/2), 0, 108, 1, 0) + camera.x = camera.x + math.remap(vx, -100, 100, -24*hd, 24*hd)*dt + camera.y = camera.y + math.remap(vy, -100, 100, -8*vd, 8*vd)*dt + if input.move_right.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, math.pi/256) + elseif input.move_left.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, -math.pi/256) + elseif input.move_down.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, math.pi/256) + elseif input.move_up.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, -math.pi/256) + else camera.r = math.lerp_angle_dt(0.005, dt, camera.r, 0) end + end self:set_angle(self.r) else - local target_distance = 10.4*self.follower_index + local target_distance = 10.4*(self.follower_index or 0) local distance_sum = 0 local p local previous = self.parent @@ -485,9 +487,9 @@ function Player:on_collision_enter(other, contact) 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)) - if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(40) - else other:hit(20) end - self:hit(20) + if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(2*self.dmg) + else other:hit(self.dmg) end + self:hit(other.dmg) HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1} for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = other.color} end @@ -500,7 +502,6 @@ function Player:hit(damage) self.hfx:use('hit', 0.25, 200, 10) self:show_hp() - local actual_damage = self:calculate_damage(damage) self.hp = self.hp - actual_damage _G[random:table{'player_hit1', 'player_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} @@ -510,6 +511,7 @@ function Player:hit(damage) if self.character == 'psykeeper' then self.psykeeper_heal = self.psykeeper_heal + actual_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 @@ -978,7 +980,7 @@ function Turret:init(args) self:set_restitution(0.5) self.hfx:add('hit', 1) self.color = orange[0] - self.attack_sensor = Circle(self.x, self.y, 96) + self.attack_sensor = Circle(self.x, self.y, 256) turret_deploy:play{pitch = 1.2, volume = 0.2} self.t:every({3.5, 4.5}, function() diff --git a/shared.lua b/shared.lua index 06ec4cd..3698f7b 100644 --- a/shared.lua +++ b/shared.lua @@ -449,6 +449,17 @@ global_text_tags = { graphics.set_color(c.color) end}, + cbyc2 = TextTag{init = function(c, i, text) + c.color = invisible + text.t:after((i-1)*0.15, function() + c.color = yellow[0] + camera:shake(3, 0.075) + pop1:play{pitch = random:float(0.95, 1.05), volume = 0.35} + end) + end, draw = function(c, i, text) + graphics.set_color(c.color) + end}, + nudge_down = TextTag{init = function(c, i, text) c.oy = -4 text.t:tween(0.1, c, {oy = 0}, math.linear) diff --git a/todo b/todo index 10a8786..ad406bf 100644 --- a/todo +++ b/todo @@ -1,17 +1,26 @@ - - - --- POST DEMO -- - Mini Boss every 3rd level Show a unit DPS list like Underlord's to the right side of the screen About 20-30 passive items that can be collected every 3 levels Lv.3 effects for every character +Boss ideas + Pretends to be dead, grants speed buffs to enemies after death, especially if the round has gone on for too long which means the player is surviving with 1 unit + Classes and characters Trapper: releases +1 trap Plague Doctor [trapper, nuker]: releases an area that deals 6 AoE DoT Fisherman [trapper, warrior]: throws a net that entangles enemies and prevents them from moving + + Lich [mage, enchanter]: nearby enemies have decreased movement speed + +Items + Resonance: hitting walls has a chance of releasing projectiles + Ouroboros Technique: rotating around yourself makes every unit release projectiles + AoE 1: all units that deal AoE damage have increased stat + AoE 2: increased stat if all your units that deal damage deal AoE damage + Proj 1: all units that release projectiles have increased stat + Proj 2: increased stat if all your units that deal damage release projectiles + Wallrider: hitting walls grants a speed buff for a small duration Enemy modifiers Grant nearby enemies a speed boost on death @@ -20,3 +29,16 @@ Enemy modifiers Charge up and headbutt towards the player at increased speed and damage Immune to knockback +UI + Highlight units of a class when hovering over the class icon in the "sets" section + Add stat details to each unit when hovering over it in the "party" section + +Balance + More damage to AoE units with big cooldowns + Warriors that deal AoE damage should deal extra damage based on number of enemies hit + +Bugs + Squire and Chronomancer don't affect leader + Sage's pull force doesn't increase with unit level + Cleric's healing amount doesn't increase with unit level + Squire and Chronomancer's buffs don't increase with unit level