From 868cae93edc05c3d578c718eb86bca68d37f6fa4 Mon Sep 17 00:00:00 2001 From: a327ex Date: Sun, 4 Jul 2021 01:50:31 -0300 Subject: [PATCH] Loop update 4/5 --- arena.lua | 46 +++++++--- assets/images/hardening.png | Bin 0 -> 425 bytes assets/images/psychoshot.png | Bin 0 -> 375 bytes buy_screen.lua | 13 +-- enemies.lua | 19 ++-- engine/system.lua | 4 +- main.lua | 63 ++++++++------ mainmenu.lua | 2 +- player.lua | 164 ++++++++++++++++++++++------------- shared.lua | 3 +- todo | 49 ++++++----- 11 files changed, 228 insertions(+), 135 deletions(-) create mode 100644 assets/images/hardening.png create mode 100644 assets/images/psychoshot.png diff --git a/arena.lua b/arena.lua index 6e75dc4..d73c037 100644 --- a/arena.lua +++ b/arena.lua @@ -380,6 +380,7 @@ function Arena:update(dt) ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = state.dark_transitions and bg[-2] or fg[0], transition_action = function() slow_amount = 1 + music_slow_amount = 1 gold = 3 passives = {} main_song_instance:stop() @@ -388,9 +389,9 @@ function Arena:update(dt) 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', 'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike', - 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', + 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', } max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) main:add(BuyScreen'buy_screen') @@ -411,9 +412,7 @@ function Arena:update(dt) end self:update_game_object(dt*slow_amount) - if not self.slow_transitioning then - main_song_instance.pitch = math.clamp(slow_amount*self.main_slow_amount, 0.05, 1) - end + main_song_instance.pitch = math.clamp(slow_amount*music_slow_amount, 0.05, 1) star_group:update(dt*slow_amount) self.floor:update(dt*slow_amount) @@ -446,6 +445,7 @@ function Arena:quit() system.save_run() trigger:tween(1, _G, {slow_amount = 0}, math.linear, function() slow_amount = 0 end, 'slow_amount') + trigger:tween(1, _G, {music_slow_amount = 0}, math.linear, function() music_slow_amount = 0 end, 'music_slow_amount') trigger:tween(4, camera, {x = gw/2, y = gh/2, r = 0}, math.linear, function() camera.x, camera.y, camera.r = gw/2, gh/2, 0 end) self.win_text = Text2{group = self.ui, x = gw/2 + 40, y = gh/2 - 69, force_update = true, lines = {{text = '[wavy_mid, cbyc2]congratulations!', font = fat_font, alignment = 'center'}}} trigger:after(2.5, function() @@ -593,7 +593,7 @@ function Arena:quit() steam.userStats.storeStats() end - if self.psyker_level >= 1 then + if self.psyker_level >= 2 then state.achievement_psykers_win = true system.save_state() steam.userStats.setAchievement('PSYKERS_WIN') @@ -684,6 +684,7 @@ function Arena:quit() input:set_mouse_visible(true) self.arena_clear_text.dead = true trigger:tween(1, _G, {slow_amount = 0}, math.linear, function() slow_amount = 0 end, 'slow_amount') + trigger:tween(1, _G, {music_slow_amount = 0}, math.linear, function() music_slow_amount = 0 end, 'music_slow_amount') trigger:tween(4, camera, {x = gw/2, y = gh/2, r = 0}, math.linear, function() camera.x, camera.y, camera.r = gw/2, gh/2, 0 end) self:set_passives() RerollButton{group = main.current.ui, x = gw - 40, y = gh - 40, parent = self, force_update = true} @@ -713,34 +714,39 @@ function Arena:set_passives(from_reroll) if self.cards[1] then self.cards[1].dead = true end if self.cards[2] then self.cards[2].dead = true end if self.cards[3] then self.cards[3].dead = true end + if self.cards[4] then self.cards[4].dead = true end self.cards = {} end - local card_w, card_h = 100, 100 - local w = 3*card_w + 2*20 + local card_w, card_h = 70, 100 + local w = 4*card_w + 3*20 self.choosing_passives = true self.cards = {} local passive_1 = random:table_remove(run_passive_pool) local passive_2 = random:table_remove(run_passive_pool) local passive_3 = random:table_remove(run_passive_pool) + local passive_4 = random:table_remove(run_passive_pool) if passive_1 then table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 0*(card_w + 20) + card_w/2 + 45, y = gh/2 - 20, w = card_w, h = card_h, card_i = 1, arena = self, passive = passive_1, force_update = true}) end if passive_2 then - table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 1*(card_w + 20) + card_w/2 + 45, y = gh/2 - 20, w = card_w, h = card_h, card_i = 2, arena = self, passive = passive_2, force_update = true}) + table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 1*(card_w + 20) + card_w/2 + 45, y = gh/2, w = card_w, h = card_h, card_i = 2, arena = self, passive = passive_2, force_update = true}) end if passive_3 then table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 2*(card_w + 20) + card_w/2 + 45, y = gh/2 - 20, w = card_w, h = card_h, card_i = 3, arena = self, passive = passive_3, force_update = true}) end + if passive_4 then + table.insert(self.cards, PassiveCard{group = main.current.ui, x = gw/2 - w/2 + 3*(card_w + 20) + card_w/2 + 45, y = gh/2, w = card_w, h = card_h, card_i = 4, arena = self, passive = passive_4, force_update = true}) + end self.passive_text = Text2{group = self.ui, x = gw/2 + 45, y = gh/2 - 75, lines = {{text = '[fg, wavy]choose one', font = fat_font, alignment = 'center'}}} - if not passive_1 and not passive_2 and not passive_3 then + if not passive_1 and not passive_2 and not passive_3 and not passive_4 then self:transition() end end function Arena:restore_passives_to_pool(j) - for i = 1, 3 do + for i = 1, 4 do if i ~= j then if self.cards[i] then table.insert(run_passive_pool, self.cards[i].passive) @@ -814,10 +820,22 @@ function Arena:die() locked_state = nil system.save_run() self.t:tween(2, self, {main_slow_amount = 0}, math.linear, function() self.main_slow_amount = 0 end) + self.t:tween(2, _G, {music_slow_amount = 0}, math.linear, function() music_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}, }} + trigger:tween(2, camera, {x = gw/2, y = gh/2, r = 0}, math.linear, function() camera.x, camera.y, camera.r = gw/2, gh/2, 0 end) self.t:after(2, function() + self.build_text = Text2{group = self.ui, x = 40, y = 20, force_update = true, lines = {{text = "[wavy_mid, fg]your build", font = pixul_font, alignment = 'center'}}} + for i, unit in ipairs(self.units) do + CharacterPart{group = self.ui, x = 20, y = 40 + (i-1)*19, character = unit.character, level = unit.level, force_update = true, cant_click = true, parent = self} + Text2{group = self.ui, x = 20 + 14 + pixul_font:get_text_width(unit.character)/2, y = 40 + (i-1)*19, force_update = true, lines = { + {text = '[' .. character_color_strings[unit.character] .. ']' .. unit.character, font = pixul_font, alignment = 'left'} + }} + end + for i, passive in ipairs(self.passives) do + ItemCard{group = self.ui, x = 120 + (i-1)*30, y = 30, w = 30, h = 45, sx = 0.75, sy = 0.75, force_update = true, passive = passive.passive , level = passive.level, xp = passive.xp, parent = self} + end self.death_info_text = Text2{group = self.ui, x = gw/2, y = gh/2, sx = 0.7, sy = 0.7, lines = { {text = '[wavy_mid, fg]level reached: [wavy_mid, yellow]' .. self.level, font = fat_font, alignment = 'center'}, }} @@ -828,6 +846,7 @@ function Arena:die() ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = state.dark_transitions and bg[-2] or fg[0], transition_action = function() slow_amount = 1 + music_slow_amount = 1 gold = 3 passives = {} main_song_instance:stop() @@ -836,9 +855,9 @@ function Arena:die() 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', 'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike', - 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', + 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', } max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) main:add(BuyScreen'buy_screen') @@ -965,6 +984,7 @@ function Arena:transition() end end slow_amount = 1 + music_slow_amount = 1 main:add(BuyScreen'buy_screen') system.save_run(self.level+1, self.loop, gold, self.units, self.passives, self.shop_level, self.shop_xp, run_passive_pool, locked_state) main:go_to('buy_screen', self.level+1, self.loop, self.units, self.passives, self.shop_level, self.shop_xp) diff --git a/assets/images/hardening.png b/assets/images/hardening.png new file mode 100644 index 0000000000000000000000000000000000000000..6c87c83ab2fde71252f3576e7a3e2af631feb6f5 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^8bEBr!3HEncK&z(q!^2X+?^QKos)S9a~60+7BevL9R^{>5}xg*Y9(GT02(9{qa!r-k>^FX_lhJqzNjajwUubD>*hT zR6MyNVT<7G#c9e-fjf0SNUc%W^kI*jvVy0Zz|`U(m5Kk8!rpLPxzhejYB5`=C3EJb zjI^&T#!u#KNO_`Lb|K*Sy7Y8CR`<6T9i`ni?|$Ra+%<=J{Xwp@6TLT5HO@cq*KnLF z6rzcpIL@ggKP9O0iS9PBt7;D`mmcg;*}GHQ@r$ycu-MIj?T&6mB7LXk8o6)3!8XNA zuyXm#X1iuVPq#Nkwa-)&RhC}cX3*qTzMbWR)tUv1J%Tm|Iw~u9p4Vt~-em9Np9N+%`E||s%zMyf*-PFJ56z4G6x$a9gO|b6)z4*}Q$iB}2HK<> literal 0 HcmV?d00001 diff --git a/assets/images/psychoshot.png b/assets/images/psychoshot.png new file mode 100644 index 0000000000000000000000000000000000000000..a7d474c04ead1692e5fa99cbc33aa58e5d14096c GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^8bEBr!3HEncK&z(q!^2X+?^QKos)S9a~60+7BevL9RguSQ4OyKpavdK7srqc=eM&iay1)>IG6tae?E_u-F26q z`N_77bKT8b_a2YY7Kz!O8-4Cf^8R_#I99m?JS}T_J2$m9e6<)@){m6}N(;{D zs@~AQQRmEB*7x|~&Z}bKNBgEczn?Vu&lHd)s!dvgA)O1nSVEOn2sw(jKX_B4J%73A z!7v#?hvU3EbGm1`tPqiO+!f37PORSg`?UOXnm4+q@;x`!+wJN0|cyDd*+=S~)Y1Wjq1~ O7K5j&pUXO@geCyO>626d literal 0 HcmV?d00001 diff --git a/buy_screen.lua b/buy_screen.lua index f6e3244..5ed686c 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -136,6 +136,7 @@ function BuyScreen:on_enter(from, level, loop, units, passives, shop_level, shop locked_state = nil TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = state.dark_transitions and bg[-2] or fg[0], transition_action = function() slow_amount = 1 + music_slow_amount = 1 gold = 3 passives = {} main_song_instance:stop() @@ -144,9 +145,9 @@ function BuyScreen:on_enter(from, level, loop, units, passives, shop_level, shop 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', 'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike', - 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', + 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', } max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) main:add(BuyScreen'buy_screen') @@ -541,6 +542,7 @@ function RestartButton:update(dt) ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = state.dark_transitions and bg[-2] or fg[0], transition_action = function() slow_amount = 1 + music_slow_amount = 1 gold = 3 passives = {} main_song_instance:stop() @@ -549,9 +551,9 @@ function RestartButton:update(dt) 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', 'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike', - 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', + 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', } system.save_state() main:add(BuyScreen'buy_screen') @@ -1330,8 +1332,9 @@ function PassiveCard:update(dt) self.arena.choosing_passives = false table.insert(self.arena.passives, {passive = self.passive, level = 1, xp = 0}) self.arena:restore_passives_to_pool(self.card_i) - trigger:tween(0.25, _G, {slow_amount = 1}, math.linear, function() + trigger:tween(0.25, _G, {slow_amount = 1, music_slow_amount = 1}, math.linear, function() slow_amount = 1 + music_slow_amount = 1 self.arena:transition() end) ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} diff --git a/enemies.lua b/enemies.lua index d165f13..3256a78 100644 --- a/enemies.lua +++ b/enemies.lua @@ -29,7 +29,7 @@ function Seeker:init(args) enemy:speed_boost(3 + self.level*0.025 + current_new_game_plus*0.1) end end - end) + end, nil, nil, 'boss_attack') elseif self.boss == 'forcer' then self.color = yellow[0]:clone() @@ -76,7 +76,7 @@ function Seeker:init(args) end self.px, self.py = nil, nil end) - end) + end, nil, nil, 'boss_attack') elseif self.boss == 'swarmer' then self.color = purple[0]:clone() @@ -92,7 +92,7 @@ function Seeker:init(args) critter3:play{pitch = random:float(0.95, 1.05), volume = 0.6} for i = 1, random:int(4, 6) do EnemyCritter{group = main.current.main, x = enemy.x, y = enemy.y, color = purple[0], r = random:float(0, 2*math.pi), v = 8 + 0.1*enemy.level, dmg = 2*enemy.dmg} end end - end) + end, nil, nil, 'boss_attack') elseif self.boss == 'exploder' then self.color = blue[0]:clone() @@ -107,7 +107,7 @@ function Seeker:init(args) mine1:play{pitch = random:float(0.95, 1.05), volume = 0.5} ExploderMine{group = main.current.main, x = enemy.x, y = enemy.y, color = blue[0], parent = enemy} end - end) + end, nil, nil, 'boss_attack') elseif self.boss == 'randomizer' then self.t:every_immediate(0.07, function() self.color = _G[random:table{'green', 'purple', 'yellow', 'blue'}][0]:clone() end) @@ -158,7 +158,7 @@ function Seeker:init(args) end end end - end) + end, nil, nil, 'boss_attack') end else @@ -355,6 +355,13 @@ function Seeker:draw() end graphics.pop() + if self.boss then + local t, c = self.t:get_timer_and_delay('boss_attack') + local n = t/c + graphics.line(self.x - self.shape.w/2, self.y + 8, self.x + self.shape.w/2, self.y + 8, bg[-3], 2) + graphics.line(self.x - self.shape.w/2, self.y + 8, self.x - self.shape.w/2 + self.shape.w*n, self.y + 8, self.color, 2) + end + if self.px and self.py then if self.phidden then return end graphics.push(self.px, self.py, self.vr, self.spring.x, self.spring.x) @@ -546,6 +553,7 @@ function Seeker:hit(damage, projectile, dot, from_enemy) end end + --[[ if main.current.healer_level > 0 then if random:bool((main.current.healer_level == 2 and 16) or (main.current.healer_level == 1 and 8) or 0) then trigger:after(0.01, function() @@ -553,6 +561,7 @@ function Seeker:hit(damage, projectile, dot, from_enemy) end) end end + ]]-- if self.boss then slow(0.25, 1) diff --git a/engine/system.lua b/engine/system.lua index b29e73c..ef9d425 100644 --- a/engine/system.lua +++ b/engine/system.lua @@ -140,12 +140,12 @@ end function system.save_run(level, loop, gold, units, passives, shop_level, shop_xp, run_passive_pool, locked_state) local run = {level = level, loop = loop, gold = gold, units = units, passives = passives, shop_level = shop_level, shop_xp = shop_xp, run_passive_pool= run_passive_pool, locked_state = locked_state} local str = "return " .. table.tostring(run) - love.filesystem.write("run_v3.txt", str) + love.filesystem.write("run_v4.txt", str) end function system.load_run() - local chunk = love.filesystem.load("run_v3.txt") + local chunk = love.filesystem.load("run_v4.txt") if chunk then return chunk() else return {} end end diff --git a/main.lua b/main.lua index 2ae2448..b5639c9 100644 --- a/main.lua +++ b/main.lua @@ -213,6 +213,7 @@ function init() orbitism = Image('orbitism') psyker_orbs = Image('psyker_orbs') psychosense = Image('psychosense') + psychosink = Image('psychosink') rearm = Image('rearm') taunt = Image('taunt') construct_instability = Image('construct_instability') @@ -235,6 +236,7 @@ function init() lightning_strike = Image('lightning_strike') psycholeak = Image('psycholeak') divine_blessing = Image('divine_blessing') + hardening = Image('hardening') class_colors = { ['warrior'] = yellow[0], @@ -597,7 +599,7 @@ function init() ['magician'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. get_character_stat('magician', lvl, 'dmg') .. ' AoE[fg] damage' end, ['archer'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('archer', lvl, 'dmg') .. '[fg] damage and pierces' end, ['scout'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. get_character_stat('scout', lvl, 'dmg') .. '[fg] damage and chains [yellow]3[fg] times' end, - ['cleric'] = function(lvl) return '[fg]creates [yellow]1[fg] healing orb' end, + ['cleric'] = function(lvl) return '[fg]creates [yellow]1[fg] healing orb every [yellow]8[fg] seconds' end, ['outlaw'] = function(lvl) return '[fg]throws a fan of [yellow]5[fg] knives, each dealing [yellow]' .. get_character_stat('outlaw', lvl, 'dmg') .. '[fg] damage' end, ['blade'] = function(lvl) return '[fg]throws multiple blades that deal [yellow]' .. get_character_stat('blade', lvl, 'dmg') .. ' AoE[fg] damage' end, ['elementor'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('elementor', lvl, 'dmg') .. ' AoE[fg] damage in a large area centered on a random target' end, @@ -612,7 +614,7 @@ function init() ['sentry'] = function(lvl) return '[fg]spawns a rotating turret that shoots [yellow]4[fg] projectiles, each dealing [yellow]' .. get_character_stat('sentry', lvl, 'dmg') .. '[fg] damage' end, ['chronomancer'] = function(lvl) return '[yellow]+20%[fg] attack speed to all allies' end, ['spellblade'] = function(lvl) return '[fg]throws knives that deal [yellow]' .. get_character_stat('spellblade', lvl, 'dmg') .. '[fg] damage, pierce and spiral outwards' end, - ['psykeeper'] = function(lvl) return '[fg]creates [yellow]1[fg] healing orb every time the psykeeper takes [yellow]20%[fg] of its max HP in damage' end, + ['psykeeper'] = function(lvl) return '[fg]creates [yellow]3[fg] healing orbs every time the psykeeper takes [yellow]25%[fg] of its max HP in damage' end, ['engineer'] = function(lvl) return '[fg]drops sentries that shoot bursts of projectiles, each dealing [yellow]' .. get_character_stat('engineer', lvl, 'dmg') .. '[fg] damage' end, ['plague_doctor'] = function(lvl) return '[fg]creates an area that deals [yellow]' .. get_character_stat('plague_doctor', lvl, 'dmg') .. '[fg] damage per second' end, ['barbarian'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('barbarian', lvl, 'dmg') .. '[fg] AoE damage and stuns enemies hit for [yellow]4[fg] seconds' end, @@ -633,7 +635,7 @@ function init() ['barrager'] = function(lvl) return '[fg]shoots a barrage of [yellow]3[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end, ['highlander'] = function(lvl) return '[fg]deals [yellow]' .. 5*get_character_stat('highlander', lvl, 'dmg') .. '[fg] AoE damage' end, ['fairy'] = function(lvl) return '[fg]creates [yellow]1[fg] healing orb and grants [yellow]1[fg] unit [yellow]+100%[fg] attack speed for [yellow]6[fg] seconds' end, - ['priest'] = function(lvl) return '[fg]creates [yellow]5[fg] healing orbs' end, + ['priest'] = function(lvl) return '[fg]creates [yellow]3[fg] healing orbs every [yellow]12[fg] seconds' end, ['infestor'] = function(lvl) return '[fg]curses [yellow]8[fg] nearby enemies for [yellow]6[fg] seconds, they will release [yellow]2[fg] critters on death' end, ['flagellant'] = function(lvl) return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', lvl, 'dmg') .. '[fg] damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end, ['arcanist'] = function(lvl) return '[fg]launches a slow moving orb that launches projectiles, each dealing [yellow]' .. get_character_stat('arcanist', lvl, 'dmg') .. '[fg] damage' end, @@ -778,7 +780,7 @@ function init() ['magician'] = function() return '[fg]the magician becomes invulnerable for [yellow]6[fg] seconds but also cannot attack' end, ['archer'] = function() return '[fg]the arrow ricochets off walls [yellow]3[fg] times' end, ['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end, - ['cleric'] = function() return '[fg]creates [yellow]4[fg] healing orbs' end, + ['cleric'] = function() return '[fg]creates [yellow]4[fg] healing orbs every [yellow]8[fg] seconds' end, ['outlaw'] = function() return "[yellow]+50%[fg] outlaw attack speed and his knives seek enemies" end, ['blade'] = function() return '[fg]deal additional [yellow]' .. math.round(get_character_stat('blade', 3, 'dmg')/3, 2) .. '[fg] damage per enemy hit' end, ['elementor'] = function() return '[fg]slows enemies by [yellow]60%[fg] for [yellow]6[fg] seconds on hit' end, @@ -994,11 +996,11 @@ function init() ['warrior'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']+25[light_bg]/[' .. ylb2(lvl) .. ']+50 [fg]defense to allied warriors' end, ['mage'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']-15[light_bg]/[' .. ylb2(lvl) .. ']-30 [fg]enemy defense' end, ['rogue'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']15%[light_bg]/[' .. ylb2(lvl) .. ']30% [fg]chance to crit to allied rogues, dealing [yellow]4x[] damage' end, - ['healer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+8%[light_bg]/[' .. ylb2(lvl) .. ']+16% [fg] chance for enemies to drop healing orbs on death' end, + ['healer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+30% [fg] chance to create [yellow]+1[fg] healing orb on healing orb creation' end, ['enchanter'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]damage to all allies' end, ['nuker'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]area damage and size to allied nukers' end, ['conjurer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]construct damage and duration' end, - ['psyker'] = function(lvl) return '[fg]create a piercing, damaging orb around each psyker' end, + ['psyker'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+2[light_bg]/[' .. ylb2(lvl) .. ']+4 [fg]total psyker orbs and [yellow]+1[fg] orb for each psyker' end, ['curser'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+1[light_bg]/[' .. ylb2(lvl) .. ']+3 [fg]max curse targets to allied cursers' end, ['forcer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]knockback force to all allies' end, ['swarmer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+1[light_bg]/[' .. ylb2(lvl) .. ']+3 [fg]hits to critters' end, @@ -1135,7 +1137,7 @@ function init() if number_of_units >= 6 then return 2 elseif number_of_units >= 3 then return 1 else return 0 end - elseif class == 'healer' or class == 'conjurer' or class == 'enchanter' or class == 'curser' or class == 'forcer' or class == 'swarmer' or class == 'voider' or class == 'mercenary' then + elseif class == 'healer' or class == 'conjurer' or class == 'enchanter' or class == 'curser' or class == 'forcer' or class == 'swarmer' or class == 'voider' or class == 'mercenary' or class == 'psyker' then if number_of_units >= 4 then return 2 elseif number_of_units >= 2 then return 1 else return 0 end @@ -1144,7 +1146,7 @@ function init() elseif number_of_units >= 4 then return 2 elseif number_of_units >= 2 then return 1 else return 0 end - elseif class == 'explorer' or class == 'psyker' then + elseif class == 'explorer' then if number_of_units >= 1 then return 1 else return 0 end end @@ -1186,7 +1188,7 @@ function init() ['healer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).healer end, ['conjurer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).conjurer end, ['enchanter'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).enchanter end, - ['psyker'] = function(units) return 1, 1, nil, get_number_of_units_per_class(units).psyker end, + ['psyker'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).psyker end, ['curser'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).curser end, ['forcer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).forcer end, ['swarmer'] = function(units) return 2, 4, nil, get_number_of_units_per_class(units).swarmer end, @@ -1257,6 +1259,7 @@ function init() ['orbitism'] = 'Orbitism', ['psyker_orbs'] = 'Psyker Orbs', ['psychosense'] = 'Psychosense', + ['psychosink'] = 'Psychosink', ['rearm'] = 'Rearm', ['taunt'] = 'Taunt', ['construct_instability'] = 'Construct Instability', @@ -1279,6 +1282,7 @@ function init() ['lightning_strike'] = 'Lightning Strike', ['psycholeak'] = 'Psycholeak', ['divine_blessing'] = 'Divine Blessing', + ['hardening'] = 'Hardening', } passive_descriptions = { @@ -1330,7 +1334,7 @@ function init() ['freezing_field'] = '[fg]creates an area that slows enemies by [yellow]50%[fg] for [yellow]2[fg] seconds on sorcerer spell repeat', ['burning_field'] = '[fg]creates an area that deals [yellow]30[fg] dps for [yellow]2[fg] seconds on sorcerer spell repeat', ['gravity_field'] = '[fg]creates an area that pulls enemies in for [yellow]1[fg] seconds on sorcerer spell repeat', - ['magnetism'] = '[fg]gold coins and healing orbs are attracted to the snake', + ['magnetism'] = '[fg]gold coins and healing orbs are attracted to the snake from a longer range', ['insurance'] = "[fg]heroes have [yellow]4[fg] times the chance of mercenary's bonus to drop [yellow]2[fg] gold on death", ['dividends'] = '[fg]mercenaries deal [yellow]+X%[fg] damage, where X is how much gold you have', ['berserking'] = '[fg]all warriors have up to [yellow]+50/75/100%[fg] attack speed based on missing HP', @@ -1339,9 +1343,10 @@ function init() ['blessing'] = '[yellow]+10/20/30%[fg] healing effectiveness', ['haste'] = '[yellow]+50%[fg] movement speed that decays over [yellow]4[fg] seconds on healing orb pick up', ['divine_barrage'] = '[yellow]20/40/60%[fg] chance to release a ricocheting barrage on healing orb pick up', - ['orbitism'] = '[yellow]+33/66/99%[fg] orb movement speed', - ['psyker_orbs'] = '[yellow]+1/2/3[fg] psyker orbs', + ['orbitism'] = '[yellow]+25/50/75%[fg] psyker orb movement speed', + ['psyker_orbs'] = '[yellow]+1/2/4[fg] total psyker orbs', ['psychosense'] = '[yellow]+33/66/99%[fg] orb range', + ['psychosink'] = '[fg]psyker orbs deal [yellow]+40/80/120%[fg] damage', ['rearm'] = '[fg]constructs repeat their attacks once', ['taunt'] = '[yellow]10/20/30%[fg] chance for constructs to taunt nearby enemies on attack', ['construct_instability'] = '[fg]constructs explode when disappearing, dealing [yellow]100/150/200%[fg] damage', @@ -1364,6 +1369,7 @@ function init() ['lightning_strike'] = '[yellow]5/10/15%[fg] chance for projectiles to create chain lightning, dealing [yellow]60/80/100%[fg] damage', ['psycholeak'] = '[fg]position [yellow]1[fg] generates [yellow]1[fg] psyker orb every [yellow]10[fg] seconds', ['divine_blessing'] = '[fg]generate [yellow]1[fg] healing orb every [yellow]8[fg] seconds', + ['hardening'] = '[yellow]+150%[fg] defense to all allies for [yellow]3[fg] seconds after an ally dies', } local ts = function(lvl, a, b, c) return '[' .. ylb1(lvl) .. ']' .. tostring(a) .. '[light_bg]/[' .. ylb2(lvl) .. ']' .. tostring(b) .. '[light_bg]/[' .. ylb3(lvl) .. ']' .. tostring(c) .. '[fg]' end @@ -1416,7 +1422,7 @@ function init() ['freezing_field'] = function(lvl) return '[fg]creates an area that slows enemies by [yellow]50%[fg] for [yellow]2[fg] seconds on sorcerer spell repeat' end, ['burning_field'] = function(lvl) return '[fg]creates an area that deals [yellow]30[fg] dps for [yellow]2[fg] seconds on sorcerer spell repeat' end, ['gravity_field'] = function(lvl) return '[fg]creates an area that pulls enemies in for [yellow]1[fg] seconds on sorcerer spell repeat' end, - ['magnetism'] = function(lvl) return '[fg]gold coins and healing orbs are attracted to the snake' end, + ['magnetism'] = function(lvl) return '[fg]gold coins and healing orbs are attracted to the snake from a longer range' end, ['insurance'] = function(lvl) return "[fg]heroes have [yellow]4[fg] times the chance of mercenary's bonus to drop [yellow]2[fg] gold on death" end, ['dividends'] = function(lvl) return '[fg]mercenaries deal [yellow]+X%[fg] damage, where X is how much gold you have' end, ['berserking'] = function(lvl) return '[fg]all warriors have up to ' .. ts(lvl, '+50%', '75%', '100%') .. ' attack speed based on missing HP' end, @@ -1425,9 +1431,10 @@ function init() ['blessing'] = function(lvl) return ts(lvl, '+10%', '20%', '30%') .. ' healing effectiveness' end, ['haste'] = function(lvl) return '[yellow]+50%[fg] movement speed that decays over [yellow]4[fg] seconds on healing orb pick up' end, ['divine_barrage'] = function(lvl) return ts(lvl, '20%', '40%', '60%') .. ' chance to release a ricocheting barrage on healing orb pick up' end, - ['orbitism'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb movement speed' end, + ['orbitism'] = function(lvl) return ts(lvl, '+25%', '50%', '75%') .. ' psyker orb movement speed' end, ['psyker_orbs'] = function(lvl) return ts(lvl, '+1', '2', '3') .. ' psyker orbs' end, ['psychosense'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb range' end, + ['psychosink'] = function(lvl) return '[fg]psyker orbs deal ' .. ts(lvl, '+40%', '80%', '120%') .. ' damage' end, ['rearm'] = function(lvl) return '[fg]constructs repeat their attacks once' end, ['taunt'] = function(lvl) return ts(lvl, '10%', '20%', '30%') .. ' chance for constructs to taunt nearby enemies on attack' end, ['construct_instability'] = function(lvl) return '[fg]constructs explode when disappearing, dealing ' .. ts(lvl, '100', '150', '200%') .. ' damage' end, @@ -1450,6 +1457,7 @@ function init() ['lightning_strike'] = function(lvl) return ts(lvl, '5', '10', '15%') .. ' chance for projectiles to create chain lightning, dealing ' .. ts(lvl, '60', '80', '100%') .. ' damage' end, ['psycholeak'] = function(lvl) return '[fg]position [yellow]1[fg] generates [yellow]1[fg] psyker orb every [yellow]10[fg] seconds' end, ['divine_blessing'] = function(lvl) return '[fg]generate [yellow]1[fg] healing orb every [yellow]8[fg] seconds' end, + ['hardening'] = function(lvl) return '[yellow]+150%[fg] defense to all allies for [yellow]3[fg] seconds after an ally dies' end, } level_to_tier_weights = { @@ -1685,7 +1693,7 @@ function init() unlevellable_items = { 'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'annihilation', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'divine_punishment', 'unleash', 'freezing_field', 'burning_field', 'gravity_field', - 'magnetism', 'insurance', 'dividends', 'haste', 'rearm', 'ceremonial_dagger', 'burning_strike', 'lucky_strike', 'healing_strike', 'psycholeak', 'divine_blessing' + 'magnetism', 'insurance', 'dividends', 'haste', 'rearm', 'ceremonial_dagger', 'burning_strike', 'lucky_strike', 'healing_strike', 'psycholeak', 'divine_blessing', 'hardening', } steam.userStats.requestCurrentStats() @@ -1698,10 +1706,8 @@ function init() main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5} main = Main() - --[[ main:add(MainMenu'mainmenu') main:go_to('mainmenu') - ]]-- --[[ main:add(BuyScreen'buy_screen') @@ -1709,25 +1715,30 @@ function init() -- main:go_to('buy_screen', 7, run.units or {}, {'unleash'}) ]]-- + --[[ gold = 10 run_passive_pool = { 'centipede', 'ouroboros_technique_r', 'ouroboros_technique_l', 'amplify', 'resonance', 'ballista', 'call_of_the_void', 'crucio', 'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', 'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike', - 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', + 'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing', 'hardening', } main:add(Arena'arena') - main:go_to('arena', 2, 0, { - {character = 'carver', level = 3}, - -- {character = 'carver', level = 2}, - -- {character = 'saboteur', level = 2}, - -- {character = 'hunter', level = 2}, + main:go_to('arena', 6, 0, { + {character = 'cleric', level = 1}, + {character = 'priest', level = 3}, + {character = 'carver', level = 1}, + {character = 'psykeeper', level = 1}, + {character = 'fairy', level = 3}, }, { - {passive = 'rearm', level = 1}, + {passive = 'psychosink', level = 3}, + {passive = 'psyker_orbs', level = 3}, + {passive = 'awakening', level = 3}, }) + ]]-- --[[ main:add(Media'media') @@ -1897,7 +1908,7 @@ function open_options(self) 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', - 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability', + 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosink', 'rearm', 'taunt', 'construct_instability', } max_units = 7 + current_new_game_plus main:add(BuyScreen'buy_screen') diff --git a/mainmenu.lua b/mainmenu.lua index 8ff0138..95fab92 100644 --- a/mainmenu.lua +++ b/mainmenu.lua @@ -63,7 +63,7 @@ function MainMenu:on_enter(from) end) self.units = { - {character = 'vagrant', level = 1}, + {character = 'psykino', level = 1}, {character = 'magician', level = 1}, {character = 'bane', level = 1}, {character = 'scout', level = 1}, diff --git a/player.lua b/player.lua index f27bf0d..608be36 100644 --- a/player.lua +++ b/player.lua @@ -24,7 +24,7 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'swordsman' then - self.attack_sensor = Circle(self.x, self.y, 64) + self.attack_sensor = Circle(self.x, self.y, 48) self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self:attack(96) end, nil, nil, 'attack') @@ -458,12 +458,14 @@ function Player:init(args) end, nil, nil, 'attack') elseif self.character == 'barbarian' then - self.t:every(8, function() + self.attack_sensor = Circle(self.x, self.y, 48) + self.t:cooldown(8, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self:attack(96, {stun = 4}) end, nil, nil, 'attack') elseif self.character == 'juggernaut' then - self.t:every(8, function() + self.attack_sensor = Circle(self.x, self.y, 64) + self.t:cooldown(8, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() self:attack(128, {juggernaut_push = true}) end, nil, nil, 'attack') @@ -662,7 +664,7 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'highlander' then - self.attack_sensor = Circle(self.x, self.y, 48) + self.attack_sensor = Circle(self.x, self.y, 36) self.t:cooldown(4, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() if self.level == 3 then self.t:every(0.25, function() @@ -681,11 +683,13 @@ function Player:init(args) local unit_2 = random:table_remove(units) if unit_1 then unit_1.fairy_aspd_m = 3 - unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1 end) + unit_1.fairyd = true + unit_1.t:after(5.98, function() unit_1.fairy_aspd_m = 1; unit_1.fairyd = false end) end if unit_2 then unit_2.fairy_aspd_m = 3 - unit_2.t:after(5.98, function() unit_2.fairy_aspd_m = 1 end) + unit_2.fairyd = true + unit_2.t:after(5.98, function() unit_2.fairy_aspd_m = 1; unit_2.fairyd = false end) end heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} @@ -708,8 +712,9 @@ function Player:init(args) else local unit = random:table(self:get_all_units()) if unit then + unit.fairyd = true unit.fairy_aspd_m = 2 - unit.t:after(5.98, function() unit.fairy_aspd_m = 1 end) + unit.t:after(5.98, function() unit.fairy_aspd_m = 1; unit.fairyd = false end) end heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} @@ -801,9 +806,9 @@ function Player:init(args) end) end - self.t:every(15, function() + self.t:every(12, function() local x, y = random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16) - for i = 1, 5 do + for i = 1, 3 do SpawnEffect{group = main.current.effects, x = x, y = y, color = green[0], action = function(x, y) local check_circle = Circle(x, y, 2) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton}) @@ -1067,7 +1072,7 @@ function Player:init(args) end if self.leader then - self.t:after(0.5, function() + self.t:after(1, function() local units = self:get_all_units() for _, unit in ipairs(units) do if table.any(unit.classes, function(v) return v == 'psyker' end) then @@ -1075,9 +1080,21 @@ function Player:init(args) end end + local psykers = {} + for _, unit in ipairs(units) do + if table.any(unit.classes, function(v) return v == 'psyker' end) then + table.insert(psykers, unit) + end + end + + for i = 1, ((main.current.psyker_level == 2 and 4) or (main.current.psyker_level == 1 and 2) or (main.current.psyker_level == 0 and 0) or 0) do + local unit = random:table(#psykers > 0 and psykers or units) + Projectile{group = main.current.main, x = unit.x + 24*math.cos(unit.r), y = unit.y + 24*math.sin(unit.r), color = fg[0], v = 200, dmg = unit.dmg, character = 'psyker', parent = unit} + end + if self.psyker_orbs then - for i = 1, self.psyker_orbs do - local unit = random:table(units) + for i = 1, ((self.psyker_orbs == 1 and 1) or (self.psyker_orbs == 2 and 2) or (self.psyker_orbs == 3 and 4) or 0) do + local unit = random:table(#psykers > 0 and psykers or units) Projectile{group = main.current.main, x = unit.x + 24*math.cos(unit.r), y = unit.y + 24*math.sin(unit.r), color = fg[0], v = 200, dmg = unit.dmg, character = 'psyker', parent = unit} end end @@ -1302,7 +1319,7 @@ function Player:update(dt) self.buff_def_a = (self.warrior_def_a or 0) self.buff_aspd_m = (self.chronomancer_aspd_m or 1)*(self.vagrant_aspd_m or 1)*(self.outlaw_aspd_m or 1)*(self.fairy_aspd_m or 1)*(self.psyker_aspd_m or 1)*(self.chronomancy_aspd_m or 1)*(self.awakening_aspd_m or 1)*(self.berserking_aspd_m or 1)*(self.reinforce_aspd_m or 1)*(self.squire_aspd_m or 1)*(self.speed_3_aspd_m or 1)*(self.last_stand_aspd_m or 1)*(self.enchanted_aspd_m or 1)*(self.explorer_aspd_m or 1) self.buff_dmg_m = (self.squire_dmg_m or 1)*(self.vagrant_dmg_m or 1)*(self.enchanter_dmg_m or 1)*(self.swordsman_dmg_m or 1)*(self.flagellant_dmg_m or 1)*(self.psyker_dmg_m or 1)*(self.ballista_dmg_m or 1)*(self.awakening_dmg_m or 1)*(self.reinforce_dmg_m or 1)*(self.payback_dmg_m or 1)*(self.immolation_dmg_m or 1)*(self.damage_4_dmg_m or 1)*(self.offensive_stance_dmg_m or 1)*(self.last_stand_dmg_m or 1)*(self.dividends_dmg_m or 1)*(self.explorer_dmg_m or 1) - self.buff_def_m = (self.squire_def_m or 1)*(self.ouroboros_def_m or 1)*(self.unwavering_stance_def_m or 1)*(self.reinforce_def_m or 1)*(self.defensive_stance_def_m or 1)*(self.last_stand_def_m or 1)*(self.unrelenting_stance_def_m or 1) + self.buff_def_m = (self.squire_def_m or 1)*(self.ouroboros_def_m or 1)*(self.unwavering_stance_def_m or 1)*(self.reinforce_def_m or 1)*(self.defensive_stance_def_m or 1)*(self.last_stand_def_m or 1)*(self.unrelenting_stance_def_m or 1)*(self.hardening_def_m or 1) self.buff_area_size_m = (self.nuker_area_size_m or 1)*(self.magnify_area_size_m or 1)*(self.unleash_area_size_m or 1)*(self.last_stand_area_size_m or 1) self.buff_area_dmg_m = (self.nuker_area_dmg_m or 1)*(self.amplify_area_dmg_m or 1)*(self.unleash_area_dmg_m or 1)*(self.last_stand_area_dmg_m or 1) self.buff_mvspd_m = (self.wall_rider_mvspd_m or 1)*(self.centipede_mvspd_m or 1)*(self.squire_mvspd_m or 1)*(self.last_stand_mvspd_m or 1)*(self.haste_mvspd_m or 1) @@ -1413,6 +1430,14 @@ function Player:draw() if self.ouroboros_def_m and self.ouroboros_def_m > 1 then graphics.rectangle(self.x, self.y, 1.25*self.shape.w, 1.25*self.shape.h, 3, 3, yellow_transparent) end + + if self.divined then + graphics.rectangle(self.x, self.y, 1.25*self.shape.w, 1.25*self.shape.h, 3, 3, green_transparent) + end + + if self.fairyd then + graphics.rectangle(self.x, self.y, 1.25*self.shape.w, 1.25*self.shape.h, 3, 3, blue_transparent) + end end graphics.pop() end @@ -1525,7 +1550,7 @@ function Player:hit(damage, from_undead) if self.character == 'psykeeper' then self.stored_heal = self.stored_heal + actual_damage - if self.stored_heal > (0.2*self.max_hp) then + if self.stored_heal > (0.25*self.max_hp) then self.stored_heal = 0 local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton}) @@ -1533,13 +1558,15 @@ function Player:hit(damage, from_undead) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton}) end - SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) - local check_circle = Circle(x, y, 2) - local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Volcano, Saboteur, Bomb, Pet, Turret, Automaton}) - if #objects == 0 then - HealingOrb{group = main.current.main, x = x, y = y} - end - end} + for i = 1, 3 do + SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) + local check_circle = Circle(x, y, 2) + local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Volcano, Saboteur, Bomb, Pet, Turret, Automaton}) + if #objects == 0 then + HealingOrb{group = main.current.main, x = x, y = y} + end + end} + end end if self.level == 3 then @@ -1609,6 +1636,14 @@ function Player:hit(damage, from_undead) end) end + if self.hardening then + local units = self:get_all_units() + for _, unit in ipairs(units) do + unit.hardening_def_m = 2.5 + unit.t:after(3, function() unit.hardening_def_m = 1 end) + end + end + if self.annihilation and table.any(self.classes, function(v) return v == 'voider' end) then local enemies = self.group:get_objects_by_classes({Seeker, EnemyCritter}) for _, enemy in ipairs(enemies) do @@ -1921,7 +1956,7 @@ Projectile:implement(Physics) function Projectile:init(args) self:init_game_object(args) self.hfx:add('hit', 1) - self:set_as_rectangle(10, 4, 'dynamic', main.current.player.warping_shots and 'true_ghost' or 'projectile') + self:set_as_rectangle(10, 4, 'dynamic', 'projectile') self.pierce = args.pierce or 0 self.chain = args.chain or 0 self.ricochet = args.ricochet or 0 @@ -1976,9 +2011,10 @@ function Projectile:init(args) elseif self.character == 'psyker' then self.pierce = 10000 - self.orbit_distance = random:float(32, 40)*((self.parent.psychosense == 1 and 1.33) or (self.parent.psychosense == 2 and 1.66) or (self.parent.psychosense == 3 and 1.99) or 1) - self.orbit_speed = random:float(4, 6)*((self.parent.orbitism == 1 and 1.33) or (self.parent.orbitism == 2 and 1.66) or (self.parent.orbitism == 3 and 1.99) or 1) + self.orbit_distance = random:float(56, 64) + self.orbit_speed = random:float(2, 4)*((self.parent.orbitism == 1 and 1.25) or (self.parent.orbitism == 2 and 1.50) or (self.parent.orbitism == 3 and 1.75) or 1)*(1/self.parent.aspd_m) self.orbit_offset = random:float(0, 2*math.pi) + self.dmg = self.dmg*((self.parent.psychosink == 1 and 1.4) or (self.parent.psychosink == 2 and 1.8) or (self.parent.psychosink == 3 and 2.2) or 1) elseif self.character == 'lich' then self.spring:pull(0.15) @@ -2048,8 +2084,8 @@ function Projectile:update(dt) if self.character == 'psyker' then if self.parent.dead then self.dead = true; self.parent = nil; return end - self:set_position(self.parent.x + self.orbit_distance*math.cos(self.orbit_speed*time + self.orbit_offset), - self.parent.y + self.orbit_distance*math.sin(self.orbit_speed*time + self.orbit_offset)) + self:set_position(self.parent.x + self.orbit_distance*math.cos(self.orbit_speed*main.current.t.time + self.orbit_offset), + self.parent.y + self.orbit_distance*math.sin(self.orbit_speed*main.current.t.time + self.orbit_offset)) local dx, dy = self.x - (self.previous_x or 0), self.y - (self.previous_y or 0) self.r = Vector(dx, dy):angle() self:set_angle(self.r) @@ -3070,7 +3106,7 @@ function Sentry:init(args) archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35} HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r), y = self.y + 0.8*self.shape.w*math.sin(r), rs = 6} local t = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), v = 200, r = r, color = self.color, - dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent} + dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent, ricochet = self.parent.level == 3 and 2 or 0} Projectile(table.merge(t, mods or {})) r = r + math.pi/2 end @@ -3093,7 +3129,7 @@ function Sentry:init(args) archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35} HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r), y = self.y + 0.8*self.shape.w*math.sin(r), rs = 6} local t = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), v = 200, r = r, color = self.color, - dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent} + dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent, ricochet = self.parent.level == 3 and 2 or 0} Projectile(table.merge(t, mods or {})) r = r + math.pi/2 end @@ -3109,7 +3145,7 @@ function Sentry:init(args) end end) end - end) + end, nil, nil, 'attack') end @@ -3117,6 +3153,7 @@ function Sentry:update(dt) self:update_game_object(dt) self.r = self.r + math.pi*dt self:set_angle(self.r) + self.t:set_every_multiplier('attack', self.parent.level == 3 and 0.75 or 1) end @@ -3606,7 +3643,8 @@ function Gold:init(args) self.cant_be_picked_up = true self.t:after(0.5, function() self.cant_be_picked_up = false end) gold1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - self.magnet_sensor = Circle(self.x, self.y, 32) + self.weak_magnet_sensor = Circle(self.x, self.y, 16) + self.magnet_sensor = Circle(self.x, self.y, 56) end @@ -3614,21 +3652,20 @@ function Gold:update(dt) self:update_game_object(dt) self.r = self:get_angle() - if main.current.player.magnetism and self.magnet_sensor then - local players = self:get_objects_in_shape(self.magnet_sensor, {Player}) - if players and #players > 0 then - local x, y = 0, 0 - for _, p in ipairs(players) do - x = x + p.x - y = y + p.y - end - x = x/#players - y = y/#players - local r = self:angle_to_point(x, y) - self:apply_force(20*math.cos(r), 20*math.sin(r)) + local players = self:get_objects_in_shape(main.current.player.magnetism and self.magnet_sensor or self.weak_magnet_sensor, {Player}) + if players and #players > 0 then + local x, y = 0, 0 + for _, p in ipairs(players) do + x = x + p.x + y = y + p.y end + x = x/#players + y = y/#players + local r = self:angle_to_point(x, y) + self:apply_force(20*math.cos(r), 20*math.sin(r)) end if self.magnet_sensor then self.magnet_sensor:move_to(self.x, self.y) end + if self.weak_magnet_sensor then self.weak_magnet_sensor:move_to(self.x, self.y) end end @@ -3710,7 +3747,16 @@ function HealingOrb:init(args) self.cant_be_picked_up = true self.t:after(0.5, function() self.cant_be_picked_up = false end) illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5} - self.magnet_sensor = Circle(self.x, self.y, 32) + self.weak_magnet_sensor = Circle(self.x, self.y, 16) + self.magnet_sensor = Circle(self.x, self.y, 56) + + if main.current.healer_level > 0 and not self.healer_effect_orb then + if random:bool((main.current.healer_level == 1 and 15) or (main.current.healer_level == 2 and 30)) then + SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = green[0], action = function(x, y) + HealingOrb{group = main.current.main, x = x, y = y, healer_effect_orb = true} + end} + end + end end @@ -3718,21 +3764,20 @@ function HealingOrb:update(dt) self:update_game_object(dt) self.r = self:get_angle() - if main.current.player.magnetism then - local players = self:get_objects_in_shape(self.magnet_sensor, {Player}) - if players and #players > 0 then - local x, y = 0, 0 - for _, p in ipairs(players) do - x = x + p.x - y = y + p.y - end - x = x/#players - y = y/#players - local r = self:angle_to_point(x, y) - self:apply_force(20*math.cos(r), 20*math.sin(r)) + local players = self:get_objects_in_shape(main.current.player.magnetism and self.magnet_sensor or self.weak_magnet_sensor, {Player}) + if players and #players > 0 then + local x, y = 0, 0 + for _, p in ipairs(players) do + x = x + p.x + y = y + p.y end + x = x/#players + y = y/#players + local r = self:angle_to_point(x, y) + self:apply_force(20*math.cos(r), 20*math.sin(r)) end if self.magnet_sensor then self.magnet_sensor:move_to(self.x, self.y) end + if self.weak_magnet_sensor then self.weak_magnet_sensor:move_to(self.x, self.y) end end @@ -3757,16 +3802,17 @@ function HealingOrb:on_trigger_enter(other, contact) heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} local units = other:get_all_units() - local lowest_hp = 10000 + local lowest_hp = 10 local lowest_unit for _, unit in ipairs(units) do - if unit.hp < lowest_hp and unit.hp < unit.max_hp then - lowest_hp = unit.hp + local r = unit.hp/unit.max_hp + if r < lowest_hp then + lowest_hp = r lowest_unit = unit end end if lowest_unit then - lowest_unit:heal(0.1*lowest_unit.max_hp*(lowest_unit.heal_effect_m or 1)) + lowest_unit:heal(0.2*lowest_unit.max_hp*(lowest_unit.heal_effect_m or 1)) end if main.current.player.haste then diff --git a/shared.lua b/shared.lua index f703803..68441ee 100644 --- a/shared.lua +++ b/shared.lua @@ -29,6 +29,7 @@ function shared_init() graphics.set_background_color(bg[0]) graphics.set_color(fg[0]) slow_amount = 1 + music_slow_amount = 1 sfx = SoundTag() sfx.volume = state.sfx_volume or 0.5 @@ -105,7 +106,7 @@ function Star:init(args) self.sx, self.sy = 0.35, 0.35 self.vr = 0 self.dvr = random:float(0, math.pi/4) - self.v = random:float(0.5, 0.7) + self.v = random:float(30, 42) end diff --git a/todo b/todo index bba6999..8e18e6f 100644 --- a/todo +++ b/todo @@ -17,27 +17,26 @@ Loop Update * Silencing Strike - 8/16/24% chance for attacks to silence for 4 seconds on hit * Culling Strike - instantly kill elites below 10/20/30% max HP * Lightning Strike - 5/10/15% chance for projectiles to create chain lightning, dealing 60/80/100% damage - * Psycholeak - Position 1 generates 1 psyker orb every 10 seconds + * Psycholeak - position 1 generates 1 psyker orb every 10 seconds * Divine Blessing - generate 1 healing orb every 8 seconds + * Hardening - +150% defense for 3 seconds after an ally dies Psyker - Additional orbs will prefer to be assigned to psykers, if there are no psykers then they will be assigned randomly - Orb speed scales with the unit's attack speed - Increase default orb range - Decrease default and maximum orb speed - Increased orb damage - Psyker class bonus: +2/+4 total orbs - Remove Psychosense - Add "Orbs shoot projectiles" + * Orb speed scales with the unit's attack speed + * Increased default orb range + * Decreased default orb speed + * Additional psyker orbs will prefer to be assigned to psykers, if there are no psykers then they will be assigned to units randomly + * Changed psyker class bonus: +2/4 total orbs + * Removed Psychosense + * Added Psychosink - psyker orbs deal +40/80/120% damage Healer - Double healing per orb - Fix heal targetting, should always target lowest HP unit - Some solution that: - Increases amount of orbs dropped with only 1 or 2 healers - Decreases amount of orbs dropped on full build - Healing orbs are slightly attracted to the snake + * Double healing per orb + * Fixed heal targetting, now it should always target the lowest HP unit + * Healing orbs and gold coins are now slightly attracted to the snake with a weak magnetism effect + * Changed healer class bonus: +15/30% chance to create an additional healing orb on healing orb creation + * Psykeeper: spawn 3 healing orbs every time the psykeeper takes 25% of max HP in damage Warriors - Increase sensor range - Set juggernaut and barbarian's attacks on :cooldown calls + * Decreased sensor range for all warriors, this will make them attack only when enemies are closer and consequently make it so that they hit more enemies in general + * Juggernaut and barbarian now only attack when there are enemies nearby Builders * Carver (builder, healer) - creates a tree that creates 1 healing orb every 6 seconds, Lv.3 effect: healing orbs are created twice as fast * Engineer (builder): unchanged @@ -52,18 +51,17 @@ Loop Update * Snake size goes up by 1 every loop, up to 12 * Don't offer items if at maximum items QoL - Increase item choice slots to 4 - Add option for mouse cursor to always be visible - Show cooldown on elite attack - Add visuals divine intervention, fairy buff - Party + items on death screen + Default to mouse controls + * Show cooldown on elite attack + * Added visuals for divine intervention and fairy buffs + * Increased item choice slots to 4 + * Party + items on death screen * Silenced units are now gray * Items on end screen * Items on passive screen * Selling items * Decreased sound effect volume for shoot 5 Bug fixes - Fix stars * Fixed a series of crashes that happened sometimes right before changing from the arena back to the shop * Fixed merchant not giving interest or free reroll if it died in combat * Fixed shoot 5 and death 6 not working if a unit placed before it on the snake died @@ -75,6 +73,10 @@ Loop Update * Fixed a bug where movement speed would become zero if the game was paused while under the effects of decaying haste * Fixed baneling burst not dealing the correct amount of damage + +Weekly maintenance updates: + + --- Invoker - casts attacks and spells from other units @@ -123,6 +125,7 @@ Enemy ideas - https://steamcommunity.com/app/915310/discussions/0/30697477836918 Unit ideas - https://i.imgur.com/VNMS2YV.png Unit ideas - https://steamcommunity.com/app/915310/discussions/0/3069747783693969554/ Unit ideas - https://steamcommunity.com/app/915310/discussions/0/3046104336668792953/ +Achievement ideas - https://i.imgur.com/Q7jHWB2.png, https://i.imgur.com/2l5eist.png Draft system Ban system