master
a327ex 2021-04-03 20:49:54 -03:00
parent 129d7f1a06
commit 6322307525
8 changed files with 221 additions and 60 deletions

106
arena.lua
View File

@ -73,7 +73,37 @@ function Arena:on_enter(from, level, units)
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'}}}
-- Wall{group = self.main, vertices = math.to_rectangle_vertices(gw/2 - 0.45*self.level_1000_text.w, gh/2 - 0.3*self.level_1000_text.h, gw/2 + 0.45*self.level_1000_text.w, gh/2 - 3), snkrx = true, color = bg[-1]}
elseif self.level == 6 or self.level == 12 or self.level == 18 or self.level == 24 or self.level == 25 then
self.boss_level = true
self.start_time = 3
self.t:after(1, function()
self.t:every(1, function()
if self.start_time > 1 then alert1:play{volume = 0.5} end
self.start_time = self.start_time - 1
self.hfx:use('condition1', 0.25, 200, 10)
end, 3, function()
alert1:play{pitch = 1.2, volume = 0.5}
camera:shake(4, 0.25)
SpawnEffect{group = self.effects, x = gw/2, y = gh/2 - 48}
SpawnEffect{group = self.effects, x = gw/2, y = gh/2, action = function(x, y)
spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15}
self.boss = Seeker{group = self.main, x = x, y = y, character = 'seeker', level = self.level, boss = boss_by_level[self.level]}
end}
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 1 end, function()
self.hfx:use('condition1', 0.25, 200, 10)
self.hfx:pull('condition2', 0.0625)
self.t:after(0.5, function()
local spawn_type = random:table{'left', 'middle', 'right'}
local spawn_points = {left = {x = self.x1 + 32, y = gh/2}, middle = {x = gw/2, y = gh/2}, right = {x = self.x2 - 32, y = gh/2}}
local p = spawn_points[spawn_type]
SpawnMarker{group = self.effects, x = p.x, y = p.y}
self.t:after(0.75, function() self:spawn_n_enemies(p, nil, 8 + math.floor(self.level/2)) end)
end)
end)
end)
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 end, function() self.can_quit = true end)
end)
else
-- Set win condition and enemy spawns
self.win_condition = random:table{'time', 'enemy_kill', 'wave'}
@ -254,6 +284,13 @@ end
function Arena:update(dt)
if input.k.pressed then
SpawnEffect{group = self.effects, x = gw/2, y = gh/2, action = function(x, y)
spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15}
Seeker{group = self.main, x = x, y = y, character = 'seeker', level = self.level, boss = 'forcer'}
end}
end
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()
@ -320,11 +357,6 @@ function Arena:update(dt)
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
@ -413,33 +445,41 @@ function Arena:draw()
graphics.pop()
end
if self.win_condition then
if self.win_condition == 'time' then
if self.start_time <= 0 then
graphics.push(self.x2 - 66, self.y1 - 9, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('time left:', fat_font, self.x2 - 66, self.y1 - 9, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 18 + fat_font:get_text_width(tostring(self.time_left))/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(tostring(self.time_left), fat_font, self.x2 - 18, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
end
elseif self.win_condition == 'wave' then
if self.start_time <= 0 then
graphics.push(self.x2 - 50, self.y1 - 10, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('wave:', fat_font, self.x2 - 50, self.y1 - 10, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 25 + fat_font:get_text_width(self.wave .. '/' .. self.max_waves)/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(self.wave .. '/' .. self.max_waves, fat_font, self.x2 - 25, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
end
elseif self.win_condition == 'enemy_kill' then
if self.start_time <= 0 then
graphics.push(self.x2 - 106, self.y1 - 10, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('enemies killed:', fat_font, self.x2 - 106, self.y1 - 10, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 41 + fat_font:get_text_width(self.enemies_killed .. '/' .. self.enemies_to_kill)/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(self.enemies_killed .. '/' .. self.enemies_to_kill, fat_font, self.x2 - 41, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
if self.boss_level then
if self.start_time <= 0 then
graphics.push(self.x2 - 106, self.y1 - 10, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('kill the elite', fat_font, self.x2 - 106, self.y1 - 10, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
end
else
if self.win_condition then
if self.win_condition == 'time' then
if self.start_time <= 0 then
graphics.push(self.x2 - 66, self.y1 - 9, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('time left:', fat_font, self.x2 - 66, self.y1 - 9, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 18 + fat_font:get_text_width(tostring(self.time_left))/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(tostring(self.time_left), fat_font, self.x2 - 18, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
end
elseif self.win_condition == 'wave' then
if self.start_time <= 0 then
graphics.push(self.x2 - 50, self.y1 - 10, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('wave:', fat_font, self.x2 - 50, self.y1 - 10, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 25 + fat_font:get_text_width(self.wave .. '/' .. self.max_waves)/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(self.wave .. '/' .. self.max_waves, fat_font, self.x2 - 25, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
end
elseif self.win_condition == 'enemy_kill' then
if self.start_time <= 0 then
graphics.push(self.x2 - 106, self.y1 - 10, 0, self.hfx.condition2.x, self.hfx.condition2.x)
graphics.print_centered('enemies killed:', fat_font, self.x2 - 106, self.y1 - 10, 0, 0.6, 0.6, nil, nil, fg[0])
graphics.pop()
graphics.push(self.x2 - 41 + fat_font:get_text_width(self.enemies_killed .. '/' .. self.enemies_to_kill)/2, self.y1 - 8, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print(self.enemies_killed .. '/' .. self.enemies_to_kill, fat_font, self.x2 - 41, self.y1 - 8, 0, 0.75, 0.75, nil, fat_font.h/2, self.hfx.condition1.f and fg[0] or yellow[0])
graphics.pop()
end
end
end
end

Binary file not shown.

View File

@ -780,3 +780,9 @@ Added a spawn marker so that it's easier for the player to tell where enemies ar
* yellow - Resistance to knockback and increased HP
* white - Remain static and shoot projectiles
* purple - Explodes into critters on death
# Day 46 - 03/04/21
* Adding mini bosses
* Speed Booster - grants speed boost to nearby enemies
* Forcer - pulls enemies together into a point and pushes them out

View File

@ -5,15 +5,80 @@ Seeker:implement(Unit)
function Seeker:init(args)
self:init_game_object(args)
self:init_unit()
self:set_as_rectangle(14, 6, 'dynamic', 'enemy')
self:set_restitution(0.5)
self.color = red[0]:clone()
self.classes = {'seeker'}
self:calculate_stats(true)
self:set_as_steerable(self.v, 2000, 4*math.pi, 4)
if self.boss then
self:set_as_rectangle(18, 7, 'dynamic', 'enemy')
self:set_restitution(0.5)
self.classes = {'mini_boss'}
self:calculate_stats(true)
self:set_as_steerable(self.v, 1000, 2*math.pi, 2)
self.spawner = random:bool(25)
if self.boss == 'speed_booster' then
self.color = green[0]:clone()
self.t:every(5, function()
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 128), main.current.enemies)
if #enemies > 0 then
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = green[0], duration = 0.1}
for _, enemy in ipairs(enemies) do
LightningLine{group = main.current.effects, src = self, dst = enemy, color = green[0]}
enemy:speed_boost(3 + self.level*0.1)
end
end
end)
elseif self.boss == 'forcer' then
self.color = yellow[0]:clone()
self.t:every(6, function()
local enemies = main.current.main:get_objects_by_classes(main.current.enemies)
local x, y = 0, 0
if #enemies > 0 then
for _, enemy in ipairs(enemies) do
x = x + enemy.x
y = y + enemy.y
end
x = x/#enemies
y = y/#enemies
else
x, y = player.x, player.y
end
self.px, self.py = x + random:float(-16, 16), y + random:float(-16, 16)
self.pull_sensor = Circle(self.px, self.py, 160)
self.prs = 0
self.t:tween(0.05, self, {prs = 4}, math.cubic_in_out, function() self.spring:pull(0.15) end)
self.t:after(2 - 0.05*7, function()
self.t:every_immediate(0.05, function() self.phidden = not self.phidden end, 7)
end)
self.color_transparent = Color(yellow[0].r, yellow[0].g, yellow[0].b, 0.08)
self.t:every(0.08, function() HitParticle{group = main.current.effects, x = self.px, y = self.py, color = yellow[0]} end, math.floor(2/0.08))
self.vr = 0
self.dvr = random:float(-math.pi/4, math.pi/4)
force1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.t:during(2, function(dt)
local enemies = self:get_objects_in_shape(self.pull_sensor, main.current.enemies)
for _, enemy in ipairs(enemies) do
enemy:apply_steering_force(math.remap(enemy:distance_to_point(self.px, self.py), 0, 160, 400, 200), enemy:angle_to_point(self.px, self.py))
end
self.vr = self.vr + self.dvr*dt
end, function()
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
local enemies = self:get_objects_in_shape(self.pull_sensor, main.current.enemies)
for _, enemy in ipairs(enemies) do
enemy:push(random:float(40, 80), enemy:angle_to_object(main.current.player), true)
end
self.px, self.py = nil, nil
end)
end)
end
else
self:set_as_rectangle(14, 6, 'dynamic', 'enemy')
self:set_restitution(0.5)
self.color = red[0]:clone()
self.classes = {'seeker'}
self:calculate_stats(true)
self:set_as_steerable(self.v, 2000, 4*math.pi, 4)
end
--[[
if random:bool(35) then
@ -99,6 +164,7 @@ function Seeker:update(dt)
if self.being_pushed then
local v = math.length(self:get_velocity())
if v < 25 then
if self.push_invulnerable then self.push_invulnerable = false end
self.being_pushed = false
self.steering_enabled = true
self:set_damping(0)
@ -110,8 +176,25 @@ function Seeker:update(dt)
self:rotate_towards_object(main.current.player, 0.5)
elseif not self.headbutting then
local player = main.current.player
self:seek_point(player.x, player.y)
self:wander(50, 100, 20)
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
for _, enemy in ipairs(enemies) do
x = x + enemy.x
y = y + enemy.y
end
x = x/#enemies
y = y/#enemies
else
x, y = player.x, player.y
end
self:seek_point(x, y)
self:wander(10, 250, 3)
else
self:seek_point(player.x, player.y)
self:wander(50, 100, 20)
end
self:steering_separate(16, main.current.enemies)
self:rotate_towards_velocity(0.5)
end
@ -124,8 +207,22 @@ end
function Seeker:draw()
graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x)
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color)
if self.boss then
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.hfx.hit.f and fg[0] or self.color)
else
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color)
end
graphics.pop()
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)
graphics.circle(self.px, self.py, self.prs + random:float(-1, 1), yellow[0])
graphics.circle(self.px, self.py, self.pull_sensor.rs, self.color_transparent)
local lw = math.remap(self.pull_sensor.rs, 32, 256, 2, 4)
for i = 1, 4 do graphics.arc('open', self.px, self.py, self.pull_sensor.rs, (i-1)*math.pi/2 + math.pi/4 - math.pi/8, (i-1)*math.pi/2 + math.pi/4 + math.pi/8, yellow[0], lw) end
graphics.pop()
end
end
@ -163,6 +260,7 @@ end
function Seeker:hit(damage, projectile)
if self.dead then return end
self.hfx:use('hit', 0.25, 200, 10)
if self.push_invulnerable then return end
self:show_hp()
local actual_damage = self:calculate_damage(damage)
@ -208,9 +306,11 @@ function Seeker:hit(damage, projectile)
end
function Seeker:push(f, r)
function Seeker:push(f, r, push_invulnerable)
local n = 1
if self.tank then n = 0.4 - 0.01*self.level end
if self.boss then n = 0.1 end
self.push_invulnerable = push_invulnerable
self.push_force = n*f
self.being_pushed = true
self.steering_enabled = false

View File

@ -231,8 +231,9 @@ function Trigger:update(dt)
trigger.last_condition = condition
elseif trigger.type == "during" then
trigger.action()
trigger.action(dt)
if trigger.timer > trigger.delay then
trigger.after()
self.triggers[tag] = nil
end

View File

@ -27,6 +27,7 @@ function init()
headbutt1 = Sound('Wind Bolt 14.ogg', s)
critter1 = Sound('Critters eating 2.ogg', s)
critter2 = Sound('Crickets Chirping 4.ogg', s)
force1 = Sound('Magical Impact 18.ogg', s)
error1 = Sound('Error 2.ogg', s)
coins1 = Sound('Coins 7.ogg', s)
coins2 = Sound('Coins 8.ogg', s)
@ -263,6 +264,7 @@ function init()
['enchanter'] = {hp = 1.2, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1.2, mvspd = 1.2},
['psy'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.5, mvspd = 1},
['seeker'] = {hp = 0.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.3},
['mini_boss'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.3},
['enemy_critter'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 0.5},
['saboteur'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 1.4},
}
@ -414,6 +416,14 @@ function init()
[25] = {100, 100},
}
boss_by_level = {
[6] = 'speed_booster',
[12] = 'exploder',
[18] = 'swarmer',
[24] = 'bouncer',
[25] = 'orbitter',
}
gold = 2
main = Main()
@ -453,13 +463,6 @@ function update(dt)
music.volume = 0.5
end
end
if input.k.pressed then
print(steam.user.getPlayerSteamLevel())
print(steam.user.getSteamID())
print(steam.friends.getFriendPersonaName(steam.user.getSteamID()))
print(steam.utils.getAppID())
end
end

View File

@ -227,11 +227,19 @@ function Unit:calculate_stats(first_run)
self.base_dmg = 10*math.pow(2, self.level-1)
self.base_mvspd = 75
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 + 55*y[x]
self.base_dmg = 10 + 3*y[x]
self.base_mvspd = 70 + 3*y[x]
if self.boss 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 = 250 + 275*y[x]
self.base_dmg = 50 + 15*y[x]
self.base_mvspd = 35 + 1.5*y[x]
else
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 + 55*y[x]
self.base_dmg = 10 + 3*y[x]
self.base_mvspd = 70 + 3*y[x]
end
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)

9
todo
View File

@ -7,7 +7,7 @@
* Psykeeper: stores damage taken by all allies up to 50% its max HP and redistributes it as healing
* Squire: +5%/10%/15% damage and defense to all allies
7. Enemy modifiers
* 7. Enemy modifiers
* green - Grant nearby enemies a speed boost on death
* blue - Explode into projectiles on death
* orange - Charge up and headbutt towards the player at increased speed and damage
@ -16,8 +16,11 @@
* purple - Explodes into critters on death
6. Mini boss every 3rd level
This is just a special enemy with more HP and ability to buff nearby enemies with modifiers, no additional AI or attack patterns
... aiming for ~5 different modifier combos that the boss uses
* Speed Booster - grants speed boost to nearby enemies
Swarmer - explodes enemies into a swarm of critters
Exploder - explodes enemies into projectiles
* Forcer - pulls enemies together into a point and pushes them out
Orbitter - spawns shooters that orbit the boss
8. Additional characters and classes
9. Lv.3 effects for every character