master
a327ex 2021-04-09 19:46:49 -03:00
parent 2e51b7b9fb
commit 1b7c4da414
7 changed files with 458 additions and 139 deletions

View File

@ -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

View File

@ -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

View File

@ -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 |

View File

@ -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
View File

@ -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, {

View File

@ -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
View File

@ -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