Day 5
parent
9d3f777342
commit
2ff3cb9445
27
arena.lua
27
arena.lua
|
@ -13,6 +13,7 @@ function Arena:on_enter(from, level)
|
||||||
self.level = level or 1
|
self.level = level or 1
|
||||||
|
|
||||||
self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
||||||
|
self.post_main = Group()
|
||||||
self.effects = Group()
|
self.effects = Group()
|
||||||
self.ui = Group():no_camera()
|
self.ui = Group():no_camera()
|
||||||
self.main:disable_collision_between('player', 'player')
|
self.main:disable_collision_between('player', 'player')
|
||||||
|
@ -44,16 +45,17 @@ function Arena:on_enter(from, level)
|
||||||
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x2, -40, gw + 40, gh + 40), color = bg[-1]}
|
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x2, -40, gw + 40, gh + 40), color = bg[-1]}
|
||||||
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x1, -40, self.x2, self.y1), color = bg[-1]}
|
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x1, -40, self.x2, self.y1), color = bg[-1]}
|
||||||
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x1, self.y2, self.x2, gh + 40), color = bg[-1]}
|
Wall{group = self.main, vertices = math.to_rectangle_vertices(self.x1, self.y2, self.x2, gh + 40), color = bg[-1]}
|
||||||
|
WallCover{group = self.post_main, vertices = math.to_rectangle_vertices(-40, -40, self.x1, gh + 40), color = bg[-1]}
|
||||||
|
WallCover{group = self.post_main, vertices = math.to_rectangle_vertices(self.x2, -40, gw + 40, gh + 40), color = bg[-1]}
|
||||||
|
WallCover{group = self.post_main, vertices = math.to_rectangle_vertices(self.x1, -40, self.x2, self.y1), color = bg[-1]}
|
||||||
|
WallCover{group = self.post_main, vertices = math.to_rectangle_vertices(self.x1, self.y2, self.x2, gh + 40), color = bg[-1]}
|
||||||
|
|
||||||
self.player = Player{group = self.main, x = gw/2, y = gh/2, leader = true, character = 'scout'}
|
self.player = Player{group = self.main, x = gw/2, y = gh/2, leader = true, character = 'swordsman'}
|
||||||
--self.player:add_follower(Player{group = self.main, character = 'scout'})
|
self.player:add_follower(Player{group = self.main, character = 'archer'})
|
||||||
--[[
|
|
||||||
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
||||||
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
self.player:add_follower(Player{group = self.main, character = 'cleric'})
|
||||||
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
self.player:add_follower(Player{group = self.main, character = 'scout'})
|
||||||
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
self.player:add_follower(Player{group = self.main, character = 'wizard'})
|
||||||
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
|
|
||||||
]]--
|
|
||||||
|
|
||||||
self.win_condition = random:table{'time', 'enemy_kill', 'wave'}
|
self.win_condition = random:table{'time', 'enemy_kill', 'wave'}
|
||||||
if self.win_condition == 'wave' then
|
if self.win_condition == 'wave' then
|
||||||
|
@ -68,9 +70,11 @@ function Arena:on_enter(from, level)
|
||||||
self.start_time = 3
|
self.start_time = 3
|
||||||
self.t:after(1, function()
|
self.t:after(1, function()
|
||||||
self.t:every(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.start_time = self.start_time - 1
|
||||||
self.hfx:use('condition1', 0.25, 200, 10)
|
self.hfx:use('condition1', 0.25, 200, 10)
|
||||||
end, 3, function()
|
end, 3, function()
|
||||||
|
alert1:play{pitch = 1.2, volume = 0.5}
|
||||||
camera:shake(4, 0.25)
|
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 - 48}
|
||||||
self.wave = 0
|
self.wave = 0
|
||||||
|
@ -101,9 +105,11 @@ function Arena:on_enter(from, level)
|
||||||
self.start_time = 3
|
self.start_time = 3
|
||||||
self.t:after(1, function()
|
self.t:after(1, function()
|
||||||
self.t:every(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.start_time = self.start_time - 1
|
||||||
self.hfx:use('condition1', 0.25, 200, 10)
|
self.hfx:use('condition1', 0.25, 200, 10)
|
||||||
end, 3, function()
|
end, 3, function()
|
||||||
|
alert1:play{pitch = 1.2, volume = 0.5}
|
||||||
camera:shake(4, 0.25)
|
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 - 48}
|
||||||
self:spawn_distributed_enemies()
|
self:spawn_distributed_enemies()
|
||||||
|
@ -127,9 +133,11 @@ function Arena:on_enter(from, level)
|
||||||
self.start_time = 3
|
self.start_time = 3
|
||||||
self.t:after(1, function()
|
self.t:after(1, function()
|
||||||
self.t:every(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.start_time = self.start_time - 1
|
||||||
self.hfx:use('condition1', 0.25, 200, 10)
|
self.hfx:use('condition1', 0.25, 200, 10)
|
||||||
end, 3, function()
|
end, 3, function()
|
||||||
|
alert1:play{pitch = 1.2, volume = 0.5}
|
||||||
camera:shake(4, 0.25)
|
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 - 48}
|
||||||
self.t:every(1, function()
|
self.t:every(1, function()
|
||||||
|
@ -152,6 +160,7 @@ end
|
||||||
function Arena:update(dt)
|
function Arena:update(dt)
|
||||||
self:update_game_object(dt*slow_amount)
|
self:update_game_object(dt*slow_amount)
|
||||||
self.main:update(dt*slow_amount)
|
self.main:update(dt*slow_amount)
|
||||||
|
self.post_main:update(dt*slow_amount)
|
||||||
self.effects:update(dt*slow_amount)
|
self.effects:update(dt*slow_amount)
|
||||||
self.ui:update(dt*slow_amount)
|
self.ui:update(dt*slow_amount)
|
||||||
|
|
||||||
|
@ -179,6 +188,7 @@ end
|
||||||
|
|
||||||
function Arena:draw()
|
function Arena:draw()
|
||||||
self.main:draw()
|
self.main:draw()
|
||||||
|
self.post_main:draw()
|
||||||
self.effects:draw()
|
self.effects:draw()
|
||||||
self.ui:draw()
|
self.ui:draw()
|
||||||
|
|
||||||
|
@ -279,6 +289,7 @@ function Arena:spawn_n_enemies(p, j, n)
|
||||||
self.t:every(0.1, function()
|
self.t:every(0.1, function()
|
||||||
local o = self.spawn_offsets[(self.t:get_every_iteration('spawn_enemies_' .. j) % 5) + 1]
|
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)
|
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}
|
||||||
if self.level == 1 then
|
if self.level == 1 then
|
||||||
Seeker{group = self.main, x = x, y = y, character = 'seeker'}
|
Seeker{group = self.main, x = x, y = y, character = 'seeker'}
|
||||||
elseif self.level == 2 then
|
elseif self.level == 2 then
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -90,3 +90,10 @@ The classes are:
|
||||||
|
|
||||||
I'm not sure what I should focus on next. I know that there's sounds left to add, but after that I should probably start doing the actual game progression, but for that I think need a bunch more characters.
|
I'm not sure what I should focus on next. I know that there's sounds left to add, but after that I should probably start doing the actual game progression, but for that I think need a bunch more characters.
|
||||||
I should probably try to think of a cast of maybe 15-20 characters (however that number should be as low as possible) that fills up the current classes to their multiple levels. Levels possible are: 1, 2, 3, 2/4, 2/4/6 and 3/6.
|
I should probably try to think of a cast of maybe 15-20 characters (however that number should be as low as possible) that fills up the current classes to their multiple levels. Levels possible are: 1, 2, 3, 2/4, 2/4/6 and 3/6.
|
||||||
|
|
||||||
|
# Day 5 - 21/02/21
|
||||||
|
|
||||||
|
Sounds done for everything. Surprising to me how much sounds added to the game and helped me sell all the different attacks way better than with just graphics.
|
||||||
|
I should probably make it a habit to add sounds earlier rather than later from now on.
|
||||||
|
|
||||||
|
Tomorrow I should probably ideaguy the full set of characters and classes that I'll need so that the game is playable and start on implementing those additional characters as well as some class bonuses.
|
||||||
|
|
18
enemies.lua
18
enemies.lua
|
@ -59,11 +59,29 @@ function Seeker:on_collision_enter(other, contact)
|
||||||
other:push(random:float(10, 15), other:angle_to_object(self))
|
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}
|
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 = self.color} end
|
||||||
|
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Seeker:hit(damage)
|
||||||
|
if self.dead then return end
|
||||||
|
self.hfx:use('hit', 0.25, 200, 10)
|
||||||
|
self:show_hp()
|
||||||
|
|
||||||
|
local actual_damage = self:calculate_damage(damage)
|
||||||
|
self.hp = self.hp - actual_damage
|
||||||
|
if self.hp <= 0 then
|
||||||
|
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
|
||||||
|
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color)
|
||||||
|
main.current:enemy_killed()
|
||||||
|
_G[random:table{'enemy_die1', 'enemy_die2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.5}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function Seeker:push(f, r)
|
function Seeker:push(f, r)
|
||||||
self.being_pushed = true
|
self.being_pushed = true
|
||||||
self.steering_enabled = false
|
self.steering_enabled = false
|
||||||
|
|
|
@ -167,6 +167,7 @@ end
|
||||||
function Group:add(object)
|
function Group:add(object)
|
||||||
local class = getmetatable(object)
|
local class = getmetatable(object)
|
||||||
object.group = self
|
object.group = self
|
||||||
|
|
||||||
if not object.id then object.id = random:uid() end
|
if not object.id then object.id = random:uid() end
|
||||||
self.objects.by_id[object.id] = object
|
self.objects.by_id[object.id] = object
|
||||||
if not self.objects.by_class[class] then self.objects.by_class[class] = {} end
|
if not self.objects.by_class[class] then self.objects.by_class[class] = {} end
|
||||||
|
|
28
main.lua
28
main.lua
|
@ -14,6 +14,34 @@ function init()
|
||||||
input:bind('move_up', {'w', 'up'})
|
input:bind('move_up', {'w', 'up'})
|
||||||
input:bind('move_down', {'s', 'down'})
|
input:bind('move_down', {'s', 'down'})
|
||||||
|
|
||||||
|
sfx_tag = {tags = {sfx}}
|
||||||
|
shoot1 = Sound('Shooting Projectile (Classic) 11.ogg', s)
|
||||||
|
archer1 = Sound('Releasing Bow String 1.ogg', s)
|
||||||
|
wizard1 = Sound('Wind Bolt 20.ogg', s)
|
||||||
|
swordsman1 = Sound('Heavy sword woosh 1.ogg', s)
|
||||||
|
swordsman2 = Sound('Heavy sword woosh 19.ogg', s)
|
||||||
|
scout1 = Sound('Throwing Knife (Thrown) 3.ogg', s)
|
||||||
|
scout2 = Sound('Throwing Knife (Thrown) 4.ogg', s)
|
||||||
|
arrow_hit_wall1 = Sound('Arrow Impact wood 3.ogg', s)
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
magic_area1 = Sound('Fire bolt 10.ogg', s)
|
||||||
|
magic_hit1 = Sound('Shadow Punch 1.ogg', s)
|
||||||
|
magic_die1 = Sound('Magical Impact 27.ogg', s)
|
||||||
|
knife_hit_wall1 = Sound('Shield Impacts Sword 1.ogg', s)
|
||||||
|
player_hit1 = Sound('Body Fall 2.ogg', s)
|
||||||
|
player_hit2 = Sound('Body Fall 18.ogg', s)
|
||||||
|
player_hit_wall1 = Sound('Wood Heavy 5.ogg', s)
|
||||||
|
pop1 = Sound('Pop sounds 10.ogg', s)
|
||||||
|
heal1 = Sound('Buff 3.ogg', s)
|
||||||
|
spawn1 = Sound('Buff 13.ogg', s)
|
||||||
|
alert1 = Sound('Alert sounds 3.ogg', s)
|
||||||
|
|
||||||
main = Main()
|
main = Main()
|
||||||
main:add(Arena'arena')
|
main:add(Arena'arena')
|
||||||
main:go_to'arena'
|
main:go_to'arena'
|
||||||
|
|
124
objects.lua
124
objects.lua
|
@ -1,8 +1,73 @@
|
||||||
|
WallKnife = Object:extend()
|
||||||
|
WallKnife:implement(GameObject)
|
||||||
|
WallKnife:implement(Physics)
|
||||||
|
function WallKnife:init(args)
|
||||||
|
self:init_game_object(args)
|
||||||
|
self:set_as_rectangle(10, 4, 'dynamic', 'projectile')
|
||||||
|
self.hfx:add('hit', 1)
|
||||||
|
self.hfx:use('hit', 0.25)
|
||||||
|
self.t:tween({0.8, 1.6}, self, {v = 0}, math.linear, function()
|
||||||
|
self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function() self.dead = true end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
self.vr = self.r
|
||||||
|
self.dvr = random:table{random:float(-8*math.pi, -4*math.pi), random:float(4*math.pi, 8*math.pi)}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallKnife:update(dt)
|
||||||
|
self:update_game_object(dt)
|
||||||
|
|
||||||
|
self:set_angle(self.r)
|
||||||
|
self:move_along_angle(self.v, self.r)
|
||||||
|
self.vr = self.vr + self.dvr*dt
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallKnife:draw()
|
||||||
|
if self.hidden then return end
|
||||||
|
graphics.push(self.x, self.y, self.vr, self.hfx.hit.x, self.hfx.hit.x)
|
||||||
|
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 2, 2, self.hfx.hit.f and fg[0] or self.color)
|
||||||
|
graphics.pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WallArrow = Object:extend()
|
||||||
|
WallArrow:implement(GameObject)
|
||||||
|
function WallArrow:init(args)
|
||||||
|
self:init_game_object(args)
|
||||||
|
self.shape = Rectangle(self.x, self.y, 10, 4)
|
||||||
|
self.hfx:add('hit', 1)
|
||||||
|
self.hfx:use('hit', 0.25)
|
||||||
|
self.t:after({0.8, 2}, function()
|
||||||
|
self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function() self.dead = true end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallArrow:update(dt)
|
||||||
|
self:update_game_object(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallArrow:draw()
|
||||||
|
if self.hidden then return end
|
||||||
|
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, 2, 2, self.hfx.hit.f and fg[0] or self.color)
|
||||||
|
graphics.pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Unit = Object:extend()
|
Unit = Object:extend()
|
||||||
function Unit:init_unit()
|
function Unit:init_unit()
|
||||||
self.hfx:add('hit', 1)
|
self.hfx:add('hit', 1)
|
||||||
self.hfx:add('shoot', 1)
|
self.hfx:add('shoot', 1)
|
||||||
self.hp_bar = HPBar{group = main.current.effects, parent = self}
|
self.hp_bar = HPBar{group = main.current.effects, parent = self}
|
||||||
|
self.heal_bar = HealBar{group = main.current.effects, parent = self}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +81,7 @@ function Unit:bounce(nx, ny)
|
||||||
self:set_velocity(-vx, vy)
|
self:set_velocity(-vx, vy)
|
||||||
self.r = math.pi - self.r
|
self.r = math.pi - self.r
|
||||||
end
|
end
|
||||||
|
return self.r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,32 +91,9 @@ function Unit:show_hp(n)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Unit:hit(damage)
|
function Unit:show_heal(n)
|
||||||
if self.dead then return end
|
self.heal_bar.hidden = false
|
||||||
|
self.t:after(n or 4, function() self.heal_bar.hidden = true end, 'heal_bar')
|
||||||
self.hfx:use('hit', 0.25, 200, 10)
|
|
||||||
self:show_hp()
|
|
||||||
|
|
||||||
local actual_damage = self:calculate_damage(damage)
|
|
||||||
self.hp = self.hp - actual_damage
|
|
||||||
if self:is(Player) then
|
|
||||||
if actual_damage >= 20 then
|
|
||||||
camera:shake(2, 1)
|
|
||||||
slow(0.25, 1)
|
|
||||||
else
|
|
||||||
camera:shake(2, 0.5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.hp <= 0 then
|
|
||||||
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
|
|
||||||
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color)
|
|
||||||
|
|
||||||
if table.any(main.current.enemies, function(v) return self:is(v) end) then
|
|
||||||
main.current:enemy_killed()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,6 +198,35 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HealBar = Object:extend()
|
||||||
|
HealBar:implement(GameObject)
|
||||||
|
HealBar:implement(Parent)
|
||||||
|
function HealBar:init(args)
|
||||||
|
self:init_game_object(args)
|
||||||
|
self.hidden = true
|
||||||
|
self.color = green[0]
|
||||||
|
self.color_transparent = Color(self.color.r, self.color.g, self.color.b, 0.2)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function HealBar:update(dt)
|
||||||
|
self:update_game_object(dt)
|
||||||
|
self:follow_parent_exclusively()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function HealBar:draw()
|
||||||
|
if self.hidden then return end
|
||||||
|
local p = self.parent
|
||||||
|
graphics.push(p.x, p.y, 0, p.hfx.hit.x, p.hfx.hit.x)
|
||||||
|
graphics.rectangle(p.x, p.y, 1.25*p.shape.w, 1.25*p.shape.h, 2, 2, self.color_transparent)
|
||||||
|
graphics.rectangle(p.x, p.y, 1.25*p.shape.w, 1.25*p.shape.h, 2, 2, self.color, 1)
|
||||||
|
graphics.pop()
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HPBar = Object:extend()
|
HPBar = Object:extend()
|
||||||
HPBar:implement(GameObject)
|
HPBar:implement(GameObject)
|
||||||
HPBar:implement(Parent)
|
HPBar:implement(Parent)
|
||||||
|
|
139
player.lua
139
player.lua
|
@ -30,7 +30,7 @@ function Player:init(args)
|
||||||
self.t:every(3, function()
|
self.t:every(3, function()
|
||||||
local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies)
|
local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies)
|
||||||
if enemies and #enemies > 0 then
|
if enemies and #enemies > 0 then
|
||||||
self:attack()
|
self:attack(96)
|
||||||
end
|
end
|
||||||
end, nil, nil, 'attack')
|
end, nil, nil, 'attack')
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ function Player:init(args)
|
||||||
self.visual_shape = 'rectangle'
|
self.visual_shape = 'rectangle'
|
||||||
self.classes = {'mage'}
|
self.classes = {'mage'}
|
||||||
|
|
||||||
self.attack_sensor = Circle(self.x, self.y, 64)
|
self.attack_sensor = Circle(self.x, self.y, 128)
|
||||||
self.t:every(2, function()
|
self.t:every(2, function()
|
||||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||||
if closest_enemy then
|
if closest_enemy then
|
||||||
|
@ -75,6 +75,25 @@ function Player:init(args)
|
||||||
self:shoot(self:angle_to_object(closest_enemy), {chain = 3})
|
self:shoot(self:angle_to_object(closest_enemy), {chain = 3})
|
||||||
end
|
end
|
||||||
end, nil, nil, 'shoot')
|
end, nil, nil, 'shoot')
|
||||||
|
|
||||||
|
elseif self.character == 'cleric' then
|
||||||
|
self.color = green[0]
|
||||||
|
self:set_as_rectangle(9, 9, 'dynamic', 'player')
|
||||||
|
self.visual_shape = 'rectangle'
|
||||||
|
self.classes = {'healer'}
|
||||||
|
|
||||||
|
self.last_heal_time = love.timer.getTime()
|
||||||
|
self.t:every(2, function()
|
||||||
|
local followers
|
||||||
|
local leader = (self.leader and self) or self.parent
|
||||||
|
if self.leader then followers = self.followers else followers = self.parent.followers end
|
||||||
|
if (table.any(followers, function(v) return v.hp <= 0.5*v.max_hp end) or (leader.hp <= 0.5*leader.max_hp)) and love.timer.getTime() - self.last_heal_time > 6 then
|
||||||
|
self.last_heal_time = love.timer.getTime()
|
||||||
|
if self.leader then self:heal(0.1*self.max_hp) else self.parent:heal(0.1*self.parent.max_hp) end
|
||||||
|
for _, f in ipairs(followers) do f:heal(0.1*f.max_hp) end
|
||||||
|
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
self:calculate_stats(true)
|
self:calculate_stats(true)
|
||||||
|
|
||||||
|
@ -93,9 +112,7 @@ function Player:update(dt)
|
||||||
self:update_game_object(dt)
|
self:update_game_object(dt)
|
||||||
self:calculate_stats()
|
self:calculate_stats()
|
||||||
|
|
||||||
if self.character == 'archer' then print(self.aspd_m) end
|
if self.attack_sensor then self.attack_sensor:move_to(self.x, self.y) end
|
||||||
|
|
||||||
self.attack_sensor:move_to(self.x, self.y)
|
|
||||||
self.t:set_every_multiplier('shoot', self.aspd_m)
|
self.t:set_every_multiplier('shoot', self.aspd_m)
|
||||||
self.t:set_every_multiplier('attack', self.aspd_m)
|
self.t:set_every_multiplier('attack', self.aspd_m)
|
||||||
|
|
||||||
|
@ -136,6 +153,7 @@ function Player:update(dt)
|
||||||
self:set_position(p.x, p.y)
|
self:set_position(p.x, p.y)
|
||||||
self.r = p.r
|
self.r = p.r
|
||||||
if not self.following then
|
if not self.following then
|
||||||
|
spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15}
|
||||||
for i = 1, random:int(3, 4) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end
|
for i = 1, random:int(3, 4) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end
|
||||||
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 10, color = fg[0]}:scale_down(0.3):change_color(0.5, self.color)
|
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 10, color = fg[0]}:scale_down(0.3):change_color(0.5, self.color)
|
||||||
self.following = true
|
self.following = true
|
||||||
|
@ -161,9 +179,22 @@ function Player:on_collision_enter(other, contact)
|
||||||
local x, y = contact:getPositions()
|
local x, y = contact:getPositions()
|
||||||
|
|
||||||
if other:is(Wall) then
|
if other:is(Wall) then
|
||||||
self.hfx:use('hit', 0.5, 200, 10, 0.1)
|
if self.leader then
|
||||||
camera:spring_shake(2, math.pi - self.r)
|
self.hfx:use('hit', 0.5, 200, 10, 0.1)
|
||||||
self:bounce(contact:getNormal())
|
camera:spring_shake(2, math.pi - self.r)
|
||||||
|
self:bounce(contact:getNormal())
|
||||||
|
local r = random:float(0.9, 1.1)
|
||||||
|
player_hit_wall1:play{pitch = r, volume = 0.1}
|
||||||
|
pop1:play{pitch = r, volume = 0.2}
|
||||||
|
|
||||||
|
for i, f in ipairs(self.followers) do
|
||||||
|
trigger:after(i*0.002*self.v, function()
|
||||||
|
f.hfx:use('hit', 0.5, 200, 10, 0.1)
|
||||||
|
player_hit_wall1:play{pitch = r + 0.025*i, volume = 0.1}
|
||||||
|
pop1:play{pitch = r + 0.05*i, volume = 0.2}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
elseif table.any(main.current.enemies, function(v) return other:is(v) end) then
|
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))
|
other:push(random:float(25, 35), self:angle_to_object(other))
|
||||||
|
@ -176,6 +207,36 @@ function Player:on_collision_enter(other, contact)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Player:hit(damage)
|
||||||
|
if self.dead then return end
|
||||||
|
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}
|
||||||
|
camera:shake(4, 0.5)
|
||||||
|
|
||||||
|
if self.hp <= 0 then
|
||||||
|
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
|
||||||
|
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12}:scale_down(0.3):change_color(0.5, self.color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function Player:heal(amount)
|
||||||
|
local hp = self.hp
|
||||||
|
|
||||||
|
self.hfx:use('hit', 0.25, 200, 10)
|
||||||
|
self:show_hp(1.5)
|
||||||
|
self:show_heal(1.5)
|
||||||
|
self.hp = self.hp + amount
|
||||||
|
if self.hp > self.max_hp then self.hp = self.max_hp end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function Player:add_follower(unit)
|
function Player:add_follower(unit)
|
||||||
table.insert(self.followers, unit)
|
table.insert(self.followers, unit)
|
||||||
unit.parent = self
|
unit.parent = self
|
||||||
|
@ -187,16 +248,30 @@ function Player:shoot(r, mods)
|
||||||
camera:spring_shake(2, r)
|
camera:spring_shake(2, r)
|
||||||
self.hfx:use('shoot', 0.25)
|
self.hfx:use('shoot', 0.25)
|
||||||
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}
|
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 = 250, r = r, color = self.color, dmg = self.dmg}
|
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 = 250, r = r, color = self.color, dmg = self.dmg, character = self.character}
|
||||||
Projectile(table.merge(t, mods or {}))
|
Projectile(table.merge(t, mods or {}))
|
||||||
|
|
||||||
|
if self.character == 'vagrant' then
|
||||||
|
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.3}
|
||||||
|
elseif self.character == 'archer' then
|
||||||
|
archer1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||||
|
elseif self.character == 'wizard' then
|
||||||
|
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
|
||||||
|
elseif self.character == 'scout' then
|
||||||
|
_G[random:table{'scout1', 'scout2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function Player:attack(mods)
|
function Player:attack(area, mods)
|
||||||
camera:shake(2, 0.5)
|
camera:shake(2, 0.5)
|
||||||
self.hfx:use('shoot', 0.25)
|
self.hfx:use('shoot', 0.25)
|
||||||
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.area_size_m*64, color = self.color, dmg = self.area_dmg_m*self.dmg}
|
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.area_size_m*(area or 64), color = self.color, dmg = self.area_dmg_m*self.dmg, character = self.character}
|
||||||
Area(table.merge(t, mods or {}))
|
Area(table.merge(t, mods or {}))
|
||||||
|
|
||||||
|
if self.character == 'swordsman' then
|
||||||
|
_G[random:table{'swordsman1', 'swordsman2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.75}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,8 +313,8 @@ function Projectile:die(x, y, r, n)
|
||||||
HitCircle{group = main.current.effects, x = x, y = y}:scale_down()
|
HitCircle{group = main.current.effects, x = x, y = y}:scale_down()
|
||||||
self.dead = true
|
self.dead = true
|
||||||
|
|
||||||
if self.wizard then
|
if self.character == 'wizard' then
|
||||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.wizard.area_size_m*32, color = self.color, dmg = self.wizard.area_dmg_m*self.dmg}
|
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.wizard.area_size_m*32, color = self.color, dmg = self.wizard.area_dmg_m*self.dmg, character = self.character}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -254,7 +329,24 @@ function Projectile:on_collision_enter(other, contact)
|
||||||
else r = 0 end
|
else r = 0 end
|
||||||
|
|
||||||
if other:is(Wall) then
|
if other:is(Wall) then
|
||||||
self:die(x, y, r, random:int(2, 3))
|
if self.character == 'archer' then
|
||||||
|
self:die(x, y, r, 0)
|
||||||
|
_G[random:table{'arrow_hit_wall1', 'arrow_hit_wall2'}]:play{pitch = random:float(0.9, 1.1), volume = 0.2}
|
||||||
|
WallArrow{group = main.current.main, x = x, y = y, r = self.r, color = self.color}
|
||||||
|
elseif self.character == 'scout' then
|
||||||
|
self:die(x, y, r, 0)
|
||||||
|
knife_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2}
|
||||||
|
local r = Unit.bounce(self, nx, ny)
|
||||||
|
trigger:after(0.01, function()
|
||||||
|
WallKnife{group = main.current.main, x = x, y = y, r = r, v = self.v*0.1, color = self.color}
|
||||||
|
end)
|
||||||
|
elseif self.character == 'wizard' then
|
||||||
|
self:die(x, y, r, random:int(2, 3))
|
||||||
|
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
|
||||||
|
else
|
||||||
|
self:die(x, y, r, random:int(2, 3))
|
||||||
|
proj_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -274,11 +366,19 @@ function Projectile:on_trigger_enter(other, contact)
|
||||||
if object then
|
if object then
|
||||||
self.r = self:angle_to_object(object)
|
self.r = self:angle_to_object(object)
|
||||||
self.v = self.v*1.25
|
self.v = self.v*1.25
|
||||||
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = fg[0], duration = 0.1}
|
|
||||||
HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color}
|
|
||||||
HitParticle{group = main.current.effects, x = self.x, y = self.y, color = other.color}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = fg[0], duration = 0.1}
|
||||||
|
HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color}
|
||||||
|
HitParticle{group = main.current.effects, x = self.x, y = self.y, color = other.color}
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.character == 'archer' or self.character == 'scout' then
|
||||||
|
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||||
|
elseif self.character == 'wizard' then
|
||||||
|
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
|
||||||
|
else
|
||||||
|
hit3:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||||
end
|
end
|
||||||
other:hit(self.dmg)
|
other:hit(self.dmg)
|
||||||
end
|
end
|
||||||
|
@ -298,6 +398,11 @@ function Area:init(args)
|
||||||
HitCircle{group = main.current.effects, x = enemy.x, y = enemy.y, rs = 6, color = fg[0], duration = 0.1}
|
HitCircle{group = main.current.effects, x = enemy.x, y = enemy.y, rs = 6, color = fg[0], duration = 0.1}
|
||||||
for i = 1, 2 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = self.color} end
|
for i = 1, 2 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = self.color} end
|
||||||
for i = 1, 2 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = enemy.color} end
|
for i = 1, 2 do HitParticle{group = main.current.effects, x = enemy.x, y = enemy.y, color = enemy.color} end
|
||||||
|
if self.character == 'wizard' then
|
||||||
|
magic_hit1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||||
|
elseif self.character == 'swordsman' then
|
||||||
|
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
self.color = fg[0]
|
self.color = fg[0]
|
||||||
|
|
22
shared.lua
22
shared.lua
|
@ -7,7 +7,6 @@ function shared_init()
|
||||||
fg_alt = ColorRamp(Color'#b0a89f', 0.025),
|
fg_alt = ColorRamp(Color'#b0a89f', 0.025),
|
||||||
yellow = ColorRamp(Color'#facf00', 0.025),
|
yellow = ColorRamp(Color'#facf00', 0.025),
|
||||||
orange = ColorRamp(Color'#f07021', 0.025),
|
orange = ColorRamp(Color'#f07021', 0.025),
|
||||||
yellow_orange = ColorRamp(Color(245, 160, 16), 0.025),
|
|
||||||
blue = ColorRamp(Color'#019bd6', 0.025),
|
blue = ColorRamp(Color'#019bd6', 0.025),
|
||||||
green = ColorRamp(Color'#8bbf40', 0.025),
|
green = ColorRamp(Color'#8bbf40', 0.025),
|
||||||
red = ColorRamp(Color'#e91d39', 0.025),
|
red = ColorRamp(Color'#e91d39', 0.025),
|
||||||
|
@ -663,3 +662,24 @@ end
|
||||||
function Wall:draw()
|
function Wall:draw()
|
||||||
self.shape:draw(self.color)
|
self.shape:draw(self.color)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WallCover = Object:extend()
|
||||||
|
WallCover:implement(GameObject)
|
||||||
|
function WallCover:init(args)
|
||||||
|
self:init_game_object(args)
|
||||||
|
self.shape = Polygon(self.vertices)
|
||||||
|
self.color = self.color or fg[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallCover:update(dt)
|
||||||
|
self:update_game_object(dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function WallCover:draw()
|
||||||
|
self.shape:draw(self.color)
|
||||||
|
end
|
||||||
|
|
7
todo
7
todo
|
@ -1,9 +1,10 @@
|
||||||
Vagrant: shoots an ethereal projectile at any nearby enemy that deals physical and magical damage, medium range
|
Vagrant: shoots an ethereal projectile at any nearby enemy that deals physical and magical damage, medium range
|
||||||
Scout: throws a knife that chains 3 times at any nearby enemy, small range
|
Scout: throws a knife that chains 3 times at any nearby enemy, small range
|
||||||
Cleric: heals every unit when any one drops below 50% HP
|
Cleric: heals every unit when any one drops below 50% HP
|
||||||
Swordsman: deals physical damage in an area around the unit, small range
|
Swordsman: deals physical damage in a medium area around the unit, small range
|
||||||
Archer: shoots an arrow that pierces at any nearby enemy, very long range
|
Archer: shoots an arrow that pierces at any nearby enemy, very long range
|
||||||
Wizard: shoots a projectile at any nearby enemy and deals AoE magical damage on contact, small range, AoE has very small range
|
Wizard: shoots a projectile at any nearby enemy and deals AoE magical damage on contact, long range, AoE has very small range
|
||||||
|
|
||||||
Engineer: drops a turret that shoots secondary projectiles very fast, medium range
|
Engineer: drops a turret that shoots secondary projectiles very fast, medium range
|
||||||
|
|
||||||
Ranger: yellow, buff attack speed
|
Ranger: yellow, buff attack speed
|
||||||
|
@ -27,4 +28,4 @@ Defense -> if defense >= 0 then dmg_m = 100/(100+defense) else dmg_m = 2-100/(10
|
||||||
* Stats: attack speed, damage, area
|
* Stats: attack speed, damage, area
|
||||||
* One or a few of the characters
|
* One or a few of the characters
|
||||||
* Port over enemy spawn logic from SHOOTRX
|
* Port over enemy spawn logic from SHOOTRX
|
||||||
Sounds
|
* Sounds
|
||||||
|
|
Loading…
Reference in New Issue