From e74d8b44eb2ed109320513622deed56484fb582c Mon Sep 17 00:00:00 2001 From: a327ex Date: Mon, 19 Apr 2021 00:31:47 -0300 Subject: [PATCH] Day 60-61 --- arena.lua | 92 ++++++++++++++++++------------------ buy_screen.lua | 115 +++++++++++++++++++++++++++++++++++++++------ devlog.md | 6 +++ main.lua | 35 ++++++++------ player.lua | 35 +++++++++++--- shared.lua | 1 + todo | 123 ------------------------------------------------- 7 files changed, 207 insertions(+), 200 deletions(-) diff --git a/arena.lua b/arena.lua index ea35e0e..ea48d01 100644 --- a/arena.lua +++ b/arena.lua @@ -7,11 +7,12 @@ function Arena:init(name) end -function Arena:on_enter(from, level, units) +function Arena:on_enter(from, level, units, passives) self.hfx:add('condition1', 1) self.hfx:add('condition2', 1) self.level = level or 1 self.units = units + self.passives = passives steam.friends.setRichPresence('steam_display', '#StatusFull') steam.friends.setRichPresence('text', 'Arena - Level ' .. self.level) @@ -63,9 +64,9 @@ function Arena:on_enter(from, level, units) for i, unit in ipairs(units) do if i == 1 then - self.player = Player{group = self.main, x = gw/2, y = gh/2 + 16, leader = true, character = unit.character, level = unit.level} + self.player = Player{group = self.main, x = gw/2, y = gh/2 + 16, leader = true, character = unit.character, level = unit.level, passives = self.passives} else - self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level}) + self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level, passives = self.passives}) end end @@ -249,8 +250,6 @@ function Arena:on_enter(from, level, units) self.healer_level = class_levels.healer self.psyker_level = class_levels.psyker self.conjurer_level = class_levels.conjurer - - self.can_quit = true end @@ -336,9 +335,6 @@ function Arena:update(dt) if self.can_quit and #self.main:get_objects_by_classes(self.enemies) <= 0 and not self.transitioning 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 self.level == 25 then if not self.win_text and not self.win_text2 then @@ -370,44 +366,12 @@ function Arena:update(dt) local passive_1 = random:table(tier_to_passives[random:weighted_pick(unpack(level_to_passive_tier_weights[level or self.level]))]) local passive_2 = random:table(tier_to_passives[random:weighted_pick(unpack(level_to_passive_tier_weights[level or self.level]))]) local passive_3 = random:table(tier_to_passives[random:weighted_pick(unpack(level_to_passive_tier_weights[level or self.level]))]) - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 0*(card_w + 20) + card_w/2, y = gh/2, w = card_w, h = card_h, arena = self, passive = passive_1, force_update = true}) - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 1*(card_w + 20) + card_w/2, y = gh/2, w = card_w, h = card_h, arena = self, passive = passive_2, force_update = true}) - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 2*(card_w + 20) + card_w/2, y = gh/2, w = card_w, h = card_h, arena = self, passive = passive_3, force_update = true}) + 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, arena = self, passive = passive_1, force_update = true}) + 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, arena = self, passive = passive_2, force_update = true}) + 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, arena = self, passive = passive_3, force_update = true}) 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'}}} else - 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() - 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 = '[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, 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)} + self:transition() end end, 'transition') end @@ -491,6 +455,46 @@ function Arena:die() end +function Arena:transition() + 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 + 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, passives) + 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() + 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 = '[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, 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 + + function Arena:enemy_killed() if self.win_condition == 'enemy_kill' then self.enemies_killed = self.enemies_killed + 1 diff --git a/buy_screen.lua b/buy_screen.lua index c08e34d..e2627c5 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -18,7 +18,6 @@ function BuyScreen:on_exit() 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 @@ -26,9 +25,10 @@ function BuyScreen:on_exit() end -function BuyScreen:on_enter(from, level, units) +function BuyScreen:on_enter(from, level, units, passives) self.level = level self.units = units + self.passives = passives camera.x, camera.y = gw/2, gh/2 if self.level == 0 then @@ -46,18 +46,15 @@ function BuyScreen:on_enter(from, level, units) self:set_cards() self:set_party_and_sets() + self:set_items() 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]classes', 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 - 55, r = -math.pi/48, lines = { - {text = '[light_bg]under', font = fat_font, alignment = 'center'}, - {text = '[light_bg]construction', font = fat_font, alignment = 'center'}, - }} 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} + GoButton{group = self.main, x = gw - 135, y = gh - 20, parent = self} -- WishlistButton{group = self.main, x = gw - 147, y = gh - 20, parent = self} end @@ -174,7 +171,7 @@ function BuyScreen:set_party_and_sets() self.characters = {} local y = 40 for i, unit in ipairs(self.units) do - table.insert(self.characters, CharacterPart{group = self.main, x = gw - 30, y = y + (i-1)*20, character = unit.character, level = unit.level, reserve = unit.reserve, i = i, spawn_effect = unit.spawn_effect, parent = self}) + table.insert(self.characters, CharacterPart{group = self.main, x = gw - 30, y = y + (i-1)*19, character = unit.character, level = unit.level, reserve = unit.reserve, i = i, spawn_effect = unit.spawn_effect, parent = self}) unit.spawn_effect = false end @@ -190,6 +187,17 @@ function BuyScreen:set_party_and_sets() end +function BuyScreen:set_items() + if self.items then for _, item in ipairs(self.items) do item:die() end end + self.items = {} + local y = 182 + for k, item in ipairs(self.passives) do + local i, j = math.index_to_coordinates(k, 4) + table.insert(self.items, ItemCard{group = self.main, x = 45 + (i-1)*60, y = y + (j-1)*50, w = 40, h = 50, passive = item}) + end +end + + WishlistButton = Object:extend() @@ -259,7 +267,7 @@ function GoButton:init(args) self:init_game_object(args) 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 = '[greenm5]GO!', font = pixul_font, alignment = 'center'}}, global_text_tags) end @@ -287,7 +295,7 @@ function GoButton:update(dt) 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) + main:go_to('arena', ((self.parent.first_screen and 1) or (self.parent.level + 1)), self.parent.units, self.parent.passives) 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 @@ -296,8 +304,8 @@ end function GoButton:draw() graphics.push(self.x, self.y, 0, self.spring.x, self.spring.y) - graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.selected and fg[0] or bg[1]) - self.text:draw(self.x, self.y + 1) + graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.selected and fg[0] or green[0]) + self.text:draw(self.x, self.y + 1, 0, 1, 1) graphics.pop() end @@ -312,7 +320,7 @@ end function GoButton:on_mouse_exit() - self.text:set_text{{text = '[bg10]GO!', font = pixul_font, alignment = 'center'}} + self.text:set_text{{text = '[greenm5]GO!', font = pixul_font, alignment = 'center'}} self.selected = false end @@ -498,7 +506,17 @@ end function PassiveCard:update(dt) self:update_game_object(dt) self.passive_name:update(dt) - print(dt) + + if self.selected and input.m1.pressed and self.arena.choosing_passives then + self.arena.choosing_passives = false + table.insert(passives, self.passive) + trigger:tween(0.25, _G, {slow_amount = 1}, math.linear, function() + slow_amount = 1 + self.arena:transition() + end) + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self:die() + end end @@ -511,6 +529,7 @@ end function PassiveCard:on_mouse_enter() + self.selected = true ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} self.spring:pull(0.2, 200, 10) self.info_text = InfoText{group = main.current.ui, force_update = true} @@ -522,12 +541,80 @@ end function PassiveCard:on_mouse_exit() + self.selected = false self.info_text:deactivate() self.info_text.dead = true self.info_text = nil end +function PassiveCard:die() + self.dead = true + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + + + +ItemCard = Object:extend() +ItemCard:implement(GameObject) +function ItemCard:init(args) + self:init_game_object(args) + self.shape = Rectangle(self.x, self.y, self.w, self.h) + self.interact_with_mouse = true +end + + +function ItemCard:update(dt) + self:update_game_object(dt) +end + + +function ItemCard:draw() + graphics.push(self.x, self.y, 0, self.spring.x, self.spring.x) + if self.selected then + graphics.rectangle(self.x, self.y, self.w, self.h, 6, 6, bg[-1]) + end + _G[self.passive]:draw(self.x, self.y, 0, 0.8, 0.7, 0, 0, fg[0]) + graphics.pop() +end + + +function ItemCard:on_mouse_enter() + self.selected = true + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} + self.spring:pull(0.2, 200, 10) + self.info_text = InfoText{group = main.current.ui, force_update = true} + self.info_text:activate({ + {text = '[fg]' .. passive_names[self.passive], font = pixul_font, alignment = 'center', height_multiplier = 1.25}, + {text = passive_descriptions[self.passive], 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 + 10 +end + + +function ItemCard:on_mouse_exit() + self.selected = false + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil +end + + +function ItemCard:die() + self.dead = true + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + ShopCard = Object:extend() ShopCard:implement(GameObject) diff --git a/devlog.md b/devlog.md index f61f12c..f7c6a2e 100644 --- a/devlog.md +++ b/devlog.md @@ -964,3 +964,9 @@ Finished remaining 5 characters and revised all class bonuses. So 40/40 characte Had to ideaguy all 40 passives. Managed to do it and also get the passive selection screen working partly. Tomorrow I should finish it and start working through the 40 passives, which should go significantly faster than the characters since I made sure to pick types of passives that were already implemented one way or another in the game. + +# Day 60-61 - 17-18/04/21 + +Finished literally everything needed to make passives work, now I only need to actually make them. The more I work on this the clearer the parts that slow me down because they're annoying to work with +become. Generally it's higher level "glue" type of code, rather than the code that actually makes the thing work as a unit. So the node refactor for instance is addressing a lot of this glue code by making it conceptually the same +thing, which should make it easier to work with. The rect cutting UI idea does something similar the high level part of UI, which tends to be mostly layouting. And so on. diff --git a/main.lua b/main.lua index 0e8ccc3..004ad37 100644 --- a/main.lua +++ b/main.lua @@ -936,8 +936,8 @@ function init() } passive_descriptions = { - ['ouroboros_technique_r'] = '[fg]rotating around yourself to the right makes every unit periodically release projectiles', - ['ouroboros_technique_l'] = '[fg]rotating around yourself to the left grants +25% defense to all units', + ['ouroboros_technique_r'] = '[fg]rotating around yourself to the right makes units release projectiles', + ['ouroboros_technique_l'] = '[fg]rotating around yourself to the left grants [yellow]+25%[fg] defense to all units', ['wall_echo'] = '[fg]hitting walls has a [yellow]25%[fg] chance of releasing [yellow]2[fg] projectiles', ['wall_rider'] = '[fg]hitting walls grants a [yellow]25%[fg] movement speed buff to your snake for [yellow]1[fg] second', ['centipede'] = '[yellow]+20%[fg] movement speed', @@ -952,19 +952,19 @@ function init() ['point_blank'] = '[fg]projectiles deal up to [yellow]+100%[fg] damage up close and down to [yellow]-50%[fg] damage far away', ['longshot'] = '[fg]projectiles deal up to [yellow]+100%[fg] damage far away and down to [yellow]-50%[fg] up close', ['blunt_arrow'] = '[fg]all arrows fired by rangers have a [yellow]20%[fg] chance to knockback', - ['explosive_arrow'] = '[fg]all arrows fired by rangers have a [yellow]20%[fg] chance to explode, dealing [yellow]+20%[fg] damage in a small area', - ['divine_machine_arrow'] = '[fg]all arrows fired by rangers have a [yellow]20%[fg] chance to seek enemies and pierce [yellow]5[fg] times', + ['explosive_arrow'] = '[fg]arrows fired by rangers have a [yellow]20%[fg] chance to explode, dealing [yellow]20%[fg] AoE damage', + ['divine_machine_arrow'] = '[fg]arrows fired by rangers have a [yellow]20%[fg] chance to seek enemies and pierce [yellow]5[fg] times', ['chronomancy'] = '[fg]all mages cast their spells [yellow]25%[fg] faster', - ['awakening'] = '[fg]at the start of the round [yellow]1[fg] mage is chosen at random and is granted [yellow]+100%[fg] attack speed and damage for that round', - ['divine_punishment'] = '[fg]periodically deal [yellow]10X[fg] damage to all enemies, where [yellow]X[fg] is the number of mages you have', - ['berserking'] = '[fg]all warriors have up to [yellow]+50%[fg]attack speed based on missing HP', + ['awakening'] = '[fg]every round [yellow]1[fg] mage is granted [yellow]+100%[fg] attack speed and damage for that round', + ['divine_punishment'] = '[fg]periodically deal [yellow]10X[fg] damage to all enemies, where [yellow]X[fg] is how many mages you have', + ['berserking'] = '[fg]all warriors have up to [yellow]+50%[fg] attack speed based on missing HP', ['unwavering_stance'] = '[fg]all warriors gain [yellow]+5%[fg] defense every [yellow]5[fg] seconds, up to [yellow]+50%[fg]', ['ultimatum'] = '[fg]projectiles that chain gain [yellow]+25%[fg] damage with each chain', ['flying_daggers'] = '[fg]all knives thrown by rogues chain [yellow]+2[fg] times', ['assassination'] = '[fg]your crits deal [yellow]8x[fg] damage (up from [yellow]4x[fg]) but normal attacks deal [yellow]half[fg] damage', ['magnify'] = '[yellow]+25%[fg] area size', ['concentrated_fire'] = '[yellow]-50%[fg] area size and [yellow]+50%[fg] area damage', - ['unleash'] = '[fg]gain [yellow]+5%[fg] area size and damage per second, this resets when an AoE attack happens', + ['unleash'] = '[yellow]+5%[fg] area size and damage per second, this resets when any AoE attack happens', ['reinforce'] = '[yellow]+10%[fg] damage, defense and attack speed to all allies if you have at least one enchanter', ['payback'] = '[yellow]+5%[fg] damage to all allies whenever an enchanter is hit', ['blessing'] = '[yellow]+20%[fg] healing effectiveness', @@ -977,7 +977,7 @@ function init() ['call_of_the_void'] = '[yellow]+25%[fg] damage over time', ['spawning_pool'] = '[yellow]+1[fg] critter health', ['hive'] = '[yellow]+2[fg] critter health', - ['void_rift'] = '[fg]all AoE attacks by mages, nukers or voiders have a [yellow]20%[fg] chance to create an area that deals [yellow]50%[fg] damage per second for [yellow]2[fg] seconds', + ['void_rift'] = '[fg]AoE attacks by mages, nukers or voiders have a [yellow]20%[fg] chance to create a void rift', } passive_tiers = { @@ -1045,17 +1045,25 @@ function init() } gold = 2 + passives = {'ouroboros_technique_r'} main = Main() - --[[ main:add(BuyScreen'buy_screen') - main:go_to('buy_screen', 3, { + main:go_to('buy_screen', 2, { {character = 'swordsman', level = 3}, {character = 'wizard', level = 3}, {character = 'scout', level = 3}, {character = 'archer', level = 3}, - }) - ]]-- + {character = 'host', level = 3}, + {character = 'beastmaster', level = 3}, + {character = 'corruptor', level = 3}, + {character = 'flagellant', level = 3}, + {character = 'psykino', level = 3}, + {character = 'juggernaut', level = 3}, + {character = 'vagrant', level = 3}, + {character = 'stormweaver', level = 3}, + }, passives) + --[[ main:add(Arena'arena') main:go_to('arena', 3, { {character = 'swordsman', level = 3}, @@ -1063,6 +1071,7 @@ function init() {character = 'scout', level = 3}, {character = 'archer', level = 3}, }) + ]]-- end diff --git a/player.lua b/player.lua index 1518835..b32e7c3 100644 --- a/player.lua +++ b/player.lua @@ -6,6 +6,8 @@ function Player:init(args) self:init_game_object(args) self:init_unit() + for k, v in pairs(self.passives) do self[v] = true end + self.color = character_colors[self.character] self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' @@ -434,6 +436,23 @@ function Player:init(args) end) end + if self.ouroboros_technique_r then + self.t:every(0.1, function() + if self.move_right_pressed and love.timer.getTime() - self.move_right_pressed > 1 then + local units = self:get_all_units() + local cx, cy = 0, 0 + for _, unit in ipairs(units) do + cx = cx + unit.x + cy = cy + unit.y + end + cx = cx/#units + cy = cy/#units + local unit = random:table(units) + unit:barrage(unit:angle_from_point(cx, cy), 1) + end + end) + end + self.first_frame_calculate_stats = true end @@ -568,6 +587,10 @@ function Player:update(dt) self.t:set_every_multiplier('attack', self.aspd_m) if self.leader then + if input.move_left.pressed and not self.move_right_pressed then self.move_left_pressed = love.timer.getTime() end + if input.move_right.pressed and not self.move_left_pressed then self.move_right_pressed = love.timer.getTime() end + if input.move_left.released then self.move_left_pressed = nil end + if input.move_right.released then self.move_right_pressed = nil end if input.move_left.down then self.r = self.r - 1.66*math.pi*dt end 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)) @@ -652,7 +675,7 @@ function Player:on_collision_enter(other, contact) end elseif table.any(main.current.enemies, function(v) return other:is(v) end) then - other:push(random:float(25, 35)*self.knockback_m, self:angle_to_object(other)) + other:push(random:float(25, 35)*(self.knockback_m or 1), self:angle_to_object(other)) if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(2*self.dmg) else other:hit(self.dmg) end if other.headbutting then @@ -1291,7 +1314,7 @@ function Projectile:on_trigger_enter(other, contact) end if self.knockback then - other:push(self.knockback*self.knockback_m, self.r) + other:push(self.knockback*(self.knockback_m or 1), self.r) end end end @@ -1347,7 +1370,7 @@ function Area:init(args) if self.juggernaut_push then local r = self.parent:angle_to_object(enemy) - enemy:push(random:float(75, 100)*self.knockback_m, r) + enemy:push(random:float(75, 100)*(self.knockback_m or 1), r) enemy.juggernaut_push = 3*self.dmg end end @@ -1531,7 +1554,7 @@ function ForceArea:init(args) local enemies = main.current.main:get_objects_in_shape(self.shape, main.current.enemies) for _, enemy in ipairs(enemies) do enemy:hit(4*self.parent.dmg) - enemy:push(50*self.knockback_m, self:angle_to_object(enemy)) + enemy:push(50*(self.knockback_m or 1), self:angle_to_object(enemy)) end end end) @@ -1763,7 +1786,7 @@ function Pet:on_trigger_enter(other) if self.pierce <= 0 then camera:shake(2, 0.5) other:hit(self.parent.dmg*(self.conjurer_buff_m or 1)) - other:push(35*self.knockback_m, self:angle_to_object(other)) + other:push(35*(self.knockback_m or 1), self:angle_to_object(other)) self.dead = true local n = random:int(3, 4) for i = 1, n do HitParticle{group = main.current.effects, x = x, y = y, r = random:float(0, 2*math.pi), color = self.color} end @@ -1771,7 +1794,7 @@ function Pet:on_trigger_enter(other) else camera:shake(2, 0.5) other:hit(self.parent.dmg*(self.conjurer_buff_m or 1)) - other:push(35*self.knockback_m, self:angle_to_object(other)) + other:push(35*(self.knockback_m or 1), self:angle_to_object(other)) self.pierce = self.pierce - 1 end hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} diff --git a/shared.lua b/shared.lua index 344d965..cc8e249 100644 --- a/shared.lua +++ b/shared.lua @@ -434,6 +434,7 @@ global_text_tags = { fg = TextTag{draw = function(c, i, text) graphics.set_color(fg[0]) end}, fgm5 = TextTag{draw = function(c, i, text) graphics.set_color(fg[-5]) end}, fgm10 = TextTag{draw = function(c, i, text) graphics.set_color(fg[-10]) end}, + greenm5 = TextTag{draw = function(c, i, text) graphics.set_color(green[-5]) end}, wavy = TextTag{update = function(c, dt, i, text) c.oy = 2*math.sin(4*time + i) end}, wavy_mid = TextTag{update = function(c, dt, i, text) c.oy = 0.75*math.sin(3*time + i) end}, wavy_mid2 = TextTag{update = function(c, dt, i, text) c.oy = 0.5*math.sin(3*time + i) end}, diff --git a/todo b/todo index 85bad76..5dd4b7a 100644 --- a/todo +++ b/todo @@ -1,135 +1,12 @@ -* 1. Enemy spawn points should have some markers before enemy spawns, or should avoid spawning near the player at all -* 2. Prevent spawning of units that cost 3 on first level -* 3. Prevent spawning of units that don't attack on first level - -* 4. Rework position based units so that position in the snake doesn't matter - * Chronomancer: +20% attack speed to all allies - * Psykeeper: stores damage taken by all allies up to 50% its max HP and redistributes it as healing - * Squire: +10% damage and defense to all allies - -* 7. Enemy modifiers - * green - Grant nearby enemies a speed boost on death - * blue - Explode into projectiles on death - * orange - Charge up and headbutt towards the player at increased speed and damage - * yellow - Resistance to knockback and increased HP - * white - Remain static and shoot projectiles - * purple - Explodes into critters on death - -* 6. Mini boss every 3rd level - * Speed Booster - grants speed boost to nearby enemies - * Swarmer - explodes enemies into a swarm of critters - * Exploder - explodes enemies into projectiles - * Forcer - pulls enemies together into a point and pushes them out - * Randomizer - randomly does the 4 ones above - Orbitter - spawns shooters that orbit the boss - -* 8. Additional characters and classes -* 9. Lv.3 effects for every character - * Classes - * Ranger: chance to release a barrage on attack - * Warrior: increased defense - * Mage: decreased enemy defense - * Nuker: increased area damage and size - * Rogue: chance to crit - * Healer: increased healing effectiveness - * Enchanter: increased damage - * Conjurer: increased summon damage and duration - * Psyker: increased damage and health based on number of active sets - * Curser: increased curse effect and duration - * Forcer: increased knockback force - * Swarmer: increased critter health - * Voider: increased damage over time - * Characters - * Vagrant [psyker, ranger, warrior]: shoots a projectile - Lv.3: Champion - gains increased damage and attack speed based on number of active sets - * Swordsman [warrior]: deals AoE damage, deals extra damage for each unit hit - Lv.3: Cleave - damage is doubled - * Wizard [mage]: shoots a projectile that deals AoE damage - Lv.3: Magic Missile - the projectile chains 5 times, each dealing AoE damage on impact - * Archer [ranger]: shoots an arrow that pierces - Lv.3: Bounce Shot - the arrow ricochets on walls 3 times - * Scout [rogue]: throws a knife that chains 3 times - Lv.3: Replica - each chain grants +15% damage and the last chain splits - * Cleric [healer]: heals a unit when its health drops below half HP - Lv.3: Mass Heal - heals all units instead of one - * Outlaw [warrior, rogue]: throws a fan of 5 knives - Lv.3: Fatal Roulette - every 3rd attack throw a nova of 15 knives instead - * Blade [warrior, nuker]: throws multiple blades that deal AoE damage - Lv.3: Blade Resonance - deal additional damage based on number of enemies hit - * Elementor [mage, nuker]: deals AoE damage to a random target in a large area - Lv.3: Windfield - slows enemies hit - * Saboteur [rogue, conjurer, nuker]: calls saboteurs to seek targets and deal AoE damage - Lv.3: Chain Reaction - should an enemy die from a saboteur explosion, it also explodes - * Stormweaver [enchanter]: infuses all allied projectiles with chain lightning that deals extra damage - Lv.3: Lightning Spire - cast a spire of lightning periodically - * Sage [nuker]: shoots a slow moving projectile that pulls enemies in - Lv.3: Dimension Compression - when the projectile expires deal massive damage to all enemies under its influence - (Repair to do after items implemented) * Squire [warrior, enchanter]: increased damage and defense to all allies - Lv.3: Repair - you can reroll your item choice once every 3 levels, these opportunities stack if unused - * Cannoneer [ranger, nuker]: shoots a projectile that deals AoE damage - Lv.3: Cannon Barrage - showers the hit area in additional cannon shots that deal AoE damage - * Dual Gunner [ranger, rogue]: shoots two parallel projectiles - Lv.3: Gun Kata - every 5th attack shoots projectiles in a rapid succession for a duration, targetting all nearby enemies - * Hunter [ranger, conjurer]: shoots an arrow that summons a pet - Lv.3: Feral Pack - summons 3 pets - * (Apply arena.chronomancer_dot when damage over time is implemented) * Chronomancer [mage, enchanter]: increased attack speed to all allies - Lv.3: Quicken - enemies take DoT faster - * Spellblade [mage, rogue]: throws knives that spiral outwards and pierce - Lv.3: Spiralism - faster projectile speed and tighter turns - * Psykeeper [healer, psyker]: stores damage taken by all allies and redistributes it as healing - Lv.3: Crucio - also redistributes it as damage to all enemies - * Engineer [conjurer]: drops sentries that shoot bursts of projectils - Lv.3: Upgrade - every 3rd sentry dropped, upgrade all sentries temporarily, giving increased damage and attack speed - * Plague Doctor [nuker, voider]: creates an area that deals DoT - Lv.3: Pandemic - inflicts enemies with a contagion that deals additional DoT, if they die from it it passes to a nearby enemy - * Barbarian [curser, warrior]: deals AoE damage and stuns enemies hit for 4 seconds - Lv.3: Seism - stunned enemies also take 100% increased damage - * Juggernaut [forcer, warrior]: creates a small area that deals AoE damage and pushes enemies away - Lv.3: Brutal Impact - enemies pushed away are instantly killed if they hit a wall - * Lich [mage]: launches a chain frost that chains 7 times, dealing damage and slowing enemies it hits - Lv.3: Piercing Frost - chain frost ignores enemy defenses - * Cryomancer [mage, voider]: nearby enemies take damage over time and have decreased movement speed - Lv.3: Frostbite - enemies killed by the cryomancer freeze nearby enemies, frozen enemies can't move and take increased damage - * Pyromancer [mage, nuker, voider]: nearby enemies take damage over time and deal decreased damage - Lv.3: Ignite - enemies killed by the pyromancer explode, dealing AoE damage - * Corruptor [ranger, swarmer]: spawn 3 small critters if the corruptor kills an enemy - Lv.3: Corruption - spawn 3 small critters if the corruptor hits an enemy - * Beastmaster [rogue, swarmer]: spawn 2 small critters if the beastmaster crits - Lv.3: Call of the Wild - spawn 2 small critters if the beastmaster gets hit - * Launcher [curser, forcer]: curses nearby enemies with a kinetic curse that triggers after 4 seconds - Lv.3: Kineticism - enemies launched that hit other enemies transfer their kinetic energy at double value - * Bard [curser, rogue]: shoots a projectile that inflicts enemies hit with the bard's curse - Lv.3: The Bard's Song - every 5th attack consume the curse to deal massive damage to enemies affected - * Assassin [rogue, voider]: throws a piercing knife that inflicts poison - Lv.3: Toxic Delivery - poison inflicted from crits deals more damage - * Host [swarmer]: creates overlords that periodically spawn small critters - Lv.3: Invasion - increased critter spawn rate - * Carver [conjurer, healer]: carves a statue that periodically heals in an area - Lv.3: World Tree - carves a tree that heals in a bigger area and removes all buffs from enemies - * Bane [curser, voider]: creates a large area that curses enemies to take increased damage - Lv.3: Nightmare - the area also deals DoT and slows enemies - * Psykino [mage, psyker, forcer]: quickly pulls enemies together and then releases them with a force - Lv.3: Magnetic Force - enemies pulled together are forced to collide with each other before being released - * Barrager [ranger, forcer]: shoots a barrage of 5 arrows that knocks enemies back - Lv.3: every 3rd attack the barrage shoots 15 projectiles and they push harder - * Highlander [warrior]: creates a small area that deals massive damage - Lv.3: Crosscut - two crosscutting areas of larger size are created instead - * Fairy [enchanter, healer]: periodically heals 1 random unit that has less than 100% HP and grants it +200% attack speed for 6 seconds - Lv.3: heals and buffs 2 units instead - * Priest [healer]: heals all units periodically - Lv.3: Divine Intervention - at the start of the round pick 3 units at random and grants them a buff that prevents them from dying once - * Infestor [curser, swarmer]: curses nearby enemies for 6 seconds, they will release multiple critters on death - Lv.3: Infestation - triples the number of critters released - * Flagellant [psyker, enchanter]: periodically deals damage to self and grants a damage buff to all allies - Lv.3: Zealotry - deals damage to all allies instead and also grants a massive damage buff - * Sets - * Ranger = 7/7 - * Warrior = 8/8 - * Mage = 8/8 - * Rogue = 8/8 - * Nuker = 7/7 - * Conjurer = 5/5 - * Forcer = 5/5 - * Voider = 5/5 - * Psyker = 4/4 - * Healer = 5/5 - * Enchanter = 5/5 - * Curser = 5/5 - * Swarmer = 4/4 - -10. Items - Ouroboros Technique R: rotating around yourself to the right makes every unit periodically release projectiles - Ouroboros Technique L: rotating around yourself to the left grants +25% defense to all units - Resonance: hitting walls has a chance of releasing projectiles - Wall Rider: hitting walls grants a speed buff for a small duration - Force Push: +25% knockback force - Heavy Impact: if knockbacked enemies hit walls they take damage according to the knockback force - Centipede: +20% movement speed - Intimidation: enemies spawn with -20% max HP - Crucio: taking damage shares 2x the amount of HP you lost across all enemies - Amplify: all units that deal AoE damage gain +25% AoE damage - Amplify X: +25% AoE damage if all your units only deal AoE damage (excluding supports) - Ballista: all units that release projectiles and don't deal AoE damage gain +25% damage - Ballista X: +25% damage if all your units only release projectiles and don't deal AoE damage (excluding supports) - Point Blank: projectiles deal increased damage based on distance not travelled, +100% at 0 distance and -50% at max distance - Longshot: projectiles deal increased damage based on distance travelled, -50% at 0 distance and +100% at max distance - Chain Reaction: projectiles that chain gain 25% damage with each chain - Call of the Void: +25% DoT damage - ... more ideas will come later I'm sure, aiming for 30 total items - 5. Stat and description details to each unit when hovering over it in the party section 6. Classes line on each unit's shop card, as well as on party section 11. Steam integration: achievements, etc 12. Hovering over a party member should show which set they belong to and vice-versa 13. Show a unit DPS list like Underlord's to the right side of the screen -* 14. Warriors that deal AoE damage should deal extra damage based on number of enemies hit 15. GO button is grayed out and thus doesn't say it's meant to be clicked on 16. 28/20 enemies or 4/3 wave confuses players and makes them think the level goals are bugged 17. Music for first 9-15 levels should be calm rather than upbeat -* 18. Crash: Error: engine/game/hitfx.lua:46: attempt to index field 'parent', engine/game/hitfx.lua:46: in function 'use' love.js:9:40605, enemies.lua:56: in function 'on_collision_enter' love.js:9:40605 -* 19. Sage's pull force doesn't increase with unit level -* 20. Cleric's healing amount doesn't increase with unit level -* 21. Squire and Chronomancer's buffs don't increase with unit level Engine improvements for after SNKRX release Node refactor: described partly somewhere in the devlog