Day 52
parent
2e51b7b9fb
commit
1b7c4da414
59
arena.lua
59
arena.lua
|
@ -235,51 +235,20 @@ function Arena:on_enter(from, level, units)
|
|||
table.insert(units, self.player)
|
||||
for _, f in ipairs(self.player.followers) do table.insert(units, f) end
|
||||
|
||||
local rangers = 0
|
||||
local warriors = 0
|
||||
local healers = 0
|
||||
local mages = 0
|
||||
local nukers = 0
|
||||
local conjurers = 0
|
||||
local rogues = 0
|
||||
local enchanters = 0
|
||||
local psys = 0
|
||||
for _, unit in ipairs(units) do
|
||||
for _, unit_class in ipairs(unit.classes) do
|
||||
if unit_class == 'ranger' then rangers = rangers + 1 end
|
||||
if unit_class == 'warrior' then warriors = warriors + 1 end
|
||||
if unit_class == 'healer' then healers = healers + 1 end
|
||||
if unit_class == 'mage' then mages = mages + 1 end
|
||||
if unit_class == 'nuker' then nukers = nukers + 1 end
|
||||
if unit_class == 'conjurer' then conjurers = conjurers + 1 end
|
||||
if unit_class == 'rogue' then rogues = rogues + 1 end
|
||||
if unit_class == 'enchanter' then enchanters = enchanters + 1 end
|
||||
if unit_class == 'psy' then psys = psys + 1 end
|
||||
end
|
||||
end
|
||||
|
||||
self.ranger_level = 0
|
||||
if rangers >= 2 then self.ranger_level = 1 end
|
||||
if rangers >= 4 then self.ranger_level = 2 end
|
||||
self.warrior_level = 0
|
||||
if warriors >= 2 then self.warrior_level = 1 end
|
||||
if warriors >= 4 then self.warrior_level = 2 end
|
||||
self.healer_level = 0
|
||||
if healers >= 3 then self.healer_level = 1 end
|
||||
self.mage_level = 0
|
||||
if mages >= 2 then self.mage_level = 1 end
|
||||
if mages >= 4 then self.mage_level = 2 end
|
||||
self.nuke_level = 0
|
||||
if nukers >= 2 then self.nuke_level = 1 end
|
||||
if nukers >= 4 then self.nuke_level = 2 end
|
||||
self.conjurer_level = 0
|
||||
if conjurers >= 2 then self.conjurer_level = 1 end
|
||||
self.rogue_level = 0
|
||||
if rogues >= 2 then self.rogue_level = 1 end
|
||||
if rogues >= 4 then self.rogue_level = 2 end
|
||||
self.enchanter_level = 0
|
||||
if enchanters >= 3 then self.enchanter_level = 1 end
|
||||
self.psy_level = psys
|
||||
local class_levels = get_class_levels(get_number_of_units_per_class(units))
|
||||
self.ranger_level = class_levels.ranger
|
||||
self.warrior_level = class_levels.warrior
|
||||
self.mage_level = class_levels.mage
|
||||
self.rogue_level = class_levels.rogue
|
||||
self.nuker_level = class_levels.nuker
|
||||
self.trapper_level = class_levels.trapper
|
||||
self.forcer_level = class_levels.forcer
|
||||
self.swarmer_level = class_levels.swarmer
|
||||
self.voider_level = class_levels.voider
|
||||
self.enchanter_level = class_levels.enchanter
|
||||
self.healer_level = class_levels.healer
|
||||
self.psyker_level = class_levels.psyker
|
||||
self.conjurer_level = class_levels.conjurer
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ function BuyScreen:on_enter(from, level, units)
|
|||
|
||||
self.shop_text = Text({{text = '[wavy_mid, fg]shop [fg]- gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.party_text = Text({{text = '[wavy_mid, fg]party', font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.sets_text = Text({{text = '[wavy_mid, fg]sets', font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.sets_text = Text({{text = '[wavy_mid, fg]classes', font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.items_text = Text({{text = '[wavy_mid, fg]items', font = pixul_font, alignment = 'center'}}, global_text_tags)
|
||||
self.under_text = Text2{group = self.main, x = 140, y = gh - 55, r = -math.pi/48, lines = {
|
||||
{text = '[light_bg]under', font = fat_font, alignment = 'center'},
|
||||
|
@ -64,7 +64,7 @@ end
|
|||
|
||||
function BuyScreen:update(dt)
|
||||
self:update_game_object(dt*slow_amount)
|
||||
cascade_instance.pitch = 1
|
||||
-- cascade_instance.pitch = 1
|
||||
|
||||
self.main:update(dt*slow_amount)
|
||||
self.effects:update(dt*slow_amount)
|
||||
|
@ -442,7 +442,11 @@ function CharacterPart:on_mouse_enter()
|
|||
self.info_text:activate({
|
||||
{text = '[' .. character_color_strings[self.character] .. ']' .. self.character:capitalize() .. '[fg] - [yellow]Lv.' .. self.level .. '[fg] - sells for [yellow]' .. self:get_sale_price(),
|
||||
font = pixul_font, alignment = 'center', height_multiplier = 1.25},
|
||||
{text = character_descriptions[self.character](self.level), font = pixul_font, alignment = 'center'},
|
||||
{text = '[fg]Classes: ' .. character_class_strings[self.character], font = pixul_font, alignment = 'center', height_multiplier = 1.25},
|
||||
{text = character_descriptions[self.character](self.level), font = pixul_font, alignment = 'center', height_multiplier = 2},
|
||||
{text = '[' .. (self.level == 3 and 'yellow' or 'light_bg') .. ']Lv.3 [' .. (self.level == 3 and 'fg' or 'light_bg') .. ']Effect - ' ..
|
||||
(self.level == 3 and character_effect_names[self.character] or character_effect_names_gray[self.character]), font = pixul_font, alignment = 'center', height_multiplier = 1.25},
|
||||
{text = character_effect_descriptions[self.character](), font = pixul_font, alignment = 'center'},
|
||||
}, nil, nil, nil, nil, 16, 4, nil, 2)
|
||||
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
|
||||
end
|
||||
|
@ -613,7 +617,9 @@ function CharacterIcon:on_mouse_enter()
|
|||
self.info_text = InfoText{group = main.current.ui}
|
||||
self.info_text:activate({
|
||||
{text = '[' .. character_color_strings[self.character] .. ']' .. self.character:capitalize() .. '[fg] - cost: [yellow]' .. self.parent.cost, font = pixul_font, alignment = 'center', height_multiplier = 1.25},
|
||||
{text = character_descriptions[self.character](get_character_stat(self.character, 1, 'dmg')), font = pixul_font, alignment = 'center'},
|
||||
{text = '[fg]Classes: ' .. character_class_strings[self.character], font = pixul_font, alignment = 'center', height_multiplier = 1.25},
|
||||
{text = character_descriptions[self.character](1), font = pixul_font, alignment = 'center'},
|
||||
-- {text = character_stats[self.character](1), font = pixul_font, alignment = 'center'},
|
||||
}, nil, nil, nil, nil, 16, 4, nil, 2)
|
||||
self.info_text.x, self.info_text.y = gw/2, gh/2 + 10
|
||||
end
|
||||
|
@ -685,9 +691,13 @@ function ClassIcon:draw()
|
|||
end
|
||||
end
|
||||
elseif i == 3 then
|
||||
graphics.line(self.x - 4, self.y + 22, self.x - 4, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 2)
|
||||
graphics.line(self.x, self.y + 22, self.x, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 2)
|
||||
graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 3) and class_colors[self.class] or bg[10], 2)
|
||||
graphics.line(self.x - 3, self.y + 19, self.x - 3, self.y + 22, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 24, self.x - 3, self.y + 27, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x - 3, self.y + 29, self.x - 3, self.y + 32, (n >= 3) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 19, self.x + 4, self.y + 22, (n >= 4) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 24, self.x + 4, self.y + 27, (n >= 5) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 29, self.x + 4, self.y + 32, (n >= 6) and class_colors[self.class] or bg[10], 3)
|
||||
--[[
|
||||
if next_n then
|
||||
if next_n == 1 then
|
||||
graphics.line(self.x - 4, self.y + 22, self.x - 4, self.y + 30, self.flash and class_colors[self.class] or bg[10], 2)
|
||||
|
@ -697,16 +707,7 @@ function ClassIcon:draw()
|
|||
graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, self.flash and class_colors[self.class] or bg[10], 2)
|
||||
end
|
||||
end
|
||||
elseif i == 1 then
|
||||
graphics.line(self.x - 3, self.y + 22, self.x - 3, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
if next_n then
|
||||
if next_n == 1 then
|
||||
graphics.line(self.x - 3, self.y + 22, self.x - 3, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 3)
|
||||
elseif next_n == 2 then
|
||||
graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 3)
|
||||
end
|
||||
end
|
||||
]]--
|
||||
end
|
||||
graphics.pop()
|
||||
end
|
||||
|
|
34
devlog.md
34
devlog.md
|
@ -796,3 +796,37 @@ Nothing.
|
|||
|
||||
Updated all tables with text descriptions as well as stats and overall gameplay numbers for all classes and characters.
|
||||
Tomorrow I start implementing the remaining 4 classes and 20 characters as well as revising the existing ones.
|
||||
|
||||
# Day 50-51 - 07-08/04/21
|
||||
|
||||
Nothing... Finding the energy to work on this has been getting harder. I'm sure I'll get to it eventually but for now I've been spending time with some more fun projects.
|
||||
|
||||
# Day 52 - 09/04/21
|
||||
|
||||
Lots of improvements and fixes to lots of different things that needed improving and fixing. I also started on the implementation of characters and Lv.3 effects. Today I got 10 out of 40 characters done completely:
|
||||
|
||||
| Character | Classes | Description |
|
||||
| --- | --- | --- |
|
||||
| Vagrant | psyker, ranger, warrior | shoots a projectile that deals X damage |
|
||||
| Swordsman | warrior | deals X AoE damage in an area, deals extra X/3 damage per unit hit |
|
||||
| Wizard | mage | shoots a projectile that deals X AoE damage |
|
||||
| Archer | ranger | shoots an arrow that deals X damage and pierces |
|
||||
| Scout | rogue | throws a knife that deals X damage and chains 3 times |
|
||||
| Cleric | healer | heals a unit for 20% of its max HP when it drops below 50% max HP |
|
||||
| Outlaw | warrior, rogue | throws a fan of 5 knives, each dealing X damage |
|
||||
| Blade | warrior, nuker | throws multiple blades that deal X AoE damage |
|
||||
| Elementor | mage, nuker | deals X AoE damage in a large area centered on a random target |
|
||||
| Saboteur | rogue, conjurer, nuker | calls 2 saboteurs to seek targets and deal X AoE damage |
|
||||
|
||||
| Character | Lv.3 Effect Name | Lv.3 Effect Description |
|
||||
| --- | --- | --- |
|
||||
| Vagrant | Champion | +10% damage and +5% attack speed per active set |
|
||||
| Swordsman | Cleave | the swordsman's damage is doubled |
|
||||
| Wizard | Magic Missile | the projectile chains 5 times |
|
||||
| Archer | Bounce Shot | the arrow ricochets off walls 3 times |
|
||||
| Scout | Dagger Resonance | +25% damage per chain and +3 chains |
|
||||
| Cleric | Mass Heal | heals all units |
|
||||
| Outlaw | Flying Daggers | +50% outlaw attack speed and his knives seek enemies |
|
||||
| Blade | Blade Resonance | deal additional X/2 damage per enemy hit |
|
||||
| Elementor | Windfield | slows enemies by 60% for 6 seconds on hit |
|
||||
| Saboteur | Demoman | the explosion has 50% chance to crit, increasing in size and dealing 2X damage |
|
||||
|
|
17
enemies.lua
17
enemies.lua
|
@ -225,15 +225,22 @@ function Seeker:update(dt)
|
|||
if main.current.mage_level == 2 then self.buff_def_a = -30
|
||||
elseif main.current.mage_level == 1 then self.buff_def_a = -15
|
||||
else self.buff_def_a = 0 end
|
||||
|
||||
if self.speed_boosting then
|
||||
local n = math.remap(love.timer.getTime() - self.speed_boosting, 0, 3, 1, 0.5)
|
||||
self.buff_mvspd_m = (3 + 0.1*self.level)*n
|
||||
self.speed_boosting_mvspd_m = (3 + 0.1*self.level)*n
|
||||
if not self.speed_booster and not self.exploder and not self.headbutter and not self.tank and not self.shooter and not self.spawner then
|
||||
self.color.r = math.remap(n, 1, 0.5, green[0].r, red[0].r)
|
||||
self.color.g = math.remap(n, 1, 0.5, green[0].g, red[0].g)
|
||||
self.color.b = math.remap(n, 1, 0.5, green[0].b, red[0].b)
|
||||
end
|
||||
end
|
||||
else self.speed_boosting_mvspd_m = 1 end
|
||||
|
||||
if self.slowed then self.slow_mvspd_m = self.slowed
|
||||
else self.slow_mvspd_m = 1 end
|
||||
|
||||
self.buff_mvspd_m = (self.speed_boosting_mvspd_m or 1)*(self.slow_mvspd_m or 1)
|
||||
|
||||
self:calculate_stats()
|
||||
|
||||
if self.shooter then
|
||||
|
@ -406,6 +413,12 @@ function Seeker:speed_boost(duration)
|
|||
end
|
||||
|
||||
|
||||
function Seeker:slow(amount, duration)
|
||||
self.slowed = amount
|
||||
self.t:after(duration, function() self.slowed = false end, 'slow')
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
EnemyCritter = Object:extend()
|
||||
|
|
288
main.lua
288
main.lua
|
@ -268,29 +268,88 @@ function init()
|
|||
['flagellant'] = {'psyker', 'enchanter'},
|
||||
}
|
||||
|
||||
character_class_strings = {
|
||||
['vagrant'] = '[fg]Psyker, [green]Ranger, [yellow]Warrior',
|
||||
['swordsman'] = '[yellow]Warrior',
|
||||
['wizard'] = '[blue]Mage',
|
||||
['archer'] = '[green]Ranger',
|
||||
['scout'] = '[red]Rogue',
|
||||
['cleric'] = '[green]Healer',
|
||||
['outlaw'] = '[yellow]Warrior, [red]Rogue',
|
||||
['blade'] = '[yellow]Warrior, [red]Nuker',
|
||||
['elementor'] = '[blue]Mage, [red]Nuker',
|
||||
['saboteur'] = '[red]Rogue, [orange]Conjurer, [red]Nuker',
|
||||
['stormweaver'] = '[blue]Enchanter',
|
||||
['sage'] = '[red]Nuker',
|
||||
['squire'] = '[yellow]Warrior, [blue]Enchanter',
|
||||
['cannoneer'] = '[green]Ranger, [red]Nuker',
|
||||
['dual_gunner'] = '[green]Ranger, [red]Rogue',
|
||||
['hunter'] = '[green]Ranger, [orange]Conjurer, [yellow]Forcer',
|
||||
['chronomancer'] = '[blue]Mage, Enchanter',
|
||||
['spellblade'] = '[blue]Mage, [red]Rogue',
|
||||
['psykeeper'] = '[green]Healer, [fg]Psyker',
|
||||
['engineer'] = '[orange]Conjurer',
|
||||
['plague_doctor'] = '[red]Nuker, [purple]Voider',
|
||||
['fisherman'] = '[orange]Trapper, [yellow]Warrior',
|
||||
['juggernaut'] = '[yellow]Forcer, Warrior',
|
||||
['lich'] = '[blue]Mage',
|
||||
['cryomancer'] = '[blue]Mage, [purple]Voider',
|
||||
['pyromancer'] = '[blue]Mage, [red]Nuker, [purple]Voider',
|
||||
['corruptor'] = '[green]Ranger, [purple]Swarmer',
|
||||
['beastmaster'] = '[red]Rogue, [purple]Swarmer',
|
||||
['launcher'] = '[orange]Trapper, [yellow]Forcer',
|
||||
['spiker'] = '[orange]Trapper, [red]Rogue',
|
||||
['assassin'] = '[red]Rogue, [purple]Voider',
|
||||
['host'] = '[orange]Conjurer, [purple]Swarmer',
|
||||
['carver'] = '[orange]Conjurer, [green]Healer',
|
||||
['bane'] = '[purple]Swarmer, Voider',
|
||||
['psykino'] = '[blue]Mage, [fg]Psyker, [yellow]Forcer',
|
||||
['arbalester'] = '[green]Ranger, [yellow]Forcer',
|
||||
['barbarian'] = '[yellow]Warrior',
|
||||
['sapper'] = '[orange]Trapper, [blue]Enchanter, [green]Healer',
|
||||
['priest'] = '[green]Healer',
|
||||
['burrower'] = '[orange]Trapper, [purple]Swarmer',
|
||||
['flagellant'] = '[fg]Psyker, [blue]Enchanter',
|
||||
}
|
||||
|
||||
get_character_stat_string = function(character, level)
|
||||
local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
||||
local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1}
|
||||
mock:update(0)
|
||||
return '[red]HP: [red]' .. mock.max_hp .. '[fg], [red]DMG: [red]' .. mock.dmg .. '[fg], [green]ASPD: [green]' .. math.round(mock.aspd_m, 2) .. 'x[fg], [blue]AREA: [blue]' ..
|
||||
math.round(mock.area_dmg_m*mock.area_size_m, 2) .. 'x[fg], [yellow]DEF: [yellow]' .. math.round(mock.def, 2) .. '[fg], [green]MVSPD: [green]' .. math.round(mock.v, 2) .. '[fg]'
|
||||
end
|
||||
|
||||
get_character_stat = function(character, level, stat)
|
||||
local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
||||
local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1}
|
||||
mock:update(0)
|
||||
return math.round(mock[stat], 2)
|
||||
end
|
||||
|
||||
character_descriptions = {
|
||||
['vagrant'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('vagrant', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['swordsman'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('swordsman', lvl, 'dmg') .. '[fg] damage in an area around the unit, deals extra [yellow]' ..
|
||||
['swordsman'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('swordsman', lvl, 'dmg') .. '[fg] damage in an area, deals extra [yellow]' ..
|
||||
math.round(get_character_stat('swordsman', lvl, 'dmg')/3, 2) .. '[fg] damage per unit hit' end,
|
||||
['wizard'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('wizard', lvl, 'dmg') .. ' AoE[fg] damage' end,
|
||||
['archer'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('archer', lvl, 'dmg') .. '[fg] damage and pierces' end,
|
||||
['scout'] = function(lvl) return '[fg]throws a knife that deals [yellow]' .. get_character_stat('scout', lvl, 'dmg') .. '[fg] damage and chains [yellow]3[fg] times' end,
|
||||
['cleric'] = function(lvl) return '[fg]heals a unit for [yellow]20%[fg] of its max hp when it drops below [yellow]50%[fg] max hp' end,
|
||||
['outlaw'] = function(lvl) return '[fg]throws a fan of [yellow]5[] knives, each dealing [yellow]' .. get_character_stat('outlaw', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['outlaw'] = function(lvl) return '[fg]throws a fan of [yellow]5[fg] knives, each dealing [yellow]' .. get_character_stat('outlaw', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['blade'] = function(lvl) return '[fg]throws multiple blades that deal [yellow]' .. get_character_stat('blade', lvl, 'dmg') .. ' AoE[fg] damage' end,
|
||||
['elementor'] = function(lvl) return '[fg]deals [yellow]' .. get_character_stat('elementor', lvl, 'dmg') .. ' AoE[fg] damage in a large area centered on a random target' end,
|
||||
['saboteur'] = function(lvl) return '[fg]calls [yellow]2[] saboteurs to seek targets and deal [yellow]' .. get_character_stat('saboteur', lvl, 'dmg') .. ' AoE[fg] damage' end,
|
||||
['saboteur'] = function(lvl) return '[fg]calls [yellow]2[fg] saboteurs to seek targets and deal [yellow]' .. get_character_stat('saboteur', lvl, 'dmg') .. ' AoE[fg] damage' end,
|
||||
['stormweaver'] = function(lvl) return '[fg]infuses all allied projectiles with chain lightning that deals [yellow]+20%[fg] damage on hit' end,
|
||||
['sage'] = function(lvl) return '[fg]shoots a slow projectile that draws enemies in' end,
|
||||
['squire'] = function(lvl) return '[yellow]+10% damage and defense to all allies' end,
|
||||
['squire'] = function(lvl) return '[yellow]+10%[fg] damage and defense to all allies' end,
|
||||
['cannoneer'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. get_character_stat('cannoneer', lvl, 'dmg') .. ' AoE[fg] damage' end,
|
||||
['dual_gunner'] = function(lvl) return '[fg]shoots two parallel projectiles' end,
|
||||
['hunter'] = function(lvl) return '[fg]shoots an arrow that deals [yellow]' .. get_character_stat('hunter', lvl, 'dmg') .. '[fg] damage and has a [yellow]20%[fg] chance to summon a pet' end,
|
||||
['chronomancer'] = function(lvl) return '[yellow]+20% attack speed[fg] to all allies' end,
|
||||
['chronomancer'] = function(lvl) return '[yellow]+20%[fg] attack speed to all allies' end,
|
||||
['spellblade'] = function(lvl) return '[fg]throws knives that deal [yellow]' .. get_character_stat('spellblade', lvl, 'dmg') .. '[fg] damage, pierce and spiral outwards' end,
|
||||
['psykeeper'] = function(lvl) return '[fg]all damage taken is stored up to [yellow]50%[fg] max HP and distributed as healing to all allies' end,
|
||||
['engineer'] = function(lvl) return '[fg]drops sentries that shoot bursts of projectiles, each dealing [yellow]' .. get_character_stat('engineer', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['plague_doctor'] = function(lvl) return '[fg]creates an area that deals [yellow]' .. get_character_stat('plague_doctor', lvl, 'dot_dmg') .. '[fg] damage per second' end,
|
||||
['plague_doctor'] = function(lvl) return '[fg]creates an area that deals [yellow]' .. get_character_stat('plague_doctor', lvl, 'dmg') .. '[fg] damage per second' end,
|
||||
['fisherman'] = function(lvl) return '[fg]throws a net that entangles enemies and prevents them from moving for [yellow]2[fg] seconds' end,
|
||||
['juggernaut'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. get_character_stat('juggernaut', lvl, 'dmg') .. '[fg] damage and pushes enemies away with a strong force' end,
|
||||
['lich'] = function(lvl) return '[fg]launches a chain frost that jumps [yellow]7[fg] times, dealing [yellow]' ..
|
||||
|
@ -302,33 +361,150 @@ function init()
|
|||
['launcher'] = function(lvl) return '[fg]creates a trap that launches enemies that trigger it' end,
|
||||
['spiker'] = function(lvl) return '[fg]creates a trap that crits when triggered, dealing [yellow]' .. 4*get_character_stat('spiker', lvl, 'dmg') .. '[fg] damage' end,
|
||||
['assassin'] = function(lvl) return '[fg]throws a piercing knife that deals [yellow]' .. get_character_stat('assassin', lvl, 'dmg') .. '[fg] damage and inflicts poison that deals [yellow]' ..
|
||||
get_character_stat('assassin', lvl, 'dot_dmg') .. '[fg] damage per second for [yellow]2[fg] seconds' end,
|
||||
get_character_stat('assassin', lvl, 'dmg')/2 .. '[fg] damage per second for [yellow]4[fg] seconds' end,
|
||||
['host'] = function(lvl) return '[fg]creates [yellow]2[fg] overlords that periodically spawn small critters' end,
|
||||
['carver'] = function(lvl) return '[fg]carves a statue that periodically heals for [yellow]20%[fg] max HP in an area around it' end,
|
||||
['bane'] = function(lvl) return '[fg]spawn a small critter that explodes and deals [yellow]' .. get_character_stat('bane', lvl, 'dot_dmg') .. '[fg] damage per second in an area' end,
|
||||
['bane'] = function(lvl) return '[fg]spawn a small critter that explodes and deals [yellow]' .. get_character_stat('bane', lvl, 'dmg') .. '[fg] damage per second in an area' end,
|
||||
['psykino'] = function(lvl) return '[fg]quickly pulls enemies together and then release them with a force' end,
|
||||
['arbalester'] = function(lvl) return '[fg]launches a massive arrow that deals [yellow]' .. get_character_stat('arbalester', lvl, 'dmg') .. '[fg] damage and pushes enemies back, ignoring knockback resistances' end,
|
||||
['barbarian'] = function(lvl) return '[fg]creates a small area that deals [yellow]' .. 4*get_character_stat('barbarian', lvl, 'dmg') .. '[fg] damage and stuns for [yellow]2[fg] seconds' end,
|
||||
['sapper'] = function(lvl) return '[fg]creates a trap that steals [yellow]10%[fg] enemy HP and grants you [yellow]+25%[fg] movement speed' end,
|
||||
['priest'] = function(lvl) return '[fg]heals all allies for [yellow]20%[fg] their max HP' end,
|
||||
['burrower'] = function(lvl) return '[fg]creates a trap that contains [yellow]6[fg] small critters' end,
|
||||
['flagellant'] = function(lvl) return '[fg]deals damage to self and grants +20% damage to all allies' end,
|
||||
['flagellant'] = function(lvl) return '[fg]deals damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end,
|
||||
}
|
||||
|
||||
get_character_stat_string = function(character, level)
|
||||
local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
||||
local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1}
|
||||
mock:update(0)
|
||||
return '[red]HP: [red]' .. mock.max_hp .. '[fg], [red]DMG: [red]' .. mock.dmg .. '[fg], [purple]DOT DMG: [purple]' .. mock.dot_dmg .. '[fg], [green]ASPD: [green]' .. math.round(mock.aspd_m, 2) .. 'x[fg], [blue]AREA: [blue]' ..
|
||||
math.round(mock.area_dmg_m*mock.area_size_m, 2) .. 'x[fg], [yellow]DEF: [yellow]' .. math.round(mock.def, 2) .. '[fg], [green]MVSPD: [green]' .. math.round(mock.v, 2) .. '[fg]'
|
||||
end
|
||||
character_effect_names = {
|
||||
['vagrant'] = '[fg]Champion',
|
||||
['swordsman'] = '[yellow]Cleave',
|
||||
['wizard'] = '[blue]Magic Missile',
|
||||
['archer'] = '[green]Bounce Shot',
|
||||
['scout'] = '[red]Dagger Resonance',
|
||||
['cleric'] = '[green]Mass Heal ',
|
||||
['outlaw'] = '[red]Flying Daggers',
|
||||
['blade'] = '[yellow]Blade Resonance',
|
||||
['elementor'] = '[blue]Windfield',
|
||||
['saboteur'] = '[orange]Demoman',
|
||||
['stormweaver'] = '[blue]Lightning Spire',
|
||||
['sage'] = '[purple]Dimension Compression',
|
||||
['squire'] = '[yellow]Repair',
|
||||
['cannoneer'] = '[orange]Cannon Barrage',
|
||||
['dual_gunner'] = '[green]Gun Kata',
|
||||
['hunter'] = '[green]Feral Pack',
|
||||
['chronomancer'] = '[blue]Quicken',
|
||||
['spellblade'] = '[blue]Spiralism',
|
||||
['psykeeper'] = '[fg]Crucio',
|
||||
['engineer'] = '[orange]Upgrade',
|
||||
['plague_doctor'] = '[purple]Pandemic',
|
||||
['fisherman'] = '[yellow]Electric Net',
|
||||
['juggernaut'] = '[yellow]Brutal Impact',
|
||||
['lich'] = '[blue]Piercing Frost',
|
||||
['cryomancer'] = '[blue]Frostbite',
|
||||
['pyromancer'] = '[red]Ignite',
|
||||
['corruptor'] = '[purple]Infestation',
|
||||
['beastmaster'] = '[red]Call of the Wild',
|
||||
['launcher'] = '[orange]Kineticism',
|
||||
['spiker'] = '[orange]Caltrops',
|
||||
['assassin'] = '[purple]Toxic Delivery',
|
||||
['host'] = '[purple]Invasion',
|
||||
['carver'] = '[green]World Tree',
|
||||
['bane'] = '[purple]Baneling Swarm',
|
||||
['psykino'] = '[fg]Magnetic Force',
|
||||
['arbalester'] = '[green]Ballista Sinitra',
|
||||
['barbarian'] = '[yellow]Berserk',
|
||||
['sapper'] = '[blue]Chain Reaction',
|
||||
['priest'] = '[green]Divine Intervention',
|
||||
['burrower'] = '[orange]Zergling Rush',
|
||||
['flagellant'] = '[red]Zealotry',
|
||||
}
|
||||
|
||||
get_character_stat = function(character, level, stat)
|
||||
local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'})
|
||||
local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1}
|
||||
mock:update(0)
|
||||
return math.round(mock[stat], 2)
|
||||
end
|
||||
character_effect_names_gray = {
|
||||
['vagrant'] = '[light_bg]Champion',
|
||||
['swordsman'] = '[light_bg]Cleave',
|
||||
['wizard'] = '[light_bg]Magic Missile',
|
||||
['archer'] = '[light_bg]Bounce Shot',
|
||||
['scout'] = '[light_bg]Replica',
|
||||
['cleric'] = '[light_bg]Mass Heal ',
|
||||
['outlaw'] = '[light_bg]Fatal Roulette',
|
||||
['blade'] = '[light_bg]Blade Resonance',
|
||||
['elementor'] = '[light_bg]Windfield',
|
||||
['saboteur'] = '[light_bg]Chain Reaction',
|
||||
['stormweaver'] = '[light_bg]Lightning Spire',
|
||||
['sage'] = '[light_bg]Dimension Compression',
|
||||
['squire'] = '[light_bg]Repair',
|
||||
['cannoneer'] = '[light_bg]Cannon Barrage',
|
||||
['dual_gunner'] = '[light_bg]Gun Kata',
|
||||
['hunter'] = '[light_bg]Feral Pack',
|
||||
['chronomancer'] = '[light_bg]Quicken',
|
||||
['spellblade'] = '[light_bg]Spiralism',
|
||||
['psykeeper'] = '[light_bg]Crucio',
|
||||
['engineer'] = '[light_bg]Upgrade',
|
||||
['plague_doctor'] = '[light_bg]Pandemic',
|
||||
['fisherman'] = '[light_bg]Electric Net',
|
||||
['juggernaut'] = '[light_bg]Brutal Impact',
|
||||
['lich'] = '[light_bg]Piercing Frost',
|
||||
['cryomancer'] = '[light_bg]Frostbite',
|
||||
['pyromancer'] = '[light_bg]Ignite',
|
||||
['corruptor'] = '[light_bg]Infestation',
|
||||
['beastmaster'] = '[light_bg]Call of the Wild',
|
||||
['launcher'] = '[light_bg]Kineticism',
|
||||
['spiker'] = '[light_bg]Caltrops',
|
||||
['assassin'] = '[light_bg]Toxic Delivery',
|
||||
['host'] = '[light_bg]Invasion',
|
||||
['carver'] = '[light_bg]World Tree',
|
||||
['bane'] = '[light_bg]Baneling Swarm',
|
||||
['psykino'] = '[light_bg]Magnetic Force',
|
||||
['arbalester'] = '[light_bg]Ballista Sinitra',
|
||||
['barbarian'] = '[light_bg]Berserk',
|
||||
['sapper'] = '[light_bg]Chain Reaction',
|
||||
['priest'] = '[light_bg]Divine Intervention',
|
||||
['burrower'] = '[light_bg]Zergling Rush',
|
||||
['flagellant'] = '[light_bg]Zealotry',
|
||||
}
|
||||
|
||||
character_effect_descriptions = {
|
||||
['vagrant'] = function() return '[yellow]+10%[fg] damage and [yellow]+5%[fg] attack speed per active set' end,
|
||||
['swordsman'] = function() return "[fg]the swordsman's damage is [yellow]doubled" end,
|
||||
['wizard'] = function() return '[fg]the projectile chains [yellow]5[fg] times' end,
|
||||
['archer'] = function() return '[fg]the arrow ricochets off walls [yellow]3[fg] times' end,
|
||||
['scout'] = function() return '[yellow]+25%[fg] damage per chain and [yellow]+3[fg] chains' end,
|
||||
['cleric'] = function() return '[fg]heals all units' end,
|
||||
['outlaw'] = function() return "[yellow]+50%[fg] outlaw attack speed and his knives seek enemies" end,
|
||||
['blade'] = function() return '[fg]deal additional [yellow]' .. get_character_stat('blade', 3, 'dmg')/2 .. '[fg] damage per enemy hit' end,
|
||||
['elementor'] = function() return '[fg]slows enemies by [yellow]60%[fg] for [yellow]6[fg] seconds on hit' end,
|
||||
['saboteur'] = function() return '[fg]the explosion has [yellow]50%[fg] chance to crit, increasing in size and dealing [yellow]2x[fg] damage' end,
|
||||
['stormweaver'] = function() return '[fg]cast a spire of lightning periodically' end,
|
||||
['sage'] = function() return '[fg]when the projectile expires deal [yellow]' .. get_character_stat('sage', 3, 'dmg') .. '[fg] to all enemies under its influence' end,
|
||||
['squire'] = function() return '[fg]you can reroll your item choices once, these opportunities stack if unused' end,
|
||||
['cannoneer'] = function() return '[fg]showers the area in additional cannon shots that deal [yellow]' .. get_character_stat('cannoneer', 3, 'dmg') .. '[fg] AoE damage' end,
|
||||
['dual_gunner'] = function() return '[fg]every 5th attack shoots projectiles in rapid succession targetting all nearby enemies for [yellow]2[fg] seconds' end,
|
||||
['hunter'] = function() return '[fg]summons 3 pets' end,
|
||||
['chronomancer'] = function() return '[fg]enemies take damave over time [yellow]50%[fg] faster' end,
|
||||
['spellblade'] = function() return '[fg]faster projectile speed and tighter turns' end,
|
||||
['psykeeper'] = function() return '[fg]also redistributes damage taken as damage to all enemies' end,
|
||||
['engineer'] = function() return '[fg]every 3rd sentry dropped upgrade all sentries, granting them [yellow]+100%[fg] damage and attack speed' end,
|
||||
['plague_doctor'] = function() return '[fg]inflicts enemies with a contagion that deals additional [yellow]' .. get_character_stat('plague_doctor', 3, 'dmg') .. '[fg] damage per second and spreads to nearby enemies' end,
|
||||
['fisherman'] = function() return '[fg]enemies caught take [yellow]' .. get_character_stat('fisherman', 3, 'dmg')/4 .. '[fg] damage per second' end,
|
||||
['juggernaut'] = function() return '[fg]enemies pushed away by the juggernaut are instantly killed if they hit a wall' end,
|
||||
['lich'] = function() return '[fg]chain frost decreases enemy defenses by [yellow]30[fg] for [yellow]4[fg] seconds' end,
|
||||
['cryomancer'] = function() return '[fg]enemies killed by the cryomancer freeze nearby enemies, frozen enemies take increased damage and do not move' end,
|
||||
['pyromancer'] = function() return '[fg]enemies killed by the pyromancer explode, dealing [yellow]' .. get_character_stat('pyromancer', 3, 'dmg') .. '[fg] AoE damage' end,
|
||||
['corruptor'] = function() return '[fg]spawn [yellow]3[fg] small critters if the corruptor hits an enemy' end,
|
||||
['beastmaster'] = function() return '[fg]spawn [yellow]2[fg] small critters if the beastmaster gets hit' end,
|
||||
['launcher'] = function() return '[fg]enemies launched that hit other enemies push those enemies at double the force they were pushed' end,
|
||||
['spiker'] = function() return '[fg]slows enemies hit by [yellow]50%[fg] for [yellow]2[fg] seconds and deals [yellow]' .. get_character_stat('spiker', 3, 'dmg') .. '[fg] damage per second' end,
|
||||
['assassin'] = function() return '[fg]poison inflicted from crits deals [yellow]8x[fg] damage' end,
|
||||
['host'] = function() return '[fg][yellow]+50%[fg] critter spawn rate' end,
|
||||
['carver'] = function() return '[fg]carves a tree that heals in a bigger area and removes all buffs from enemies' end,
|
||||
['bane'] = function() return '[fg]spawn [yellow]4[fg] banelings' end,
|
||||
['psykino'] = function() return '[fg]enemies pulled together are forced to collide with each other multiple times' end,
|
||||
['arbalester'] = function() return '[fg]enemies hit by the arrow have defense decreased by [yellow]100[fg] for [yellow]4[fg] seconds' end,
|
||||
['barbarian'] = function() return '[fg][yellow]+50%[fg] attack speed' end,
|
||||
['sapper'] = function() return '[fg]when a sapper trap is triggered other nearby traps are also triggered' end,
|
||||
['priest'] = function() return '[fg]at the start of the round pick [yellow]3[fg] units at random and grants them a buff that prevents death once' end,
|
||||
['burrower'] = function() return '[fg][yellow]triples[fg] the number of critters released' end,
|
||||
['flagellant'] = function() return '[fg]deals damage to all allies instead and grants [yellow]+10%[fg] damage to all allies per cast' end,
|
||||
}
|
||||
|
||||
character_stats = {
|
||||
['vagrant'] = function(lvl) return get_character_stat_string('vagrant', lvl) end,
|
||||
|
@ -375,19 +551,19 @@ function init()
|
|||
}
|
||||
|
||||
class_stat_multipliers = {
|
||||
['ranger'] = {hp = 1, dmg = 1.2, aspd = 1.5, area_dmg = 1, area_size = 1, dot_dmg = 1.1, def = 0.9, mvspd = 1.2},
|
||||
['warrior'] = {hp = 1.4, dmg = 1.1, aspd = 0.9, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 1.25, mvspd = 0.9},
|
||||
['mage'] = {hp = 0.6, dmg = 1.4, aspd = 1, area_dmg = 1.25, area_size = 1.2, dot_dmg = 1.25, def = 0.75, mvspd = 1},
|
||||
['rogue'] = {hp = 0.8, dmg = 1.3, aspd = 1.1, area_dmg = 0.6, area_size = 0.6, dot_dmg = 1.4, def = 0.8, mvspd = 1.4},
|
||||
['healer'] = {hp = 1.2, dmg = 1, aspd = 0.5, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 1.2, mvspd = 1},
|
||||
['enchanter'] = {hp = 1.2, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 1.2, mvspd = 1.2},
|
||||
['nuker'] = {hp = 0.9, dmg = 1, aspd = 0.75, area_dmg = 1.5, area_size = 1.5, dot_dmg = 0.75, def = 1, mvspd = 1},
|
||||
['conjurer'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 1, mvspd = 1},
|
||||
['psyker'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 0.5, mvspd = 1},
|
||||
['trapper'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, dot_dmg = 1.1, def = 0.75, mvspd = 1},
|
||||
['forcer'] = {hp = 1.25, dmg = 1.1, aspd = 0.9, area_dmg = 0.75, area_size = 0.75, dot_dmg = 1, def = 1.2, mvspd = 1},
|
||||
['swarmer'] = {hp = 1.2, dmg = 1, aspd = 1.25, area_dmg = 1, area_size = 1, dot_dmg = 1, def = 0.75, mvspd = 0.5},
|
||||
['voider'] = {hp = 0.75, dmg = 1.3, aspd = 1, area_dmg = 0.8, area_size = 0.75, dot_dmg = 2, def = 0.6, mvspd = 0.8},
|
||||
['ranger'] = {hp = 1, dmg = 1.2, aspd = 1.5, area_dmg = 1, area_size = 1, def = 0.9, mvspd = 1.2},
|
||||
['warrior'] = {hp = 1.4, dmg = 1.1, aspd = 0.9, area_dmg = 1, area_size = 1, def = 1.25, mvspd = 0.9},
|
||||
['mage'] = {hp = 0.6, dmg = 1.4, aspd = 1, area_dmg = 1.25, area_size = 1.2, def = 0.75, mvspd = 1},
|
||||
['rogue'] = {hp = 0.8, dmg = 1.3, aspd = 1.1, area_dmg = 0.6, area_size = 0.6, def = 0.8, mvspd = 1.4},
|
||||
['healer'] = {hp = 1.2, dmg = 1, aspd = 0.5, area_dmg = 1, area_size = 1, def = 1.2, mvspd = 1},
|
||||
['enchanter'] = {hp = 1.2, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1.2, mvspd = 1.2},
|
||||
['nuker'] = {hp = 0.9, dmg = 1, aspd = 0.75, area_dmg = 1.5, area_size = 1.5, def = 1, mvspd = 1},
|
||||
['conjurer'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 1, mvspd = 1},
|
||||
['psyker'] = {hp = 1.5, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.5, mvspd = 1},
|
||||
['trapper'] = {hp = 1, dmg = 1, aspd = 1, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 1},
|
||||
['forcer'] = {hp = 1.25, dmg = 1.1, aspd = 0.9, area_dmg = 0.75, area_size = 0.75, def = 1.2, mvspd = 1},
|
||||
['swarmer'] = {hp = 1.2, dmg = 1, aspd = 1.25, area_dmg = 1, area_size = 1, def = 0.75, mvspd = 0.5},
|
||||
['voider'] = {hp = 0.75, dmg = 1.3, aspd = 1, area_dmg = 0.8, area_size = 0.75, def = 0.6, mvspd = 0.8},
|
||||
['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},
|
||||
|
@ -414,9 +590,9 @@ function init()
|
|||
|
||||
tier_to_characters = {
|
||||
[1] = {'vagrant', 'swordsman', 'wizard', 'archer', 'scout', 'cleric'},
|
||||
[2] = {'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'fisherman', 'cryomancer', 'beastmaster', 'launcher', 'spiker', 'carver'}
|
||||
[3] = {'outlaw', 'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'corruptor', 'assassin', 'bane', 'arbalester', 'burrower', 'flagellant'}
|
||||
[4] = {'priest', 'barbarian', 'psykino', 'lich', 'host', 'sapper', 'blade', 'plague_doctor', 'cannoneer'}
|
||||
[2] = {'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'fisherman', 'cryomancer', 'beastmaster', 'launcher', 'spiker', 'carver'},
|
||||
[3] = {'outlaw', 'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'corruptor', 'assassin', 'bane', 'arbalester', 'burrower', 'flagellant'},
|
||||
[4] = {'priest', 'barbarian', 'psykino', 'lich', 'host', 'sapper', 'blade', 'plague_doctor', 'cannoneer'},
|
||||
}
|
||||
|
||||
non_attacking_characters = {'cleric', 'stormweaver', 'squire', 'chronomancer', 'sage'}
|
||||
|
@ -500,6 +676,36 @@ function init()
|
|||
enchanter = enchanters, psyker = psykers, trapper = trappers, forcer = forcers, swarmer = swarmers, voider = voiders}
|
||||
end
|
||||
|
||||
get_class_levels = function(units)
|
||||
local units_per_class = get_number_of_units_per_class(units)
|
||||
local units_to_class_level = function(number_of_units, class)
|
||||
if class == 'ranger' or class == 'warrior' or class == 'mage' or class == 'nuker' or class == 'rogue' then
|
||||
if number_of_units >= 6 then return 2
|
||||
elseif number_of_units >= 3 then return 1
|
||||
else return 0 end
|
||||
elseif class == 'healer' or class == 'conjurer' or class == 'enchanter' or class == 'psyker' or class == 'trapper' or class == 'forcer' or class == 'swarmer' or class == 'voider' then
|
||||
if number_of_units >= 4 then return 2
|
||||
elseif number_of_units >= 2 then return 1
|
||||
else return 0 end
|
||||
end
|
||||
end
|
||||
return {
|
||||
ranger = units_to_class_level(units_per_class.ranger, 'ranger'),
|
||||
warrior = units_to_class_level(units_per_class.warrior, 'warrior'),
|
||||
mage = units_to_class_level(units_per_class.mage, 'mage'),
|
||||
nuker = units_to_class_level(units_per_class.nuker, 'nuker'),
|
||||
rogue = units_to_class_level(units_per_class.rogue, 'rogue'),
|
||||
healer = units_to_class_level(units_per_class.healer, 'healer'),
|
||||
conjurer = units_to_class_level(units_per_class.conjurer, 'conjurer'),
|
||||
enchanter = units_to_class_level(units_per_class.enchanter, 'enchanter'),
|
||||
psyker = units_to_class_level(units_per_class.psyker, 'psyker'),
|
||||
trapper = units_to_class_level(units_per_class.trapper, 'trapper'),
|
||||
forcer = units_to_class_level(units_per_class.forcer, 'forcer'),
|
||||
swarmer = units_to_class_level(units_per_class.swarmer, 'swarmer'),
|
||||
voider = units_to_class_level(units_per_class.voider, 'voider'),
|
||||
}
|
||||
end
|
||||
|
||||
get_classes = function(units)
|
||||
local classes = {}
|
||||
for _, unit in ipairs(units) do
|
||||
|
@ -580,7 +786,7 @@ function init()
|
|||
[25] = {100, 100},
|
||||
}
|
||||
|
||||
boss_by_level = {
|
||||
level_to_boss = {
|
||||
[6] = 'speed_booster',
|
||||
[12] = 'exploder',
|
||||
[18] = 'swarmer',
|
||||
|
@ -592,7 +798,9 @@ function init()
|
|||
|
||||
main = Main()
|
||||
main:add(BuyScreen'buy_screen')
|
||||
main:go_to('buy_screen', 0, {})
|
||||
main:go_to('buy_screen', 15, {
|
||||
{character = 'saboteur', level = 3},
|
||||
})
|
||||
--[[
|
||||
main:add(Arena'arena')
|
||||
main:go_to('arena', 18, {
|
||||
|
|
144
player.lua
144
player.lua
|
@ -41,7 +41,7 @@ function Player:init(args)
|
|||
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
|
||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy))
|
||||
self:shoot(self:angle_to_object(closest_enemy), {chain = (self.level == 3 and 5 or 0)})
|
||||
end
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
|
@ -55,7 +55,7 @@ function Player:init(args)
|
|||
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
|
||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000})
|
||||
self:shoot(self:angle_to_object(closest_enemy), {pierce = 1000, ricochet = (self.level == 3 and 3 or 0)})
|
||||
end
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
|
@ -69,7 +69,7 @@ function Player:init(args)
|
|||
self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
|
||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy), {chain = 3})
|
||||
self:shoot(self:angle_to_object(closest_enemy), {chain = (self.level == 3 and 6 or 3)})
|
||||
end
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
|
@ -82,9 +82,15 @@ function Player:init(args)
|
|||
self.last_heal_time = love.timer.getTime()
|
||||
self.t:every(2, function()
|
||||
local all_units = self:get_all_units()
|
||||
if table.any(all_units, function(v) return v.hp <= 0.5*v.max_hp end) and love.timer.getTime() - self.last_heal_time > 6 then
|
||||
local unit_index = table.contains(all_units, function(v) return v.hp <= 0.5*v.max_hp end)
|
||||
if unit_index and love.timer.getTime() - self.last_heal_time > 6 then
|
||||
local unit = all_units[unit_index]
|
||||
self.last_heal_time = love.timer.getTime()
|
||||
for _, unit in ipairs(all_units) do unit:heal(0.1*unit.max_hp*(self.heal_effect_m or 1)) end
|
||||
if self.level == 3 then
|
||||
for _, unit in ipairs(all_units) do unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1)) end
|
||||
else
|
||||
unit:heal(0.2*unit.max_hp*(self.heal_effect_m or 1))
|
||||
end
|
||||
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
|
||||
end
|
||||
end)
|
||||
|
@ -99,7 +105,7 @@ function Player:init(args)
|
|||
self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function()
|
||||
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
|
||||
if closest_enemy then
|
||||
self:shoot(self:angle_to_object(closest_enemy))
|
||||
self:shoot(self:angle_to_object(closest_enemy), {homing = (self.level == 3)})
|
||||
end
|
||||
end, nil, nil, 'shoot')
|
||||
|
||||
|
@ -137,7 +143,7 @@ function Player:init(args)
|
|||
self.t:every(8, function()
|
||||
self.t:every(0.25, function()
|
||||
SpawnEffect{group = main.current.effects, x = self.x, y = self.y, action = function(x, y)
|
||||
Saboteur{group = main.current.main, x = x, y = y, parent = self, conjurer_buff_m = self.conjurer_buff_m or 1}
|
||||
Saboteur{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1, crit = (self.level == 3) and random:bool(50)}
|
||||
end}
|
||||
end, 2)
|
||||
end)
|
||||
|
@ -257,6 +263,19 @@ function Player:init(args)
|
|||
end)
|
||||
end
|
||||
|
||||
--[[
|
||||
elseif self.character == 'plague_doctor' then
|
||||
self.color = character_colors.plague_doctor
|
||||
self:set_as_rectangle(9, 9, 'dynamic', 'player')
|
||||
self.visual_shape = 'rectangle'
|
||||
self.classes = character_classes.plague_doctor
|
||||
|
||||
self.t:every(5, function()
|
||||
self:attack(64)
|
||||
end, nil, nil, 'attack')
|
||||
end
|
||||
]]--
|
||||
|
||||
self:calculate_stats(true)
|
||||
|
||||
if self.leader then
|
||||
|
@ -286,6 +305,33 @@ function Player:update(dt)
|
|||
end
|
||||
end
|
||||
|
||||
if self.character == 'vagrant' and self.level == 3 then
|
||||
local class_levels = get_class_levels(self:get_all_units())
|
||||
local number_of_active_sets = 0
|
||||
if class_levels.ranger >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.warrior >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.mage >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.rogue >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.healer >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.conjurer >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.enchanter >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.psyker >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.trapper >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.forcer >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.swarmer >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
if class_levels.voider >= 1 then number_of_active_sets = number_of_active_sets + 1 end
|
||||
self.vagrant_dmg_m = 1 + 0.1*number_of_active_sets
|
||||
self.vagrant_aspd_m = 1 + 0.05*number_of_active_sets
|
||||
end
|
||||
|
||||
if self.character == 'swordsman' and self.level == 3 then
|
||||
self.swordsman_dmg_m = 2
|
||||
end
|
||||
|
||||
if self.character == 'outlaw' and self.level == 3 then
|
||||
self.outlaw_aspd_m = 1.5
|
||||
end
|
||||
|
||||
if table.any(self.classes, function(v) return v == 'ranger' end) then
|
||||
if main.current.ranger_level == 2 then self.chance_to_barrage = 20
|
||||
elseif main.current.ranger_level == 1 then self.chance_to_barrage = 10
|
||||
|
@ -326,8 +372,8 @@ function Player:update(dt)
|
|||
end
|
||||
|
||||
self.buff_def_a = (self.warrior_def_a or 0)
|
||||
self.buff_aspd_m = (self.chronomancer_aspd_m or 1)
|
||||
self.buff_dmg_m = (self.squire_dmg_m or 1)*(main.current.enchanter_dmg_m or 1)
|
||||
self.buff_aspd_m = (self.chronomancer_aspd_m or 1)*(self.vagrant_aspd_m or 1)*(self.outlaw_aspd_m or 1)
|
||||
self.buff_dmg_m = (self.squire_dmg_m or 1)*(self.vagrant_dmg_m or 1)*(main.current.enchanter_dmg_m or 1)*(self.swordsman_dmg_m or 1)
|
||||
self.buff_def_m = (self.squire_def_m or 1)
|
||||
self.buff_area_size_m = (self.nuker_area_size_m or 1)
|
||||
self.buff_area_dmg_m = (self.nuker_area_dmg_m or 1)
|
||||
|
@ -559,7 +605,7 @@ function Player:shoot(r, mods)
|
|||
r = r - 2*math.pi/8
|
||||
for i = 1, 5 do
|
||||
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*dmg_m, crit = crit, character = self.character,
|
||||
parent = self}
|
||||
parent = self, level = self.level}
|
||||
Projectile(table.merge(t, mods or {}))
|
||||
r = r + math.pi/8
|
||||
end
|
||||
|
@ -571,30 +617,31 @@ function Player:shoot(r, mods)
|
|||
local r = self:angle_to_object(enemy)
|
||||
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*dmg_m, crit = crit, character = self.character,
|
||||
parent = self}
|
||||
parent = self, level = self.level}
|
||||
Projectile(table.merge(t, mods or {}))
|
||||
end
|
||||
end
|
||||
|
||||
elseif self.character == 'sage' then
|
||||
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 = 25, r = r, color = self.color, dmg = self.dmg, pierce = 1000, character = 'sage', parent = self}
|
||||
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 = 25, r = r, color = self.color, dmg = self.dmg, pierce = 1000, character = 'sage',
|
||||
parent = self, level = self.level}
|
||||
Projectile(table.merge(t, mods or {}))
|
||||
|
||||
elseif self.character == 'dual_gunner' then
|
||||
HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r) + 4*math.cos(r - math.pi/2), y = self.y + 0.8*self.shape.w*math.sin(r) + 4*math.sin(r - math.pi/2), rs = 6}
|
||||
HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r) + 4*math.cos(r + math.pi/2), y = self.y + 0.8*self.shape.w*math.sin(r) + 4*math.sin(r + math.pi/2), rs = 6}
|
||||
local t1 = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r) + 4*math.cos(r - math.pi/2) , y = self.y + 1.6*self.shape.w*math.sin(r) + 4*math.sin(r - math.pi/2),
|
||||
v = 250, r = r, color = self.color, dmg = self.dmg*dmg_m, crit = crit, character = self.character, parent = self}
|
||||
v = 250, r = r, color = self.color, dmg = self.dmg*dmg_m, crit = crit, character = self.character, parent = self, level = self.level}
|
||||
local t2 = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r) + 4*math.cos(r + math.pi/2) , y = self.y + 1.6*self.shape.w*math.sin(r) + 4*math.sin(r + math.pi/2),
|
||||
v = 250, r = r, color = self.color, dmg = self.dmg*dmg_m, crit = crit, character = self.character, parent = self}
|
||||
v = 250, r = r, color = self.color, dmg = self.dmg*dmg_m, crit = crit, character = self.character, parent = self, level = self.level}
|
||||
Projectile(table.merge(t1, mods or {}))
|
||||
Projectile(table.merge(t2, mods or {}))
|
||||
|
||||
else
|
||||
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*dmg_m, crit = crit, character = self.character,
|
||||
parent = self}
|
||||
parent = self, level = self.level}
|
||||
Projectile(table.merge(t, mods or {}))
|
||||
end
|
||||
|
||||
|
@ -623,7 +670,7 @@ function Player:attack(area, mods)
|
|||
mods = mods or {}
|
||||
camera:shake(2, 0.5)
|
||||
self.hfx:use('shoot', 0.25)
|
||||
local t = {group = main.current.effects, x = mods.x or self.x, y = mods.y or 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}
|
||||
local t = {group = main.current.effects, x = mods.x or self.x, y = mods.y or 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, level = self.level}
|
||||
Area(table.merge(t, mods))
|
||||
|
||||
if self.character == 'swordsman' then
|
||||
|
@ -641,7 +688,7 @@ function Player:barrage(r, n)
|
|||
archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35}
|
||||
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 + random:float(-math.pi/16, math.pi/16), color = self.color, dmg = self.dmg,
|
||||
parent = self, character = 'barrage'}
|
||||
parent = self, character = 'barrage', level = self.level}
|
||||
Projectile(table.merge(t, mods or {}))
|
||||
end)
|
||||
end
|
||||
|
@ -658,6 +705,7 @@ function Projectile:init(args)
|
|||
self:set_as_rectangle(10, 4, 'dynamic', 'projectile')
|
||||
self.pierce = args.pierce or 0
|
||||
self.chain = args.chain or 0
|
||||
self.ricochet = args.ricochet or 0
|
||||
self.chain_enemies_hit = {}
|
||||
self.infused_enemies_hit = {}
|
||||
|
||||
|
@ -685,6 +733,14 @@ function Projectile:init(args)
|
|||
self.t:tween(12.25, self, {orbit_vr = 0}, math.linear)
|
||||
end)
|
||||
end
|
||||
|
||||
if self.homing then
|
||||
self.homing = false
|
||||
self.t:after(0.1, function()
|
||||
self.homing = true
|
||||
self.closest_sensor = Circle(self.x, self.y, 64)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -695,8 +751,22 @@ function Projectile:update(dt)
|
|||
self.orbit_r = self.orbit_r + self.orbit_vr*dt
|
||||
end
|
||||
|
||||
self:set_angle(self.r)
|
||||
self:move_along_angle(self.v, self.r + (self.orbit_r or 0))
|
||||
if self.homing then
|
||||
self.closest_sensor:move_to(self.x, self.y)
|
||||
local target = self:get_closest_object_in_shape(self.closest_sensor, main.current.enemies)
|
||||
if target then
|
||||
self:rotate_towards_object(target, 0.1)
|
||||
self.r = self:get_angle()
|
||||
self:move_along_angle(self.v, self.r + (self.orbit_r or 0))
|
||||
else
|
||||
self:set_angle(self.r)
|
||||
self:move_along_angle(self.v, self.r + (self.orbit_r or 0))
|
||||
end
|
||||
else
|
||||
self:set_angle(self.r)
|
||||
self:move_along_angle(self.v, self.r + (self.orbit_r or 0))
|
||||
end
|
||||
|
||||
|
||||
if self.character == 'sage' then
|
||||
self.pull_sensor:move_to(self.x, self.y)
|
||||
|
@ -738,11 +808,11 @@ function Projectile:die(x, y, r, n)
|
|||
self.dead = true
|
||||
|
||||
if self.character == 'wizard' then
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*32, color = self.color, dmg = self.parent.area_dmg_m*self.dmg, character = self.character}
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*32, color = self.color, dmg = self.parent.area_dmg_m*self.dmg, character = self.character, level = self.level}
|
||||
elseif self.character == 'blade' then
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*64, color = self.color, dmg = self.parent.area_dmg_m*self.dmg, character = self.character}
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*64, color = self.color, dmg = self.parent.area_dmg_m*self.dmg, character = self.character, level = self.level}
|
||||
elseif self.character == 'cannoneer' then
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*96, color = self.color, dmg = 2*self.parent.area_dmg_m*self.dmg, character = self.character}
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*96, color = self.color, dmg = 2*self.parent.area_dmg_m*self.dmg, character = self.character, level = self.level}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -758,9 +828,15 @@ function Projectile:on_collision_enter(other, contact)
|
|||
|
||||
if other:is(Wall) then
|
||||
if self.character == 'archer' or self.character == 'hunter' or self.character == 'barrage' then
|
||||
self:die(x, y, r, 0)
|
||||
if self.ricochet <= 0 then
|
||||
self:die(x, y, r, 0)
|
||||
WallArrow{group = main.current.main, x = x, y = y, r = self.r, color = self.color}
|
||||
else
|
||||
local r = Unit.bounce(self, nx, ny)
|
||||
self.r = r
|
||||
self.ricochet = self.ricochet - 1
|
||||
end
|
||||
_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' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'spellblade' then
|
||||
self:die(x, y, r, 0)
|
||||
knife_hit_wall1:play{pitch = random:float(0.9, 1.1), volume = 0.2}
|
||||
|
@ -805,6 +881,9 @@ function Projectile:on_trigger_enter(other, contact)
|
|||
if object then
|
||||
self.r = self:angle_to_object(object)
|
||||
self.v = self.v*1.25
|
||||
if self.level == 3 and self.character == 'scout' then
|
||||
self.dmg = self.dmg*1.25
|
||||
end
|
||||
end
|
||||
end
|
||||
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = fg[0], duration = 0.1}
|
||||
|
@ -825,6 +904,10 @@ function Projectile:on_trigger_enter(other, contact)
|
|||
|
||||
other:hit(self.dmg, self)
|
||||
|
||||
if self.character == 'wizard' and self.level == 3 then
|
||||
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*32, color = self.color, dmg = self.parent.area_dmg_m*self.dmg, character = self.character}
|
||||
end
|
||||
|
||||
if self.character == 'hunter' and random:bool(40) then
|
||||
trigger:after(0.01, function()
|
||||
SpawnEffect{group = main.current.effects, x = self.parent.x, y = self.parent.y, color = orange[0], action = function(x, y)
|
||||
|
@ -877,9 +960,17 @@ function Area:init(args)
|
|||
self:init_game_object(args)
|
||||
self.shape = Rectangle(self.x, self.y, 1.5*self.w, 1.5*self.w, self.r)
|
||||
local enemies = main.current.main:get_objects_in_shape(self.shape, main.current.enemies)
|
||||
if self.character == 'saboteur' then print(self.dmg) end
|
||||
for _, enemy in ipairs(enemies) do
|
||||
if self.character == 'elementor' then
|
||||
enemy:hit(2*self.dmg)
|
||||
if self.level == 3 then
|
||||
enemy:slow(0.4, 6)
|
||||
end
|
||||
elseif self.character == 'swordsman' then
|
||||
enemy:hit(self.dmg + self.dmg*0.33*#enemies)
|
||||
elseif self.character == 'blade' and self.level == 3 then
|
||||
enemy:hit(self.dmg + self.dmg*0.5*#enemies)
|
||||
else
|
||||
enemy:hit(self.dmg)
|
||||
end
|
||||
|
@ -1081,6 +1172,8 @@ function Saboteur:init(args)
|
|||
|
||||
_G[random:table{'saboteur1', 'saboteur2', 'saboteur3'}]:play{pitch = random:float(0.8, 1.2), volume = 0.2}
|
||||
self.target = random:table(self.group:get_objects_by_classes(main.current.enemies))
|
||||
|
||||
self.actual_dmg = get_character_stat('saboteur', self.level, 'dmg')
|
||||
end
|
||||
|
||||
|
||||
|
@ -1109,7 +1202,8 @@ end
|
|||
function Saboteur:on_collision_enter(other, contact)
|
||||
if table.any(main.current.enemies, function(v) return other:is(v) end) then
|
||||
camera:shake(4, 0.5)
|
||||
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.area_size_m*64, color = self.color, dmg = self.area_dmg_m*self.dmg*(self.conjurer_buff_m or 1), character = self.character}
|
||||
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = (self.crit and 1.5 or 1)*self.area_size_m*64, color = self.color,
|
||||
dmg = (self.crit and 2 or 1)*self.area_dmg_m*self.actual_dmg*(self.conjurer_buff_m or 1), character = self.character}
|
||||
Area(table.merge(t, mods or {}))
|
||||
self.dead = true
|
||||
end
|
||||
|
|
20
todo
20
todo
|
@ -40,16 +40,16 @@
|
|||
Swarmer: increased critter health
|
||||
Voider: increased damage over time
|
||||
Characters
|
||||
Vagrant [psyker, ranger, warrior]: shoots a projectile - Lv.3: Champion - gains increased damage and attack speed based on number of active sets
|
||||
Swordsman [warrior]: deals AoE damage, deals extra damage for each unit hit - Lv.3: Cleave - damage is doubled
|
||||
Wizard [mage]: shoots a projectile that deals AoE damage - Lv.3: Magic Missile - the projectile chains 5 times, each dealing AoE damage on impact
|
||||
Archer [ranger]: shoots an arrow that pierces - Lv.3: Bounce Shot - the arrow ricochets on walls 3 times
|
||||
Scout [rogue]: throws a knife that chains 3 times - Lv.3: Replica - each chain grants +15% damage and the last chain splits
|
||||
Cleric [healer]: heals a unit when its health drops below half HP - Lv.3: Mass Heal - heals all units instead of one
|
||||
Outlaw [warrior, rogue]: throws a fan of 5 knives - Lv.3: Fatal Roulette - every 3rd attack throw a nova of 15 knives instead
|
||||
Blade [warrior, nuker]: throws multiple blades that deal AoE damage - Lv.3: Blade Resonance - deal additional damage based on number of enemies hit
|
||||
Elementor [mage, nuker]: deals AoE damage to a random target in a large area - Lv.3: Windfield - slows enemies hit
|
||||
Saboteur [rogue, conjurer, nuker]: calls saboteurs to seek targets and deal AoE damage - Lv.3: Chain Reaction - should an enemy die from a saboteur explosion, it also explodes
|
||||
* Vagrant [psyker, ranger, warrior]: shoots a projectile - Lv.3: Champion - gains increased damage and attack speed based on number of active sets
|
||||
* Swordsman [warrior]: deals AoE damage, deals extra damage for each unit hit - Lv.3: Cleave - damage is doubled
|
||||
* Wizard [mage]: shoots a projectile that deals AoE damage - Lv.3: Magic Missile - the projectile chains 5 times, each dealing AoE damage on impact
|
||||
* Archer [ranger]: shoots an arrow that pierces - Lv.3: Bounce Shot - the arrow ricochets on walls 3 times
|
||||
* Scout [rogue]: throws a knife that chains 3 times - Lv.3: Replica - each chain grants +15% damage and the last chain splits
|
||||
* Cleric [healer]: heals a unit when its health drops below half HP - Lv.3: Mass Heal - heals all units instead of one
|
||||
* Outlaw [warrior, rogue]: throws a fan of 5 knives - Lv.3: Fatal Roulette - every 3rd attack throw a nova of 15 knives instead
|
||||
* Blade [warrior, nuker]: throws multiple blades that deal AoE damage - Lv.3: Blade Resonance - deal additional damage based on number of enemies hit
|
||||
* Elementor [mage, nuker]: deals AoE damage to a random target in a large area - Lv.3: Windfield - slows enemies hit
|
||||
* Saboteur [rogue, conjurer, nuker]: calls saboteurs to seek targets and deal AoE damage - Lv.3: Chain Reaction - should an enemy die from a saboteur explosion, it also explodes
|
||||
Stormweaver [enchanter]: infuses all allied projectiles with chain lightning that deals extra damage - Lv.3: Lightning Spire - cast a spire of lightning periodically
|
||||
Sage [nuker]: shoots a slow moving projectile that pulls enemies in - Lv.3: Dimension Compression - when the projectile expires deal massive damage to all enemies under its influence
|
||||
Squire [warrior, enchanter]: increased damage and defense to all allies - Lv.3: Repair - you can reroll your item choice once every 3 levels, these opportunities stack if unused
|
||||
|
|
Loading…
Reference in New Issue