Day 69-72
244
arena.lua
|
@ -65,12 +65,18 @@ function Arena:on_enter(from, level, units, passives)
|
|||
|
||||
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, passives = self.passives}
|
||||
self.player = Player{group = self.main, x = gw/2, y = gh/2 + 16, leader = true, character = unit.character, level = unit.level, passives = self.passives, ii = i}
|
||||
else
|
||||
self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level, passives = self.passives})
|
||||
self.player:add_follower(Player{group = self.main, character = unit.character, level = unit.level, passives = self.passives, ii = i})
|
||||
end
|
||||
end
|
||||
|
||||
local units = self.player:get_all_units()
|
||||
for _, unit in ipairs(units) do
|
||||
local chp = CharacterHP{group = self.effects, x = self.x1 + 8 + (unit.ii-1)*22, y = self.y2 + 14, parent = unit}
|
||||
unit.character_hp = chp
|
||||
end
|
||||
|
||||
if self.level == 1000 then
|
||||
self.level_1000_text = Text2{group = self.ui, x = gw/2, y = gh/2, lines = {{text = '[fg, wavy_mid]SNKRX', font = fat_font, alignment = 'center'}}}
|
||||
-- self.level_1000_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 64, lines = {{text = '[fg, wavy_mid]SNKRX', font = pixul_font, alignment = 'center'}}}
|
||||
|
@ -104,7 +110,35 @@ function Arena:on_enter(from, level, units, passives)
|
|||
end)
|
||||
end)
|
||||
end)
|
||||
self.t:every(function() return self.start_time <= 0 and (self.boss and self.boss.dead) and #self.main:get_objects_by_classes(self.enemies) <= 0 end, function() self.can_quit = true end)
|
||||
self.t:every(function() return self.start_time <= 0 and (self.boss and self.boss.dead) and #self.main:get_objects_by_classes(self.enemies) <= 0 end, function()
|
||||
self.can_quit = true
|
||||
if self.level == 6 then
|
||||
state.achievement_speed_booster = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('SPEED_BOOSTER')
|
||||
steam.userStats.storeStats()
|
||||
elseif self.level == 12 then
|
||||
state.achievement_exploder = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('EXPLODER')
|
||||
steam.userStats.storeStats()
|
||||
elseif self.level == 18 then
|
||||
state.achievement_swarmer = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('SWARMER')
|
||||
steam.userStats.storeStats()
|
||||
elseif self.level == 24 then
|
||||
state.achievement_forcer = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('FORCER')
|
||||
steam.userStats.storeStats()
|
||||
elseif self.level == 25 then
|
||||
state.achievement_cluster = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('CLUSTER')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
else
|
||||
-- Set win condition and enemy spawns
|
||||
|
@ -174,13 +208,13 @@ function Arena:on_enter(from, level, units, passives)
|
|||
end, self.time_left)
|
||||
|
||||
self.t:every_immediate(2, function()
|
||||
if #self.main:get_objects_by_classes(self.enemies) <= 0 or love.timer.getTime() - self.last_spawn_enemy_time >= 8 and not self.transitioning then
|
||||
if #self.main:get_objects_by_classes(self.enemies) <= 0 or love.timer.getTime() - self.last_spawn_enemy_time >= 8 and not self.transitioning and not self.can_quit then
|
||||
self:spawn_distributed_enemies()
|
||||
end
|
||||
end, self.time_left/2)
|
||||
end)
|
||||
end)
|
||||
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 and self.time_left <= 0 end, function() self.can_quit = true end)
|
||||
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 and self.time_left <= 0 and not self.can_quit end, function() self.can_quit = true end)
|
||||
end
|
||||
|
||||
if self.level == 18 and self.trailer then
|
||||
|
@ -314,17 +348,140 @@ function Arena:update(dt)
|
|||
camera.x, camera.y = gw/2, gh/2
|
||||
self.win_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 66, lines = {{text = '[wavy_mid, cbyc2]congratulations!', font = fat_font, alignment = 'center'}}}
|
||||
self.t:after(2.5, function()
|
||||
self.win_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 20, lines = {
|
||||
{text = "[fg]you've beaten the game!", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]i made this game in 2 months as a dev challenge", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]and i'm happy with how it turned out!", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]if you liked it too and want to play more games like this:", font = pixul_font, alignment = 'center', height_multiplier = 5},
|
||||
{text = "[fg]i will release more games this year, so stay tuned!", font = pixul_font, alignment = 'center', height_multiplier = 1.4},
|
||||
{text = "[wavy_mid, yellow]thanks for playing!", font = pixul_font, alignment = 'center'},
|
||||
}}
|
||||
SteamFollowButton{group = self.ui, x = gw/2, y = gh/2 + 37}
|
||||
RestartButton{group = self.ui, x = gw - 40, y = gh - 20}
|
||||
if new_game_plus == 10 then
|
||||
|
||||
else
|
||||
self.win_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 20, lines = {
|
||||
{text = "[fg]you've beaten the game!", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]i made this game in 3 months as a dev challenge", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]and i'm happy with how it turned out!", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
|
||||
{text = "[fg]if you liked it too and want to play more games like this:", font = pixul_font, alignment = 'center', height_multiplier = 5},
|
||||
{text = "[fg]i will release more games this year, so stay tuned!", font = pixul_font, alignment = 'center', height_multiplier = 1.4},
|
||||
{text = "[wavy_mid, yellow]thanks for playing!", font = pixul_font, alignment = 'center'},
|
||||
}}
|
||||
SteamFollowButton{group = self.ui, x = gw/2, y = gh/2 + 37}
|
||||
RestartButton{group = self.ui, x = gw - 40, y = gh - 20}
|
||||
end
|
||||
end)
|
||||
|
||||
if new_game_plus == 1 then
|
||||
state.achievement_new_game_1 = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('NEW_GAME_1')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if new_game_plus == 5 then
|
||||
state.achievement_new_game_5 = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('NEW_GAME_5')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if new_game_plus == 10 then
|
||||
state.achievement_game_complete = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('GAME_COMPLETE')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.ranger_level >= 2 then
|
||||
state.achievement_rangers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('RANGERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.warrior_level >= 2 then
|
||||
state.achievement_warriors_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('WARRIORS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.mage_level >= 2 then
|
||||
state.achievement_mages_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('MAGES_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.rogue_level >= 2 then
|
||||
state.achievement_rogues_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('ROGUES_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.healer_level >= 2 then
|
||||
state.achievement_healers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('HEALERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.enchanter_level >= 2 then
|
||||
state.achievement_enchanters_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('ENCHANTERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.nuker_level >= 2 then
|
||||
state.achievement_nukers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('NUKERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.conjurer_level >= 2 then
|
||||
state.achievement_conjurers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('CONJURERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.psyker_level >= 2 then
|
||||
state.achievement_psykers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('PSYKERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.curser_level >= 2 then
|
||||
state.achievement_cursers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('CURSERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.forcer_level >= 2 then
|
||||
state.achievement_forcers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('FORCERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.swarmer_level >= 2 then
|
||||
state.achievement_swarmers_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('SWARMERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if self.voider_level >= 2 then
|
||||
state.achievement_voiders_win = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('VOIDERS_WIN')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
--[[
|
||||
state.achievement_speed_booster = true
|
||||
system.save_state()
|
||||
steam.userStats.setAchievement('SPEED_BOOSTER')
|
||||
steam.userStats.storeStats()
|
||||
]]--
|
||||
end
|
||||
|
||||
else
|
||||
|
@ -359,9 +516,6 @@ function Arena:draw()
|
|||
self.main:draw()
|
||||
self.post_main:draw()
|
||||
self.effects:draw()
|
||||
if self.level == 18 and self.trailer then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end
|
||||
if self.choosing_passives or self.won or self.paused or self.died then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end
|
||||
self.ui:draw()
|
||||
|
||||
graphics.draw_with_mask(function()
|
||||
star_canvas:draw(0, 0, 0, 1, 1)
|
||||
|
@ -408,6 +562,11 @@ function Arena:draw()
|
|||
end
|
||||
end
|
||||
camera:detach()
|
||||
|
||||
if self.level == 18 and self.trailer then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end
|
||||
if self.choosing_passives or self.won or self.paused or self.died then graphics.rectangle(gw/2, gh/2, 2*gw, 2*gh, nil, nil, modal_transparent) end
|
||||
|
||||
self.ui:draw()
|
||||
end
|
||||
|
||||
|
||||
|
@ -550,3 +709,52 @@ function Arena:spawn_n_enemies(p, j, n)
|
|||
end}
|
||||
end, n, nil, 'spawn_enemies_' .. j)
|
||||
end
|
||||
|
||||
|
||||
|
||||
CharacterHP = Object:extend()
|
||||
CharacterHP:implement(GameObject)
|
||||
function CharacterHP:init(args)
|
||||
self:init_game_object(args)
|
||||
self.hfx:add('hit', 1)
|
||||
self.cooldown_ratio = 0
|
||||
end
|
||||
|
||||
|
||||
function CharacterHP:update(dt)
|
||||
self:update_game_object(dt)
|
||||
local t, d = self.parent.t:get_timer_and_delay'shoot'
|
||||
if t and d then
|
||||
local m = self.parent.t:get_every_multiplier'shoot'
|
||||
self.cooldown_ratio = math.min(t/(d*m), 1)
|
||||
end
|
||||
local t, d = self.parent.t:get_timer_and_delay'attack'
|
||||
if t and d then
|
||||
local m = self.parent.t:get_every_multiplier'attack'
|
||||
self.cooldown_ratio = math.min(t/(d*m), 1)
|
||||
end
|
||||
local t, d = self.parent.t:get_timer_and_delay'heal'
|
||||
if t and d then self.cooldown_ratio = math.min(t/d, 1) end
|
||||
local t, d = self.parent.t:get_timer_and_delay'buff'
|
||||
if t and d then self.cooldown_ratio = math.min(t/d, 1) end
|
||||
local t, d = self.parent.t:get_timer_and_delay'spawn'
|
||||
if t and d then self.cooldown_ratio = math.min(t/d, 1) end
|
||||
end
|
||||
|
||||
|
||||
function CharacterHP:draw()
|
||||
graphics.push(self.x, self.y, 0, self.hfx.hit.x, self.hfx.hit.x)
|
||||
graphics.rectangle(self.x, self.y - 2, 14, 4, 2, 2, self.parent.dead and bg[5] or (self.hfx.hit.f and fg[0] or _G[character_color_strings[self.parent.character]][-2]), 2)
|
||||
if self.parent.hp > 0 then
|
||||
graphics.rectangle2(self.x - 7, self.y - 4, 14*(self.parent.hp/self.parent.max_hp), 4, nil, nil, self.parent.dead and bg[5] or (self.hfx.hit.f and fg[0] or _G[character_color_strings[self.parent.character]][-2]))
|
||||
end
|
||||
if not self.parent.dead then
|
||||
graphics.line(self.x - 8, self.y + 5, self.x - 8 + 15.5*self.cooldown_ratio, self.y + 5, self.hfx.hit.f and fg[0] or _G[character_color_strings[self.parent.character]][-2], 2)
|
||||
end
|
||||
graphics.pop()
|
||||
end
|
||||
|
||||
|
||||
function CharacterHP:change_hp()
|
||||
self.hfx:use('hit', 0.5)
|
||||
end
|
||||
|
|
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 399 B |
After Width: | Height: | Size: 312 B |
After Width: | Height: | Size: 389 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 4.2 KiB |
151
buy_screen.lua
|
@ -317,7 +317,7 @@ function RestartButton:init(args)
|
|||
self:init_game_object(args)
|
||||
self.shape = Rectangle(self.x, self.y, pixul_font:get_text_width('restart') + 4, pixul_font.h + 4)
|
||||
self.interact_with_mouse = true
|
||||
self.text = Text({{text = '[bg10]restart', font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.text = Text({{text = '[bg10]NG+' .. tostring(new_game_plus+1), font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
end
|
||||
|
||||
|
||||
|
@ -334,6 +334,9 @@ function RestartButton:update(dt)
|
|||
gold = 2
|
||||
passives = {}
|
||||
cascade_instance:stop()
|
||||
new_game_plus = new_game_plus + 1
|
||||
state.new_game_plus = new_game_plus
|
||||
system.save_state()
|
||||
main:add(BuyScreen'buy_screen')
|
||||
main:go_to('buy_screen', 0, {}, passives)
|
||||
end, text = Text({{text = '[wavy, bg]restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)}
|
||||
|
@ -353,13 +356,13 @@ function RestartButton:on_mouse_enter()
|
|||
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
|
||||
pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
self.selected = true
|
||||
self.text:set_text{{text = '[fgm5]restart', font = pixul_font, alignment = 'center'}}
|
||||
self.text:set_text{{text = '[fgm5]NG+' .. tostring(new_game_plus+1), font = pixul_font, alignment = 'center'}}
|
||||
self.spring:pull(0.2, 200, 10)
|
||||
end
|
||||
|
||||
|
||||
function RestartButton:on_mouse_exit()
|
||||
self.text:set_text{{text = '[bg10]restart', font = pixul_font, alignment = 'center'}}
|
||||
self.text:set_text{{text = '[bg10]NG+' .. tostring(new_game_plus+1), font = pixul_font, alignment = 'center'}}
|
||||
self.selected = false
|
||||
end
|
||||
|
||||
|
@ -541,8 +544,8 @@ end
|
|||
|
||||
function CharacterPart:draw()
|
||||
graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x)
|
||||
graphics.rectangle(self.x, self.y, 14, 14, 3, 3, character_colors[self.character])
|
||||
graphics.print_centered(self.level, pixul_font, self.x + 0.5, self.y + 2, 0, 1, 1, 0, 0, _G[character_color_strings[self.character]][-5])
|
||||
graphics.rectangle(self.x, self.y, 14, 14, 3, 3, self.highlighted and fg[0] or character_colors[self.character])
|
||||
graphics.print_centered(self.level, pixul_font, self.x + 0.5, self.y + 2, 0, 1, 1, 0, 0, self.highlighted and fg[-5] or _G[character_color_strings[self.character]][-5])
|
||||
graphics.pop()
|
||||
end
|
||||
|
||||
|
@ -562,15 +565,23 @@ function CharacterPart:on_mouse_enter()
|
|||
{text = (self.level == 3 and character_effect_descriptions[self.character]() or character_effect_descriptions_gray[self.character]()), font = pixul_font, alignment = 'center'},
|
||||
}, nil, nil, nil, nil, 16, 4, nil, 2)
|
||||
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
|
||||
|
||||
if self.parent:is(BuyScreen) then
|
||||
for _, set in ipairs(self.parent.sets) do
|
||||
if table.any(character_classes[self.character], function(v) return v == set.class end) then
|
||||
set:highlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function CharacterPart:get_sale_price()
|
||||
local total = 0
|
||||
total = total + ((self.level == 1 and 1) or (self.level == 2 and 4) or (self.level == 3 and 8))
|
||||
total = total + ((self.level == 1 and character_tiers[self.character]) or (self.level == 2 and 2*character_tiers[self.character]) or (self.level == 3 and 6*character_tiers[self.character]))
|
||||
if self.reserve then
|
||||
if self.reserve[2] then total = total + self.reserve[2]*4 end
|
||||
if self.reserve[1] then total = total + self.reserve[1] end
|
||||
if self.reserve[2] then total = total + self.reserve[2]*character_tiers[self.character]*2 end
|
||||
if self.reserve[1] then total = total + self.reserve[1]*character_tiers[self.character] end
|
||||
end
|
||||
return total
|
||||
end
|
||||
|
@ -578,9 +589,19 @@ end
|
|||
|
||||
function CharacterPart:on_mouse_exit()
|
||||
self.selected = false
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
if self.info_text then
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
end
|
||||
self.info_text = nil
|
||||
|
||||
if self.parent:is(BuyScreen) then
|
||||
for _, set in ipairs(self.parent.sets) do
|
||||
if table.any(character_classes[self.character], function(v) return v == set.class end) then
|
||||
set:unhighlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -592,6 +613,26 @@ function CharacterPart:die()
|
|||
self.info_text.dead = true
|
||||
self.info_text = nil
|
||||
end
|
||||
|
||||
if self.selected and self.parent:is(BuyScreen) then
|
||||
for _, set in ipairs(self.parent.sets) do
|
||||
if table.any(character_classes[self.character], set.class) then
|
||||
set:unhighlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function CharacterPart:highlight()
|
||||
self.highlighted = true
|
||||
self.spring:pull(0.2, 200, 10)
|
||||
end
|
||||
|
||||
|
||||
function CharacterPart:unhighlight()
|
||||
self.highlighted = false
|
||||
self.spring:pull(0.05, 200, 10)
|
||||
end
|
||||
|
||||
|
||||
|
@ -863,8 +904,10 @@ end
|
|||
|
||||
|
||||
function CharacterIcon:on_mouse_exit()
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
if self.info_text then
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
end
|
||||
self.info_text = nil
|
||||
end
|
||||
|
||||
|
@ -908,14 +951,21 @@ function ClassIcon:draw()
|
|||
if table.any(self.units, function(v) return v.character == self.character end) then next_n = nil end
|
||||
end
|
||||
|
||||
graphics.rectangle(self.x, self.y, 16, 24, 4, 4, (n >= i) and class_colors[self.class] or bg[3])
|
||||
_G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, (n >= i) and _G[class_color_strings[self.class]][-5] or bg[10])
|
||||
graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, bg[3])
|
||||
graphics.rectangle(self.x, self.y, 16, 24, 4, 4, self.highlighted and fg[0] or ((n >= i) and class_colors[self.class] or bg[3]))
|
||||
_G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, self.highlighted and fg[-5] or ((n >= i) and _G[class_color_strings[self.class]][-5] or bg[10]))
|
||||
graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, self.highlighted and fg[0] or bg[3])
|
||||
if i == 2 then
|
||||
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 20, self.x + 4, self.y + 25, (n >= 3) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, (n >= 4) and class_colors[self.class] or bg[10], 3)
|
||||
if self.highlighted then
|
||||
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x + 4, self.y + 20, self.x + 4, self.y + 25, (n >= 3) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, (n >= 4) and fg[-5] or fg[-10], 3)
|
||||
else
|
||||
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 20, self.x + 4, self.y + 25, (n >= 3) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, (n >= 4) and class_colors[self.class] or bg[10], 3)
|
||||
end
|
||||
if next_n then
|
||||
if next_n == 1 then
|
||||
graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, self.flash and class_colors[self.class] or bg[10], 3)
|
||||
|
@ -928,12 +978,21 @@ function ClassIcon:draw()
|
|||
end
|
||||
end
|
||||
elseif i == 3 then
|
||||
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 24, self.x - 3, self.y + 27, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 29, self.x - 3, self.y + 32, (n >= 3) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 19, self.x + 4, self.y + 22, (n >= 4) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 24, self.x + 4, self.y + 27, (n >= 5) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 29, self.x + 4, self.y + 32, (n >= 6) and class_colors[self.class] or bg[10], 3)
|
||||
if self.highlighted then
|
||||
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x - 3, self.y + 24, self.x - 3, self.y + 27, (n >= 2) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x - 3, self.y + 29, self.x - 3, self.y + 32, (n >= 3) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x + 4, self.y + 19, self.x + 4, self.y + 22, (n >= 4) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x + 4, self.y + 24, self.x + 4, self.y + 27, (n >= 5) and fg[-5] or fg[-10], 3)
|
||||
graphics.line(self.x + 4, self.y + 29, self.x + 4, self.y + 32, (n >= 6) and fg[-5] or fg[-10], 3)
|
||||
else
|
||||
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 24, self.x - 3, self.y + 27, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 29, self.x - 3, self.y + 32, (n >= 3) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 19, self.x + 4, self.y + 22, (n >= 4) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 24, self.x + 4, self.y + 27, (n >= 5) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 29, self.x + 4, self.y + 32, (n >= 6) and class_colors[self.class] or bg[10], 3)
|
||||
end
|
||||
if next_n then
|
||||
if next_n == 1 then
|
||||
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, self.flash and class_colors[self.class] or bg[10], 3)
|
||||
|
@ -964,13 +1023,31 @@ function ClassIcon:on_mouse_enter()
|
|||
{text = class_descriptions[self.class]((owned >= j and 2) or (owned >= i and 1) or 0), font = pixul_font, alignment = 'center'},
|
||||
}, nil, nil, nil, nil, 16, 4, nil, 2)
|
||||
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
|
||||
|
||||
if not self.parent:is(ShopCard) then
|
||||
for _, character in ipairs(self.parent.characters) do
|
||||
if table.any(character_classes[character.character], function(v) return v == self.class end) then
|
||||
character:highlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ClassIcon:on_mouse_exit()
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
if self.info_text then
|
||||
self.info_text:deactivate()
|
||||
self.info_text.dead = true
|
||||
end
|
||||
self.info_text = nil
|
||||
|
||||
if not self.parent:is(ShopCard) then
|
||||
for _, character in ipairs(self.parent.characters) do
|
||||
if table.any(character_classes[character.character], function(v) return v == self.class end) then
|
||||
character:unhighlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -983,4 +1060,24 @@ function ClassIcon:die(dont_spawn_effect)
|
|||
self.info_text.dead = true
|
||||
self.info_text = nil
|
||||
end
|
||||
|
||||
if self.selected and not self.parent:is(ShopCard) then
|
||||
for _, character in ipairs(self.parent.characters) do
|
||||
if table.any(character.classes, function(v) return v == self.class end) then
|
||||
character:highlight()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ClassIcon:highlight()
|
||||
self.highlighted = true
|
||||
self.spring:pull(0.2, 200, 10)
|
||||
end
|
||||
|
||||
|
||||
function ClassIcon:unhighlight()
|
||||
self.highlighted = false
|
||||
self.spring:pull(0.05, 200, 10)
|
||||
end
|
||||
|
|
17
devlog.md
|
@ -1060,3 +1060,20 @@ Added an end game screen and started work on making elites spawn throughout the
|
|||
|
||||
Elites now spawn at appropriate rates. Testing out the game a little with this and it seems a lot better than before, but I need to balance a few of the elite units more (headbutter and spawner seem weak).
|
||||
Also went through a bunch of smaller bug fixes and changes as I play the game more and missing details start popping up. I should leave proper balancing for later and start work on final UI improvements tomorrow.
|
||||
|
||||
# Day 69-72 - 26-29/04/21
|
||||
|
||||
Everything is done except these:
|
||||
|
||||
* General balance
|
||||
* Trailers
|
||||
* 3-4 pure gameplay playthroughs showcasing different builds
|
||||
* 1 normal 30-40s trailer
|
||||
* Misc
|
||||
* NG+1-10 (difficulty ramps up faster and goes higher than normal at the end, the player also gains more gold per round, and on NG+1 and NG+5 the maximum number of units is increased by 1 (10->11->12)
|
||||
* NG+10 end screen
|
||||
* New music
|
||||
* Credits
|
||||
|
||||
Tomorrow I'll start balancing the game out, which should lead to a bunch of bug fixes and small changes, and after that's done I'll get NG+1-10 working.
|
||||
Once that's done I'll do credits screen, NG+10 (game complete) screen, and find new music for the game. I want something more ambient generally and less upbeat.
|
||||
|
|
|
@ -171,8 +171,10 @@ function Seeker:init(args)
|
|||
if self.speed_booster then
|
||||
self.color = green[0]:clone()
|
||||
self.area_sensor = Circle(self.x, self.y, 128)
|
||||
self.t:after({16, 32}, function() self:hit(10000) end)
|
||||
elseif self.exploder then
|
||||
self.color = blue[0]:clone()
|
||||
self.t:after({16, 32}, function() self:hit(10000) end)
|
||||
elseif self.headbutter then
|
||||
self.color = orange[0]:clone()
|
||||
self.last_headbutt_time = 0
|
||||
|
@ -285,7 +287,7 @@ function Seeker:update(dt)
|
|||
if self.boss then
|
||||
local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
|
||||
local x, y = 0, 0
|
||||
if #enemies > 0 then
|
||||
if #enemies > 1 then
|
||||
for _, enemy in ipairs(enemies) do
|
||||
x = x + enemy.x
|
||||
y = y + enemy.y
|
||||
|
|
|
@ -63,9 +63,11 @@ function Group:update(dt)
|
|||
self.cells = {}
|
||||
for _, object in ipairs(self.objects) do
|
||||
local cx, cy = math.floor(object.x/self.cell_size), math.floor(object.y/self.cell_size)
|
||||
if tostring(cx) == tostring(0/0) or tostring(cy) == tostring(0/0) then goto continue end
|
||||
if not self.cells[cx] then self.cells[cx] = {} end
|
||||
if not self.cells[cx][cy] then self.cells[cx][cy] = {} end
|
||||
table.insert(self.cells[cx][cy], object)
|
||||
::continue::
|
||||
end
|
||||
|
||||
for i = #self.objects, 1, -1 do
|
||||
|
|
|
@ -151,13 +151,26 @@ function Trigger:set_every_multiplier(tag, multiplier)
|
|||
end
|
||||
|
||||
|
||||
function Trigger:get_every_multiplier(tag)
|
||||
if not self.triggers[tag] then return end
|
||||
return self.triggers[tag].multiplier
|
||||
end
|
||||
|
||||
|
||||
-- Returns the elapsed time of a given trigger as a number between 0 and 1.
|
||||
-- Useful if you need to know where you currently are in the duration of a during call.
|
||||
function Trigger:get_during_elapsed_time(tag)
|
||||
if not self.triggers[tag] then return end
|
||||
return self.triggers[tag].timer/self.triggers[tag].delay
|
||||
end
|
||||
|
||||
|
||||
function Trigger:get_timer_and_delay(tag)
|
||||
if not self.triggers[tag] then return end
|
||||
return self.triggers[tag].timer, self.triggers[tag].delay
|
||||
end
|
||||
|
||||
|
||||
function Trigger:resolve_delay(delay)
|
||||
if type(delay) == "table" then
|
||||
return random:float(delay[1], delay[2])
|
||||
|
|
32
main.lua
|
@ -101,6 +101,11 @@ function init()
|
|||
rogue_crit2 = Sound('Sword hits another sword 6.ogg', s)
|
||||
cascade = Sound('Kubbi - Ember - 04 Cascade.ogg', {tags = {music}})
|
||||
|
||||
speed_booster_elite = Image('speed_booster_elite')
|
||||
exploder_elite = Image('exploder_elite')
|
||||
swarmer_elite = Image('swarmer_elite')
|
||||
forcer_elite = Image('forcer_elite')
|
||||
cluster_elite = Image('cluster_elite')
|
||||
warrior = Image('warrior')
|
||||
ranger = Image('ranger')
|
||||
healer = Image('healer')
|
||||
|
@ -428,7 +433,7 @@ function init()
|
|||
character_descriptions = {
|
||||
['vagrant'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('vagrant', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['swordsman'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('swordsman', lvl, 'dmg') .. '[fg] damage in an area, deals extra [yellow]' ..
|
||||
math.round(get_character_stat('swordsman', lvl, 'dmg')/3, 2) .. '[fg] damage per unit hit' end,
|
||||
math.round(get_character_stat('swordsman', lvl, 'dmg')*0.15, 2) .. '[fg] damage per unit hit' end,
|
||||
['wizard'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('wizard', 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,
|
||||
|
@ -567,7 +572,7 @@ function init()
|
|||
['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end,
|
||||
['cleric'] = function() return '[fg]heals all units' end,
|
||||
['outlaw'] = function() return "[yellow]+50%[fg] outlaw attack speed and his knives seek enemies" end,
|
||||
['blade'] = function() return '[fg]deal additional [yellow]' .. get_character_stat('blade', 3, 'dmg')/2 .. '[fg] damage per enemy hit' end,
|
||||
['blade'] = function() return '[fg]deal additional [yellow]' .. get_character_stat('blade', 3, 'dmg')/3 .. '[fg] damage per enemy hit' end,
|
||||
['elementor'] = function() return '[fg]slows enemies by [yellow]60%[fg] for [yellow]6[fg] seconds on hit' end,
|
||||
['saboteur'] = function() return '[fg]the explosion has [yellow]50%[fg] chance to crit, increasing in size and dealing [yellow]2x[fg] damage' end,
|
||||
['stormweaver'] = function() return "[fg]chain lightning's trigger area of effect and number of units hit is [yellow]doubled" end,
|
||||
|
@ -1148,14 +1153,15 @@ function init()
|
|||
gold = 2
|
||||
passives = {}
|
||||
system.load_state()
|
||||
new_game_plus = state.new_game_plus or 0
|
||||
steam.userStats.requestCurrentStats()
|
||||
|
||||
main = Main()
|
||||
main:add(BuyScreen'buy_screen')
|
||||
main:go_to('buy_screen', 0, {}, passives)
|
||||
--[[
|
||||
--main:add(BuyScreen'buy_screen')
|
||||
--main:go_to('buy_screen', 0, {}, passives)
|
||||
|
||||
main:add(Media'media')
|
||||
main:go_to('media')
|
||||
]]--
|
||||
end
|
||||
|
||||
|
||||
|
@ -1178,6 +1184,16 @@ function update(dt)
|
|||
music.volume = 0.5
|
||||
end
|
||||
end
|
||||
|
||||
if input.k.pressed then
|
||||
steam.userStats.setAchievement('ASCENSION_1')
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
|
||||
if input.l.pressed then
|
||||
steam.userStats.resetAllStats(true)
|
||||
steam.userStats.storeStats()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -1191,7 +1207,7 @@ end
|
|||
function love.run()
|
||||
return engine_run({
|
||||
game_name = 'SNKRX',
|
||||
window_width = 480*3,
|
||||
window_height = 270*3,
|
||||
window_width = 480*4,
|
||||
window_height = 270*4,
|
||||
})
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ function Media:on_enter(from)
|
|||
self.ui = Group()
|
||||
|
||||
self.mode = 'achievements'
|
||||
graphics.set_background_color(purple[0])
|
||||
graphics.set_background_color(fg[0])
|
||||
end
|
||||
|
||||
|
||||
|
@ -29,6 +29,6 @@ function Media:draw()
|
|||
self.ui:draw()
|
||||
|
||||
if self.mode == 'achievements' then
|
||||
graphics.print_centered('Lv2', fat_font, 32, 32, 0, 1, 1, 0, 0, purple[-5])
|
||||
graphics.print_centered('GG', fat_font, 32, 32, 0, 1, 1, 0, 0, fg[-5])
|
||||
end
|
||||
end
|
||||
|
|
63
player.lua
|
@ -12,6 +12,7 @@ function Player:init(args)
|
|||
self:set_as_rectangle(9, 9, 'dynamic', 'player')
|
||||
self.visual_shape = 'rectangle'
|
||||
self.classes = character_classes[self.character]
|
||||
self.damage_dealt = 0
|
||||
|
||||
if self.character == 'vagrant' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 96)
|
||||
|
@ -70,7 +71,7 @@ function Player:init(args)
|
|||
end
|
||||
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'heal')
|
||||
|
||||
elseif self.character == 'outlaw' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 96)
|
||||
|
@ -103,7 +104,7 @@ function Player:init(args)
|
|||
Saboteur{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1, crit = (self.level == 3) and random:bool(50)}
|
||||
end}
|
||||
end, 2)
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
|
||||
elseif self.character == 'stormweaver' then
|
||||
self.t:every(8, function()
|
||||
|
@ -112,7 +113,7 @@ function Player:init(args)
|
|||
for _, unit in ipairs(units) do
|
||||
unit:chain_infuse(4)
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'buff')
|
||||
|
||||
elseif self.character == 'sage' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 96)
|
||||
|
@ -121,7 +122,7 @@ function Player:init(args)
|
|||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy))
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
elseif self.character == 'cannoneer' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 128)
|
||||
|
@ -183,12 +184,12 @@ function Player:init(args)
|
|||
turret:upgrade()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
|
||||
elseif self.character == 'plague_doctor' then
|
||||
self.t:every(5, function()
|
||||
self:dot_attack(24, {duration = 12})
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
if self.level == 3 then
|
||||
self.t:after(0.01, function()
|
||||
|
@ -199,12 +200,12 @@ function Player:init(args)
|
|||
elseif self.character == 'barbarian' then
|
||||
self.t:every(8, function()
|
||||
self:attack(96, {stun = 4})
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
elseif self.character == 'juggernaut' then
|
||||
self.t:every(8, function()
|
||||
self:attack(64, {juggernaut_push = true})
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
elseif self.character == 'lich' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 128)
|
||||
|
@ -230,7 +231,7 @@ function Player:init(args)
|
|||
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
|
||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy), {spawn_critters_on_kill = 3, spawn_critters_on_hit = (self.level == 3 and 3 or 0)})
|
||||
self:shoot(self:angle_to_object(closest_enemy), {spawn_critters_on_kill = 3, spawn_critters_on_hit = (self.level == 3 and 3 or nil)})
|
||||
end
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
|
@ -246,7 +247,7 @@ function Player:init(args)
|
|||
elseif self.character == 'launcher' then
|
||||
self.t:every(8, function()
|
||||
self:attack(128)
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
elseif self.character == 'bard' then
|
||||
self.bard_counter = 0
|
||||
|
@ -274,24 +275,24 @@ function Player:init(args)
|
|||
for i = 1, 2 do
|
||||
Critter{group = main.current.main, x = self.x, y = self.y, color = orange[0], r = random:float(0, 2*math.pi), v = 10, dmg = self.dmg, parent = self}
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
else
|
||||
self.t:every(2, function()
|
||||
critter1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||
Critter{group = main.current.main, x = self.x, y = self.y, color = orange[0], r = random:float(0, 2*math.pi), v = 10, dmg = self.dmg, parent = self}
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
end
|
||||
|
||||
elseif self.character == 'carver' then
|
||||
self.t:every(16, function()
|
||||
Tree{group = main.current.main, x = self.x, y = self.y, color = self.color, parent = self, rs = self.area_size_m*(self.level == 3 and 128 or 64), level = self.level}
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
|
||||
elseif self.character == 'bane' then
|
||||
self.t:every(12, function()
|
||||
self.dot_area = DotArea{group = main.current.effects, x = self.x, y = self.y, rs = self.area_size_m*128, color = self.color, dmg = self.area_dmg_m*(self.level == 3 and self.dmg or 0),
|
||||
character = self.character, level = self.level, parent = self, duration = 8}
|
||||
end)
|
||||
end, nil, nil, 'spawn')
|
||||
|
||||
elseif self.character == 'psykino' then
|
||||
self.t:every(4, function()
|
||||
|
@ -299,7 +300,7 @@ function Player:init(args)
|
|||
if center_enemy then
|
||||
ForceArea{group = main.current.effects, x = center_enemy.x, y = center_enemy.y, rs = self.area_size_m*64, color = self.color, character = self.character, level = self.level, parent = self}
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
elseif self.character == 'barrager' then
|
||||
self.barrager_counter = 0
|
||||
|
@ -322,7 +323,7 @@ function Player:init(args)
|
|||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
elseif self.character == 'highlander' then
|
||||
self.attack_sensor = Circle(self.x, self.y, 64)
|
||||
|
@ -358,7 +359,7 @@ function Player:init(args)
|
|||
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'heal')
|
||||
|
||||
elseif self.character == 'priest' then
|
||||
if self.level == 3 then
|
||||
|
@ -377,7 +378,7 @@ function Player:init(args)
|
|||
local all_units = self:get_all_units()
|
||||
for _, unit in ipairs(all_units) do unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1)) end
|
||||
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
end)
|
||||
end, nil, nil, 'heal')
|
||||
|
||||
elseif self.character == 'infestor' then
|
||||
self.t:every(8, function()
|
||||
|
@ -389,7 +390,7 @@ function Player:init(args)
|
|||
LightningLine{group = main.current.effects, src = self, dst = enemy, color = orange[0]}
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'attack')
|
||||
|
||||
elseif self.character == 'flagellant' then
|
||||
self.t:every(8, function()
|
||||
|
@ -422,7 +423,7 @@ function Player:init(args)
|
|||
unit.flagellant_dmg_m = unit.flagellant_dmg_m + 0.04
|
||||
end
|
||||
end
|
||||
end)
|
||||
end, nil, nil, 'buff')
|
||||
end
|
||||
|
||||
self:calculate_stats(true)
|
||||
|
@ -542,6 +543,9 @@ function Player:init(args)
|
|||
self.t:every(1, function()
|
||||
self.unleash_area_dmg_m = self.unleash_area_dmg_m + 0.02
|
||||
self.unleash_area_size_m = self.unleash_area_size_m + 0.02
|
||||
if self.dot_area then
|
||||
self.dot_area:scale(self.unleash_area_size_m)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
@ -707,7 +711,7 @@ function Player:update(dt)
|
|||
elseif main.current.voider_level == 1 then self.dot_dmg_m = 1.15
|
||||
else self.dot_dmg_m = 1 end
|
||||
end
|
||||
if self.call_of_the_void then self.dot_dmg_m = self.dot_dmg_m*1.25 end
|
||||
if self.call_of_the_void then self.dot_dmg_m = (self.dot_dmg_m or 1)*1.25 end
|
||||
|
||||
if self.ouroboros_technique_l and self.leader then
|
||||
local units = self:get_all_units()
|
||||
|
@ -925,6 +929,8 @@ function Player:hit(damage)
|
|||
end
|
||||
end
|
||||
|
||||
self.character_hp:change_hp()
|
||||
|
||||
if self.hp <= 0 then
|
||||
if self.divined then
|
||||
self:heal(self.max_hp)
|
||||
|
@ -961,6 +967,8 @@ function Player:heal(amount)
|
|||
self:show_heal(1.5)
|
||||
self.hp = self.hp + amount
|
||||
if self.hp > self.max_hp then self.hp = self.max_hp end
|
||||
|
||||
self.character_hp:change_hp()
|
||||
end
|
||||
|
||||
|
||||
|
@ -1590,11 +1598,11 @@ function Area:init(args)
|
|||
enemy:slow(0.4, 6)
|
||||
end
|
||||
elseif self.character == 'swordsman' then
|
||||
if self.parent.resonance then resonance_dmg = (self.dmg + self.dmg*0.15*#enemies)*0.05*#enemies end
|
||||
enemy:hit(self.dmg + self.dmg*0.15*#enemies + resonance_dmg)
|
||||
elseif self.character == 'blade' and self.level == 3 then
|
||||
if self.parent.resonance then resonance_dmg = (self.dmg + self.dmg*0.33*#enemies)*0.05*#enemies end
|
||||
enemy:hit(self.dmg + self.dmg*0.33*#enemies + resonance_dmg)
|
||||
elseif self.character == 'blade' and self.level == 3 then
|
||||
if self.parent.resonance then resonance_dmg = (self.dmg + self.dmg*0.5*#enemies)*0.05*#enemies end
|
||||
enemy:hit(self.dmg + self.dmg*0.5*#enemies + resonance_dmg)
|
||||
elseif self.character == 'highlander' then
|
||||
if self.parent.resonance then resonance_dmg = 6*self.dmg*0.05*#enemies end
|
||||
enemy:hit(6*self.dmg + resonance_dmg)
|
||||
|
@ -1802,6 +1810,11 @@ function DotArea:draw()
|
|||
end
|
||||
|
||||
|
||||
function DotArea:scale(v)
|
||||
self.shape = Circle(self.x, self.y, (v or 1)*self.rs)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
ForceArea = Object:extend()
|
||||
|
@ -2146,7 +2159,7 @@ function Saboteur:on_collision_enter(other, contact)
|
|||
if table.any(main.current.enemies, function(v) return other:is(v) end) then
|
||||
camera:shake(4, 0.5)
|
||||
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = (self.crit and 1.5 or 1)*self.area_size_m*64, color = self.color,
|
||||
dmg = (self.crit and 2 or 1)*self.area_dmg_m*self.actual_dmg*(self.conjurer_buff_m or 1), character = self.character}
|
||||
dmg = (self.crit and 2 or 1)*self.area_dmg_m*self.actual_dmg*(self.conjurer_buff_m or 1), character = self.character, parent = self.parent}
|
||||
Area(table.merge(t, mods or {}))
|
||||
self.dead = true
|
||||
end
|
||||
|
|
|
@ -13,9 +13,12 @@ function shared_init()
|
|||
red = ColorRamp(Color'#e91d39', 0.025),
|
||||
purple = ColorRamp(Color'#8e559e', 0.025),
|
||||
}
|
||||
for name, color in pairs(colors) do _G[name] = color end
|
||||
for name, color in pairs(colors) do
|
||||
_G[name] = color
|
||||
_G[name .. '_transparent'] = Color(color[0].r, color[0].g, color[0].b, 0.5)
|
||||
_G[name .. '_transparent_weak'] = Color(color[0].r, color[0].g, color[0].b, 0.25)
|
||||
end
|
||||
modal_transparent = Color(0.1, 0.1, 0.1, 0.6)
|
||||
fg_transparent = Color(fg[0].r, fg[0].g, fg[0].b, 0.5)
|
||||
|
||||
bg_off = Color(47, 47, 47)
|
||||
bg_gradient = GradientImage('vertical', Color(128, 128, 128, 0), Color(0, 0, 0, 0.3))
|
||||
|
@ -48,6 +51,7 @@ end
|
|||
|
||||
|
||||
function shared_draw(draw_action)
|
||||
--[[
|
||||
star_canvas:draw_to(function()
|
||||
star_group:draw()
|
||||
end)
|
||||
|
@ -70,6 +74,7 @@ function shared_draw(draw_action)
|
|||
bg_gradient:draw(gw/2, gh/2, 480, 270)
|
||||
camera:detach()
|
||||
end)
|
||||
]]--
|
||||
|
||||
main_canvas:draw_to(function()
|
||||
draw_action()
|
||||
|
|
29
todo
|
@ -1,28 +1,12 @@
|
|||
Selling should keep units value unless it's already merged into a higher level
|
||||
Boss stands still for 1 second before enemies spawn
|
||||
|
||||
General balance
|
||||
* Enemies should have a chance to be spawned with a modifier as levels increase
|
||||
* Every 3rd level should be wave only
|
||||
* Remove "enemies killed" mode
|
||||
Balance playthroughs (record all balance playthroughs as they can be used for trailers; do this after graphical improvements done)
|
||||
UI improvements
|
||||
Hover class highlight
|
||||
DPS list (right)
|
||||
HP list (bottom)
|
||||
Item list (left)
|
||||
Graphical improvements
|
||||
Further graphical improvements if there's time
|
||||
Trailers
|
||||
3-4 pure gameplay playthroughs showcasing different builds
|
||||
1 normal 30-40s trailer
|
||||
Misc
|
||||
* Better pause screen
|
||||
* End screen
|
||||
Ascension mode (difficulty ramps up faster and goes higher than normal at the end, the player also gains more gold, and on ascension 1 and 5 the maximum number of units is increased by 1 (10->11->12)
|
||||
Music for bosses and shop
|
||||
Achievements
|
||||
Come up with a few new ones as I play the game more and balance the numbers
|
||||
Implement all the ones I already uploaded to Steam
|
||||
NG+1-10 (difficulty ramps up faster and goes higher than normal at the end, the player also gains more gold per round, and on NG+1 and NG+5 the maximum number of units is increased by 1 (10->11->12)
|
||||
NG+10 end screen
|
||||
New music
|
||||
Credits
|
||||
|
||||
|
||||
Engine improvements for after SNKRX release
|
||||
|
@ -33,3 +17,6 @@ Engine improvements for after SNKRX release
|
|||
Defining on_hit on the Wall creation call for that specific Wall, and thus that specific Wall will have this behavior while other walls won't
|
||||
https://i.imgur.com/asPdpnQ.png ?
|
||||
Not sure if I should go all the way with event systems like this or only have it work for specific cases, need to think about it more
|
||||
|
||||
Rewrite
|
||||
DPS list - needs every damage event to be logged with source, destination and damage values being detached from intermediary objects (areas, projectiles, etc)
|
||||
|
|