Loop update 3/5

master
a327ex 2021-07-03 02:08:35 -03:00
parent 95df672169
commit 894a492cc3
26 changed files with 642 additions and 187 deletions

View File

@ -330,10 +330,6 @@ function Arena:on_enter(from, level, loop, units, passives, shop_level, shop_xp,
self.t:after(1.125 + math.floor(n/4)*0.25, function() self.spawning_enemies = false end, 'spawning_enemies') self.t:after(1.125 + math.floor(n/4)*0.25, function() self.spawning_enemies = false end, 'spawning_enemies')
self.enemy_spawns_prevented = 0 self.enemy_spawns_prevented = 0
end) end)
self.level = 25*(self.loop+1)
self.won = true
self:quit()
end end
@ -392,7 +388,9 @@ function Arena:update(dt)
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike',
'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing',
} }
max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12)
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')
@ -838,7 +836,9 @@ function Arena:die()
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike',
'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing',
} }
max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12)
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')
@ -908,6 +908,8 @@ function Arena:create_credits()
open_url(b, 'https://freesound.org/people/benzix2/sounds/467951/') end} open_url(b, 'https://freesound.org/people/benzix2/sounds/467951/') end}
Button{group = self.credits, x = 204, y = 160, button_text = 'lord', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b) Button{group = self.credits, x = 204, y = 160, button_text = 'lord', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b)
open_url(b, 'https://store.steampowered.com/developer/T_TGames') end} open_url(b, 'https://store.steampowered.com/developer/T_TGames') end}
Button{group = self.credits, x = 254, y = 160, button_text = 'InspectorJ', fg_color = 'yellowm5', bg_color = 'yellow', credits_button = true, action = function(b)
open_url(b, 'https://freesound.org/people/InspectorJ/sounds/458586/') end}
Text2{group = self.credits, x = 70, y = 190, lines = {{text = '[red]playtesters: ', font = pixul_font}}} Text2{group = self.credits, x = 70, y = 190, lines = {{text = '[red]playtesters: ', font = pixul_font}}}
Button{group = self.credits, x = 130, y = 190, button_text = 'Jofer', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b) Button{group = self.credits, x = 130, y = 190, button_text = 'Jofer', fg_color = 'redm5', bg_color = 'red', credits_button = true, action = function(b)
open_url(b, 'https://twitter.com/JofersGames') end} open_url(b, 'https://twitter.com/JofersGames') end}
@ -1108,7 +1110,7 @@ function Arena:spawn_n_enemies(p, j, n, pass)
spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15} spawn1:play{pitch = random:float(0.8, 1.2), volume = 0.15}
if not pass then if not pass then
check_circle:move_to(x, y) check_circle:move_to(x, y)
local objects = self.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Player, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = self.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Player, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
if #objects > 0 then self.enemy_spawns_prevented = self.enemy_spawns_prevented + 1; return end if #objects > 0 then self.enemy_spawns_prevented = self.enemy_spawns_prevented + 1; return end
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

View File

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

View File

@ -144,7 +144,9 @@ function BuyScreen:on_enter(from, level, loop, units, passives, shop_level, shop
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike',
'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing',
} }
max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12) max_units = math.clamp(7 + current_new_game_plus + self.loop, 7, 12)
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')
@ -547,7 +549,9 @@ function RestartButton:update(dt)
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike',
'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing',
} }
system.save_state() system.save_state()
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')

View File

@ -214,6 +214,7 @@ function Seeker:init(args)
self.hp = self.max_hp self.hp = self.max_hp
local n = math.remap(current_new_game_plus, 0, 5, 1, 0.75) local n = math.remap(current_new_game_plus, 0, 5, 1, 0.75)
self.t:every({3*n, 5*n}, function() self.t:every({3*n, 5*n}, function()
if self.silenced or self.barbarian_stunned then return end
local enemy = self:get_closest_object_in_shape(Circle(self.x, self.y, 64), main.current.enemies) local enemy = self:get_closest_object_in_shape(Circle(self.x, self.y, 64), main.current.enemies)
if enemy then if enemy then
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.5} wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -247,17 +248,17 @@ function Seeker:init(args)
local player = main.current.player local player = main.current.player
if player and player.intimidation and not self.boss and not self.tank then if player and player.intimidation and not self.boss and not self.tank then
self.buff_hp_m = 0.8 self.buff_hp_m = (player.intimidation == 1 and 0.9) or (player.intimidation == 2 and 0.8) or (player.intimidation == 3 and 0.7)
self:calculate_stats() self:calculate_stats()
self.hp = self.max_hp self.hp = self.max_hp
end end
if player and player.vulnerability then if player and player.vulnerability then
self.vulnerable = true self.vulnerable = (player.vulnerability == 1 and 1.1) or (player.vulnerability == 2 and 1.2) or (player.vulnerability == 3 and 1.3)
end end
if player and player.temporal_chains then if player and player.temporal_chains then
self.temporal_chains_mvspd_m = 0.8 self.temporal_chains_mvspd_m = (player.temporal_chains and 0.9) or (player.temporal_chains and 0.8) or (player.temporal_chains and 0.7)
end end
self.usurer_count = 0 self.usurer_count = 0
@ -348,9 +349,9 @@ end
function Seeker:draw() function Seeker:draw()
graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x) graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x)
if self.boss then if self.boss then
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.hfx.hit.f and fg[0] or self.color) graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.hfx.hit.f and fg[0] or (self.silenced and bg[10]) or self.color)
else else
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color) graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or (self.silenced and bg[10]) or self.color)
end end
graphics.pop() graphics.pop()
@ -384,7 +385,7 @@ function Seeker:on_collision_enter(other, contact)
if main.current.player.heavy_impact then if main.current.player.heavy_impact then
if self.being_pushed then if self.being_pushed then
self:hit(self.push_force) self:hit(self.push_force, nil, nil, true)
end end
end end
@ -413,8 +414,8 @@ function Seeker:on_collision_enter(other, contact)
elseif table.any(main.current.enemies, function(v) return other:is(v) end) then elseif table.any(main.current.enemies, function(v) return other:is(v) end) then
if self.being_pushed and math.length(self:get_velocity()) > 60 then if self.being_pushed and math.length(self:get_velocity()) > 60 then
other:hit(math.floor(self.push_force/4)) other:hit(math.floor(self.push_force/4), nil, nil, true)
self:hit(math.floor(self.push_force/2)) self:hit(math.floor(self.push_force/2), nil, nil, true)
other:push(math.floor(self.push_force/2), other:angle_to_object(self)) other:push(math.floor(self.push_force/2), other:angle_to_object(self))
HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1} HitCircle{group = main.current.effects, x = x, y = y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end for i = 1, 2 do HitParticle{group = main.current.effects, x = x, y = y, color = self.color} end
@ -431,13 +432,13 @@ function Seeker:on_collision_enter(other, contact)
elseif other:is(Turret) then elseif other:is(Turret) then
self.headbutting = false self.headbutting = false
_G[random:table{'player_hit1', 'player_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35} _G[random:table{'player_hit1', 'player_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35}
self:hit(0) self:hit(0, nil, nil, true)
self:push(random:float(2.5, 7), other:angle_to_object(self)) self:push(random:float(2.5, 7), other:angle_to_object(self))
end end
end end
function Seeker:hit(damage, projectile, dot) function Seeker:hit(damage, projectile, dot, from_enemy)
local pyrod = self.pyrod local pyrod = self.pyrod
self.pyrod = false self.pyrod = false
if self.dead then return end if self.dead then return end
@ -445,12 +446,65 @@ function Seeker:hit(damage, projectile, dot)
if self.push_invulnerable then return end if self.push_invulnerable then return end
self:show_hp() self:show_hp()
local actual_damage = math.max(self:calculate_damage(damage)*(self.stun_dmg_m or 1), 0) local crit = 1
if self.vulnerable then actual_damage = actual_damage*1.2 end if main.current.player.critical_strike and not dot and not from_enemy then
if random:bool((main.current.player.critical_strike == 1 and 5) or (main.current.player.critical_strike == 2 and 10) or (main.current.player.critical_strike == 3 and 15)) then
crit = 2
camera:shake(2.5, 0.25)
rogue_crit1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
rogue_crit2:play{pitch = random:float(0.95, 1.05), volume = 0.15}
for i = 1, 2 do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color, v = random:float(100, 400)} end
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 12, color = fg[0], duration = 0.3}:scale_down():change_color(0.5, self.color)
end
end
if main.current.player.kinetic_strike and not dot and not from_enemy then
if random:bool((main.current.player.kinetic_strike == 1 and 10) or (main.current.player.kinetic_strike == 2 and 20) or (main.current.player.kinetic_strike == 3 and 30)) then
local units = main.current.player:get_all_units()
local cx, cy = 0, 0
for _, unit in ipairs(units) do
cx = cx + unit.x
cy = cy + unit.y
end
cx = cx/#units
cy = cy/#units
self:push(random:float(30, 60), projectile and projectile.r or self:angle_from_point(cx, cy))
end
end
if main.current.player.stunning_strike and not dot and not from_enemy then
if random:bool((main.current.player.stunning_strike == 1 and 8) or (main.current.player.stunning_strike == 2 and 16) or (main.current.player.stunning_strike == 3 and 24)) then
self:slow(0.1, 2)
self.barbarian_stunned = true
self.t:after(2, function() self.barbarian_stunned = false end)
end
end
if main.current.player.silencing_strike and not dot and not from_enemy then
if random:bool((main.current.player.silencing_strike == 1 and 8) or (main.current.player.silencing_strike == 2 and 16) or (main.current.player.silencing_strike == 3 and 24)) then
self.silenced = true
self.t:after(4, function() self.silenced = false end)
end
end
local actual_damage = math.max(self:calculate_damage(damage)*(self.stun_dmg_m or 1)*crit, 0)
if self.vulnerable then actual_damage = actual_damage*self.vulnerable end
self.hp = self.hp - actual_damage self.hp = self.hp - actual_damage
if self.hp > self.max_hp then self.hp = self.max_hp end if self.hp > self.max_hp then self.hp = self.max_hp end
main.current.damage_dealt = main.current.damage_dealt + actual_damage main.current.damage_dealt = main.current.damage_dealt + actual_damage
if main.current.player.noxious_strike and not dot and not from_enemy then
if random:bool((main.current.player.noxious_strike == 1 and 8) or (main.current.player.noxious_strike == 2 and 16) or (main.current.player.noxious_strike == 3 and 24)) then
self:apply_dot(0.6*actual_damage*(main.current.player.dot_dmg_m or 1)*(main.current.chronomancer_dot or 1), 3)
end
end
if main.current.player.burning_strike and not dot and not from_enemy then
if random:bool(15) then
self:apply_dot(0.6*actual_damage*(main.current.player.dot_dmg_m or 1)*(main.current.chronomancer_dot or 1), 3, red[0])
end
end
if dot then if dot then
self.seeping_def_m = (main.current.player.seeping == 1 and 0.85) or (main.current.player.seeping == 2 and 0.75) or (main.current.player.seeping == 3 and 0.65) or 1 self.seeping_def_m = (main.current.player.seeping == 1 and 0.85) or (main.current.player.seeping == 2 and 0.75) or (main.current.player.seeping == 3 and 0.65) or 1
self.t:after(1, function() self.t:after(1, function()
@ -472,6 +526,12 @@ function Seeker:hit(damage, projectile, dot)
end) end)
end end
if self.boss and main.current.player.culling_strike then
if self.hp <= self.max_hp*((main.current.player.culling_strike == 1 and 0.1) or (main.current.player.culling_strike == 2 and 0.2) or (main.current.player.culling_strike == 3 and 0.3)) then
self.hp = 0
end
end
if self.hp <= 0 then if self.hp <= 0 then
self.dead = true self.dead = true
for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end for i = 1, random:int(4, 6) do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end
@ -578,6 +638,54 @@ function Seeker:hit(damage, projectile, dot)
dmg = self.bane_ref.area_dmg_m*self.bane_ref.dmg*(self.bane_ref.dot_dmg_m or 1), void_rift = true, duration = 1} dmg = self.bane_ref.area_dmg_m*self.bane_ref.dmg*(self.bane_ref.dot_dmg_m or 1), void_rift = true, duration = 1}
end) end)
end end
if main.current.player.ceremonial_dagger and not from_enemy then
trigger:after(0.01, function()
if tostring(self.x) == tostring(0/0) or tostring(self.y) == tostring(0/0) then return end
_G[random:table{'scout1', 'scout2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.35}
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6}
local r = random:float(0, 2*math.pi)
local t = {group = main.current.main, x = self.x + 8*math.cos(r), y = self.y + 8*math.sin(r), v = 250, r = r, color = red[0], dmg = self.max_hp,
homing = true, character = 'jester', parent = main.current.player}
Projectile(table.merge(t, mods or {}))
end)
end
if main.current.player.homing_barrage and not from_enemy then
trigger:after(0.01, function()
if random:bool((main.current.player.homing_barrage == 1 and 8) or (main.current.player.homing_barrage == 2 and 16) or (main.current.player.homing_barrage == 3 and 24)) then
local target = main.current.player:get_closest_object_in_shape(Circle(main.current.player.x, main.current.player.y, 128), main.current.enemies)
main.current.player:barrage(target and main.current.player:angle_to_object(target) or main.current.player.r, 4, nil, nil, nil, true)
end
end)
end
if main.current.player.infesting_strike and not from_enemy then
trigger:after(0.01, function()
if random:bool((main.current.player.infesting_strike == 1 and 10) or (main.current.player.infesting_strike == 2 and 20) or (main.current.player.infesting_strike == 3 and 30)) then
critter1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
for i = 1, 2 do
Critter{group = main.current.main, x = self.x, y = self.y, color = orange[0], r = random:float(0, 2*math.pi), v = 5, dmg = main.current.player.dmg, parent = main.current.player}
end
end
end)
end
if main.current.player.lucky_strike and not from_enemy then
if random:bool(8) then
trigger:after(0.01, function()
Gold{group = main.current.main, x = self.x, y = self.y}
end)
end
end
if main.current.player.healing_strike and not from_enemy then
if random:bool(8) then
trigger:after(0.01, function()
HealingOrb{group = main.current.main, x = self.x, y = self.y}
end)
end
end
end end
end end
@ -668,13 +776,13 @@ function Seeker:curse(curse, duration, arg1, arg2, arg3)
end end
function Seeker:apply_dot(dmg, duration) function Seeker:apply_dot(dmg, duration, color)
self.t:every(0.25, function() self.t:every(0.25, function()
hit2:play{pitch = random:float(0.8, 1.2), volume = 0.2} hit2:play{pitch = random:float(0.8, 1.2), volume = 0.2}
self:hit(dmg/4, nil, true) self:hit(dmg/4, nil, true)
HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = fg[0], duration = 0.1} HitCircle{group = main.current.effects, x = self.x, y = self.y, rs = 6, color = fg[0], duration = 0.1}
for i = 1, 1 do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end for i = 1, 1 do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = self.color} end
for i = 1, 1 do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = purple[0]} end for i = 1, 1 do HitParticle{group = main.current.effects, x = self.x, y = self.y, color = color or purple[0]} end
end, math.floor(duration/0.2)) end, math.floor(duration/0.2))
end end
@ -833,7 +941,7 @@ end
function EnemyCritter:on_trigger_enter(other, contact) function EnemyCritter:on_trigger_enter(other, contact)
if other:is(Player) then if other:is(Player) then
self:die(self.x, self.y, nil, random:int(2, 3)) self:die(self.x, self.y, nil, random:int(2, 3))
other:hit(self.dmg) other:hit(self.dmg, nil, nil, true)
end end
end end
@ -978,7 +1086,7 @@ function EnemyProjectile:on_trigger_enter(other, contact)
elseif other:is(Seeker) or other:is(EnemyCritter) then elseif other:is(Seeker) or other:is(EnemyCritter) then
if self.source == 'shooter' then if self.source == 'shooter' then
self:die(self.x, self.y, nil, random:int(2, 3)) self:die(self.x, self.y, nil, random:int(2, 3))
other:hit(0.5*self.dmg) other:hit(0.5*self.dmg, nil, nil, true)
end end
end end
end end

192
main.lua
View File

@ -21,6 +21,8 @@ function init()
input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'}) input:bind('enter', {'space', 'return', 'fleft', 'fdown', 'fright'})
local s = {tags = {sfx}} local s = {tags = {sfx}}
artificer1 = Sound('458586__inspectorj__ui-mechanical-notification-01-fx.ogg', s)
explosion1 = Sound('Explosion Grenade_04.ogg', s)
mine1 = Sound('Weapon Swap 2.ogg', s) mine1 = Sound('Weapon Swap 2.ogg', s)
level_up1 = Sound('Buff 4.ogg', s) level_up1 = Sound('Buff 4.ogg', s)
unlock1 = Sound('Unlock 3.ogg', s) unlock1 = Sound('Unlock 3.ogg', s)
@ -213,7 +215,26 @@ function init()
psychosense = Image('psychosense') psychosense = Image('psychosense')
rearm = Image('rearm') rearm = Image('rearm')
taunt = Image('taunt') taunt = Image('taunt')
summon_instability = Image('summon_instability') construct_instability = Image('construct_instability')
intimidation = Image('intimidation')
vulnerability = Image('vulnerability')
temporal_chains = Image('temporal_chains')
ceremonial_dagger = Image('ceremonial_dagger')
homing_barrage = Image('homing_barrage')
critical_strike = Image('critical_strike')
noxious_strike = Image('noxious_strike')
infesting_strike = Image('infesting_strike')
kinetic_strike = Image('kinetic_strike')
burning_strike = Image('burning_strike')
lucky_strike = Image('lucky_strike')
healing_strike = Image('healing_strike')
stunning_strike = Image('stunning_strike')
silencing_strike = Image('silencing_strike')
warping_shots = Image('warping_shots')
culling_strike = Image('culling_strike')
lightning_strike = Image('lightning_strike')
psycholeak = Image('psycholeak')
divine_blessing = Image('divine_blessing')
class_colors = { class_colors = {
['warrior'] = yellow[0], ['warrior'] = yellow[0],
@ -265,12 +286,14 @@ function init()
['blade'] = 'Blade', ['blade'] = 'Blade',
['elementor'] = 'Elementor', ['elementor'] = 'Elementor',
['saboteur'] = 'Saboteur', ['saboteur'] = 'Saboteur',
['bomber'] = 'Bomber',
['stormweaver'] = 'Stormweaver', ['stormweaver'] = 'Stormweaver',
['sage'] = 'Sage', ['sage'] = 'Sage',
['squire'] = 'Squire', ['squire'] = 'Squire',
['cannoneer'] = 'Cannoneer', ['cannoneer'] = 'Cannoneer',
['dual_gunner'] = 'Dual Gunner', ['dual_gunner'] = 'Dual Gunner',
['hunter'] = 'Hunter', ['hunter'] = 'Hunter',
['sentry'] = 'Sentry',
['chronomancer'] = 'Chronomancer', ['chronomancer'] = 'Chronomancer',
['spellblade'] = 'Spellblade', ['spellblade'] = 'Spellblade',
['psykeeper'] = 'Psykeeper', ['psykeeper'] = 'Psykeeper',
@ -298,6 +321,7 @@ function init()
['flagellant'] = 'Flagellant', ['flagellant'] = 'Flagellant',
['arcanist'] = 'Arcanist', ['arcanist'] = 'Arcanist',
['illusionist'] = 'Illusionist', ['illusionist'] = 'Illusionist',
['artificer'] = 'Artificer',
['witch'] = 'Witch', ['witch'] = 'Witch',
['silencer'] = 'Silencer', ['silencer'] = 'Silencer',
['vulcanist'] = 'Vulcanist', ['vulcanist'] = 'Vulcanist',
@ -322,12 +346,14 @@ function init()
['blade'] = yellow[0], ['blade'] = yellow[0],
['elementor'] = blue[0], ['elementor'] = blue[0],
['saboteur'] = orange[0], ['saboteur'] = orange[0],
['bomber'] = orange[0],
['stormweaver'] = blue[0], ['stormweaver'] = blue[0],
['sage'] = purple[0], ['sage'] = purple[0],
['squire'] = yellow[0], ['squire'] = yellow[0],
['cannoneer'] = orange[0], ['cannoneer'] = orange[0],
['dual_gunner'] = green[0], ['dual_gunner'] = green[0],
['hunter'] = green[0], ['hunter'] = green[0],
['sentry'] = green[0],
['chronomancer'] = blue[0], ['chronomancer'] = blue[0],
['spellblade'] = blue[0], ['spellblade'] = blue[0],
['psykeeper'] = fg[0], ['psykeeper'] = fg[0],
@ -355,6 +381,7 @@ function init()
['flagellant'] = fg[0], ['flagellant'] = fg[0],
['arcanist'] = blue2[0], ['arcanist'] = blue2[0],
['illusionist'] = blue2[0], ['illusionist'] = blue2[0],
['artificer'] = blue2[0],
['witch'] = purple[0], ['witch'] = purple[0],
['silencer'] = blue2[0], ['silencer'] = blue2[0],
['vulcanist'] = red[0], ['vulcanist'] = red[0],
@ -379,12 +406,14 @@ function init()
['blade'] = 'yellow', ['blade'] = 'yellow',
['elementor'] = 'blue', ['elementor'] = 'blue',
['saboteur'] = 'orange', ['saboteur'] = 'orange',
['bomber'] = 'orange',
['stormweaver'] = 'blue', ['stormweaver'] = 'blue',
['sage'] = 'purple', ['sage'] = 'purple',
['squire'] = 'yellow', ['squire'] = 'yellow',
['cannoneer'] = 'orange', ['cannoneer'] = 'orange',
['dual_gunner'] = 'green', ['dual_gunner'] = 'green',
['hunter'] = 'green', ['hunter'] = 'green',
['sentry'] = 'green',
['chronomancer'] = 'blue', ['chronomancer'] = 'blue',
['spellblade'] = 'blue', ['spellblade'] = 'blue',
['psykeeper'] = 'fg', ['psykeeper'] = 'fg',
@ -412,6 +441,7 @@ function init()
['flagellant'] = 'fg', ['flagellant'] = 'fg',
['arcanist'] = 'blue2', ['arcanist'] = 'blue2',
['illusionist'] = 'blue2', ['illusionist'] = 'blue2',
['artificer'] = 'blue2',
['witch'] = 'purple', ['witch'] = 'purple',
['silencer'] = 'blue2', ['silencer'] = 'blue2',
['vulcanist'] = 'red', ['vulcanist'] = 'red',
@ -435,13 +465,15 @@ function init()
['outlaw'] = {'warrior', 'rogue'}, ['outlaw'] = {'warrior', 'rogue'},
['blade'] = {'warrior', 'nuker'}, ['blade'] = {'warrior', 'nuker'},
['elementor'] = {'mage', 'nuker'}, ['elementor'] = {'mage', 'nuker'},
['saboteur'] = {'rogue', 'conjurer', 'nuker'}, -- ['saboteur'] = {'rogue', 'conjurer', 'nuker'},
['bomber'] = {'nuker', 'conjurer'},
['stormweaver'] = {'enchanter'}, ['stormweaver'] = {'enchanter'},
['sage'] = {'nuker', 'forcer'}, ['sage'] = {'nuker', 'forcer'},
['squire'] = {'warrior', 'enchanter'}, ['squire'] = {'warrior', 'enchanter'},
['cannoneer'] = {'ranger', 'nuker'}, ['cannoneer'] = {'ranger', 'nuker'},
['dual_gunner'] = {'ranger', 'rogue'}, ['dual_gunner'] = {'ranger', 'rogue'},
['hunter'] = {'ranger', 'conjurer', 'forcer'}, -- ['hunter'] = {'ranger', 'conjurer', 'forcer'},
['sentry'] = {'ranger', 'conjurer'},
['chronomancer'] = {'mage', 'enchanter'}, ['chronomancer'] = {'mage', 'enchanter'},
['spellblade'] = {'mage', 'rogue'}, ['spellblade'] = {'mage', 'rogue'},
['psykeeper'] = {'healer', 'psyker'}, ['psykeeper'] = {'healer', 'psyker'},
@ -468,7 +500,8 @@ function init()
['infestor'] = {'curser', 'swarmer'}, ['infestor'] = {'curser', 'swarmer'},
['flagellant'] = {'psyker', 'enchanter'}, ['flagellant'] = {'psyker', 'enchanter'},
['arcanist'] = {'sorcerer'}, ['arcanist'] = {'sorcerer'},
['illusionist'] = {'sorcerer', 'conjurer'}, -- ['illusionist'] = {'sorcerer', 'conjurer'},
['artificer'] = {'sorcerer', 'conjurer'},
['witch'] = {'sorcerer', 'voider'}, ['witch'] = {'sorcerer', 'voider'},
['silencer'] = {'sorcerer', 'curser'}, ['silencer'] = {'sorcerer', 'curser'},
['vulcanist'] = {'sorcerer', 'nuker'}, ['vulcanist'] = {'sorcerer', 'nuker'},
@ -492,17 +525,19 @@ function init()
['outlaw'] = '[yellow]Warrior, [red]Rogue', ['outlaw'] = '[yellow]Warrior, [red]Rogue',
['blade'] = '[yellow]Warrior, [red]Nuker', ['blade'] = '[yellow]Warrior, [red]Nuker',
['elementor'] = '[blue]Mage, [red]Nuker', ['elementor'] = '[blue]Mage, [red]Nuker',
['saboteur'] = '[red]Rogue, [orange]Conjurer, [red]Nuker', -- ['saboteur'] = '[red]Rogue, [orange]Conjurer, [red]Nuker',
['bomber'] = '[red]Nuker, [orange]Builder',
['stormweaver'] = '[blue]Enchanter', ['stormweaver'] = '[blue]Enchanter',
['sage'] = '[red]Nuker, [yellow]Forcer', ['sage'] = '[red]Nuker, [yellow]Forcer',
['squire'] = '[yellow]Warrior, [blue]Enchanter', ['squire'] = '[yellow]Warrior, [blue]Enchanter',
['cannoneer'] = '[green]Ranger, [red]Nuker', ['cannoneer'] = '[green]Ranger, [red]Nuker',
['dual_gunner'] = '[green]Ranger, [red]Rogue', ['dual_gunner'] = '[green]Ranger, [red]Rogue',
['hunter'] = '[green]Ranger, [orange]Conjurer, [yellow]Forcer', -- ['hunter'] = '[green]Ranger, [orange]Conjurer, [yellow]Forcer',
['sentry'] = '[green]Ranger, [orange]Builder',
['chronomancer'] = '[blue]Mage, Enchanter', ['chronomancer'] = '[blue]Mage, Enchanter',
['spellblade'] = '[blue]Mage, [red]Rogue', ['spellblade'] = '[blue]Mage, [red]Rogue',
['psykeeper'] = '[green]Healer, [fg]Psyker', ['psykeeper'] = '[green]Healer, [fg]Psyker',
['engineer'] = '[orange]Conjurer', ['engineer'] = '[orange]Builder',
['plague_doctor'] = '[red]Nuker, [purple]Voider', ['plague_doctor'] = '[red]Nuker, [purple]Voider',
['barbarian'] = '[purple]Curser, [yellow]Warrior', ['barbarian'] = '[purple]Curser, [yellow]Warrior',
['juggernaut'] = '[yellow]Forcer, Warrior', ['juggernaut'] = '[yellow]Forcer, Warrior',
@ -515,7 +550,7 @@ function init()
['jester'] = '[purple]Curser, [red]Rogue', ['jester'] = '[purple]Curser, [red]Rogue',
['assassin'] = '[red]Rogue, [purple]Voider', ['assassin'] = '[red]Rogue, [purple]Voider',
['host'] = '[orange]Swarmer', ['host'] = '[orange]Swarmer',
['carver'] = '[orange]Conjurer, [green]Healer', ['carver'] = '[orange]Builder, [green]Healer',
['bane'] = '[purple]Curser, Voider', ['bane'] = '[purple]Curser, Voider',
['psykino'] = '[blue]Mage, [fg]Psyker, [yellow]Forcer', ['psykino'] = '[blue]Mage, [fg]Psyker, [yellow]Forcer',
['barrager'] = '[green]Ranger, [yellow]Forcer', ['barrager'] = '[green]Ranger, [yellow]Forcer',
@ -525,7 +560,8 @@ function init()
['infestor'] = '[purple]Curser, [orange]Swarmer', ['infestor'] = '[purple]Curser, [orange]Swarmer',
['flagellant'] = '[fg]Psyker, [blue]Enchanter', ['flagellant'] = '[fg]Psyker, [blue]Enchanter',
['arcanist'] = '[blue2]Sorcerer', ['arcanist'] = '[blue2]Sorcerer',
['illusionist'] = '[blue2]Sorcerer, [orange]Conjurer', -- ['illusionist'] = '[blue2]Sorcerer, [orange]Conjurer',
['artificer'] = '[blue2]Sorcerer, [orange]Builder',
['witch'] = '[blue2]Sorcerer, [purple]Voider', ['witch'] = '[blue2]Sorcerer, [purple]Voider',
['silencer'] = '[blue2]Sorcerer, [purple]Curser', ['silencer'] = '[blue2]Sorcerer, [purple]Curser',
['vulcanist'] = '[blue2]Sorcerer, [red]Nuker', ['vulcanist'] = '[blue2]Sorcerer, [red]Nuker',
@ -566,12 +602,14 @@ function init()
['blade'] = function(lvl) return '[fg]throws multiple blades that deal [yellow]' .. get_character_stat('blade', lvl, 'dmg') .. ' AoE[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, ['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[fg] 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,
['bomber'] = function(lvl) return '[fg]plants a bomb, when it explodes it deals [yellow]' .. 2*get_character_stat('bomber', lvl, 'dmg') .. ' AoE[fg] damage' end,
['stormweaver'] = function(lvl) return '[fg]infuses projectiles with chain lightning that deals [yellow]20%[fg] damage to [yellow]2[fg] enemies' end, ['stormweaver'] = function(lvl) return '[fg]infuses projectiles with chain lightning that deals [yellow]20%[fg] damage to [yellow]2[fg] enemies' end,
['sage'] = function(lvl) return '[fg]shoots a slow projectile that draws enemies in' end, ['sage'] = function(lvl) return '[fg]shoots a slow projectile that draws enemies in' end,
['squire'] = function(lvl) return '[yellow]+20%[fg] damage and defense to all allies' end, ['squire'] = function(lvl) return '[yellow]+20%[fg] damage and defense to all allies' end,
['cannoneer'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. 2*get_character_stat('cannoneer', lvl, 'dmg') .. ' AoE[fg] damage' end, ['cannoneer'] = function(lvl) return '[fg]shoots a projectile that deals [yellow]' .. 2*get_character_stat('cannoneer', lvl, 'dmg') .. ' AoE[fg] damage' end,
['dual_gunner'] = function(lvl) return '[fg]shoots two parallel projectiles, each dealing [yellow]' .. get_character_stat('dual_gunner', lvl, 'dmg') .. '[fg] damage' end, ['dual_gunner'] = function(lvl) return '[fg]shoots two parallel projectiles, each dealing [yellow]' .. get_character_stat('dual_gunner', lvl, 'dmg') .. '[fg] damage' 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, ['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,
['sentry'] = function(lvl) return '[fg]spawns a rotating turret that shoots [yellow]4[fg] projectiles, each dealing [yellow]' .. get_character_stat('sentry', lvl, 'dmg') .. '[fg] damage' end,
['chronomancer'] = function(lvl) return '[yellow]+20%[fg] attack speed 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, ['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]creates [yellow]1[fg] healing orb every time the psykeeper takes [yellow]20%[fg] of its max HP in damage' end, ['psykeeper'] = function(lvl) return '[fg]creates [yellow]1[fg] healing orb every time the psykeeper takes [yellow]20%[fg] of its max HP in damage' end,
@ -589,7 +627,7 @@ function init()
['assassin'] = function(lvl) return '[fg]throws a piercing knife that deals [yellow]' .. get_character_stat('assassin', lvl, 'dmg') .. '[fg] damage + [yellow]' .. ['assassin'] = function(lvl) return '[fg]throws a piercing knife that deals [yellow]' .. get_character_stat('assassin', lvl, 'dmg') .. '[fg] damage + [yellow]' ..
get_character_stat('assassin', lvl, 'dmg')/2 .. '[fg] damage per second' end, get_character_stat('assassin', lvl, 'dmg')/2 .. '[fg] damage per second' end,
['host'] = function(lvl) return '[fg]periodically spawn [yellow]1[fg] small critter' end, ['host'] = function(lvl) return '[fg]periodically spawn [yellow]1[fg] small critter' end,
['carver'] = function(lvl) return '[fg]carves a statue that periodically heals [yellow]1[fg] unit for [yellow]20%[fg] max HP if in range' end, ['carver'] = function(lvl) return '[fg]carves a statue that creates [yellow]1[fg] healing orb every [yellow]6[fg] seconds' end,
['bane'] = function(lvl) return '[fg]curses [yellow]6[fg] nearby enemies for [yellow]6[fg] seconds, they will create small void rifts on death' end, ['bane'] = function(lvl) return '[fg]curses [yellow]6[fg] nearby enemies for [yellow]6[fg] seconds, they will create small void rifts on death' end,
['psykino'] = function(lvl) return '[fg]pulls enemies together for [yellow]2[fg] seconds' end, ['psykino'] = function(lvl) return '[fg]pulls enemies together for [yellow]2[fg] seconds' end,
['barrager'] = function(lvl) return '[fg]shoots a barrage of [yellow]3[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end, ['barrager'] = function(lvl) return '[fg]shoots a barrage of [yellow]3[fg] arrows, each dealing [yellow]' .. get_character_stat('barrager', lvl, 'dmg') .. '[fg] damage and pushing enemies' end,
@ -600,6 +638,7 @@ function init()
['flagellant'] = function(lvl) return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', lvl, 'dmg') .. '[fg] damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end, ['flagellant'] = function(lvl) return '[fg]deals [yellow]' .. 2*get_character_stat('flagellant', lvl, 'dmg') .. '[fg] damage to self and grants [yellow]+4%[fg] damage to all allies per cast' end,
['arcanist'] = function(lvl) return '[fg]launches a slow moving orb that launches projectiles, each dealing [yellow]' .. get_character_stat('arcanist', lvl, 'dmg') .. '[fg] damage' end, ['arcanist'] = function(lvl) return '[fg]launches a slow moving orb that launches projectiles, each dealing [yellow]' .. get_character_stat('arcanist', lvl, 'dmg') .. '[fg] damage' end,
['illusionist'] = function(lvl) return '[fg]launches a projectile that deals [yellow]' .. get_character_stat('illusionist', lvl, 'dmg') .. '[fg] damage and creates copies that do the same' end, ['illusionist'] = function(lvl) return '[fg]launches a projectile that deals [yellow]' .. get_character_stat('illusionist', lvl, 'dmg') .. '[fg] damage and creates copies that do the same' end,
['artificer'] = function(lvl) return '[fg]spawns an automaton that shoots a projectile that deals [yellow]' .. get_character_stat('artificer', lvl, 'dmg') .. '[fg] damage' end,
['witch'] = function(lvl) return '[fg]creates an area that ricochets and deals [yellow]' .. get_character_stat('witch', lvl, 'dmg') .. '[fg] damage per second' end, ['witch'] = function(lvl) return '[fg]creates an area that ricochets and deals [yellow]' .. get_character_stat('witch', lvl, 'dmg') .. '[fg] damage per second' end,
['silencer'] = function(lvl) return '[fg]curses [yellow]5[fg] nearby enemies for [yellow]6[fg] seconds, preventing them from using special attacks' end, ['silencer'] = function(lvl) return '[fg]curses [yellow]5[fg] nearby enemies for [yellow]6[fg] seconds, preventing them from using special attacks' end,
['vulcanist'] = function(lvl) return '[fg]creates a volcano that explodes the nearby area [yellow]4[fg] times, dealing [yellow]' .. get_character_stat('vulcanist', lvl, 'dmg') .. ' AoE [fg]damage' end, ['vulcanist'] = function(lvl) return '[fg]creates a volcano that explodes the nearby area [yellow]4[fg] times, dealing [yellow]' .. get_character_stat('vulcanist', lvl, 'dmg') .. ' AoE [fg]damage' end,
@ -619,17 +658,19 @@ function init()
['magician'] = '[blue]Ethereal Form', ['magician'] = '[blue]Ethereal Form',
['archer'] = '[green]Bounce Shot', ['archer'] = '[green]Bounce Shot',
['scout'] = '[red]Dagger Resonance', ['scout'] = '[red]Dagger Resonance',
['cleric'] = '[green]Mass Heal ', ['cleric'] = '[green]Mass Heal',
['outlaw'] = '[red]Flying Daggers', ['outlaw'] = '[red]Flying Daggers',
['blade'] = '[yellow]Blade Resonance', ['blade'] = '[yellow]Blade Resonance',
['elementor'] = '[blue]Windfield', ['elementor'] = '[blue]Windfield',
['saboteur'] = '[orange]Demoman', ['saboteur'] = '[orange]Demoman',
['bomber'] = '[orange]Demoman',
['stormweaver'] = '[blue]Wide Lightning', ['stormweaver'] = '[blue]Wide Lightning',
['sage'] = '[purple]Dimension Compression', ['sage'] = '[purple]Dimension Compression',
['squire'] = '[yellow]Shiny Gear', ['squire'] = '[yellow]Shiny Gear',
['cannoneer'] = '[orange]Cannon Barrage', ['cannoneer'] = '[orange]Cannon Barrage',
['dual_gunner'] = '[green]Gun Kata', ['dual_gunner'] = '[green]Gun Kata',
['hunter'] = '[green]Feral Pack', ['hunter'] = '[green]Feral Pack',
['sentry'] = '[green]Sentry Barrage',
['chronomancer'] = '[blue]Quicken', ['chronomancer'] = '[blue]Quicken',
['spellblade'] = '[blue]Spiralism', ['spellblade'] = '[blue]Spiralism',
['psykeeper'] = '[fg]Crucio', ['psykeeper'] = '[fg]Crucio',
@ -657,6 +698,7 @@ function init()
['flagellant'] = '[red]Zealotry', ['flagellant'] = '[red]Zealotry',
['arcanist'] = '[blue2]Arcane Orb', ['arcanist'] = '[blue2]Arcane Orb',
['illusionist'] = '[blue2]Mirror Image', ['illusionist'] = '[blue2]Mirror Image',
['artificer'] = '[blue2]Spell Formula Efficiency',
['witch'] = '[purple]Death Pool', ['witch'] = '[purple]Death Pool',
['silencer'] = '[blue2]Arcane Curse', ['silencer'] = '[blue2]Arcane Curse',
['vulcanist'] = '[red]Lava Burst', ['vulcanist'] = '[red]Lava Burst',
@ -681,12 +723,14 @@ function init()
['blade'] = '[light_bg]Blade Resonance', ['blade'] = '[light_bg]Blade Resonance',
['elementor'] = '[light_bg]Windfield', ['elementor'] = '[light_bg]Windfield',
['saboteur'] = '[light_bg]Demoman', ['saboteur'] = '[light_bg]Demoman',
['bomber'] = '[light_bg]Demoman',
['stormweaver'] = '[light_bg]Wide Lightning', ['stormweaver'] = '[light_bg]Wide Lightning',
['sage'] = '[light_bg]Dimension Compression', ['sage'] = '[light_bg]Dimension Compression',
['squire'] = '[light_bg]Shiny Gear', ['squire'] = '[light_bg]Shiny Gear',
['cannoneer'] = '[light_bg]Cannon Barrage', ['cannoneer'] = '[light_bg]Cannon Barrage',
['dual_gunner'] = '[light_bg]Gun Kata', ['dual_gunner'] = '[light_bg]Gun Kata',
['hunter'] = '[light_bg]Feral Pack', ['hunter'] = '[light_bg]Feral Pack',
['sentry'] = '[light_bg]Sentry Barrage',
['chronomancer'] = '[light_bg]Quicken', ['chronomancer'] = '[light_bg]Quicken',
['spellblade'] = '[light_bg]Spiralism', ['spellblade'] = '[light_bg]Spiralism',
['psykeeper'] = '[light_bg]Crucio', ['psykeeper'] = '[light_bg]Crucio',
@ -714,6 +758,7 @@ function init()
['flagellant'] = '[light_bg]Zealotry', ['flagellant'] = '[light_bg]Zealotry',
['arcanist'] = '[light_bg]Arcane Orb', ['arcanist'] = '[light_bg]Arcane Orb',
['illusionist'] = '[light_bg]Mirror Image', ['illusionist'] = '[light_bg]Mirror Image',
['artificer'] = '[light_bg]Spell Formula Efficiency',
['witch'] = '[light_bg]Death Pool', ['witch'] = '[light_bg]Death Pool',
['silencer'] = '[light_bg]Arcane Curse', ['silencer'] = '[light_bg]Arcane Curse',
['vulcanist'] = '[light_bg]Lava Burst', ['vulcanist'] = '[light_bg]Lava Burst',
@ -738,12 +783,14 @@ function init()
['blade'] = function() return '[fg]deal additional [yellow]' .. math.round(get_character_stat('blade', 3, 'dmg')/3, 2) .. '[fg] damage per enemy hit' end, ['blade'] = function() return '[fg]deal additional [yellow]' .. math.round(get_character_stat('blade', 3, 'dmg')/3, 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, ['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, ['saboteur'] = function() return '[fg]the explosion has [yellow]50%[fg] chance to crit, increasing in size and dealing [yellow]2x[fg] damage' end,
['bomber'] = function() return '[yellow]+100%[fg] bomb area and damage' end,
['stormweaver'] = function() return "[fg]chain lightning's trigger area of effect and number of units hit is [yellow]doubled" end, ['stormweaver'] = function() return "[fg]chain lightning's trigger area of effect and number of units hit is [yellow]doubled" end,
['sage'] = function() return '[fg]when the projectile expires deal [yellow]' .. 3*get_character_stat('sage', 3, 'dmg') .. '[fg] damage to all enemies under its influence' end, ['sage'] = function() return '[fg]when the projectile expires deal [yellow]' .. 3*get_character_stat('sage', 3, 'dmg') .. '[fg] damage to all enemies under its influence' end,
['squire'] = function() return '[yellow]+30%[fg] damage, attack speed, movement speed and defense to all allies' end, ['squire'] = function() return '[yellow]+30%[fg] damage, attack speed, movement speed and defense to all allies' end,
['cannoneer'] = function() return '[fg]showers the hit area in [yellow]7[fg] additional cannon shots that deal [yellow]' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. '[fg] AoE damage' end, ['cannoneer'] = function() return '[fg]showers the hit area in [yellow]7[fg] additional cannon shots that deal [yellow]' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. '[fg] AoE damage' end,
['dual_gunner'] = function() return '[fg]every 5th attack shoot in rapid succession for [yellow]2[fg] seconds' end, ['dual_gunner'] = function() return '[fg]every 5th attack shoot in rapid succession for [yellow]2[fg] seconds' end,
['hunter'] = function() return '[fg]summons [yellow]3[fg] pets and the pets ricochet off walls once' end, ['hunter'] = function() return '[fg]summons [yellow]3[fg] pets and the pets ricochet off walls once' end,
['sentry'] = function() return '[yellow]+50%[fg] sentry attack speed and the projectiles ricochet [yellow]twice[fg]' end,
['chronomancer'] = function() return '[fg]enemies take damage over time [yellow]50%[fg] faster' end, ['chronomancer'] = function() return '[fg]enemies take damage over time [yellow]50%[fg] faster' end,
['spellblade'] = function() return '[fg]faster projectile speed and tighter turns' end, ['spellblade'] = function() return '[fg]faster projectile speed and tighter turns' end,
['psykeeper'] = function() return '[fg]deal [yellow]double[fg] the damage taken by the psykeeper to all enemies' end, ['psykeeper'] = function() return '[fg]deal [yellow]double[fg] the damage taken by the psykeeper to all enemies' end,
@ -760,7 +807,7 @@ function init()
['jester'] = function() return '[fg]all knives seek enemies and pierce [yellow]2[fg] times' end, ['jester'] = function() return '[fg]all knives seek enemies and pierce [yellow]2[fg] times' end,
['assassin'] = function() return '[fg]poison inflicted from crits deals [yellow]8x[fg] damage' end, ['assassin'] = function() return '[fg]poison inflicted from crits deals [yellow]8x[fg] damage' end,
['host'] = function() return '[fg][yellow]+100%[fg] critter spawn rate and spawn [yellow]2[fg] critters instead' end, ['host'] = function() return '[fg][yellow]+100%[fg] critter spawn rate and spawn [yellow]2[fg] critters instead' end,
['carver'] = function() return '[fg]carves a tree that heals [yellow]twice[fg] as fast, in a bigger area, and heals [yellow]2[fg] units instead' end, ['carver'] = function() return '[fg]carves a tree that creates healing orbs [yellow]twice[fg] as fast' end,
['bane'] = function() return "[yellow]100%[fg] increased area for bane's void rifts" end, ['bane'] = function() return "[yellow]100%[fg] increased area for bane's void rifts" end,
['psykino'] = function() return '[fg]enemies take [yellow]' .. 4*get_character_stat('psykino', 3, 'dmg') .. '[fg] damage and are pushed away when the area expires' end, ['psykino'] = function() return '[fg]enemies take [yellow]' .. 4*get_character_stat('psykino', 3, 'dmg') .. '[fg] damage and are pushed away when the area expires' end,
['barrager'] = function() return '[fg]every 3rd attack the barrage shoots [yellow]15[fg] projectiles and they push harder' end, ['barrager'] = function() return '[fg]every 3rd attack the barrage shoots [yellow]15[fg] projectiles and they push harder' end,
@ -771,6 +818,7 @@ function init()
['flagellant'] = function() return '[yellow]2X[fg] flagellant max HP and grants [yellow]+12%[fg] damage to all allies per cast instead' end, ['flagellant'] = function() return '[yellow]2X[fg] flagellant max HP and grants [yellow]+12%[fg] damage to all allies per cast instead' end,
['arcanist'] = function() return '[yellow]+50%[fg] attack speed for the orb and [yellow]2[fg] projectiles are released per cast' end, ['arcanist'] = function() return '[yellow]+50%[fg] attack speed for the orb and [yellow]2[fg] projectiles are released per cast' end,
['illusionist'] = function() return '[yellow]doubles[fg] the number of copies created and they release [yellow]12[fg] projectiles on death' end, ['illusionist'] = function() return '[yellow]doubles[fg] the number of copies created and they release [yellow]12[fg] projectiles on death' end,
['artificer'] = function() return '[fg]automatons shoot and move 50% faster and release [yellow]12[fg] projectiles on death' end,
['witch'] = function() return '[fg]the area releases projectiles, each dealing [yellow]' .. get_character_stat('witch', 3, 'dmg') .. '[fg] damage and chaining once' end, ['witch'] = function() return '[fg]the area releases projectiles, each dealing [yellow]' .. get_character_stat('witch', 3, 'dmg') .. '[fg] damage and chaining once' end,
['silencer'] = function() return '[fg]the curse also deals [yellow]' .. get_character_stat('silencer', 3, 'dmg') .. '[fg] damage per second' end, ['silencer'] = function() return '[fg]the curse also deals [yellow]' .. get_character_stat('silencer', 3, 'dmg') .. '[fg] damage per second' end,
['vulcanist'] = function() return '[fg]the number and speed of explosions is [yellow]doubled[fg]' end, ['vulcanist'] = function() return '[fg]the number and speed of explosions is [yellow]doubled[fg]' end,
@ -795,12 +843,14 @@ function init()
['blade'] = function() return '[light_bg]deal additional ' .. math.round(get_character_stat('blade', 3, 'dmg')/2, 2) .. ' damage per enemy hit' end, ['blade'] = function() return '[light_bg]deal additional ' .. math.round(get_character_stat('blade', 3, 'dmg')/2, 2) .. ' damage per enemy hit' end,
['elementor'] = function() return '[light_bg]slows enemies by 60% for 6 seconds on hit' end, ['elementor'] = function() return '[light_bg]slows enemies by 60% for 6 seconds on hit' end,
['saboteur'] = function() return '[light_bg]the explosion has 50% chance to crit, increasing in size and dealing 2x damage' end, ['saboteur'] = function() return '[light_bg]the explosion has 50% chance to crit, increasing in size and dealing 2x damage' end,
['bomber'] = function() return '[light_bg]+100% bomb area and damage' end,
['stormweaver'] = function() return "[light_bg]chain lightning's trigger area of effect and number of units hit is doubled" end, ['stormweaver'] = function() return "[light_bg]chain lightning's trigger area of effect and number of units hit is doubled" end,
['sage'] = function() return '[light_bg]when the projectile expires deal ' .. 3*get_character_stat('sage', 3, 'dmg') .. ' damage to all enemies under its influence' end, ['sage'] = function() return '[light_bg]when the projectile expires deal ' .. 3*get_character_stat('sage', 3, 'dmg') .. ' damage to all enemies under its influence' end,
['squire'] = function() return '[light_bg]+30% damage, attack speed, movement speed and defense to all allies' end, ['squire'] = function() return '[light_bg]+30% damage, attack speed, movement speed and defense to all allies' end,
['cannoneer'] = function() return '[light_bg]showers the hit area in 7 additional cannon shots that deal ' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. ' AoE damage' end, ['cannoneer'] = function() return '[light_bg]showers the hit area in 7 additional cannon shots that deal ' .. get_character_stat('cannoneer', 3, 'dmg')/2 .. ' AoE damage' end,
['dual_gunner'] = function() return '[light_bg]every 5th attack shoot in rapid succession for 2 seconds' end, ['dual_gunner'] = function() return '[light_bg]every 5th attack shoot in rapid succession for 2 seconds' end,
['hunter'] = function() return '[light_bg]summons 3 pets and the pets ricochet off walls once' end, ['hunter'] = function() return '[light_bg]summons 3 pets and the pets ricochet off walls once' end,
['sentry'] = function() return '[light_bg]+50% attack speed and the projectiles ricochet twice' end,
['chronomancer'] = function() return '[light_bg]enemies take damage over time 50% faster' end, ['chronomancer'] = function() return '[light_bg]enemies take damage over time 50% faster' end,
['spellblade'] = function() return '[light_bg]faster projectile speed and tighter turns' end, ['spellblade'] = function() return '[light_bg]faster projectile speed and tighter turns' end,
['psykeeper'] = function() return '[light_bg]deal double the damage taken by the psykeeper to all enemies' end, ['psykeeper'] = function() return '[light_bg]deal double the damage taken by the psykeeper to all enemies' end,
@ -828,6 +878,7 @@ function init()
['flagellant'] = function() return '[light_bg]2X flagellant max HP and grants +12% damage to all allies per cast instead' end, ['flagellant'] = function() return '[light_bg]2X flagellant max HP and grants +12% damage to all allies per cast instead' end,
['arcanist'] = function() return '[light_bg]+50% attack speed for the orb and 2 projectiles are released per cast' end, ['arcanist'] = function() return '[light_bg]+50% attack speed for the orb and 2 projectiles are released per cast' end,
['illusionist'] = function() return '[light_bg]doubles the number of copies created and they release 12 projectiles on death' end, ['illusionist'] = function() return '[light_bg]doubles the number of copies created and they release 12 projectiles on death' end,
['artificer'] = function() return '[light_bg]automatons shoot and move 50% faster and release 12 projectiles on death' end,
['witch'] = function() return '[light_bg]the area periodically releases projectiles, each dealing ' .. get_character_stat('witch', 3, 'dmg') .. ' damage and chaining once' end, ['witch'] = function() return '[light_bg]the area periodically releases projectiles, each dealing ' .. get_character_stat('witch', 3, 'dmg') .. ' damage and chaining once' end,
['silencer'] = function() return '[light_bg]the curse also deals ' .. get_character_stat('silencer', 3, 'dmg') .. ' damage per second' end, ['silencer'] = function() return '[light_bg]the curse also deals ' .. get_character_stat('silencer', 3, 'dmg') .. ' damage per second' end,
['vulcanist'] = function() return '[light_bg]the number and speed of explosions is doubled' end, ['vulcanist'] = function() return '[light_bg]the number and speed of explosions is doubled' end,
@ -852,12 +903,14 @@ function init()
['blade'] = function(lvl) return get_character_stat_string('blade', lvl) end, ['blade'] = function(lvl) return get_character_stat_string('blade', lvl) end,
['elementor'] = function(lvl) return get_character_stat_string('elementor', lvl) end, ['elementor'] = function(lvl) return get_character_stat_string('elementor', lvl) end,
['saboteur'] = function(lvl) return get_character_stat_string('saboteur', lvl) end, ['saboteur'] = function(lvl) return get_character_stat_string('saboteur', lvl) end,
['bomber'] = function(lvl) return get_character_stat_string('bomber', lvl) end,
['stormweaver'] = function(lvl) return get_character_stat_string('stormweaver', lvl) end, ['stormweaver'] = function(lvl) return get_character_stat_string('stormweaver', lvl) end,
['sage'] = function(lvl) return get_character_stat_string('sage', lvl) end, ['sage'] = function(lvl) return get_character_stat_string('sage', lvl) end,
['squire'] = function(lvl) return get_character_stat_string('squire', lvl) end, ['squire'] = function(lvl) return get_character_stat_string('squire', lvl) end,
['cannoneer'] = function(lvl) return get_character_stat_string('cannoneer', lvl) end, ['cannoneer'] = function(lvl) return get_character_stat_string('cannoneer', lvl) end,
['dual_gunner'] = function(lvl) return get_character_stat_string('dual_gunner', lvl) end, ['dual_gunner'] = function(lvl) return get_character_stat_string('dual_gunner', lvl) end,
['hunter'] = function(lvl) return get_character_stat_string('hunter', lvl) end, ['hunter'] = function(lvl) return get_character_stat_string('hunter', lvl) end,
['sentry'] = function(lvl) return get_character_stat_string('sentry', lvl) end,
['chronomancer'] = function(lvl) return get_character_stat_string('chronomancer', lvl) end, ['chronomancer'] = function(lvl) return get_character_stat_string('chronomancer', lvl) end,
['spellblade'] = function(lvl) return get_character_stat_string('spellblade', lvl) end, ['spellblade'] = function(lvl) return get_character_stat_string('spellblade', lvl) end,
['psykeeper'] = function(lvl) return get_character_stat_string('psykeeper', lvl) end, ['psykeeper'] = function(lvl) return get_character_stat_string('psykeeper', lvl) end,
@ -885,6 +938,7 @@ function init()
['flagellant'] = function(lvl) return get_character_stat_string('flagellant', lvl) end, ['flagellant'] = function(lvl) return get_character_stat_string('flagellant', lvl) end,
['arcanist'] = function(lvl) return get_character_stat_string('arcanist', lvl) end, ['arcanist'] = function(lvl) return get_character_stat_string('arcanist', lvl) end,
['illusionist'] = function(lvl) return get_character_stat_string('illusionist', lvl) end, ['illusionist'] = function(lvl) return get_character_stat_string('illusionist', lvl) end,
['artificer'] = function(lvl) return get_character_stat_string('artificer', lvl) end,
['witch'] = function(lvl) return get_character_stat_string('witch', lvl) end, ['witch'] = function(lvl) return get_character_stat_string('witch', lvl) end,
['silencer'] = function(lvl) return get_character_stat_string('silencer', lvl) end, ['silencer'] = function(lvl) return get_character_stat_string('silencer', lvl) end,
['vulcanist'] = function(lvl) return get_character_stat_string('vulcanist', lvl) end, ['vulcanist'] = function(lvl) return get_character_stat_string('vulcanist', lvl) end,
@ -943,7 +997,7 @@ function init()
['healer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+8%[light_bg]/[' .. ylb2(lvl) .. ']+16% [fg] chance for enemies to drop healing orbs on death' end, ['healer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+8%[light_bg]/[' .. ylb2(lvl) .. ']+16% [fg] chance for enemies to drop healing orbs on death' end,
['enchanter'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]damage to all allies' end, ['enchanter'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]damage to all allies' end,
['nuker'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]area damage and size to allied nukers' end, ['nuker'] = function(lvl) return '[' .. ylb1(lvl) .. ']3[light_bg]/[' .. ylb2(lvl) .. ']6 [fg]- [' .. ylb1(lvl) .. ']+15%[light_bg]/[' .. ylb2(lvl) .. ']+25% [fg]area damage and size to allied nukers' end,
['conjurer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]summon damage and duration' end, ['conjurer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]construct damage and duration' end,
['psyker'] = function(lvl) return '[fg]create a piercing, damaging orb around each psyker' end, ['psyker'] = function(lvl) return '[fg]create a piercing, damaging orb around each psyker' end,
['curser'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+1[light_bg]/[' .. ylb2(lvl) .. ']+3 [fg]max curse targets to allied cursers' end, ['curser'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+1[light_bg]/[' .. ylb2(lvl) .. ']+3 [fg]max curse targets to allied cursers' end,
['forcer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]knockback force to all allies' end, ['forcer'] = function(lvl) return '[' .. ylb1(lvl) .. ']2[light_bg]/[' .. ylb2(lvl) .. ']4 [fg]- [' .. ylb1(lvl) .. ']+25%[light_bg]/[' .. ylb2(lvl) .. ']+50% [fg]knockback force to all allies' end,
@ -959,8 +1013,8 @@ function init()
tier_to_characters = { tier_to_characters = {
[1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist', 'merchant'}, [1] = {'vagrant', 'swordsman', 'magician', 'archer', 'scout', 'cleric', 'arcanist', 'merchant'},
[2] = {'wizard', 'saboteur', 'sage', 'squire', 'dual_gunner', 'hunter', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw', 'miner'}, [2] = {'wizard', 'bomber', 'sage', 'squire', 'dual_gunner', 'sentry', 'chronomancer', 'barbarian', 'cryomancer', 'beastmaster', 'jester', 'carver', 'psychic', 'witch', 'silencer', 'outlaw', 'miner'},
[3] = {'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'host', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant', 'illusionist', 'usurer', 'gambler'}, [3] = {'elementor', 'stormweaver', 'spellblade', 'psykeeper', 'engineer', 'juggernaut', 'pyromancer', 'host', 'assassin', 'bane', 'barrager', 'infestor', 'flagellant', 'artificer', 'usurer', 'gambler'},
[4] = {'priest', 'highlander', 'psykino', 'fairy', 'blade', 'plague_doctor', 'cannoneer', 'vulcanist', 'warden', 'corruptor', 'thief'}, [4] = {'priest', 'highlander', 'psykino', 'fairy', 'blade', 'plague_doctor', 'cannoneer', 'vulcanist', 'warden', 'corruptor', 'thief'},
} }
@ -977,14 +1031,16 @@ function init()
['outlaw'] = 2, ['outlaw'] = 2,
['blade'] = 4, ['blade'] = 4,
['elementor'] = 3, ['elementor'] = 3,
['saboteur'] = 2, -- ['saboteur'] = 2,
['bomber'] = 2,
['wizard'] = 2, ['wizard'] = 2,
['stormweaver'] = 3, ['stormweaver'] = 3,
['sage'] = 2, ['sage'] = 2,
['squire'] = 2, ['squire'] = 2,
['cannoneer'] = 4, ['cannoneer'] = 4,
['dual_gunner'] = 2, ['dual_gunner'] = 2,
['hunter'] = 2, -- ['hunter'] = 2,
['sentry'] = 2,
['chronomancer'] = 2, ['chronomancer'] = 2,
['spellblade'] = 3, ['spellblade'] = 3,
['psykeeper'] = 3, ['psykeeper'] = 3,
@ -1011,7 +1067,8 @@ function init()
['infestor'] = 3, ['infestor'] = 3,
['flagellant'] = 3, ['flagellant'] = 3,
['arcanist'] = 1, ['arcanist'] = 1,
['illusionist'] = 3, -- ['illusionist'] = 3,
['artificer'] = 3,
['witch'] = 2, ['witch'] = 2,
['silencer'] = 2, ['silencer'] = 2,
['vulcanist'] = 4, ['vulcanist'] = 4,
@ -1026,7 +1083,7 @@ function init()
launches_projectiles = function(character) launches_projectiles = function(character)
local classes = {'vagrant', 'archer', 'scout', 'outlaw', 'blade', 'wizard', 'cannoneer', 'dual_gunner', 'hunter', 'spellblade', 'engineer', 'corruptor', 'beastmaster', 'jester', 'assassin', 'barrager', local classes = {'vagrant', 'archer', 'scout', 'outlaw', 'blade', 'wizard', 'cannoneer', 'dual_gunner', 'hunter', 'spellblade', 'engineer', 'corruptor', 'beastmaster', 'jester', 'assassin', 'barrager',
'arcanist', 'illusionist', 'miner', 'thief'} 'arcanist', 'illusionist', 'artificer', 'miner', 'thief', 'sentry'}
return table.any(classes, function(v) return v == character end) return table.any(classes, function(v) return v == character end)
end end
@ -1202,7 +1259,26 @@ function init()
['psychosense'] = 'Psychosense', ['psychosense'] = 'Psychosense',
['rearm'] = 'Rearm', ['rearm'] = 'Rearm',
['taunt'] = 'Taunt', ['taunt'] = 'Taunt',
['summon_instability'] = 'Summon Instability', ['construct_instability'] = 'Construct Instability',
['intimidation'] = 'Intimidation',
['vulnerability'] = 'Vulnerability',
['temporal_chains'] = 'Temporal Chains',
['ceremonial_dagger'] = 'Ceremonial Dagger',
['homing_barrage'] = 'Homing Barrage',
['critical_strike'] = 'Critical Strike',
['noxious_strike'] = 'Noxious Strike',
['infesting_strike'] = 'Infesting Strike',
['kinetic_strike'] = 'Kinetic Strike',
['burning_strike'] = 'Burning Strike',
['lucky_strike'] = 'Lucky Strike',
['healing_strike'] = 'Healing Strike',
['stunning_strike'] = 'Stunning Strike',
['silencing_strike'] = 'Silencing Strike',
['warping_shots'] = 'Warping Shots',
['culling_strike'] = 'Culling Strike',
['lightning_strike'] = 'Lightning Strike',
['psycholeak'] = 'Psycholeak',
['divine_blessing'] = 'Divine Blessing',
} }
passive_descriptions = { passive_descriptions = {
@ -1266,9 +1342,28 @@ function init()
['orbitism'] = '[yellow]+33/66/99%[fg] orb movement speed', ['orbitism'] = '[yellow]+33/66/99%[fg] orb movement speed',
['psyker_orbs'] = '[yellow]+1/2/3[fg] psyker orbs', ['psyker_orbs'] = '[yellow]+1/2/3[fg] psyker orbs',
['psychosense'] = '[yellow]+33/66/99%[fg] orb range', ['psychosense'] = '[yellow]+33/66/99%[fg] orb range',
['rearm'] = '[fg]summons repeat their attacks once', ['rearm'] = '[fg]constructs repeat their attacks once',
['taunt'] = '[yellow]10/20/30%[fg] chance for summons to taunt nearby enemies on attack', ['taunt'] = '[yellow]10/20/30%[fg] chance for constructs to taunt nearby enemies on attack',
['summon_instability'] = '[fg]summons explode when disappearing, dealing [yellow]100/150/200%[fg] damage', ['construct_instability'] = '[fg]constructs explode when disappearing, dealing [yellow]100/150/200%[fg] damage',
['intimidation'] = '[fg]enemies spawn with [yellow]-10/20/30%[fg] max HP',
['vulnerability'] = '[fg]enemies take [yellow]+10/20/30%[fg] damage',
['temporal_chains'] = '[fg]enemies are [yellow]10/20/30%[fg] slower',
['ceremonial_dagger'] = '[fg]killing an enemy fires a homing dagger',
['homing_barrage'] = '[yellow]8/16/24%[fg] chance to release a homing barrage on enemy kill',
['critical_strike'] = '[yellow]5/10/15%[fg] chance for attacks to critically strike, dealing [yellow]2x[fg] damage',
['noxious_strike'] = '[yellow]8/16/24%[fg] chance for attacks to poison, dealing [yellow]20%[fg] dps for [yellow]3[fg] seconds',
['infesting_strike'] = '[yellow]10/20/30%[fg] chance for attacks to spawn [yellow]2[fg] critters on kill',
['kinetic_strike'] = '[yellow]10/20/30%[fg] chance for attacks to push enemies away with high force',
['burning_strike'] = '[yellow]15%[fg] chance for attacks to burn, dealing [yellow]20%[fg] dps for [yellow]3[fg] seconds',
['lucky_strike'] = '[yellow]8%[fg] chance for attacks to cause enemies to drop gold on death',
['healing_strike'] = '[yellow]8%[fg] chance for attacks to spawn a healing orb on kill',
['stunning_strike'] = '[yellow]8/16/24%[fg] chance for attacks to stun for [yellow]2[fg] seconds',
['silencing_strike'] = '[yellow]8/16/24%[fg] chance for attacks to silence for [yellow]2[fg] seconds on hit',
['warping_shots'] = 'projectiles ignore wall collisions and warp around the screen [yellow]1/2/3[fg] times',
['culling_strike'] = '[fg]instantly kill elites below [yellow]10/20/30%[fg] max HP',
['lightning_strike'] = '[yellow]5/10/15%[fg] chance for projectiles to create chain lightning, dealing [yellow]60/80/100%[fg] damage',
['psycholeak'] = '[fg]position [yellow]1[fg] generates [yellow]1[fg] psyker orb every [yellow]10[fg] seconds',
['divine_blessing'] = '[fg]generate [yellow]1[fg] healing orb every [yellow]8[fg] seconds',
} }
local ts = function(lvl, a, b, c) return '[' .. ylb1(lvl) .. ']' .. tostring(a) .. '[light_bg]/[' .. ylb2(lvl) .. ']' .. tostring(b) .. '[light_bg]/[' .. ylb3(lvl) .. ']' .. tostring(c) .. '[fg]' end local ts = function(lvl, a, b, c) return '[' .. ylb1(lvl) .. ']' .. tostring(a) .. '[light_bg]/[' .. ylb2(lvl) .. ']' .. tostring(b) .. '[light_bg]/[' .. ylb3(lvl) .. ']' .. tostring(c) .. '[fg]' end
@ -1333,9 +1428,28 @@ function init()
['orbitism'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb movement speed' end, ['orbitism'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb movement speed' end,
['psyker_orbs'] = function(lvl) return ts(lvl, '+1', '2', '3') .. ' psyker orbs' end, ['psyker_orbs'] = function(lvl) return ts(lvl, '+1', '2', '3') .. ' psyker orbs' end,
['psychosense'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb range' end, ['psychosense'] = function(lvl) return ts(lvl, '+33%', '66%', '99%') .. ' orb range' end,
['rearm'] = function(lvl) return '[fg]summons repeat their attacks once' end, ['rearm'] = function(lvl) return '[fg]constructs repeat their attacks once' end,
['taunt'] = function(lvl) return ts(lvl, '10%', '20%', '30%') .. ' chance for summons to taunt nearby enemies on attack' end, ['taunt'] = function(lvl) return ts(lvl, '10%', '20%', '30%') .. ' chance for constructs to taunt nearby enemies on attack' end,
['summon_instability'] = function(lvl) return '[fg]summons explode when disappearing, dealing [yellow]100/150/200%[fg] damage' end, ['construct_instability'] = function(lvl) return '[fg]constructs explode when disappearing, dealing ' .. ts(lvl, '100', '150', '200%') .. ' damage' end,
['intimidation'] = function(lvl) return '[fg]enemies spawn with ' .. ts(lvl, '-10', '20', '30%') .. ' max HP' end,
['vulnerability'] = function(lvl) return '[fg]enemies take ' .. ts(lvl, '+10', '20', '30%').. ' damage' end,
['temporal_chains'] = function(lvl) return '[fg]enemies are ' .. ts(lvl, '10', '20', '30%').. ' slower' end,
['ceremonial_dagger'] = function(lvl) return '[fg]killing an enemy fires a homing dagger' end,
['homing_barrage'] = function(lvl) return ts(lvl, '8', '16', '24%') .. ' chance to release a homing barrage on enemy kill' end,
['critical_strike'] = function(lvl) return ts(lvl, '5', '10', '15%') .. ' chance for attacks to critically strike, dealing [yellow]2x[fg] damage' end,
['noxious_strike'] = function(lvl) return ts(lvl, '8', '16', '24%') .. ' chance for attacks to poison, dealing [yellow]20%[fg] dps for [yellow]3[fg] seconds' end,
['infesting_strike'] = function(lvl) return ts(lvl, '10', '20', '30%') .. ' chance for attacks to spawn [yellow]2[fg] critters on kill' end,
['kinetic_strike'] = function(lvl) return ts(lvl, '10', '20', '30%') .. ' chance for attacks to push enemies away with high force' end,
['burning_strike'] = function(lvl) return '[yellow]15%[fg] chance for attacks to burn, dealing [yellow]20%[fg] dps for [yellow]3[fg] seconds' end,
['lucky_strike'] = function(lvl) return '[yellow]8%[fg] chance for attacks to cause enemies to drop gold on death' end,
['healing_strike'] = function(lvl) return '[yellow]8%[fg] chance for attacks to spawn a healing orb on kill' end,
['stunning_strike'] = function(lvl) return ts(lvl, '8', '16', '24%') .. ' chance for attacks to stun for [yellow]2[fg] seconds' end,
['silencing_strike'] = function(lvl) return ts(lvl, '8', '16', '24%') .. ' chance for attacks to silence for [yellow]2[fg] seconds on hit' end,
['warping_shots'] = function(lvl) return 'projectiles ignore wall collisions and warp around the screen ' .. ts(lvl, '1', '2', '3') .. ' times' end,
['culling_strike'] = function(lvl) return '[fg]instantly kill elites below ' .. ts(lvl, '10', '20', '30%') .. ' max HP' end,
['lightning_strike'] = function(lvl) return ts(lvl, '5', '10', '15%') .. ' chance for projectiles to create chain lightning, dealing ' .. ts(lvl, '60', '80', '100%') .. ' damage' end,
['psycholeak'] = function(lvl) return '[fg]position [yellow]1[fg] generates [yellow]1[fg] psyker orb every [yellow]10[fg] seconds' end,
['divine_blessing'] = function(lvl) return '[fg]generate [yellow]1[fg] healing orb every [yellow]8[fg] seconds' end,
} }
level_to_tier_weights = { level_to_tier_weights = {
@ -1571,7 +1685,7 @@ function init()
unlevellable_items = { unlevellable_items = {
'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'annihilation', 'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'annihilation',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'divine_punishment', 'unleash', 'freezing_field', 'burning_field', 'gravity_field', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'divine_punishment', 'unleash', 'freezing_field', 'burning_field', 'gravity_field',
'magnetism', 'insurance', 'dividends', 'haste', 'rearm', 'magnetism', 'insurance', 'dividends', 'haste', 'rearm', 'ceremonial_dagger', 'burning_strike', 'lucky_strike', 'healing_strike', 'psycholeak', 'divine_blessing'
} }
steam.userStats.requestCurrentStats() steam.userStats.requestCurrentStats()
@ -1584,8 +1698,10 @@ function init()
main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5} main_song_instance = _G[random:table{'song1', 'song2', 'song3', 'song4', 'song5'}]:play{volume = 0.5}
main = Main() main = Main()
--[[
main:add(MainMenu'mainmenu') main:add(MainMenu'mainmenu')
main:go_to('mainmenu') main:go_to('mainmenu')
]]--
--[[ --[[
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')
@ -1593,33 +1709,25 @@ function init()
-- main:go_to('buy_screen', 7, run.units or {}, {'unleash'}) -- main:go_to('buy_screen', 7, run.units or {}, {'unleash'})
]]-- ]]--
--[[
gold = 10 gold = 10
run_passive_pool = { run_passive_pool = {
'centipede', 'ouroboros_technique_r', 'ouroboros_technique_l', 'amplify', 'resonance', 'ballista', 'call_of_the_void', 'crucio', 'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7', 'centipede', 'ouroboros_technique_r', 'ouroboros_technique_l', 'amplify', 'resonance', 'ballista', 'call_of_the_void', 'crucio', 'speed_3', 'damage_4', 'shoot_5', 'death_6', 'lasting_7',
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
'intimidation', 'vulnerability', 'temporal_chains', 'ceremonial_dagger', 'homing_barrage', 'critical_strike', 'noxious_strike', 'infesting_strike', 'burning_strike', 'lucky_strike', 'healing_strike', 'stunning_strike',
'silencing_strike', 'culling_strike', 'lightning_strike', 'psycholeak', 'divine_blessing',
} }
main:add(Arena'arena') main:add(Arena'arena')
main:go_to('arena', 1, { main:go_to('arena', 2, 0, {
{character = 'vagrant', level = 3}, {character = 'carver', level = 3},
-- {character = 'carver', level = 2}, -- {character = 'carver', level = 2},
{character = 'dual_gunner', level = 3},
-- {character = 'saboteur', level = 2}, -- {character = 'saboteur', level = 2},
-- {character = 'hunter', level = 2}, -- {character = 'hunter', level = 2},
}, { }, {
{passive = 'summon_instability', level = 3}, {passive = 'rearm', level = 1},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
{passive = 'summon_instability', level = 3},
}) })
]]--
--[[ --[[
main:add(Media'media') main:add(Media'media')
@ -1789,7 +1897,7 @@ function open_options(self)
'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom', 'defensive_stance', 'offensive_stance', 'kinetic_bomb', 'porcupine_technique', 'last_stand', 'seeping', 'deceleration', 'annihilation', 'malediction', 'hextouch', 'whispers_of_doom',
'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment', 'tremor', 'heavy_impact', 'fracture', 'meat_shield', 'hive', 'baneling_burst', 'blunt_arrow', 'explosive_arrow', 'divine_machine_arrow', 'chronomancy', 'awakening', 'divine_punishment',
'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism', 'assassination', 'flying_daggers', 'ultimatum', 'magnify', 'echo_barrage', 'unleash', 'reinforce', 'payback', 'enchanted', 'freezing_field', 'burning_field', 'gravity_field', 'magnetism',
'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'summon_instability', 'insurance', 'dividends', 'berserking', 'unwavering_stance', 'unrelenting_stance', 'blessing', 'haste', 'divine_barrage', 'orbitism', 'psyker_orbs', 'psychosense', 'rearm', 'taunt', 'construct_instability',
} }
max_units = 7 + current_new_game_plus max_units = 7 + current_new_game_plus
main:add(BuyScreen'buy_screen') main:add(BuyScreen'buy_screen')

View File

@ -310,7 +310,7 @@ function Unit:calculate_stats(first_run)
self.base_hp = 100*math.pow(2, self.level-1) self.base_hp = 100*math.pow(2, self.level-1)
self.base_dmg = 10*math.pow(2, self.level-1) self.base_dmg = 10*math.pow(2, self.level-1)
self.base_mvspd = 75 self.base_mvspd = 75
elseif self:is(Illusion) then elseif self:is(Automaton) then
self.base_hp = 100*math.pow(2, self.level-1) self.base_hp = 100*math.pow(2, self.level-1)
self.base_dmg = 10*math.pow(2, self.level-1) self.base_dmg = 10*math.pow(2, self.level-1)
self.base_mvspd = 15 self.base_mvspd = 15

View File

@ -141,14 +141,14 @@ function Player:init(args)
if self.level == 3 then if self.level == 3 then
for i = 1, 4 do for i = 1, 4 do
local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
while #objects > 0 do while #objects > 0 do
check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16))
objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
end end
SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
if #objects == 0 then if #objects == 0 then
HealingOrb{group = main.current.main, x = x, y = y} HealingOrb{group = main.current.main, x = x, y = y}
end end
@ -156,14 +156,14 @@ function Player:init(args)
end end
else else
local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
while #objects > 0 do while #objects > 0 do
check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16))
objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
end end
SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Automaton, Bomb, Volcano, Saboteur, Pet, Turret})
if #objects == 0 then if #objects == 0 then
HealingOrb{group = main.current.main, x = x, y = y} HealingOrb{group = main.current.main, x = x, y = y}
end end
@ -205,32 +205,15 @@ function Player:init(args)
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
elseif self.character == 'illusionist' then elseif self.character == 'artificer' then
self.sorcerer_count = 0 self.sorcerer_count = 0
self.attack_sensor = Circle(self.x, self.y, 96) self.attack_sensor = Circle(self.x, self.y, 96)
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() self.t:every(6, 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))
if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1
if self.sorcerer_count >= ((main.current.sorcerer_level == 3 and 2) or (main.current.sorcerer_level == 2 and 3) or (main.current.sorcerer_level == 1 and 4)) then
self:sorcerer_repeat()
self.sorcerer_count = 0
self.t:after(0.25, function()
self:shoot(self:angle_to_object(closest_enemy))
end)
end
end
end
end, nil, nil, 'shoot')
self.t:every(8, function()
self.t:every(0.25, function()
SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y) SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y)
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5} artificer1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
local check_circle = Circle(self.x, self.y, 2) local check_circle = Circle(self.x, self.y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Pet, Turret, Sentry, Bomb})
if #objects == 0 then Illusion{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1} end if #objects == 0 then Automaton{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1} end
end} end}
if main.current.sorcerer_level > 0 then if main.current.sorcerer_level > 0 then
self.sorcerer_count = self.sorcerer_count + 1 self.sorcerer_count = self.sorcerer_count + 1
@ -239,15 +222,14 @@ function Player:init(args)
self.sorcerer_count = 0 self.sorcerer_count = 0
self.t:after(0.25, function() self.t:after(0.25, function()
SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y) SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y)
illusion1:play{pitch = random:float(0.95, 1.05), volume = 0.5} artificer1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
local check_circle = Circle(self.x, self.y, 2) local check_circle = Circle(self.x, self.y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Pet, Turret, Sentry, Bomb})
if #objects == 0 then Illusion{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1} end if #objects == 0 then Automaton{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1} end
end} end}
end) end)
end end
end end
end, self.level == 3 and 2 or 1)
end) end)
elseif self.character == 'outlaw' then elseif self.character == 'outlaw' then
@ -316,6 +298,13 @@ function Player:init(args)
end, 2) end, 2)
end, nil, nil, 'spawn') end, nil, nil, 'spawn')
elseif self.character == 'bomber' then
self.t:every(8, function()
SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = self.color, action = function(x, y)
Bomb{group = main.current.main, x = x, y = y, parent = self, level = self.level, conjurer_buff_m = self.conjurer_buff_m or 1}
end}
end, nil, nil, 'spawn')
elseif self.character == 'stormweaver' then elseif self.character == 'stormweaver' then
self.t:every(8, function() self.t:every(8, function()
stormweaver1:play{pitch = random:float(0.95, 1.05), volume = 0.5} stormweaver1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -363,7 +352,7 @@ function Player:init(args)
x, y = x/2, y/2 x, y = x/2, y/2
main.current.t:every_immediate(0.1, function() main.current.t:every_immediate(0.1, function()
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Player, Seeker, EnemyCritter, Critter, Illusion, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Player, Seeker, EnemyCritter, Critter, Saboteur, Pet, Turret, Sentry, Bomb})
if #objects == 0 then if #objects == 0 then
Volcano{group = main.current.main, x = x, y = y, color = self.color, parent = self, rs = 24, level = self.level} Volcano{group = main.current.main, x = x, y = y, color = self.color, parent = self, rs = 24, level = self.level}
main.current.t:cancel('volcano_spawn') main.current.t:cancel('volcano_spawn')
@ -619,7 +608,12 @@ function Player:init(args)
elseif self.character == 'carver' then elseif self.character == 'carver' then
self.t:every(16, function() self.t:every(16, function()
Tree{group = main.current.main, x = self.x, y = self.y, color = self.color, parent = self, rs = self.area_size_m*(self.level == 3 and 128 or 64), level = self.level} Tree{group = main.current.main, x = self.x, y = self.y, color = self.color, parent = self, level = self.level}
end, nil, nil, 'spawn')
elseif self.character == 'sentry' then
self.t:every(7, function()
Sentry{group = main.current.main, x = self.x, y = self.y, color = self.color, parent = self, level = self.level}
end, nil, nil, 'spawn') end, nil, nil, 'spawn')
elseif self.character == 'bane' then elseif self.character == 'bane' then
@ -697,14 +691,14 @@ function Player:init(args)
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
for i = 1, 2 do for i = 1, 2 do
local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry})
while #objects > 0 do while #objects > 0 do
check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16))
objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Pet, Turret, Sentry, Bomb})
end end
SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry})
if #objects == 0 then if #objects == 0 then
HealingOrb{group = main.current.main, x = x, y = y} HealingOrb{group = main.current.main, x = x, y = y}
end end
@ -720,14 +714,14 @@ function Player:init(args)
heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5} heal1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5} buff1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry})
while #objects > 0 do while #objects > 0 do
check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16))
objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry})
end end
SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Pet, Turret, Sentry, Bomb})
if #objects == 0 then if #objects == 0 then
HealingOrb{group = main.current.main, x = x, y = y} HealingOrb{group = main.current.main, x = x, y = y}
end end
@ -812,7 +806,7 @@ function Player:init(args)
for i = 1, 5 do for i = 1, 5 do
SpawnEffect{group = main.current.effects, x = x, y = y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = x, y = y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton})
if #objects == 0 then HealingOrb{group = main.current.main, x = x, y = y} end if #objects == 0 then HealingOrb{group = main.current.main, x = x, y = y} end
end} end}
end end
@ -1090,6 +1084,24 @@ function Player:init(args)
end) end)
end end
if self.leader and self.psycholeak then
main.current.t:every(10, function()
local unit = main.current.player
Projectile{group = main.current.main, x = unit.x + 24*math.cos(unit.r), y = unit.y + 24*math.sin(unit.r), color = fg[0], v = 200, dmg = unit.dmg, character = 'psyker', parent = unit}
end)
end
if self.leader and self.divine_blessing then
main.current.t:every(8, function()
local x, y = random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)
SpawnEffect{group = main.current.effects, x = x, y = y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton})
if #objects == 0 then HealingOrb{group = main.current.main, x = x, y = y} end
end}
end)
end
self.mouse_control_v_buffer = {} self.mouse_control_v_buffer = {}
if main.current:is(MainMenu) then if main.current:is(MainMenu) then
@ -1516,14 +1528,14 @@ function Player:hit(damage, from_undead)
if self.stored_heal > (0.2*self.max_hp) then if self.stored_heal > (0.2*self.max_hp) then
self.stored_heal = 0 self.stored_heal = 0
local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2) local check_circle = Circle(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16), 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton})
while #objects > 0 do while #objects > 0 do
check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16)) check_circle:move_to(random:float(main.current.x1 + 16, main.current.x2 - 16), random:float(main.current.y1 + 16, main.current.y2 - 16))
objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Volcano, Saboteur, Bomb, Pet, Turret, Sentry, Automaton})
end end
SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y) SpawnEffect{group = main.current.effects, x = check_circle.x, y = check_circle.y, color = green[0], action = function(x, y)
local check_circle = Circle(x, y, 2) local check_circle = Circle(x, y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Seeker, EnemyCritter, Critter, Sentry, Volcano, Saboteur, Bomb, Pet, Turret, Automaton})
if #objects == 0 then if #objects == 0 then
HealingOrb{group = main.current.main, x = x, y = y} HealingOrb{group = main.current.main, x = x, y = y}
end end
@ -1817,7 +1829,7 @@ function Player:shoot(r, mods)
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
end end
if self.character == 'vagrant' or self.character == 'illusionist' then if self.character == 'vagrant' or self.character == 'artificer' then
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2} shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2}
elseif self.character == 'dual_gunner' then elseif self.character == 'dual_gunner' then
dual_gunner1:play{pitch = random:float(0.95, 1.05), volume = 0.3} dual_gunner1:play{pitch = random:float(0.95, 1.05), volume = 0.3}
@ -1886,7 +1898,7 @@ function Player:dot_attack(area, mods)
end end
function Player:barrage(r, n, pierce, ricochet, shoot_5) function Player:barrage(r, n, pierce, ricochet, shoot_5, homing)
n = n or 8 n = n or 8
for i = 1, n do for i = 1, n do
self.t:after((i-1)*0.075, function() self.t:after((i-1)*0.075, function()
@ -1894,7 +1906,7 @@ function Player:barrage(r, n, pierce, ricochet, shoot_5)
else archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35} end else archer1:play{pitch = random:float(0.95, 1.05), volume = 0.35} end
HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r), y = self.y + 0.8*self.shape.w*math.sin(r), rs = 6} HitCircle{group = main.current.effects, x = self.x + 0.8*self.shape.w*math.cos(r), y = self.y + 0.8*self.shape.w*math.sin(r), rs = 6}
local t = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), v = 250, r = r + random:float(-math.pi/16, math.pi/16), color = self.color, dmg = self.dmg, local t = {group = main.current.main, x = self.x + 1.6*self.shape.w*math.cos(r), y = self.y + 1.6*self.shape.w*math.sin(r), v = 250, r = r + random:float(-math.pi/16, math.pi/16), color = self.color, dmg = self.dmg,
parent = self, character = 'barrage', level = self.level, pierce = pierce or 0, ricochet = ricochet or 0, shoot_5 = shoot_5} parent = self, character = 'barrage', level = self.level, pierce = pierce or 0, ricochet = ricochet or 0, shoot_5 = shoot_5, homing = homing}
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
end) end)
end end
@ -1909,7 +1921,7 @@ Projectile:implement(Physics)
function Projectile:init(args) function Projectile:init(args)
self:init_game_object(args) self:init_game_object(args)
self.hfx:add('hit', 1) self.hfx:add('hit', 1)
self:set_as_rectangle(10, 4, 'dynamic', 'projectile') self:set_as_rectangle(10, 4, 'dynamic', main.current.player.warping_shots and 'true_ghost' or 'projectile')
self.pierce = args.pierce or 0 self.pierce = args.pierce or 0
self.chain = args.chain or 0 self.chain = args.chain or 0
self.ricochet = args.ricochet or 0 self.ricochet = args.ricochet or 0
@ -1986,7 +1998,7 @@ function Projectile:init(args)
local t = {group = main.current.main, x = self.x + 8*math.cos(r), y = self.y + 8*math.sin(r), v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, pierce = 2, character = 'arcanist_projectile', local t = {group = main.current.main, x = self.x + 8*math.cos(r), y = self.y + 8*math.sin(r), v = 250, r = r, color = self.parent.color, dmg = self.parent.dmg, pierce = 2, character = 'arcanist_projectile',
parent = self.parent, level = self.parent.level} parent = self.parent, level = self.parent.level}
local check_circle = Circle(t.x, t.y, 2) local check_circle = Circle(t.x, t.y, 2)
local objects = main.current.main:get_objects_in_shape(check_circle, {Player, Seeker, EnemyCritter, Critter, Illusion, Volcano, Saboteur, Pet, Turret}) local objects = main.current.main:get_objects_in_shape(check_circle, {Player, Seeker, EnemyCritter, Critter, Sentry, Volcano, Saboteur, Bomb, Pet, Turret, Automaton})
if #objects == 0 then Projectile(table.merge(t, mods or {})) end if #objects == 0 then Projectile(table.merge(t, mods or {})) end
end end
end) end)
@ -2162,7 +2174,7 @@ function Projectile:on_collision_enter(other, contact)
else r = 0 end else r = 0 end
if other:is(Wall) then if other:is(Wall) then
if self.character == 'archer' or self.character == 'hunter' or self.character == 'barrage' or self.character == 'barrager' then if self.character == 'archer' or self.character == 'hunter' or self.character == 'barrage' or self.character == 'barrager' or self.character == 'sentry' then
if self.ricochet <= 0 then if self.ricochet <= 0 then
self:die(x, y, r, 0) self:die(x, y, r, 0)
WallArrow{group = main.current.main, x = x, y = y, r = self.r, color = self.color} WallArrow{group = main.current.main, x = x, y = y, r = self.r, color = self.color}
@ -2183,7 +2195,7 @@ function Projectile:on_collision_enter(other, contact)
if self.character == 'spellblade' then if self.character == 'spellblade' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
end end
elseif self.character == 'illusionist_death' then elseif self.character == 'artificer_death' then
if self.ricochet <= 0 then if self.ricochet <= 0 then
self:die(x, y, r, random:int(2, 3)) self:die(x, y, r, random:int(2, 3))
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.075}
@ -2249,7 +2261,7 @@ function Projectile:on_trigger_enter(other, contact)
if self.character == 'archer' or self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'hunter' or self.character == 'spellblade' or self.character == 'engineer' or if self.character == 'archer' or self.character == 'scout' or self.character == 'outlaw' or self.character == 'blade' or self.character == 'hunter' or self.character == 'spellblade' or self.character == 'engineer' or
self.character == 'jester' or self.character == 'assassin' or self.character == 'barrager' or self.character == 'beastmaster' or self.character == 'witch' or self.character == 'miner' or self.character == 'thief' or self.character == 'jester' or self.character == 'assassin' or self.character == 'barrager' or self.character == 'beastmaster' or self.character == 'witch' or self.character == 'miner' or self.character == 'thief' or
self.character == 'psyker' then self.character == 'psyker' or self.character == 'sentry' then
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35} hit2:play{pitch = random:float(0.95, 1.05), volume = 0.35}
if self.character == 'spellblade' or self.character == 'psyker' then if self.character == 'spellblade' or self.character == 'psyker' then
magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15} magic_area1:play{pitch = random:float(0.95, 1.05), volume = 0.15}
@ -2312,6 +2324,26 @@ function Projectile:on_trigger_enter(other, contact)
end end
end end
if self.parent and self.parent.lightning_strike then
if random:bool((self.parent.lightning_strike == 1 and 5) or (self.parent.lightning_strike == 2 and 10) or (self.parent.lightning_strike == 3 and 15)) then
local src = other
for j = 1, 3 do
main.current.t:after((j-1)*0.1, function()
_G[random:table{'spark1', 'spark2', 'spark3'}]:play{pitch = random:float(0.9, 1.1), volume = 0.3}
for i = 1, 3 do
table.insert(self.infused_enemies_hit, src)
local dst = src:get_random_object_in_shape(Circle(src.x, src.y, 64), main.current.enemies, self.infused_enemies_hit)
if dst then
dst:hit(0.33*((self.parent.lightning_strike == 1 and 0.6) or (self.parent.lightning_strike == 2 and 0.8) or (self.parent.lightning_strike == 3 and 1))*self.dmg*(self.distance_dmg_m or 1))
LightningLine{group = main.current.effects, src = src, dst = dst}
src = dst
end
end
end)
end
end
end
if self.crit then if self.crit then
camera:shake(5, 0.25) camera:shake(5, 0.25)
rogue_crit1:play{pitch = random:float(0.95, 1.05), volume = 0.5} rogue_crit1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
@ -2388,7 +2420,7 @@ function Area:init(args)
elseif self.character == 'blade' then elseif self.character == 'blade' then
blade_hit1:play{pitch = random:float(0.9, 1.1), volume = 0.35} blade_hit1:play{pitch = random:float(0.9, 1.1), volume = 0.35}
hit2:play{pitch = random:float(0.95, 1.05), volume = 0.2} hit2:play{pitch = random:float(0.95, 1.05), volume = 0.2}
elseif self.character == 'saboteur' or self.character == 'pyromancer' then elseif self.character == 'saboteur' or self.character == 'pyromancer' or self.character == 'bomber' then
if self.character == 'pyromancer' then pyro2:play{pitch = random:float(0.95, 1.05), volume = 0.4} end if self.character == 'pyromancer' then pyro2:play{pitch = random:float(0.95, 1.05), volume = 0.4} end
_G[random:table{'saboteur_hit1', 'saboteur_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.2} _G[random:table{'saboteur_hit1', 'saboteur_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.2}
elseif self.character == 'cannoneer' then elseif self.character == 'cannoneer' then
@ -2729,7 +2761,7 @@ function Tree:init(args)
self:set_restitution(0.5) self:set_restitution(0.5)
self.hfx:add('hit', 1) self.hfx:add('hit', 1)
self.color = orange[0] self.color = orange[0]
self.heal_sensor = Circle(self.x, self.y, args.rs) self.heal_sensor = Circle(self.x, self.y, 48)
self.vr = 0 self.vr = 0
self.dvr = random:float(-math.pi/4, math.pi/4) self.dvr = random:float(-math.pi/4, math.pi/4)
@ -2743,6 +2775,39 @@ function Tree:init(args)
self.t:tween(0.05, self, {rs = args.rs}, math.cubic_in_out, function() self.spring:pull(0.15) end) self.t:tween(0.05, self, {rs = args.rs}, math.cubic_in_out, function() self.spring:pull(0.15) end)
self.t:after(0.2, function() self.color = args.color end) self.t:after(0.2, function() self.color = args.color end)
self.t:every(self.parent.level == 3 and 3 or 6, function()
self.hfx:use('hit', 0.2)
HealingOrb{group = main.current.main, x = self.x, y = self.y}
if self.parent.taunt and random:bool((self.parent.taunt == 1 and 10) or (self.parent.taunt == 2 and 20) or (self.parent.taunt == 3 and 30)) then
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 96), main.current.enemies)
if #enemies > 0 then
for _, enemy in ipairs(enemies) do
enemy.taunted = self
enemy.t:after(4, function() enemy.taunted = false end, 'taunt')
end
end
end
if self.parent.rearm then
self.t:after(0.25, function()
self.hfx:use('hit', 0.2)
HealingOrb{group = main.current.main, x = self.x, y = self.y}
if self.parent.taunt and random:bool((self.parent.taunt == 1 and 10) or (self.parent.taunt == 2 and 20) or (self.parent.taunt == 3 and 30)) then
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 96), main.current.enemies)
if #enemies > 0 then
for _, enemy in ipairs(enemies) do
enemy.taunted = self
enemy.t:after(4, function() enemy.taunted = false end, 'taunt')
end
end
end
end)
end
end)
--[[
self.t:cooldown(3.33/(self.level == 3 and 2 or 1), function() return #self:get_objects_in_shape(self.heal_sensor, {Player}) > 0 end, function() self.t:cooldown(3.33/(self.level == 3 and 2 or 1), function() return #self:get_objects_in_shape(self.heal_sensor, {Player}) > 0 end, function()
local n = n or random:int(3, 4) local n = n or random:int(3, 4)
for i = 1, n do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end for i = 1, n do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end
@ -2815,14 +2880,15 @@ function Tree:init(args)
end end
end end
end) end)
]]--
self.t:after(10*(self.parent.conjurer_buff_m or 1), function() self.t:after(12*(self.parent.conjurer_buff_m or 1), function()
self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function() self.t:every_immediate(0.05, function() self.hidden = not self.hidden end, 7, function()
self.dead = true self.dead = true
if self.parent.summon_instability then if self.parent.construct_instability then
camera:shake(2, 0.5) camera:shake(2, 0.5)
local n = (self.parent.summon_instability == 1 and 1) or (self.parent.summon_instability == 2 and 1.5) or (self.parent.summon_instability == 3 and 2) or 1 local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent} Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end end
@ -2974,6 +3040,97 @@ end
Sentry = Object:extend()
Sentry:implement(GameObject)
Sentry:implement(Physics)
function Sentry:init(args)
self:init_game_object(args)
self:set_as_rectangle(6, 6, 'static', 'player')
self:set_restitution(0.5)
self.hfx:add('hit', 1)
self.t:after(15*(self.parent.conjurer_buff_m or 1), function()
local n = n or random:int(3, 4)
for i = 1, n do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end
HitCircle{group = main.current.effects, x = self.x, y = self.y}:scale_down()
self.dead = true
if self.parent.construct_instability then
camera:shake(2, 0.5)
local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end
end)
self.t:every({2.75, 3.5}, function()
self.hfx:use('hit', 0.25, 200, 10)
local r = self.r
for i = 1, 4 do
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 = 200, r = r, color = self.color,
dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent}
Projectile(table.merge(t, mods or {}))
r = r + math.pi/2
end
if self.parent.taunt and random:bool((self.parent.taunt == 1 and 10) or (self.parent.taunt == 2 and 20) or (self.parent.taunt == 3 and 30)) then
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 96), main.current.enemies)
if #enemies > 0 then
for _, enemy in ipairs(enemies) do
enemy.taunted = self
enemy.t:after(4, function() enemy.taunted = false end, 'taunt')
end
end
end
if self.parent.rearm then
self.t:after(0.25, function()
self.hfx:use('hit', 0.25, 200, 10)
local r = self.r
for i = 1, 4 do
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 = 200, r = r, color = self.color,
dmg = self.parent.dmg*(self.parent.conjurer_buff_m or 1), character = 'sentry', parent = self.parent}
Projectile(table.merge(t, mods or {}))
r = r + math.pi/2
end
if self.parent.taunt and random:bool((self.parent.taunt == 1 and 10) or (self.parent.taunt == 2 and 20) or (self.parent.taunt == 3 and 30)) then
local enemies = self:get_objects_in_shape(Circle(self.x, self.y, 96), main.current.enemies)
if #enemies > 0 then
for _, enemy in ipairs(enemies) do
enemy.taunted = self
enemy.t:after(4, function() enemy.taunted = false end, 'taunt')
end
end
end
end)
end
end)
end
function Sentry:update(dt)
self:update_game_object(dt)
self.r = self.r + math.pi*dt
self:set_angle(self.r)
end
function Sentry:draw()
if self.hidden then return end
graphics.push(self.x, self.y, self.r, self.spring.x, self.spring.x)
graphics.rectangle(self.x, self.y, 2*self.shape.w, 4, 2, 2, self.hfx.hit.f and fg[0] or self.color)
graphics.rectangle(self.x, self.y, 4, 2*self.shape.h, 2, 2, self.hfx.hit.f and fg[0] or self.color)
graphics.pop()
end
Turret = Object:extend() Turret = Object:extend()
Turret:implement(GameObject) Turret:implement(GameObject)
Turret:implement(Physics) Turret:implement(Physics)
@ -3038,9 +3195,9 @@ function Turret:init(args)
HitCircle{group = main.current.effects, x = self.x, y = self.y}:scale_down() HitCircle{group = main.current.effects, x = self.x, y = self.y}:scale_down()
self.dead = true self.dead = true
if self.parent.summon_instability then if self.parent.construct_instability then
camera:shake(2, 0.5) camera:shake(2, 0.5)
local n = (self.parent.summon_instability == 1 and 1) or (self.parent.summon_instability == 2 and 1.5) or (self.parent.summon_instability == 3 and 2) or 1 local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent} Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end end
@ -3135,9 +3292,9 @@ function Pet:on_collision_enter(other, contact)
else else
self.dead = true self.dead = true
if self.parent.summon_instability then if self.parent.construct_instability then
camera:shake(2, 0.5) camera:shake(2, 0.5)
local n = (self.parent.summon_instability == 1 and 1) or (self.parent.summon_instability == 2 and 1.5) or (self.parent.summon_instability == 3 and 2) or 1 local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent} Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end end
@ -3173,6 +3330,74 @@ end
Bomb = Object:extend()
Bomb:implement(GameObject)
Bomb:implement(Physics)
function Bomb:init(args)
self:init_game_object(args)
self:set_as_rectangle(8, 8, 'static', 'player')
self:set_restitution(0.5)
self.hfx:add('hit', 1)
mine1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.color = orange[0]
self.dmg = 2*get_character_stat('bomber', self.level, 'dmg')
self.t:after(8, function() self:explode() end)
end
function Bomb:update(dt)
self:update_game_object(dt)
end
function Bomb:draw()
graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x)
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color)
graphics.pop()
end
function Bomb:explode()
camera:shake(4, 0.5)
local t = {group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*64*(self.level == 3 and 2 or 1), color = self.color,
dmg = self.parent.area_dmg_m*self.dmg*(self.parent.conjurer_buff_m or 1)*(self.level == 3 and 2 or 1), character = self.character, parent = self.parent}
Area(table.merge(t, mods or {}))
if not self.parent.construct_instability and not self.parent.rearm then self.dead = true end
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
_G[random:table{'saboteur_hit1', 'saboteur_hit2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
explosion1:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.t:after(0.25, function()
if self.parent.construct_instability then
camera:shake(2, 0.5)
local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r + random:float(-math.pi/16, math.pi/16), w = self.parent.area_size_m*48*(self.level == 3 and 2 or 1), color = self.color,
dmg = n*self.parent.dmg*self.parent.area_dmg_m*(self.level == 3 and 2 or 1), parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.dead = true
end
if self.parent.rearm then
camera:shake(2, 0.5)
local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r + random:float(-math.pi/16, math.pi/16), w = self.parent.area_size_m*48*(self.level == 3 and 2 or 1), color = self.color,
dmg = n*self.parent.dmg*self.parent.area_dmg_m*(self.level == 3 and 2 or 1), parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.dead = true
end
end)
end
function Bomb:on_collision_enter(other, contact)
if table.any(main.current.enemies, function(v) return other:is(v) end) then
self:explode()
end
end
Saboteur = Object:extend() Saboteur = Object:extend()
Saboteur:implement(GameObject) Saboteur:implement(GameObject)
@ -3232,10 +3457,10 @@ function Saboteur:on_collision_enter(other, contact)
dmg = (self.crit and 2 or 1)*self.area_dmg_m*self.actual_dmg*(self.conjurer_buff_m or 1), character = self.character, parent = self.parent} dmg = (self.crit and 2 or 1)*self.area_dmg_m*self.actual_dmg*(self.conjurer_buff_m or 1), character = self.character, parent = self.parent}
Area(table.merge(t, mods or {})) Area(table.merge(t, mods or {}))
if self.parent.summon_instability then if self.parent.construct_instability then
self.t:after(0.25, function() self.t:after(0.25, function()
camera:shake(2, 0.5) camera:shake(2, 0.5)
local n = (self.parent.summon_instability == 1 and 1) or (self.parent.summon_instability == 2 and 1.5) or (self.parent.summon_instability == 3 and 2) or 1 local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent} Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
self.dead = true self.dead = true
@ -3248,18 +3473,18 @@ end
Illusion = Object:extend() Automaton = Object:extend()
Illusion:implement(GameObject) Automaton:implement(GameObject)
Illusion:implement(Physics) Automaton:implement(Physics)
Illusion:implement(Unit) Automaton:implement(Unit)
function Illusion:init(args) function Automaton:init(args)
self:init_game_object(args) self:init_game_object(args)
self:init_unit() self:init_unit()
self:set_as_rectangle(8, 8, 'dynamic', 'player') self:set_as_rectangle(8, 8, 'dynamic', 'player')
self:set_restitution(0.5) self:set_restitution(0.5)
self.color = character_colors.illusionist self.color = character_colors.artificer
self.character = 'illusionist' self.character = 'artificer'
self.classes = {'sorcerer', 'conjurer'} self.classes = {'sorcerer', 'conjurer'}
self:calculate_stats(true) self:calculate_stats(true)
self:set_as_steerable(self.v, 2000, 4*math.pi, 4) self:set_as_steerable(self.v, 2000, 4*math.pi, 4)
@ -3268,10 +3493,12 @@ function Illusion: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() 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) local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then if closest_enemy then
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.05} turret1:play{pitch = random:float(0.95, 1.05), volume = 0.10}
turret2:play{pitch = random:float(0.95, 1.05), volume = 0.10}
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.10}
local r = self:angle_to_object(closest_enemy) local r = self:angle_to_object(closest_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} 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.parent.color, dmg = self.parent.dmg, character = 'illusionist', 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.parent.color, dmg = self.parent.dmg, character = 'artificer',
parent = self.parent, level = self.parent.level} parent = self.parent, level = self.parent.level}
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
end end
@ -3280,10 +3507,12 @@ function Illusion:init(args)
self.t:after(0.25, function() self.t:after(0.25, function()
local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies) local closest_enemy = self:get_closest_object_in_shape(self.attack_sensor, main.current.enemies)
if closest_enemy then if closest_enemy then
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.05} turret1:play{pitch = random:float(0.95, 1.05), volume = 0.10}
turret2:play{pitch = random:float(0.95, 1.05), volume = 0.10}
wizard1:play{pitch = random:float(0.95, 1.05), volume = 0.10}
local r = self:angle_to_object(closest_enemy) local r = self:angle_to_object(closest_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} 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.parent.color, dmg = self.parent.dmg, character = 'illusionist', 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.parent.color, dmg = self.parent.dmg, character = 'artificer',
parent = self.parent, level = self.parent.level} parent = self.parent, level = self.parent.level}
Projectile(table.merge(t, mods or {})) Projectile(table.merge(t, mods or {}))
end end
@ -3301,7 +3530,7 @@ function Illusion:init(args)
end end
end, nil, nil, 'shoot') end, nil, nil, 'shoot')
self.t:after(12*(self.parent.conjurer_buff_m or 1), function() self.t:after(18*(self.parent.conjurer_buff_m or 1), function()
local n = n or random:int(3, 4) local n = n or random:int(3, 4)
for i = 1, n do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end for i = 1, n do HitParticle{group = main.current.effects, x = self.x, y = self.y, r = random:float(0, 2*math.pi), color = self.color} end
HitCircle{group = main.current.effects, x = self.x, y = self.y}:scale_down() HitCircle{group = main.current.effects, x = self.x, y = self.y}:scale_down()
@ -3310,14 +3539,14 @@ function Illusion:init(args)
if self.parent.level == 3 then if self.parent.level == 3 then
shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2} shoot1:play{pitch = random:float(0.95, 1.05), volume = 0.2}
for i = 1, 12 do for i = 1, 12 do
Projectile{group = main.current.main, x = self.x, y = self.y, color = self.color, r = (i-1)*math.pi/6, v = 200, dmg = self.parent.dmg, character = 'illusionist_death', Projectile{group = main.current.main, x = self.x, y = self.y, color = self.color, r = (i-1)*math.pi/6, v = 200, dmg = self.parent.dmg, character = 'artificer_death',
parent = self.parent, level = self.parent.level, pierce = 1, ricochet = 1} parent = self.parent, level = self.parent.level, pierce = 1, ricochet = 1}
end end
end end
if self.parent.summon_instability then if self.parent.construct_instability then
camera:shake(2, 0.5) camera:shake(2, 0.5)
local n = (self.parent.summon_instability == 1 and 1) or (self.parent.summon_instability == 2 and 1.5) or (self.parent.summon_instability == 3 and 2) or 1 local n = (self.parent.construct_instability == 1 and 1) or (self.parent.construct_instability == 2 and 1.5) or (self.parent.construct_instability == 3 and 2) or 1
Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent} Area{group = main.current.effects, x = self.x, y = self.y, r = self.r, w = self.parent.area_size_m*48, color = self.color, dmg = n*self.parent.dmg*self.parent.area_dmg_m, parent = self.parent}
_G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} _G[random:table{'cannoneer1', 'cannoneer2'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5}
end end
@ -3325,7 +3554,7 @@ function Illusion:init(args)
end end
function Illusion:update(dt) function Automaton:update(dt)
self:update_game_object(dt) self:update_game_object(dt)
self:calculate_stats() self:calculate_stats()
@ -3346,11 +3575,12 @@ function Illusion:update(dt)
end end
self.r = self:get_angle() self.r = self:get_angle()
self.t:set_every_multiplier('shoot', self.parent.level == 3 and 0.75 or 1)
self.attack_sensor:move_to(self.x, self.y) self.attack_sensor:move_to(self.x, self.y)
end end
function Illusion:draw() function Automaton:draw()
graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x) graphics.push(self.x, self.y, self.r, self.hfx.hit.x, self.hfx.hit.x)
graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color) graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 3, 3, self.hfx.hit.f and fg[0] or self.color)
graphics.pop() graphics.pop()

53
todo
View File

@ -1,24 +1,24 @@
Loop Update Loop Update
New items: New items:
General: General:
Intimidation - enemies spawn with -10/20/30% max HP * Intimidation - enemies spawn with -10/20/30% max HP
Vulnerability - enemies take +10/20/30% damage * Vulnerability - enemies take +10/20/30% damage
Ceremonial Dagger - killing an enemy fires a homing dagger * Temporal Chains - enemies are 10/20/30% slower
Homing Barrage - X/Y/Z% chance to release a homing barrage on enemy kill * Ceremonial Dagger - killing an enemy fires a homing dagger
Critical Strike - X/Y/Z% chance for attacks to critically strike, dealing 2x damage * Homing Barrage - 8/16/24% chance to release a homing barrage on enemy kill
Noxious Strike - X/Y/Z% chance for attacks to poison enemies, dealing 20% damage per second for 3 seconds * Critical Strike - 5/10/15% chance for attacks to critically strike, dealing 2x damage
Infesting Strike - X/Y/Z% chance for attacks to spawn 2 critters on kill * Noxious Strike - 8/16/24% chance for attacks to poison enemies, dealing 20% dps for 3 seconds
Kinetic Strike - X/Y/Z% chance for attacks to push enemies away with high force * Infesting Strike - 10/20/30% chance for attacks to spawn 2 critters on kill
Burning Strike - X% chance for attacks to ignite, dealing 20% dps for 3 seconds, ignited enemies ignite nearby enemies on death * Kinetic Strike - 10/20/30% chance for attacks to push enemies away with high force
Lucky Strike - X% chance for attacks to cause enemies to drop gold on death * Burning Strike - 15% chance for attacks to ignite, dealing 20% dps for 3 seconds
Healing Strike - X% chance for attacks to spawn a healing orb on kill * Lucky Strike - 8% chance for attacks to cause enemies to drop gold on death
Stunning Strike - X/Y/Z% chance for attacks to stun for 2 seconds * Healing Strike - 8% chance for attacks to spawn a healing orb on kill
Silencing Strike - X/Y/Z% chance for attacks to silence on hit * Stunning Strike - 8/16/24% chance for attacks to stun for 2 seconds
Warping Shots - X/Y/Z% chance for projectiles to ignore wall collisions and warp around the screen 1/2/3 times * Silencing Strike - 8/16/24% chance for attacks to silence for 4 seconds on hit
Culling Strike - instantly kill elites below 10/20/30% max HP * Culling Strike - instantly kill elites below 10/20/30% max HP
Lightning Strike - X/Y/Z% chance for attacks to create chain lightning, dealing 60/80/100% damage and hitting 2/3/4 enemies * Lightning Strike - 5/10/15% chance for projectiles to create chain lightning, dealing 60/80/100% damage
Psycholeak - Position X generates 1 additional orb every Y seconds * Psycholeak - Position 1 generates 1 psyker orb every 10 seconds
Divine Blessing - generate 1 healing orb every X seconds * Divine Blessing - generate 1 healing orb every 8 seconds
Psyker Psyker
Additional orbs will prefer to be assigned to psykers, if there are no psykers then they will be assigned randomly Additional orbs will prefer to be assigned to psykers, if there are no psykers then they will be assigned randomly
Orb speed scales with the unit's attack speed Orb speed scales with the unit's attack speed
@ -35,12 +35,15 @@ Loop Update
Increases amount of orbs dropped with only 1 or 2 healers Increases amount of orbs dropped with only 1 or 2 healers
Decreases amount of orbs dropped on full build Decreases amount of orbs dropped on full build
Healing orbs are slightly attracted to the snake Healing orbs are slightly attracted to the snake
Warriors
Increase sensor range
Set juggernaut and barbarian's attacks on :cooldown calls
Builders Builders
Carver (builder, healer) - every 12 seconds, creates a tree that drops 3 healing orbs, Lv.3 effect: drops 6 healing orbs instead * Carver (builder, healer) - creates a tree that creates 1 healing orb every 6 seconds, Lv.3 effect: healing orbs are created twice as fast
Engineer (builder) - unchanged * Engineer (builder): unchanged
Illusionist -> Golemancer (builder, sorcerer): spawns 1 golem every 6 seconds, it shoots 2 rocks that deal X damage each, Lv.3 effect: golem rocks stun enemies for 2 seconds * Illusionist -> Artificer (builder, sorcerer): unchanged
Saboteur -> Bomber (builder, nuker): plants a static bomb, when it explodes it deals 2X AoE damage, Lv.3 effect: 100% increased bomb area and damage * Saboteur -> Bomber (builder, nuker): plants a bomb, when it explodes it deals 2X AoE damage, Lv.3 effect: +100% bomb area and damage
Hunter (builder, ranger, forcer): shoots a projectile that has 20% chance to spawn a pet, Lv.3 effect: spawns 3 pets instead * Hunter -> Sentry (builder, ranger): spawns a turret that shoots projectiles, each dealing X damage, Lv.3 effect: +50% attack speed and the projectiles ricochet twice
Looping Looping
* Change end screen * Change end screen
* Loop button on end screen * Loop button on end screen
@ -53,14 +56,14 @@ Loop Update
Add option for mouse cursor to always be visible Add option for mouse cursor to always be visible
Show cooldown on elite attack Show cooldown on elite attack
Add visuals divine intervention, fairy buff Add visuals divine intervention, fairy buff
warrior attack range
barbarian jugg attack
Party + items on death screen Party + items on death screen
* Silenced units are now gray
* Items on end screen * Items on end screen
* Items on passive screen * Items on passive screen
* Selling items * Selling items
* Decreased sound effect volume for shoot 5 * Decreased sound effect volume for shoot 5
Bug fixes Bug fixes
Fix stars
* Fixed a series of crashes that happened sometimes right before changing from the arena back to the shop * Fixed a series of crashes that happened sometimes right before changing from the arena back to the shop
* Fixed merchant not giving interest or free reroll if it died in combat * Fixed merchant not giving interest or free reroll if it died in combat
* Fixed shoot 5 and death 6 not working if a unit placed before it on the snake died * Fixed shoot 5 and death 6 not working if a unit placed before it on the snake died