master
a327ex 2021-02-21 02:47:59 -03:00
parent 8f8910fec9
commit 9d3f777342
6 changed files with 369 additions and 29 deletions

256
arena.lua
View File

@ -7,7 +7,11 @@ function Arena:init(name)
end
function Arena:on_enter(from)
function Arena:on_enter(from, level)
self.hfx:add('condition1', 1)
self.hfx:add('condition2', 1)
self.level = level or 1
self.main = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
self.effects = Group()
self.ui = Group():no_camera()
@ -34,13 +38,15 @@ function Arena:on_enter(from)
{x = gw/2, y = gh/2, r = random:float(0, 2*math.pi)}
}
self.spawn_offsets = {{x = -12, y = -12}, {x = 12, y = -12}, {x = 12, y = 12}, {x = -12, y = 12}, {x = 0, y = 0}}
self.last_spawn_enemy_time = love.timer.getTime()
Wall{group = self.main, vertices = math.to_rectangle_vertices(-40, -40, self.x1, 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, self.y2, self.x2, gh + 40), color = bg[-1]}
self.player = Player{group = self.main, x = gw/2, y = gh/2, leader = true, character = 'vagrant'}
self.player:add_follower(Player{group = self.main, character = 'swordsman'})
self.player = Player{group = self.main, x = gw/2, y = gh/2, leader = true, character = 'scout'}
--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 = 'vagrant'})
@ -48,6 +54,98 @@ function Arena:on_enter(from)
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
self.player:add_follower(Player{group = self.main, character = 'vagrant'})
]]--
self.win_condition = random:table{'time', 'enemy_kill', 'wave'}
if self.win_condition == 'wave' then
self.level_to_max_waves = {
2, 2, random:int(2, 3),
3, 3, 3, random:int(3, 4),
4, 4, 4, 4, random:int(4, 5),
5, 5, 5, 5, 5, random:int(5, 6),
6, 7, 8, 9, 9, 10
}
self.max_waves = self.level_to_max_waves[self.level]
self.start_time = 3
self.t:after(1, function()
self.t:every(1, function()
self.start_time = self.start_time - 1
self.hfx:use('condition1', 0.25, 200, 10)
end, 3, function()
camera:shake(4, 0.25)
SpawnEffect{group = self.effects, x = gw/2, y = gh/2 - 48}
self.wave = 0
self.t:every(function() return #self.main:get_objects_by_classes(self.enemies) <= 0 end, function()
self.wave = self.wave + 1
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}}
self:spawn_n_enemies(spawn_points[spawn_type], nil, 8 + (self.wave-1)*2)
end)
end, self.max_waves, function() self.can_quit = true end)
end)
end)
elseif self.win_condition == 'enemy_kill' then
self.level_to_enemies_to_kill = {
16, 16, random:int(16, 18),
18, 18, 18, random:int(18, 20),
20, 20, 20, 20, random:int(20, 22),
22, 22, 22, 22, 22, random:int(22, 24),
24, 26, 28, 30, 30, 32
}
self.enemies_killed = 0
self.enemies_to_kill = self.level_to_enemies_to_kill[self.level]
self.enemy_spawn_delay = 8
self.start_time = 3
self.t:after(1, function()
self.t:every(1, function()
self.start_time = self.start_time - 1
self.hfx:use('condition1', 0.25, 200, 10)
end, 3, function()
camera:shake(4, 0.25)
SpawnEffect{group = self.effects, x = gw/2, y = gh/2 - 48}
self:spawn_distributed_enemies()
self.t:every(2, function()
if love.timer.getTime() - self.last_spawn_enemy_time >= self.enemy_spawn_delay then
self:spawn_distributed_enemies()
end
end, nil, nil, 'spawn_enemies')
end)
end)
elseif self.win_condition == 'time' then
self.level_to_time_left = {
20, 20, random:int(20, 25),
25, 25, 25, random:int(25, 30),
30, 30, 30, 30, random:int(30, 35),
35, 35, 35, 35, 35, random:int(35, 40),
40, 45, 50, 55, 55, 60
}
self.time_left = self.level_to_time_left[self.level]
self.start_time = 3
self.t:after(1, function()
self.t:every(1, function()
self.start_time = self.start_time - 1
self.hfx:use('condition1', 0.25, 200, 10)
end, 3, function()
camera:shake(4, 0.25)
SpawnEffect{group = self.effects, x = gw/2, y = gh/2 - 48}
self.t:every(1, function()
self.time_left = self.time_left - 1
self.hfx:use('condition1', 0.25, 200, 10)
self.hfx:pull('condition2', 0.0625)
end, self.time_left, function() self.can_quit = true end)
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 then
self:spawn_distributed_enemies()
end
end, self.time_left/2)
end)
end)
end
end
@ -57,8 +155,24 @@ function Arena:update(dt)
self.effects:update(dt*slow_amount)
self.ui:update(dt*slow_amount)
if input.k.pressed then
self:spawn_enemy(4)
if self.win_condition == 'enemy_kill' then
if self.can_quit then
self.t:after(2, function()
-- PostArenaScreen{group = self.ui, x = gw/2, y = gh/2}
end)
end
else
if self.can_quit and #self.main:get_objects_by_classes(self.enemies) <= 0 then
self.can_quit = false
self.t:after(2, function()
if #self.main:get_objects_by_classes(self.enemies) > 0 then
self.can_quit = true
else
-- PostArenaScreen{group = self.ui, x = gw/2, y = gh/2}
end
end)
end
end
end
@ -67,16 +181,132 @@ function Arena:draw()
self.main:draw()
self.effects:draw()
self.ui:draw()
camera:attach()
if self.start_time and self.start_time > 0 then
graphics.push(gw/2, gh/2 - 48, 0, self.hfx.condition1.x, self.hfx.condition1.x)
graphics.print_centered(tostring(self.start_time), fat_font, gw/2, gh/2 - 48, 0, 1, 1, nil, nil, self.hfx.condition1.f and fg[0] or red[0])
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()
end
end
end
camera:detach()
end
function Arena:spawn_enemy(n)
n = n or 1
local p = table.random(self.spawn_points)
for i = 1, n do
self.t:after((i-1)*0.1, function()
local o = table.random(self.spawn_offsets)
SpawnEffect{group = self.effects, x = p.x + o.x, y = p.y + o.y, action = function(x, y) Seeker{group = self.main, x = x, y = y, character = 'seeker'} end}
end)
function Arena:enemy_killed()
if self.win_condition == 'enemy_kill' then
self.enemies_killed = self.enemies_killed + 1
self.hfx:use('condition1', 0.25, 200, 10)
self.hfx:pull('condition2', 0.0625)
self.enemy_spawn_delay = self.enemy_spawn_delay*0.95
if self.enemies_killed >= self.enemies_to_kill then
self.can_quit = true
self.t:cancel'spawn_enemies'
end
end
end
function Arena:spawn_distributed_enemies()
local t = {'4', '4+4', '4+4+4', '2x4', '3x4', '4x2'}
local spawn_type = t[random:weighted_pick(40, 20, 5, 15, 5, 15)]
local spawn_points = table.copy(self.spawn_points)
if spawn_type == '4' then
self:spawn_n_enemies(random:table_remove(spawn_points))
elseif spawn_type == '4+4' then
local p = random:table_remove(spawn_points)
self:spawn_n_enemies(p)
self.t:after(2, function() self:spawn_n_enemies(p) end)
elseif spawn_type == '4+4+4' then
local p = random:table_remove(spawn_points)
self:spawn_n_enemies(p)
self.t:after(1, function()
self:spawn_n_enemies(p)
self.t:after(1, function()
self:spawn_n_enemies(p)
end)
end)
elseif spawn_type == '2x4' then
self:spawn_n_enemies(random:table_remove(spawn_points), 1)
self:spawn_n_enemies(random:table_remove(spawn_points), 2)
elseif spawn_type == '3x4' then
self:spawn_n_enemies(random:table_remove(spawn_points), 1)
self:spawn_n_enemies(random:table_remove(spawn_points), 2)
self:spawn_n_enemies(random:table_remove(spawn_points), 3)
elseif spawn_type == '4x2' then
self:spawn_n_enemies(random:table_remove(spawn_points), 1, 2)
self:spawn_n_enemies(random:table_remove(spawn_points), 2, 2)
self:spawn_n_enemies(random:table_remove(spawn_points), 3, 2)
self:spawn_n_enemies(random:table_remove(spawn_points), 4, 2)
end
end
function Arena:spawn_n_enemies(p, j, n)
j = j or 1
n = n or 4
self.last_spawn_enemy_time = love.timer.getTime()
self.t:every(0.1, function()
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)
if self.level == 1 then
Seeker{group = self.main, x = x, y = y, character = 'seeker'}
elseif self.level == 2 then
Seeker{group = self.main, x = x, y = y, character = 'seeker'}
elseif self.level == 3 then
elseif self.level == 4 then
elseif self.level == 5 then
elseif self.level == 6 then
elseif self.level == 7 then
elseif self.level == 8 then
elseif self.level == 9 then
elseif self.level == 10 then
elseif self.level == 11 then
elseif self.level == 12 then
elseif self.level == 13 then
elseif self.level == 14 then
elseif self.level == 15 then
elseif self.level == 16 then
elseif self.level == 17 then
elseif self.level == 18 then
elseif self.level == 19 then
elseif self.level == 20 then
elseif self.level == 21 then
elseif self.level == 22 then
elseif self.level == 23 then
elseif self.level == 24 then
elseif self.level == 25 then
end
end}
end, n, nil, 'spawn_enemies_' .. j)
end

View File

@ -66,3 +66,27 @@ And the stats are:
HP, damage and defense are flat stats, whereas area damage, area of effect and attack speed are multipliers. This is because each character/attack has its own attack speed/area and trying to generalize that
too much wouldn't work well. For tomorrow I'll just try to finish the rest of the todo, which is add more characters, port enemy spawning logic from SHOOTRX and add sounds.
# Day 4 - 20/02/21
Ported over enemy spawning logic and added all characters. The characters currently are:
* 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
* Cleric: heals every unit when any one drops below 50% HP
* Swordsman: deals physical damage in an area around the unit, small 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
The classes are:
* Ranger: yellow, buff attack speed
* Warrior: orange, buff attack damage
* Healer: green, buff healing effectiveness
* Mage: blue, debuff enemy defense
* Void: purple, buff area damage and size
* Builder: orange, buffs construct damage, attack speed and duration
* Rogue: red, chance to crit dealing 4x damage
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.

View File

@ -46,6 +46,10 @@ function Unit:hit(damage)
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
@ -93,6 +97,7 @@ function Unit:calculate_stats(first_run)
elseif class == 'mage' then self.class_hp_m = self.class_hp_m*0.6
elseif class == 'healer' then self.class_hp_m = self.class_hp_m*1.1
elseif class == 'void' then self.class_hp_m = self.class_hp_m*0.9
elseif class == 'rogue' then self.class_hp_m = self.class_hp_m*0.8
elseif class == 'seeker' then self.class_hp_m = self.class_hp_m*0.5 end
end
self.max_hp = (self.base_hp + self.class_hp_a + self.buff_hp_a)*self.class_hp_m*self.buff_hp_m
@ -101,27 +106,31 @@ function Unit:calculate_stats(first_run)
for _, class in ipairs(self.classes) do
if class == 'warrior' then self.class_dmg_m = self.class_dmg_m*1.1
elseif class == 'ranger' then self.class_dmg_m = self.class_dmg_m*1.2
elseif class == 'rogue' then self.class_dmg_m = self.class_dmg_m*1.2
elseif class == 'mage' then self.class_dmg_m = self.class_dmg_m*1.4 end
end
self.dmg = (self.base_dmg + self.class_dmg_a + self.buff_dmg_a)*self.class_dmg_m*self.buff_dmg_m
for _, class in ipairs(self.classes) do
if class == 'warrior' then self.class_aspd_m = self.class_aspd_m*0.9
elseif class == 'ranger' then self.class_aspd_m = self.class_aspd_m*1.4
elseif class == 'ranger' then self.class_aspd_m = self.class_aspd_m*1.5
elseif class == 'healer' then self.class_aspd_m = self.class_aspd_m*0.5
elseif class == 'rogue' then self.class_aspd_m = self.class_aspd_m*1.1
elseif class == 'void' then self.class_aspd_m = self.class_aspd_m*0.75 end
end
self.aspd_m = 1/(self.base_aspd_m*self.class_aspd_m*self.buff_aspd_m)
for _, class in ipairs(self.classes) do
if class == 'mage' then self.class_area_dmg_m = self.class_area_dmg_m*1.25
elseif class == 'void' then self.class_area_dmg_m = self.class_area_m*1.5 end
elseif class == 'void' then self.class_area_dmg_m = self.class_area_dmg_m*1.5
elseif class == 'rogue' then self.class_area_dmg_m = self.class_area_dmg_m*0.6 end
end
self.area_dmg_m = self.base_area_dmg_m*self.class_area_dmg_m*self.buff_area_dmg_m
for _, class in ipairs(self.classes) do
if class == 'mage' then self.class_area_size_m = self.class_area_size_m*1.2
elseif class == 'void' then self.class_area_size_m = self.class_area_m*1.3 end
elseif class == 'void' then self.class_area_size_m = self.class_area_size_m*1.3
elseif class == 'rogue' then self.class_area_size_m = self.class_area_size_m*0.6 end
end
self.area_size_m = self.base_area_size_m*self.class_area_size_m*self.buff_area_size_m
@ -129,6 +138,7 @@ function Unit:calculate_stats(first_run)
if class == 'warrior' then self.class_def_m = self.class_def_m*1.25
elseif class == 'ranger' then self.class_def_m = self.class_def_m*1.1
elseif class == 'mage' then self.class_def_m = self.class_def_m*0.8
elseif class == 'rogue' then self.class_def_m = self.class_def_m*0.8
elseif class == 'healer' then self.class_def_m = self.class_def_m*1.2 end
end
self.def = (self.base_def + self.class_def_a + self.buff_def_a)*self.class_def_m*self.buff_def_m
@ -136,6 +146,7 @@ function Unit:calculate_stats(first_run)
for _, class in ipairs(self.classes) do
if class == 'warrior' then self.class_mvspd_m = self.class_mvspd_m*0.9
elseif class == 'ranger' then self.class_mvspd_m = self.class_mvspd_m*1.2
elseif class == 'rogue' then self.class_mvspd_m = self.class_mvspd_m*1.4
elseif class == 'seeker' then self.class_mvspd_m = self.class_mvspd_m*0.3 end
end
self.v = (self.base_mvspd + self.class_mvspd_a + self.buff_mvspd_a)*self.class_mvspd_m*self.buff_mvspd_m

View File

@ -7,7 +7,7 @@ function Player:init(args)
self:init_unit()
if self.character == 'vagrant' then
self.color = blue[0]
self.color = fg[0]
self:set_as_rectangle(9, 9, 'dynamic', 'player')
self.visual_shape = 'rectangle'
self.classes = {'ranger', 'warrior', 'mage'}
@ -33,6 +33,48 @@ function Player:init(args)
self:attack()
end
end, nil, nil, 'attack')
elseif self.character == 'wizard' then
self.color = blue[0]
self:set_as_rectangle(9, 9, 'dynamic', 'player')
self.visual_shape = 'rectangle'
self.classes = {'mage'}
self.attack_sensor = Circle(self.x, self.y, 64)
self.t:every(2, 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), {wizard = self})
end
end, nil, nil, 'shoot')
elseif self.character == 'archer' then
self.color = yellow[0]
self:set_as_rectangle(9, 9, 'dynamic', 'player')
self.visual_shape = 'rectangle'
self.classes = {'ranger'}
self.attack_sensor = Circle(self.x, self.y, 160)
self.t:every(2, 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), {pierce = 1000})
end
end, nil, nil, 'shoot')
elseif self.character == 'scout' then
self.color = red[0]
self:set_as_rectangle(9, 9, 'dynamic', 'player')
self.visual_shape = 'rectangle'
self.classes = {'rogue'}
self.attack_sensor = Circle(self.x, self.y, 64)
self.t:every(2, 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), {chain = 3})
end
end, nil, nil, 'shoot')
end
self:calculate_stats(true)
@ -51,6 +93,8 @@ function Player:update(dt)
self:update_game_object(dt)
self:calculate_stats()
if self.character == 'archer' then print(self.aspd_m) end
self.attack_sensor:move_to(self.x, self.y)
self.t:set_every_multiplier('shoot', self.aspd_m)
self.t:set_every_multiplier('attack', self.aspd_m)
@ -109,6 +153,7 @@ function Player:draw()
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, (self.hfx.hit.f or self.hfx.shoot.f) and fg[0] or self.color)
end
graphics.pop()
-- self.attack_sensor:draw(self.color, 2)
end
@ -138,18 +183,20 @@ function Player:add_follower(unit)
end
function Player:shoot(r)
function Player:shoot(r, mods)
camera:spring_shake(2, r)
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}
Projectile{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}
Projectile(table.merge(t, mods or {}))
end
function Player:attack()
function Player:attack(mods)
camera:shake(2, 0.5)
self.hfx:use('shoot', 0.25)
Area{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*64, color = self.color, dmg = self.area_dmg_m*self.dmg}
Area(table.merge(t, mods or {}))
end
@ -161,6 +208,9 @@ Projectile:implement(Physics)
function Projectile:init(args)
self:init_game_object(args)
self:set_as_rectangle(10, 4, 'dynamic', 'projectile')
self.pierce = args.pierce or 0
self.chain = args.chain or 0
self.chain_enemies_hit = {}
end
@ -187,6 +237,10 @@ function Projectile:die(x, y, r, n)
for i = 1, n do HitParticle{group = main.current.effects, x = x, y = y, r = random:float(0, 2*math.pi), color = self.color} end
HitCircle{group = main.current.effects, x = x, y = y}:scale_down()
self.dead = true
if self.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}
end
end
@ -207,7 +261,25 @@ end
function Projectile:on_trigger_enter(other, contact)
if table.any(main.current.enemies, function(v) return other:is(v) end) then
self:die(self.x, self.y, nil, random:int(2, 3))
if self.pierce <= 0 and self.chain <= 0 then
self:die(self.x, self.y, nil, random:int(2, 3))
else
if self.pierce > 0 then
self.pierce = self.pierce - 1
end
if self.chain > 0 then
self.chain = self.chain - 1
table.insert(self.chain_enemies_hit, other)
local object = self:get_random_object_in_shape(Circle(self.x, self.y, 160), main.current.enemies, self.chain_enemies_hit)
if object then
self.r = self:angle_to_object(object)
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
other:hit(self.dmg)
end
end

View File

@ -7,6 +7,7 @@ function shared_init()
fg_alt = ColorRamp(Color'#b0a89f', 0.025),
yellow = ColorRamp(Color'#facf00', 0.025),
orange = ColorRamp(Color'#f07021', 0.025),
yellow_orange = ColorRamp(Color(245, 160, 16), 0.025),
blue = ColorRamp(Color'#019bd6', 0.025),
green = ColorRamp(Color'#8bbf40', 0.025),
red = ColorRamp(Color'#e91d39', 0.025),

16
todo
View File

@ -1,16 +1,18 @@
Vagrant: shoots an ethereal projectile at any nearby enemy that deals physical and magical damage, medium range
Scout: throws a knife at any nearby enemy that deals physical damage and chains, 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
Swordsman: deals physical damage in an area around the unit, small range
Archer: shoots an arrow at any nearby enemy in front of the unit, very long range
Wizard: shoots a projectile at any nearby enemy and deals AoE magical damage on contact, small range
Engineer: drops a turret that shoots secondary projectiles very fast, 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
Engineer: drops a turret that shoots secondary projectiles very fast, medium range
Ranger: yellow, buff attack speed
Warrior: orange, buff attack damage
Healer: green, buff healing effectiveness
Mage: blue, debuff enemy defense
Void: purple, buff area damage and size
Builder: orange, buffs construct damage, attack speed and duration
Rogue: red, chance to crit dealing 4x damage
HP
Damage
@ -22,7 +24,7 @@ Defense -> if defense >= 0 then dmg_m = 100/(100+defense) else dmg_m = 2-100/(10
* HP bar should be drawn on top of all player units
* Projectiles
* Areas
* Stats: attack speed, damage
One or a few of the characters
Port over enemy spawn logic from SHOOTRX
* Stats: attack speed, damage, area
* One or a few of the characters
* Port over enemy spawn logic from SHOOTRX
Sounds