master
a327ex 2021-03-17 06:30:20 -03:00
parent 4ddee5119c
commit bafd765ab3
12 changed files with 247 additions and 79 deletions

100
arena.lua
View File

@ -113,6 +113,7 @@ function Arena:on_enter(from, level, units)
self.enemies_killed = 0
self.enemies_to_kill = self.level_to_enemies_to_kill[self.level]
self.enemy_spawn_delay = 8
self.enemies_spawned = 0
self.start_time = 3
self.t:after(1, function()
self.t:every(1, function()
@ -171,7 +172,7 @@ function Arena:on_enter(from, level, units)
if self.level == 1 then
local t1 = Text2{group = self.floor, x = gw/2, y = gh/2 + 2, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]<- or a -> or d', font = fat_font, alignment = 'center'}}}
local t2 = Text2{group = self.floor, x = gw/2, y = gh/2 + 18, lines = {{text = '[light_bg]turn left turn right', font = pixul_font, alignment = 'center'}}}
local t3 = Text2{group = self.floor, x = gw/2, y = gh/2 + 46, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]n - mute sfx', font = fat_font, alignment = 'center'}}}
local t3 = Text2{group = self.floor, x = gw/2, y = gh/2 + 46, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]s - mute sfx', font = fat_font, alignment = 'center'}}}
local t4 = Text2{group = self.floor, x = gw/2, y = gh/2 + 68, sx = 0.6, sy = 0.6, lines = {{text = '[light_bg]m - mute music', font = fat_font, alignment = 'center'}}}
t1.t:after(8, function() t1.t:tween(0.2, t1, {sy = 0}, math.linear, function() t1.sy = 0 end) end)
t2.t:after(8, function() t2.t:tween(0.2, t2, {sy = 0}, math.linear, function() t2.sy = 0 end) end)
@ -233,7 +234,76 @@ end
function Arena:update(dt)
if input.escape.pressed and not self.transitioning then
if not self.paused then
trigger:tween(0.25, _G, {slow_amount = 0}, math.linear, function()
slow_amount = 0
self.paused = true
self.paused_t1 = Text2{group = self.ui, x = gw/2, y = gh/2 - 68, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]<- or a -> or d', font = fat_font, alignment = 'center'}}}
self.paused_t2 = Text2{group = self.ui, x = gw/2, y = gh/2 - 52, lines = {{text = '[bg10]turn left turn right', font = pixul_font, alignment = 'center'}}}
self.paused_t3 = Text2{group = self.ui, x = gw/2, y = gh/2 - 22, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]s - mute sfx', font = fat_font, alignment = 'center'}}}
self.paused_t4 = Text2{group = self.ui, x = gw/2, y = gh/2 + 0, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]m - mute music', font = fat_font, alignment = 'center'}}}
self.paused_t5 = Text2{group = self.ui, x = gw/2, y = gh/2 + 22, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]esc - resume game', font = fat_font, alignment = 'center'}}}
self.paused_t6 = Text2{group = self.ui, x = gw/2, y = gh/2 + 44, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]r - restart run', font = fat_font, alignment = 'center'}}}
self.paused_t7 = Text2{group = self.ui, x = gw/2, y = gh/2 + 68, sx = 0.6, sy = 0.6, lines = {{text = '[bg10]w - wishlist on steam', font = fat_font, alignment = 'center'}}}
end, 'pause')
else
trigger:tween(0.25, _G, {slow_amount = 1}, math.linear, function()
slow_amount = 1
self.paused = false
self.paused_t1.dead = true
self.paused_t2.dead = true
self.paused_t3.dead = true
self.paused_t4.dead = true
self.paused_t5.dead = true
self.paused_t6.dead = true
self.paused_t7.dead = true
self.paused_t1 = nil
self.paused_t2 = nil
self.paused_t3 = nil
self.paused_t4 = nil
self.paused_t5 = nil
self.paused_t6 = nil
self.paused_t7 = nil
end, 'pause')
end
end
if self.paused or self.died and not self.transitioning then
if input.r.pressed then
self.transitioning = true
ui_transition2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
TransitionEffect{group = main.transitions, x = gw/2, y = gh/2, color = fg[0], transition_action = function()
slow_amount = 1
gold = 2
cascade_instance:stop()
main:add(BuyScreen'buy_screen')
main:go_to('buy_screen', 0, {})
end, text = Text({{text = '[wavy, bg]restarting...', font = pixul_font, alignment = 'center'}}, global_text_tags)}
end
if input.w.pressed then
ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
system.open_url'https://store.steampowered.com/app/915310/SNKRX/'
end
end
if input.w.pressed and self.won then
ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
system.open_url'https://store.steampowered.com/app/915310/SNKRX/'
end
self:update_game_object(dt*slow_amount)
cascade_instance.pitch = math.clamp(slow_amount*self.main_slow_amount, 0.05, 1)
if input.k.pressed then
local enemies = self.main:get_objects_by_classes(self.enemies)
for _, enemy in ipairs(enemies) do enemy:hit(1000000000000) end
end
if self.enchanter_level == 1 then self.enchanter_dmg_m = 1.25
else self.enchanter_dmg_m = 1 end
@ -248,8 +318,25 @@ function Arena:update(dt)
self.can_quit = false
self.transitioning = true
local gold_gained = random:int(level_to_gold_gained[self.level][1], level_to_gold_gained[self.level][2])
print(gold_gained)
gold = gold + gold_gained
if self.level == 25 then
if not self.win_text and not self.win_text2 then
self.won = true
camera.x, camera.y = gw/2, gh/2
self.win_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 64, lines = {{text = '[wavy_mid, cbyc2]congratulations!', font = fat_font, alignment = 'center'}}}
self.t:after(2.5, function()
self.win_text2 = Text2{group = self.ui, x = gw/2, y = gh/2 + 16, lines = {
{text = "[fg]you've beaten the demo!", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
{text = "[fg]the game's full version is coming in a few weeks,", font = pixul_font, alignment = 'center', height_multiplier = 1.2},
{text = "[fg]so if you liked the game, make sure to wishlist it!", font = pixul_font, alignment = 'center', height_multiplier = 5},
{text = "[wavy_mid, fg]thanks for playing!", font = pixul_font, alignment = 'center'},
}}
WishlistButton{group = self.ui, x = gw/2, y = gh/2 + 30, w_to_wishlist = true}
end)
end
else
if not self.arena_clear_text then self.arena_clear_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 48, lines = {{text = '[wavy_mid, cbyc]arena clear!', font = fat_font, alignment = 'center'}}} end
self.t:after(3, function()
ui_transition2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -287,6 +374,7 @@ function Arena:update(dt)
}, global_text_tags)}
end, 'transition')
end
end
end
@ -339,14 +427,14 @@ end
function Arena:die()
if not self.died_text then
if not self.died_text and not self.won then
self.died = true
self.t:tween(2, self, {main_slow_amount = 0}, math.linear, function() self.main_slow_amount = 0 end)
self.died_text = Text2{group = self.ui, x = gw/2, y = gh/2 - 32, lines = {
{text = '[wavy_mid, cbyc]you died...', font = fat_font, alignment = 'center', height_multiplier = 1.25},
}}
self.t:after(2, function()
self.death_info_text = Text2{group = self.ui, x = gw/2, y = gh/2 + 16, sx = 0.7, sy = 0.7, lines = {
self.death_info_text = Text2{group = self.ui, x = gw/2, y = gh/2 + 24, sx = 0.7, sy = 0.7, lines = {
{text = '[wavy_mid, light_bg]level reached: [wavy_mid, yellow]' .. self.level, font = fat_font, alignment = 'center'},
{text = '[wavy_mid, light_bg]r - start new run', font = fat_font, alignment = 'center'},
{text = '[wavy_mid, light_bg]w - wishlist on steam', font = fat_font, alignment = 'center'},
@ -411,6 +499,10 @@ function Arena:spawn_n_enemies(p, j, n)
n = n or 4
self.last_spawn_enemy_time = love.timer.getTime()
self.t:every(0.1, function()
if self.win_condition == 'enemy_kill' then
if self.enemies_spawned >= math.floor(1.4*self.enemies_to_kill) then return end
self.enemies_spawned = self.enemies_spawned + 1
end
local o = self.spawn_offsets[(self.t:get_every_iteration('spawn_enemies_' .. j) % 5) + 1]
SpawnEffect{group = self.effects, x = p.x + o.x, y = p.y + o.y, action = function(x, y)
spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15}

Binary file not shown.

Binary file not shown.

View File

@ -32,6 +32,7 @@ function BuyScreen:on_enter(from, level, units)
camera.x, camera.y = gw/2, gh/2
if self.level == 0 then
cascade_instance = cascade:play{volume = 0.5, loop = true}
self.level = 1
self.first_screen = true
end
@ -60,6 +61,8 @@ end
function BuyScreen:update(dt)
self:update_game_object(dt*slow_amount)
cascade_instance.pitch = 1
self.main:update(dt*slow_amount)
self.effects:update(dt*slow_amount)
self.ui:update(dt*slow_amount)
@ -180,9 +183,14 @@ WishlistButton = Object:extend()
WishlistButton:implement(GameObject)
function WishlistButton:init(args)
self:init_game_object(args)
self.shape = Rectangle(self.x, self.y, 110, 18)
self.interact_with_mouse = true
if self.w_to_wishlist then
self.shape = Rectangle(self.x, self.y, 85, 18)
self.text = Text({{text = '[bg10]w to wishlist', font = pixul_font, alignment = 'center'}}, global_text_tags)
else
self.shape = Rectangle(self.x, self.y, 110, 18)
self.text = Text({{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}}, global_text_tags)
end
end
@ -194,7 +202,7 @@ function WishlistButton:update(dt)
self.spring:pull(0.2, 200, 10)
self.selected = true
ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
system.open_url'https://store.steampowered.com/app/760330/BYTEPATH/'
system.open_url'https://store.steampowered.com/app/915310/SNKRX/'
end
end
@ -211,13 +219,21 @@ function WishlistButton:on_mouse_enter()
ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5}
pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.selected = true
if self.w_to_wishlist then
self.text:set_text{{text = '[fgm5]w to wishlist', font = pixul_font, alignment = 'center'}}
else
self.text:set_text{{text = '[fgm5]wishlist on steam', font = pixul_font, alignment = 'center'}}
end
self.spring:pull(0.2, 200, 10)
end
function WishlistButton:on_mouse_exit()
if self.w_to_wishlist then
self.text:set_text{{text = '[bg10]w to wishlist', font = pixul_font, alignment = 'center'}}
else
self.text:set_text{{text = '[bg10]wishlist on steam', font = pixul_font, alignment = 'center'}}
end
self.selected = false
end

View File

@ -406,4 +406,10 @@ Mostly done with balance tuning. Now all that's left are some final details:
* Win screen
* W to wishlist
* R to restart
* Unit death sound
* Allied unit death sound
# Day 28 - 16/03/21
The demo is finally 100% complete. Now tomorrow I'll spend some time recording gameplay and hopefully finishing the trailer. After that I can start working on the steam page.
If I have it done by tomorrow and Valve takes 5 business days to approve the store page I should have everything ready by the 25th. And then I can release the game 14 days after that, which would be the 8th of April.
I definitely want to release it around that time, before the 15th because then I will have completed the game in less than 60 days which is my limit, although I should probably aim for 40 days going forward.

View File

@ -58,8 +58,8 @@ function Seeker:on_collision_enter(other, contact)
elseif table.any(main.current.enemies, function(v) return other:is(v) end) then
if self.being_pushed and math.length(self:get_velocity()) > 60 then
other:hit(5)
self:hit(10)
other:hit(math.floor(self.dmg/2))
self:hit(self.dmg)
other:push(random:float(10, 15), other:angle_to_object(self))
HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end

View File

@ -37,7 +37,8 @@ function init()
arrow_hit_wall2 = Sound('Arrow Impact wood 1.ogg', s)
hit1 = Sound('Player Takes Damage 17.ogg', s)
hit2 = Sound('Body Head (Headshot) 1.ogg', s)
hit3 = Sound('Kick 16.ogg', s)
hit3 = Sound('Kick 16_1.ogg', s)
hit4 = Sound('Kick 16_2.ogg', s)
proj_hit_wall1 = Sound('Player Takes Damage 2.ogg', s)
enemy_die1 = Sound('Bloody punches 7.ogg', s)
enemy_die2 = Sound('Bloody punches 10.ogg', s)
@ -77,6 +78,7 @@ function init()
turret_deploy = Sound('321215__hybrid-v__sci-fi-weapons-deploy.ogg', s)
rogue_crit1 = Sound('Dagger Stab (Flesh) 4.ogg', s)
rogue_crit2 = Sound('Sword hits another sword 6.ogg', s)
cascade = Sound('Kubbi - Ember - 04 Cascade.ogg', {tags = {music}})
warrior = Image('warrior')
ranger = Image('ranger')
@ -376,29 +378,29 @@ function init()
level_to_gold_gained = {
[1] = {2, 2},
[2] = {2, 2},
[3] = {2, 3},
[3] = {4, 6},
[4] = {2, 3},
[5] = {3, 5},
[6] = {3, 5},
[6] = {6, 10},
[7] = {4, 7},
[8] = {4, 7},
[9] = {5, 8},
[9] = {10, 16},
[10] = {5, 8},
[11] = {5, 8},
[12] = {6, 10},
[12] = {12, 20},
[13] = {6, 10},
[14] = {6, 10},
[15] = {7, 11},
[15] = {14, 22},
[16] = {8, 12},
[17] = {8, 12},
[18] = {8, 12},
[18] = {16, 24},
[19] = {8, 12},
[20] = {10, 14},
[21] = {10, 14},
[21] = {20, 28},
[22] = {11, 15},
[23] = {11, 15},
[24] = {12, 18},
[25] = {12, 18},
[24] = {24, 36},
[25] = {100, 100},
}
gold = 2
@ -411,6 +413,23 @@ end
function update(dt)
main:update(dt)
if input.s.pressed then
if sfx.volume == 0.5 then
sfx.volume = 0
elseif sfx.volume == 0 then
sfx.volume = 0.5
end
end
if input.m.pressed then
print(music.volume)
if music.volume == 0.5 then
music.volume = 0
elseif music.volume == 0 then
music.volume = 0.5
end
end
end

View File

@ -204,9 +204,9 @@ function Unit:calculate_stats(first_run)
elseif self:is(Seeker) then
local x = self.level
local y = {0, 1, 4, 2, 3, 6, 3, 5, 9, 4, 6, 11, 7, 9, 15, 8, 10, 18, 9, 11, 21, 14, 15, 24, 25}
self.base_hp = 50 + 60*y[x]
self.base_dmg = 10 + 40*y[x]
self.base_mvspd = 70 + 10*y[x]
self.base_hp = 50 + 55*y[x]
self.base_dmg = 10 + 3*y[x]
self.base_mvspd = 70 + 3*y[x]
elseif self:is(Saboteur) then
self.base_hp = 100*math.pow(2, self.level-1)
self.base_dmg = 10*math.pow(2, self.level-1)

View File

@ -188,8 +188,8 @@ function Player:init(args)
local followers
local leader = (self.leader and self) or self.parent
if self.leader then followers = self.followers else followers = self.parent.followers end
local next_character = followers[self.follower_index + 1]
local previous_character = followers[self.follower_index - 1]
local next_character = followers[(self.follower_index or 0) + 1]
local previous_character = followers[(self.follower_index or 0) - 1]
if next_character then next_character:squire_buff(8) end
if previous_character then previous_character:squire_buff(8) end
self.t:after(8, function() self.applying_buff = false end, 'squire_buff_apply')
@ -250,8 +250,8 @@ function Player:init(args)
local followers
local leader = (self.leader and self) or self.parent
if self.leader then followers = self.followers else followers = self.parent.followers end
local next_character = followers[self.follower_index + 1]
local previous_character = followers[self.follower_index - 1]
local next_character = followers[(self.follower_index or 0) + 1]
local previous_character = followers[(self.follower_index or 0) - 1]
if next_character then next_character:chronomancer_buff(2) end
if previous_character then previous_character:chronomancer_buff(2) end
end)
@ -320,8 +320,8 @@ function Player:update(dt)
local followers
local leader = (self.leader and self) or self.parent
if self.leader then followers = self.followers else followers = self.parent.followers end
local next_character = followers[self.follower_index + 1]
local previous_character = followers[self.follower_index - 1]
local next_character = followers[(self.follower_index or 0) + 1]
local previous_character = followers[(self.follower_index or 0) - 1]
if self.applying_buff then
if next_character then
next_character.squire_dmg_a = 10
@ -346,8 +346,8 @@ function Player:update(dt)
local followers
local leader = (self.leader and self) or self.parent
if self.leader then followers = self.followers else followers = self.parent.followers end
local next_character = followers[self.follower_index + 1]
local previous_character = followers[self.follower_index - 1]
local next_character = followers[(self.follower_index or 0) + 1]
local previous_character = followers[(self.follower_index or 0) - 1]
if next_character then next_character.chronomancer_aspd_m = 1.25 end
if previous_character then previous_character.chronomancer_aspd_m = 1.25 end
end
@ -409,6 +409,7 @@ function Player:update(dt)
if input.move_right.down then self.r = self.r + 1.66*math.pi*dt end
self:set_velocity(self.v*math.cos(self.r), self.v*math.sin(self.r))
if not main.current.won then
local vx, vy = self:get_velocity()
local hd = math.remap(math.abs(self.x - gw/2), 0, 192, 1, 0)
local vd = math.remap(math.abs(self.y - gh/2), 0, 108, 1, 0)
@ -419,11 +420,12 @@ function Player:update(dt)
elseif input.move_down.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, math.pi/256)
elseif input.move_up.down then camera.r = math.lerp_angle_dt(0.01, dt, camera.r, -math.pi/256)
else camera.r = math.lerp_angle_dt(0.005, dt, camera.r, 0) end
end
self:set_angle(self.r)
else
local target_distance = 10.4*self.follower_index
local target_distance = 10.4*(self.follower_index or 0)
local distance_sum = 0
local p
local previous = self.parent
@ -485,9 +487,9 @@ function Player:on_collision_enter(other, contact)
elseif table.any(main.current.enemies, function(v) return other:is(v) end) then
other:push(random:float(25, 35), self:angle_to_object(other))
if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(40)
else other:hit(20) end
self:hit(20)
if self.character == 'vagrant' or self.character == 'psykeeper' then other:hit(2*self.dmg)
else other:hit(self.dmg) end
self:hit(other.dmg)
HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = other.color} end
@ -500,7 +502,6 @@ function Player:hit(damage)
self.hfx:use('hit', 0.25, 200, 10)
self:show_hp()
local actual_damage = self:calculate_damage(damage)
self.hp = self.hp - actual_damage
_G[random:table{'player_hit1', 'player_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -510,6 +511,7 @@ function Player:hit(damage)
if self.character == 'psykeeper' then self.psykeeper_heal = self.psykeeper_heal + actual_damage end
if self.hp <= 0 then
hit4:play{pitch = random:float(0.95, 1.05), volume = 0.5}
slow(0.25, 1)
self.dead = true
for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end
@ -978,7 +980,7 @@ function Turret:init(args)
self:set_restitution(0.5)
self.hfx:add('hit', 1)
self.color = orange[0]
self.attack_sensor = Circle(self.x, self.y, 96)
self.attack_sensor = Circle(self.x, self.y, 256)
turret_deploy:play{pitch = 1.2, volume = 0.2}
self.t:every({3.5, 4.5}, function()

View File

@ -449,6 +449,17 @@ global_text_tags = {
graphics.set_color(c.color)
end},
cbyc2 = TextTag{init = function(c, i, text)
c.color = invisible
text.t:after((i-1)*0.15, function()
c.color = yellow[0]
camera:shake(3, 0.075)
pop1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
end)
end, draw = function(c, i, text)
graphics.set_color(c.color)
end},
nudge_down = TextTag{init = function(c, i, text)
c.oy = -4
text.t:tween(0.1, c, {oy = 0}, math.linear)

32
todo
View File

@ -1,18 +1,27 @@
-- POST DEMO --
Mini Boss every 3rd level
Show a unit DPS list like Underlord's to the right side of the screen
About 20-30 passive items that can be collected every 3 levels
Lv.3 effects for every character
Boss ideas
Pretends to be dead, grants speed buffs to enemies after death, especially if the round has gone on for too long which means the player is surviving with 1 unit
Classes and characters
Trapper: releases +1 trap
Plague Doctor [trapper, nuker]: releases an area that deals 6 AoE DoT
Fisherman [trapper, warrior]: throws a net that entangles enemies and prevents them from moving
Lich [mage, enchanter]: nearby enemies have decreased movement speed
Items
Resonance: hitting walls has a chance of releasing projectiles
Ouroboros Technique: rotating around yourself makes every unit release projectiles
AoE 1: all units that deal AoE damage have increased stat
AoE 2: increased stat if all your units that deal damage deal AoE damage
Proj 1: all units that release projectiles have increased stat
Proj 2: increased stat if all your units that deal damage release projectiles
Wallrider: hitting walls grants a speed buff for a small duration
Enemy modifiers
Grant nearby enemies a speed boost on death
Grant nearby enemies a damage boost on death
@ -20,3 +29,16 @@ Enemy modifiers
Charge up and headbutt towards the player at increased speed and damage
Immune to knockback
UI
Highlight units of a class when hovering over the class icon in the "sets" section
Add stat details to each unit when hovering over it in the "party" section
Balance
More damage to AoE units with big cooldowns
Warriors that deal AoE damage should deal extra damage based on number of enemies hit
Bugs
Squire and Chronomancer don't affect leader
Sage's pull force doesn't increase with unit level
Cleric's healing amount doesn't increase with unit level
Squire and Chronomancer's buffs don't increase with unit level