diff --git a/arena.lua b/arena.lua index 9cb5be5..daacd42 100644 --- a/arena.lua +++ b/arena.lua @@ -29,8 +29,10 @@ function Arena:on_enter(from, level, units) self.main:enable_trigger_between('projectile', 'enemy') self.main:enable_trigger_between('enemy_projectile', 'player') + self.damage_dealt = 0 + self.damage_taken = 0 + self.main_slow_amount = 1 self.enemies = {Seeker} - self.resources_gained = 0 self.color = self.color or fg[0] -- Spawn solids and player @@ -237,7 +239,7 @@ function Arena:update(dt) else self.enchanter_dmg_m = 1 end self.floor:update(dt*slow_amount) - self.main:update(dt*slow_amount) + self.main:update(dt*slow_amount*self.main_slow_amount) self.post_main:update(dt*slow_amount) self.effects:update(dt*slow_amount) self.ui:update(dt*slow_amount) @@ -245,6 +247,8 @@ function Arena:update(dt) if self.can_quit and #self.main:get_objects_by_classes(self.enemies) <= 0 then 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]) + 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() self.transitioning = false @@ -254,32 +258,32 @@ function Arena:update(dt) main:go_to('buy_screen', self.level, self.units) t.t:after(0.1, function() t.text:set_text({ - {text = '[nudge_down, bg]resources gained: ' .. tostring(self.resources_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]interest: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]total: 0', font = pixul_font, alignment = 'center'} + {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]resources gained: ' .. tostring(self.resources_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[nudge_down, bg]interest: ' .. tostring(math.floor(resource/10)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]total: 0', font = pixul_font, alignment = 'center'} + {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 = '[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]resources gained: ' .. tostring(self.resources_gained), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]interest: ' .. tostring(math.floor(resource/10)), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[nudge_down, bg]total: ' .. tostring(self.resources_gained + math.floor(resource/10)), font = pixul_font, alignment = 'center'} + {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, text = Text({ - {text = '[wavy_lower, bg]resources gained: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]interest: 0', font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - {text = '[wavy_lower, bg]total: 0', font = pixul_font, alignment = 'center'} + {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 @@ -334,6 +338,23 @@ function Arena:draw() end +function Arena:die() + if not self.died_text 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 = { + {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'}, + }} + end) + end +end + + function Arena:enemy_killed() if self.win_condition == 'enemy_kill' then self.enemies_killed = self.enemies_killed + 1 @@ -384,6 +405,7 @@ end function Arena:spawn_n_enemies(p, j, n) + if self.died then return end j = j or 1 n = n or 4 self.last_spawn_enemy_time = love.timer.getTime() diff --git a/buy_screen.lua b/buy_screen.lua index 8d9407d..3d9ab85 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -7,46 +7,53 @@ function BuyScreen:init(name) end +function BuyScreen:on_exit() + self.main:destroy() + self.effects:destroy() + self.ui:destroy() + self.main = nil + self.effects = nil + self.ui = nil + self.shop_text = nil + self.party_text = nil + self.sets_text = nil + self.items_text = nil + self.under_text = nil + self.characters = nil + self.sets = nil + self.cards = nil + self.info_text = nil +end + + function BuyScreen:on_enter(from, level, units) self.level = level self.units = units + camera.x, camera.y = gw/2, gh/2 + + if self.level == 0 then + self.level = 1 + self.first_screen = true + end self.main = Group() self.effects = Group() self.ui = Group() - if self.level == 0 then - pop1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} - player_hit_wall1:play{pitch = r, volume = 0.5} - self.first_screen = true - self.cards = {} - self.selected_card_index = 1 - local units = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'} - self.cards[1] = PairCard{group = self.main, x = gw/2, y = 85, w = gw, h = gh/4, unit_1 = random:table_remove(units), unit_2 = random:table_remove(units), i = 1, parent = self} - local units = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'} - self.cards[2] = PairCard{group = self.main, x = gw/2, y = 155, w = gw, h = gh/4, unit_1 = random:table_remove(units), unit_2 = random:table_remove(units), i = 2, parent = self} - local units = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'} - self.cards[3] = PairCard{group = self.main, x = gw/2, y = 225, w = gw, h = gh/4, unit_1 = random:table_remove(units), unit_2 = random:table_remove(units), i = 3, parent = self} - self.title_sy = 1 - self.title = Text({{text = '[wavy_mid, fg]choose your initial party', font = pixul_font, alignment = 'center'}}, global_text_tags) + self:set_cards() + self:set_party_and_sets() - else - self:set_cards() - self:set_party_and_sets() + self.shop_text = Text({{text = '[wavy_mid, fg]shop [fg]- gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}, global_text_tags) + self.party_text = Text({{text = '[wavy_mid, fg]party', font = pixul_font, alignment = 'center'}}, global_text_tags) + self.sets_text = Text({{text = '[wavy_mid, fg]sets', font = pixul_font, alignment = 'center'}}, global_text_tags) + self.items_text = Text({{text = '[wavy_mid, fg]items', font = pixul_font, alignment = 'center'}}, global_text_tags) + self.under_text = Text2{group = self.main, x = 140, y = gh - 60, r = -math.pi/48, lines = { + {text = '[light_bg]under', font = fat_font, alignment = 'center'}, + {text = '[light_bg]construction', font = fat_font, alignment = 'center'}, + }} - self.shop_text = Text({{text = '[wavy_mid, fg]shop [fg]- gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}, global_text_tags) - self.party_text = Text({{text = '[wavy_mid, fg]party', font = pixul_font, alignment = 'center'}}, global_text_tags) - self.sets_text = Text({{text = '[wavy_mid, fg]sets', font = pixul_font, alignment = 'center'}}, global_text_tags) - self.items_text = Text({{text = '[wavy_mid, fg]items', font = pixul_font, alignment = 'center'}}, global_text_tags) - self.under_text = Text2{group = self.main, x = 140, y = gh - 60, r = -math.pi/48, lines = { - {text = '[light_bg]under', font = fat_font, alignment = 'center'}, - {text = '[light_bg]construction', font = fat_font, alignment = 'center'}, - }} - - RerollButton{group = self.main, x = 150, y = 18, parent = self} - GoButton{group = self.main, x = gw - 30, y = gh - 20, parent = self} - end + if not self.first_screen then RerollButton{group = self.main, x = 150, y = 18, parent = self} end + GoButton{group = self.main, x = gw - 30, y = gh - 20, parent = self} end @@ -56,59 +63,10 @@ function BuyScreen:update(dt) self.effects:update(dt*slow_amount) self.ui:update(dt*slow_amount) - if self.level == 0 and self.first_screen then - if self.title then self.title:update(dt) end - - if input.move_up.pressed then - self.selected_card_index = self.selected_card_index - 1 - if self.selected_card_index == 0 then self.selected_card_index = 3 end - for i = 1, 3 do self.cards[i]:unselect() end - self.cards[self.selected_card_index]:select() - pop1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} - player_hit_wall1:play{pitch = r, volume = 0.5} - end - if input.move_down.pressed then - self.selected_card_index = self.selected_card_index + 1 - if self.selected_card_index == 4 then self.selected_card_index = 1 end - for i = 1, 3 do self.cards[i]:unselect() end - self.cards[self.selected_card_index]:select() - pop1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} - player_hit_wall1:play{pitch = r, volume = 0.5} - end - - if input.enter.pressed and not self.transitioning then - 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 - self.t:tween(0.1, self, {title_sy = 0}, math.linear, function() self.title_sy = 0; self.title = nil end) - - local unit_1, unit_2 = self.cards[self.selected_card_index].unit_1, self.cards[self.selected_card_index].unit_2 - TransitionEffect{group = main.transitions, x = 50, y = 85 + (self.selected_card_index-1)*70, color = character_colors[unit_1], transition_action = function() - main:add(Arena'arena') - main:go_to('arena', 1, {{character = unit_1, level = 1}, {character = unit_2, level = 1}}) - end} - --[[ - , text = Text({ - {text = '[' .. character_color_strings[unit_1] .. ']' .. unit_1:upper() .. ' [yellow]Lv.1 [fg]- ' .. table.reduce(character_classes[unit_1], - function(memo, v) return memo .. '[' .. class_color_strings[v] .. ']' .. v .. '[fg], ' end, ''):sub(1, -3), font = pixul_font, height_multiplier = 1.7, alignment = 'center'}, - {text = character_stats[unit_1](1), font = pixul_font, height_multiplier = 1.3, alignment = 'center'}, - {text = character_descriptions[unit_1](get_character_stat(unit_1, 1, 'dmg')), font = pixul_font, alignment = 'center', height_multiplier = 3}, - {text = '[' .. character_color_strings[unit_2] .. ']' .. unit_2:upper() .. ' [yellow]Lv.1 [fg]- ' .. table.reduce(character_classes[unit_2], - function(memo, v) return memo .. '[' .. class_color_strings[v] .. ']' .. v .. '[fg], ' end, ''):sub(1, -3), font = pixul_font, height_multiplier = 1.7, alignment = 'center'}, - {text = character_stats[unit_2](1), font = pixul_font, height_multiplier = 1.3, alignment = 'center'}, - {text = character_descriptions[unit_2](get_character_stat(unit_2, 1, 'dmg')), font = pixul_font, alignment = 'center', height_multiplier = 1.5}, - }, global_text_tags)} - ]]-- - end - - else - if self.shop_text then self.shop_text:update(dt) end - if self.sets_text then self.sets_text:update(dt) end - if self.party_text then self.party_text:update(dt) end - if self.items_text then self.items_text:update(dt) end - end + if self.shop_text then self.shop_text:update(dt) end + if self.sets_text then self.sets_text:update(dt) end + if self.party_text then self.party_text:update(dt) end + if self.items_text then self.items_text:update(dt) end end @@ -118,19 +76,15 @@ function BuyScreen:draw() if self.items_text then self.items_text:draw(32, 150) end self.ui:draw() - if self.level == 0 then - if self.title then self.title:draw(3.25*gw/4, 32, 0, 1, self.title_sy) end - else - if self.shop_text then self.shop_text:draw(64, 20) end - if self.sets_text then self.sets_text:draw(328, 20) end - if self.party_text then self.party_text:draw(440, 20) end - end + if self.shop_text then self.shop_text:draw(64, 20) end + if self.sets_text then self.sets_text:draw(328, 20) end + if self.party_text then self.party_text:draw(440, 20) end end function BuyScreen:buy(character, i) local bought - if table.any(self.units, function(v) return v.character == character end) then + if table.any(self.units, function(v) return v.character == character end) and gold >= character_tiers[character] then gold = gold - character_tiers[character] self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} for _, unit in ipairs(self.units) do @@ -170,10 +124,12 @@ function BuyScreen:buy(character, i) end self.t:after(2, function() self.info_text:deactivate(); self.info_text.dead = true; self.info_text = nil end, 'info_text') else - gold = gold - character_tiers[character] - self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} - table.insert(self.units, {character = character, level = 1, reserve = {0, 0}}) - bought = true + if gold >= character_tiers[character] then + gold = gold - character_tiers[character] + self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} + table.insert(self.units, {character = character, level = 1, reserve = {0, 0}}) + bought = true + end end end self:set_party_and_sets() @@ -223,27 +179,39 @@ GoButton = Object:extend() GoButton:implement(GameObject) function GoButton:init(args) self:init_game_object(args) - self.shape = Rectangle(self.x, self.y, 24, 16) + self.shape = Rectangle(self.x, self.y, 28, 18) self.interact_with_mouse = true - self.text = Text({{text = '[bg10]go!', font = pixul_font, alignment = 'center'}}, global_text_tags) + self.text = Text({{text = '[bg10]GO!', font = pixul_font, alignment = 'center'}}, global_text_tags) end function GoButton:update(dt) self:update_game_object(dt) + if self.selected and input.m1.pressed and not self.transitioning then - ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} - self.spring:pull(0.2, 200, 10) - self.selected = true + if #self.parent.units == 0 then + if not self.info_text then + error1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.info_text = InfoText{group = main.current.ui} + self.info_text:activate({ + {text = '[fg]cannot start the round with [yellow]0 [fg]units', font = pixul_font, alignment = 'center'}, + }, nil, nil, nil, nil, 16, 4, nil, 2) + self.info_text.x, self.info_text.y = gw/2, gh/2 + 10 + end + self.t:after(2, function() self.info_text:deactivate(); self.info_text.dead = true; self.info_text = nil end, 'info_text') - 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 - - TransitionEffect{group = main.transitions, x = self.x, y = self.y, color = character_colors[random:table(self.parent.units).character], transition_action = function() - main:add(Arena'arena') - main:go_to('arena', 1, self.parent.units) - end} + else + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.spring:pull(0.2, 200, 10) + self.selected = true + 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 + TransitionEffect{group = main.transitions, x = self.x, y = self.y, color = 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) + end, text = Text({{text = '[wavy, bg]level ' .. ((self.parent.first_screen and 1) or (self.parent.level + 1)), font = pixul_font, alignment = 'center'}}, global_text_tags)} + end end end @@ -260,13 +228,13 @@ function GoButton: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]go!', font = pixul_font, alignment = 'center'}} + self.text:set_text{{text = '[fgm5]GO!', font = pixul_font, alignment = 'center'}} self.spring:pull(0.2, 200, 10) end function GoButton:on_mouse_exit() - self.text:set_text{{text = '[bg10]go!', font = pixul_font, alignment = 'center'}} + self.text:set_text{{text = '[bg10]GO!', font = pixul_font, alignment = 'center'}} self.selected = false end @@ -682,85 +650,3 @@ function ClassIcon:die(dont_spawn_effect) self.info_text = nil end end - - - - -PairCard = Object:extend() -PairCard:implement(GameObject) -function PairCard:init(args) - self:init_game_object(args) - self.plus_r = 0 - if self.i == 1 then self:select() end -end - - -function PairCard:update(dt) - self:update_game_object(dt) -end - - -function PairCard:select() - self.selected = true - self.spring:pull(0.2, 200, 10) - self.t:every_immediate(1.4, function() - if self.selected then - self.t:tween(0.7, self, {sx = 0.97, sy = 0.97, plus_r = -math.pi/32}, math.linear, function() - self.t:tween(0.7, self, {sx = 1.03, sy = 1.03, plus_r = math.pi/32}, math.linear, nil, 'pulse_1') - end, 'pulse_2') - end - end, nil, nil, 'pulse') -end - - -function PairCard:unselect() - self.selected = false - self.t:cancel'pulse' - self.t:cancel'pulse_1' - self.t:cancel'pulse_2' - self.t:tween(0.1, self, {sx = 1, sy = 1, plus_r = 0}, math.linear, function() self.sx, self.sy, self.plus_r = 1, 1, 0 end, 'pulse') -end - - -function PairCard:draw() - local x = self.x - self.w/3 - - if self.selected then - graphics.push(x + (fat_font:get_text_width(self.i) + 20)/2, self.y - 25 + 37/2, 0, self.spring.x*self.sx, self.spring.x*self.sy) - graphics.rectangle2(x - 52, self.y - 25, fat_font:get_text_width(self.i) + 20, 37, 6, 6, bg[2]) - graphics.pop() - end - - -- 1, 2, 3 - graphics.push(x - 40 + fat_font:get_text_width(self.i)/2, self.y - fat_font.h/8, 0, self.spring.x*self.sx, self.spring.x*self.sy) - graphics.print(self.i, fat_font, x - 40, self.y, 0, self.sx, self.sy, nil, fat_font.h/2, fg[0]) - graphics.pop() - - -- Unit 1 + class symbols - graphics.push(x + (fat_font:get_text_width(self.unit_1:capitalize() .. 'w') + table.reduce(character_classes[self.unit_1], function(memo, v) return memo + 0.5*_G[v].w end, 0))/2, self.y - fat_font.h/8, 0, - self.spring.x*self.sx, self.spring.x*self.sy) - graphics.print(self.unit_1:capitalize(), fat_font, x, self.y, 0, 1, 1, nil, fat_font.h/2, character_colors[self.unit_1]) - x = x + fat_font:get_text_width(self.unit_1 .. 'w') - for i, class in ipairs(character_classes[self.unit_1]) do - _G[class]:draw(x, self.y, 0, 0.4, 0.4, nil, 20, class_colors[class]) - x = x + 0.5*_G[class].w - end - graphics.pop() - - -- + - graphics.push(x + fat_font:get_text_width('+')/2, self.y, self.plus_r, self.spring.x*self.sx, self.spring.x*self.sy) - graphics.print('+', fat_font, x, self.y, 0, 1, 1, nil, fat_font.h/2, fg[0]) - graphics.pop() - - -- Unit 2 + class symbols - x = x + fat_font:get_text_width('+l') - graphics.push(x + (fat_font:get_text_width(self.unit_2:capitalize() .. 'w') + table.reduce(character_classes[self.unit_2], function(memo, v) return memo + 0.5*_G[v].w end, 0))/2, self.y - fat_font.h/8, 0, - self.spring.x*self.sx, self.spring.x*self.sy) - graphics.print(self.unit_2:capitalize(), fat_font, x, self.y, 0, 1, 1, nil, fat_font.h/2, character_colors[self.unit_2]) - x = x + fat_font:get_text_width(self.unit_2 .. 'w') - for i, class in ipairs(character_classes[self.unit_2]) do - _G[class]:draw(x, self.y, 0, 0.4, 0.4, nil, 20, class_colors[class]) - x = x + 0.5*_G[class].w - end - graphics.pop() -end diff --git a/devlog.md b/devlog.md index c0b83a7..ea850bf 100644 --- a/devlog.md +++ b/devlog.md @@ -365,3 +365,33 @@ I'm planning will probably help with this, especially the idea of everything sim Finished buy screen. Now the only two things left is are redoing the first screen to take advantage of all the UI built for the buy screen, balance/progression and then fixing smaller details and finishing everything up. I can probably finish it all before day 30 which would be great. + +# Day 26 - 14/03/21 + +The game is finally playable from start to finish. It is pretty fun as it is but it's clear that a few things need to be added so it can be even better. I'll add these after I release the demo with the game in the current +state since these additions will take some time and I don't want to delay the demo's release any more than necessary. + +#### Enemy Modifiers + +Enemies right now feel pretty samey, and a few small modifiers would help a lot: + +* Grant nearby enemies a speed boost on death +* Grant nearby enemies a damage boost on death +* Explode into projectiles on death +* Charge up and headbutt towards the player at increased speed and damage +* Immune to knockback + +#### Mini Boss + +Every 3rd level there should be a difficult increase in the multiplier for enemy stats as well as a mini boss. This mini boss has significantly increased HP and damage and can spawn enemies of his own on top of the ones +spawned by the level. He can also grant modifiers to enemies. Upon completing such a level, the player will be granted the chance to choose 1 out of 3 passive items. + +#### Other Ideas + +* 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 +* New classes and characters (I'm not in idea guy mode ATM so I can't think of much, but it will come to me eventually): + * 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 diff --git a/enemies.lua b/enemies.lua index 94b95c5..12c9bb7 100644 --- a/enemies.lua +++ b/enemies.lua @@ -81,6 +81,7 @@ function Seeker:hit(damage) local actual_damage = self:calculate_damage(damage) self.hp = self.hp - actual_damage + main.current.damage_dealt = main.current.damage_dealt + actual_damage if self.hp <= 0 then 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 diff --git a/engine/game/group.lua b/engine/game/group.lua index 907d1fb..b628f3a 100644 --- a/engine/game/group.lua +++ b/engine/game/group.lua @@ -154,7 +154,7 @@ end function Group:destroy() - for _, object in ipairs(self.objects) do object:destroy() end + for _, object in ipairs(self.objects) do if object.destroy then object:destroy() end end self.objects = {} self.objects.by_id = {} self.objects.by_class = {} diff --git a/main.lua b/main.lua index b7c11e6..c8da342 100644 --- a/main.lua +++ b/main.lua @@ -191,7 +191,7 @@ function init() ['outlaw'] = function(dmg) return '[fg]throws a fan of [yellow]5[] knives, each dealing [yellow]' .. dmg .. '[fg] damage' end, ['blade'] = function(dmg) return '[fg]throws multiple blades that deal [yellow]' .. dmg .. ' AoE[fg] damage' end, ['elementor'] = function(dmg) return '[fg]deals [yellow]' .. dmg .. ' AoE[fg] damage to a random target' end, - ['saboteur'] = function(dmg) return '[fg]calls [yellow]4[] saboteus to seek targets and deal [yellow]' .. dmg .. ' AoE[fg] damage' end, + ['saboteur'] = function(dmg) return '[fg]calls [yellow]2[] saboteurs to seek targets and deal [yellow]' .. dmg .. ' AoE[fg] damage' end, ['stormweaver'] = function(dmg) return '[fg]infuses all allied projectiles with chain lightning that deals [yellow]+' .. dmg .. '[fg] damage on hit' end, ['sage'] = function(dmg) return '[fg]shoots a slow projectile that draws enemies in' end, ['squire'] = function(dmg) return '[yellow]+10 dmg[fg] & [yellow]+25 def[fg] to adjacent units, heal them for [yellow]10%[fg] max hp every 8 seconds' end, @@ -373,13 +373,39 @@ function init() [25] = {0, 55, 45}, } - gold = 100 + level_to_gold_gained = { + [1] = {1, 1}, + [2] = {1, 2}, + [3] = {2, 3}, + [4] = {2, 3}, + [5] = {3, 5}, + [6] = {3, 5}, + [7] = {4, 7}, + [8] = {4, 7}, + [9] = {5, 8}, + [10] = {5, 8}, + [11] = {5, 8}, + [12] = {6, 10}, + [13] = {6, 10}, + [14] = {6, 10}, + [15] = {7, 11}, + [16] = {8, 12}, + [17] = {8, 12}, + [18] = {8, 12}, + [19] = {8, 12}, + [20] = {10, 14}, + [21] = {10, 14}, + [22] = {11, 15}, + [23] = {11, 15}, + [24] = {12, 18}, + [25] = {12, 18}, + } + + gold = 2 main = Main() main:add(BuyScreen'buy_screen') - main:go_to('buy_screen', 1, { - {character = 'vagrant', level = 1, reserve = {0, 0}}, {character = 'swordsman', level = 1, reserve = {0, 0}}, - }) + main:go_to('buy_screen', 0, {}) end diff --git a/objects.lua b/objects.lua index f2a57ce..e7a9751 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, 4, 8, 4, 5, 10, 5, 6, 12, 7, 8, 15, 9, 10, 18, 14, 15, 24, 25} - self.base_hp = 50 + 20*y[x] - self.base_dmg = 10 + 3*y[x] - self.base_mvspd = 70 + 2*y[x] + self.base_hp = 50 + 40*y[x] + self.base_dmg = 10 + 20*y[x] + self.base_mvspd = 70 + 7*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 78f114f..4ecb659 100644 --- a/player.lua +++ b/player.lua @@ -142,7 +142,7 @@ function Player:init(args) SpawnEffect{group = main.current.effects, x = self.x, y = self.y, action = function(x, y) Saboteur{group = main.current.main, x = x, y = y, parent = self, conjurer_buff_m = self.conjurer_buff_m or 1} end} - end, 4) + end, 2) end) elseif self.character == 'stormweaver' then @@ -300,7 +300,6 @@ function Player:init(args) end) end - print(self.character) self:calculate_stats(true) if self.leader then @@ -500,11 +499,13 @@ function Player:hit(damage) if self.dead then return end 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} camera:shake(4, 0.5) + main.current.damage_taken = main.current.damage_taken + actual_damage if self.character == 'psykeeper' then self.psykeeper_heal = self.psykeeper_heal + actual_damage end @@ -513,6 +514,12 @@ function Player:hit(damage) 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 end end @@ -545,6 +552,35 @@ function Player:chronomancer_buff(duration) end +function Player:recalculate_followers() + if self.dead then + local new_leader = table.remove(self.followers, 1) + new_leader.leader = true + new_leader.previous_positions = {} + new_leader.followers = self.followers + new_leader.t:every(0.01, function() + table.insert(new_leader.previous_positions, 1, {x = new_leader.x, y = new_leader.y, r = new_leader.r}) + if #new_leader.previous_positions > 256 then new_leader.previous_positions[257] = nil end + end) + main.current.player = new_leader + for i, follower in ipairs(self.followers) do + follower.parent = new_leader + follower.follower_index = i + end + else + for i = #self.followers, 1, -1 do + if self.followers[i].dead then + table.remove(self.followers, i) + break + end + end + for i, follower in ipairs(self.followers) do + follower.follower_index = i + end + end +end + + function Player:add_follower(unit) table.insert(self.followers, unit) unit.parent = self @@ -990,7 +1026,7 @@ function Pet:init(args) self:set_as_rectangle(8, 8, 'dynamic', 'projectile') self:set_restitution(0.5) self.hfx:add('hit', 1) - self.color = orange[0] + self.color = character_colors.hunter self.pierce = 6 pet1:play{pitch = random:float(0.95, 1.05), volume = 0.35} end