1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-08 00:39:30 +02:00
ComfyFactorio/modules/wave_defense/main.lua

803 lines
26 KiB
Lua
Raw Normal View History

2020-08-09 20:23:45 +02:00
local BiterHealthBooster = require 'modules.biter_health_booster'
local BiterRolls = require 'modules.wave_defense.biter_rolls'
local SideTargets = require 'modules.wave_defense.side_targets'
local ThreatEvent = require 'modules.wave_defense.threat_events'
local update_gui = require 'modules.wave_defense.gui'
local threat_values = require 'modules.wave_defense.threat_values'
local WD = require 'modules.wave_defense.table'
2020-06-07 13:33:24 +02:00
local Alert = require 'utils.alert'
2020-10-30 23:05:05 +02:00
local Event = require 'utils.event'
local Public = {}
2019-11-09 14:18:30 +02:00
local math_random = math.random
local math_floor = math.floor
local table_insert = table.insert
local math_sqrt = math.sqrt
local math_round = math.round
2019-10-28 18:38:36 +02:00
2019-11-09 14:18:30 +02:00
local group_size_modifier_raffle = {}
2020-08-09 20:23:45 +02:00
local group_size_chances = {
{4, 0.4},
{5, 0.5},
{6, 0.6},
{7, 0.7},
{8, 0.8},
{9, 0.9},
{10, 1},
{9, 1.1},
{8, 1.2},
{7, 1.3},
{6, 1.4},
{5, 1.5},
{4, 1.6},
{3, 1.7},
{2, 1.8}
}
2019-11-09 14:18:30 +02:00
for _, v in pairs(group_size_chances) do
2020-10-30 23:05:05 +02:00
for _ = 1, v[1], 1 do
2020-08-09 20:23:45 +02:00
table_insert(group_size_modifier_raffle, v[2])
end
2019-11-09 14:18:30 +02:00
end
local group_size_modifier_raffle_size = #group_size_modifier_raffle
2019-10-08 01:17:00 +02:00
local function debug_print(msg)
2020-08-17 20:18:06 +02:00
local debug = WD.get('debug')
if not debug then
2020-08-09 20:23:45 +02:00
return
end
print('WaveDefense: ' .. msg)
2019-10-08 01:17:00 +02:00
end
2020-10-22 13:32:18 +02:00
local function is_closer(pos1, pos2, pos)
return ((pos1.x - pos.x) ^ 2 + (pos1.y - pos.y) ^ 2) < ((pos2.x - pos.x) ^ 2 + (pos2.y - pos.y) ^ 2)
end
local function shuffle_distance(tbl, position)
local size = #tbl
for i = size, 1, -1 do
local rand = math_random(size)
if is_closer(tbl[i].position, tbl[rand].position, position) and i > rand then
tbl[i], tbl[rand] = tbl[rand], tbl[i]
end
end
return tbl
end
2020-08-04 12:10:15 +02:00
local function remove_trees(entity)
2020-08-09 20:23:45 +02:00
local surface = entity.surface
2020-10-24 14:46:14 +02:00
local radius = 15
2020-08-09 20:23:45 +02:00
local pos = entity.position
local area = {{pos.x - radius, pos.y - radius}, {pos.x + radius, pos.y + radius}}
local trees = surface.find_entities_filtered {area = area, type = 'tree'}
if #trees > 0 then
for i, tree in pairs(trees) do
if tree and tree.valid then
tree.destroy()
end
end
end
2020-08-04 12:10:15 +02:00
end
local function remove_rocks(entity)
2020-08-09 20:23:45 +02:00
local surface = entity.surface
2020-10-24 14:46:14 +02:00
local radius = 15
2020-08-09 20:23:45 +02:00
local pos = entity.position
local area = {{pos.x - radius, pos.y - radius}, {pos.x + radius, pos.y + radius}}
local rocks = surface.find_entities_filtered {area = area, type = 'simple-entity'}
if #rocks > 0 then
for i, rock in pairs(rocks) do
if rock and rock.valid then
rock.destroy()
end
end
end
end
2020-10-30 23:05:05 +02:00
2019-10-15 04:20:40 +02:00
local function is_unit_valid(biter)
2020-11-17 13:45:47 +02:00
local max_biter_age = WD.get('max_biter_age')
2020-08-09 20:23:45 +02:00
if not biter.entity then
debug_print('is_unit_valid - unit destroyed - does no longer exist')
return false
end
if not biter.entity.valid then
debug_print('is_unit_valid - unit destroyed - invalid')
return false
end
if not biter.entity.unit_group then
debug_print('is_unit_valid - unit destroyed - no unitgroup')
return false
end
2020-11-17 13:45:47 +02:00
if biter.spawn_tick + max_biter_age < game.tick then
2020-08-09 20:23:45 +02:00
debug_print('is_unit_valid - unit destroyed - timed out')
return false
end
return true
2019-10-07 22:40:05 +02:00
end
2019-10-25 08:09:39 +02:00
local function refresh_active_unit_threat()
2020-11-17 13:45:47 +02:00
local active_biter_threat = WD.get('active_biter_threat')
local active_biters = WD.get('active_biters')
debug_print('refresh_active_unit_threat - current value ' .. active_biter_threat)
local biter_threat = 0
for k, biter in pairs(active_biters) do
2020-08-09 20:23:45 +02:00
if biter.entity then
if biter.entity.valid then
2020-11-17 13:45:47 +02:00
biter_threat = biter_threat + threat_values[biter.entity.name]
2020-08-09 20:23:45 +02:00
end
end
end
2020-11-17 13:45:47 +02:00
active_biter_threat = math_round(biter_threat * global.biter_health_boost, 2)
debug_print('refresh_active_unit_threat - new value ' .. active_biter_threat)
2019-10-25 08:09:39 +02:00
end
2019-10-14 06:52:17 +02:00
local function time_out_biters()
2020-11-17 13:45:47 +02:00
local active_biters = WD.get('active_biters')
local active_biter_count = WD.get('active_biter_count')
local active_biter_threat = WD.get('active_biter_threat')
for k, biter in pairs(active_biters) do
2020-08-09 20:23:45 +02:00
if not is_unit_valid(biter) then
2020-11-17 13:45:47 +02:00
active_biter_count = active_biter_count - 1
2020-08-09 20:23:45 +02:00
if biter.entity then
if biter.entity.valid then
2020-11-17 13:45:47 +02:00
WD.set(
'active_biter_threat',
active_biter_threat - math_round(threat_values[biter.entity.name] * global.biter_health_boost, 2)
)
2020-08-09 20:23:45 +02:00
if biter.entity.force.index == 2 then
biter.entity.destroy()
end
end
end
2020-11-17 13:45:47 +02:00
active_biters[k] = nil
2020-08-09 20:23:45 +02:00
end
end
2019-10-07 04:37:23 +02:00
end
local function get_random_close_spawner()
2020-11-17 13:45:47 +02:00
local nests = WD.get('nests')
local target = WD.get('target')
local get_random_close_spawner_attempts = WD.get('get_random_close_spawner_attempts')
local center = target.position
local spawner
2020-11-17 13:45:47 +02:00
for i = 1, get_random_close_spawner_attempts, 1 do
::retry::
2020-11-17 13:45:47 +02:00
if #nests < 1 then
return false
end
2020-11-17 13:45:47 +02:00
local k = math_random(1, #nests)
local spawner_2 = nests[k]
2020-10-22 17:39:23 +02:00
if not spawner_2 or not spawner_2.valid then
2020-11-17 13:45:47 +02:00
nests[k] = nil
goto retry
end
2020-08-09 20:23:45 +02:00
if
not spawner or
(center.x - spawner_2.position.x) ^ 2 + (center.y - spawner_2.position.y) ^ 2 <
(center.x - spawner.position.x) ^ 2 + (center.y - spawner.position.y) ^ 2
2020-08-09 20:23:45 +02:00
then
spawner = spawner_2
end
end
debug_print('get_random_close_spawner - Found at x' .. spawner.position.x .. ' y' .. spawner.position.y)
return spawner
2019-10-07 01:46:26 +02:00
end
2020-11-17 13:45:47 +02:00
local function get_random_character()
2020-08-09 20:23:45 +02:00
local characters = {}
2020-11-17 13:45:47 +02:00
local surface_index = WD.get('surface_index')
local p = game.connected_players
for _, player in pairs(p) do
2020-08-09 20:23:45 +02:00
if player.character then
if player.character.valid then
2020-11-17 13:45:47 +02:00
if player.character.surface.index == surface_index then
2020-08-09 20:23:45 +02:00
characters[#characters + 1] = player.character
end
end
end
end
if not characters[1] then
return
end
return characters[math_random(1, #characters)]
2020-01-01 15:05:49 +02:00
end
2019-10-25 08:09:39 +02:00
local function set_main_target()
2020-11-17 13:45:47 +02:00
local target = WD.get('target')
if target then
if target.valid then
2020-08-09 20:23:45 +02:00
return
end
end
2020-11-17 13:45:47 +02:00
local sec_target = SideTargets.get_side_target()
if not sec_target then
sec_target = get_random_character()
2020-08-09 20:23:45 +02:00
end
2020-11-17 13:45:47 +02:00
if not sec_target then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
WD.set('target', sec_target)
2020-08-09 20:23:45 +02:00
debug_print(
'set_main_target -- New main target ' ..
2020-11-17 13:45:47 +02:00
sec_target.name .. ' at position x' .. sec_target.position.x .. ' y' .. sec_target.position.y .. ' selected.'
2020-08-09 20:23:45 +02:00
)
2019-10-25 08:09:39 +02:00
end
2019-10-12 04:06:48 +02:00
local function set_group_spawn_position(surface)
local spawner = get_random_close_spawner()
2020-08-09 20:23:45 +02:00
if not spawner then
return
end
local position = surface.find_non_colliding_position('behemoth-biter', spawner.position, 64, 1)
if not position then
return
end
2020-11-17 13:45:47 +02:00
WD.set('spawn_position', {x = position.x, y = position.y})
local spawn_position = WD.get('spawn_position')
debug_print('set_group_spawn_position -- Changed position to x' .. spawn_position.x .. ' y' .. spawn_position.y .. '.')
2019-10-07 01:46:26 +02:00
end
local function set_enemy_evolution()
2020-11-17 13:45:47 +02:00
local wave_number = WD.get('wave_number')
local biter_health_boost = WD.get('biter_health_boost')
local threat = WD.get('threat')
local evolution_factor = wave_number * 0.001
local biter_h_boost = 1
2020-08-09 20:23:45 +02:00
--local damage_increase = 0
if evolution_factor > 1 then
evolution_factor = 1
end
2020-11-17 13:45:47 +02:00
if biter_health_boost then
biter_h_boost = math_round(biter_health_boost + (threat - 5000) * 0.000033, 3)
2020-10-25 18:02:37 +02:00
else
2020-11-17 13:45:47 +02:00
biter_h_boost = math_round(biter_h_boost + (threat - 5000) * 0.000033, 3)
2020-10-25 18:02:37 +02:00
end
2020-11-17 13:45:47 +02:00
if biter_h_boost <= 1 then
biter_h_boost = 1
2020-10-30 23:05:05 +02:00
end
2020-11-17 13:45:47 +02:00
--damage_increase = math_round(damage_increase + threat * 0.0000025, 3)
2020-08-09 20:23:45 +02:00
2020-11-17 13:45:47 +02:00
global.biter_health_boost = biter_h_boost
2020-08-09 20:23:45 +02:00
--game.forces.enemy.set_ammo_damage_modifier("melee", damage_increase)
--game.forces.enemy.set_ammo_damage_modifier("biological", damage_increase)
game.forces.enemy.evolution_factor = evolution_factor
2019-10-25 08:09:39 +02:00
end
local function can_units_spawn()
2020-11-17 13:45:47 +02:00
local threat = WD.get('threat')
if threat <= 0 then
2020-08-09 20:23:45 +02:00
debug_print('can_units_spawn - threat too low')
return false
end
2020-11-17 13:45:47 +02:00
local active_biter_count = WD.get('active_biter_count')
local max_active_biters = WD.get('max_active_biters')
if active_biter_count >= max_active_biters then
2020-08-09 20:23:45 +02:00
debug_print('can_units_spawn - active biter count too high')
return false
end
2020-11-17 13:45:47 +02:00
local active_biter_threat = WD.get('active_biter_threat')
if active_biter_threat >= threat then
debug_print('can_units_spawn - active biter threat too high (' .. active_biter_threat .. ')')
2020-08-09 20:23:45 +02:00
return false
end
return true
2019-10-25 08:09:39 +02:00
end
local function get_active_unit_groups_count()
2020-11-17 13:45:47 +02:00
local unit_groups = WD.get('unit_groups')
2020-08-09 20:23:45 +02:00
local count = 0
2020-11-17 13:45:47 +02:00
for _, g in pairs(unit_groups) do
2020-08-09 20:23:45 +02:00
if g.valid then
if #g.members > 0 then
count = count + 1
else
g.destroy()
end
end
end
debug_print('Active unit group count: ' .. count)
return count
2019-10-07 01:46:26 +02:00
end
local function spawn_biter(surface, is_boss_biter)
2020-08-09 20:23:45 +02:00
if not is_boss_biter then
if not can_units_spawn() then
return
end
end
2020-11-17 13:45:47 +02:00
local boosted_health = global.biter_health_boost
2020-08-09 20:23:45 +02:00
local name
if math_random(1, 100) > 73 then
name = BiterRolls.wave_defense_roll_spitter_name()
else
name = BiterRolls.wave_defense_roll_biter_name()
end
2020-11-17 13:45:47 +02:00
local spawn_position = WD.get('spawn_position')
local position = spawn_position
2020-08-09 20:23:45 +02:00
local biter = surface.create_entity({name = name, position = position, force = 'enemy'})
biter.ai_settings.allow_destroy_when_commands_fail = true
biter.ai_settings.allow_try_return_to_spawner = false
2020-08-21 13:56:01 +02:00
biter.ai_settings.do_separation = true
2020-11-17 13:45:47 +02:00
biter.ai_settings.path_resolution_modifier = -5
local remove_entities = WD.get('remove_entities')
if remove_entities then
2020-08-09 20:23:45 +02:00
remove_trees(biter)
remove_rocks(biter)
end
if is_boss_biter then
2020-11-17 13:45:47 +02:00
local modified_boss_health = WD.get('modified_boss_health')
if modified_boss_health then
local wave_number = WD.get('wave_number')
if boosted_health == 1 then
boosted_health = 1.25
end
boosted_health = boosted_health * (wave_number * 0.05)
local sum = boosted_health * 5
debug_print('Boss Health Boosted: ' .. sum)
if sum >= 150 then
sum = 150
end
BiterHealthBooster.add_boss_unit(biter, sum, 0.55)
else
local sum = boosted_health * 5
debug_print('Boss Health Boosted: ' .. sum)
BiterHealthBooster.add_boss_unit(biter, sum, 0.55)
end
2020-08-09 20:23:45 +02:00
end
2020-11-17 13:45:47 +02:00
WD.set('active_biters')[biter.unit_number] = {entity = biter, spawn_tick = game.tick}
local active_biter_count = WD.get('active_biter_count')
WD.set('active_biter_count', active_biter_count + 1)
local active_biter_threat = WD.get('active_biter_threat')
WD.set('active_biter_threat', active_biter_threat + math_round(threat_values[name] * boosted_health, 2))
2020-08-09 20:23:45 +02:00
return biter
2019-10-07 01:46:26 +02:00
end
2019-10-07 22:40:05 +02:00
local function set_next_wave()
2020-11-17 13:45:47 +02:00
local wave_number = WD.get('wave_number')
WD.set('wave_number', wave_number + 1)
wave_number = WD.get('wave_number')
local threat_gain_multiplier = WD.get('threat_gain_multiplier')
local threat_gain = wave_number * threat_gain_multiplier
if wave_number > 1000 then
threat_gain = threat_gain * (wave_number * 0.001)
end
if wave_number % 25 == 0 then
WD.set('boss_wave', true)
WD.set('boss_wave_warning', true)
local alert_boss_wave = WD.get('alert_boss_wave')
local spawn_position = WD.get('spawn_position')
if alert_boss_wave then
local msg = 'Boss Wave: ' .. wave_number
2020-08-09 20:23:45 +02:00
local pos = {
2020-11-17 13:45:47 +02:00
position = spawn_position
2020-08-09 20:23:45 +02:00
}
Alert.alert_all_players_location(pos, msg, {r = 0.8, g = 0.1, b = 0.1})
end
threat_gain = threat_gain * 2
else
2020-11-17 13:45:47 +02:00
local boss_wave_warning = WD.get('boss_wave_warning')
if boss_wave_warning then
WD.set('boss_wave_warning', false)
2020-08-09 20:23:45 +02:00
end
end
2020-11-17 13:45:47 +02:00
local threat = WD.get('threat')
WD.set('threat', threat + math_floor(threat_gain))
local wave_enforced = WD.get('wave_enforced')
local next_wave = WD.get('next_wave')
local wave_interval = WD.get('wave_interval')
if not wave_enforced then
WD.set('last_wave', next_wave)
WD.set('next_wave', game.tick + wave_interval)
2020-10-24 14:46:14 +02:00
end
2020-11-17 13:45:47 +02:00
local clear_corpses = WD.get('clear_corpses')
if clear_corpses then
local surface_index = WD.get('surface_index')
local surface = game.surfaces[surface_index]
2020-08-09 20:23:45 +02:00
for _, entity in pairs(surface.find_entities_filtered {type = 'corpse'}) do
if math_random(1, 2) == 1 then
entity.destroy()
end
end
end
2019-10-07 22:40:05 +02:00
end
local function reform_group(group)
2020-11-17 13:45:47 +02:00
local unit_group_command_step_length = WD.get('unit_group_command_step_length')
2020-08-09 20:23:45 +02:00
local group_position = {x = group.position.x, y = group.position.y}
2020-11-17 13:45:47 +02:00
local step_length = unit_group_command_step_length
2020-08-09 20:23:45 +02:00
local position = group.surface.find_non_colliding_position('biter-spawner', group_position, step_length, 4)
if position then
local new_group = group.surface.create_unit_group {position = position, force = group.force}
for key, biter in pairs(group.members) do
new_group.add_member(biter)
end
debug_print('Creating new unit group, because old one was stuck.')
2020-11-17 13:45:47 +02:00
local unit_groups = WD.get('unit_groups')
unit_groups[new_group.group_number] = new_group
local index = WD.get('index')
WD.set('index', index + 1)
2020-08-09 20:23:45 +02:00
return new_group
else
debug_print('Destroying stuck group.')
2020-11-17 13:45:47 +02:00
local unit_groups = WD.get('unit_groups')
if unit_groups[group.group_number] then
table.remove(unit_groups, group.group_number)
local index = WD.get('index')
WD.set('index', index - 1)
index = WD.get('index')
if index <= 0 then
WD.set('index', 0)
end
end
2020-08-09 20:23:45 +02:00
group.destroy()
end
return nil
end
2019-10-08 01:17:00 +02:00
local function get_commmands(group)
2020-11-17 13:45:47 +02:00
local unit_group_command_step_length = WD.get('unit_group_command_step_length')
local enable_side_target = WD.get('enable_side_target')
2020-08-09 20:23:45 +02:00
local commands = {}
local group_position = {x = group.position.x, y = group.position.y}
2020-11-17 13:45:47 +02:00
local step_length = unit_group_command_step_length
2020-08-09 20:23:45 +02:00
if math_random(1, 2) == 1 then
2020-11-17 13:45:47 +02:00
if not enable_side_target then
goto continue
end
2020-08-09 20:23:45 +02:00
local side_target = SideTargets.get_side_target()
if side_target then
local target_position = side_target.position
local distance_to_target =
2020-11-17 13:45:47 +02:00
math_floor(math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2))
2020-08-09 20:23:45 +02:00
local steps = math_floor(distance_to_target / step_length) + 1
local vector = {
math_round((target_position.x - group_position.x) / steps, 3),
math_round((target_position.y - group_position.y) / steps, 3)
}
2020-11-17 13:45:47 +02:00
local d = WD.get('debug')
if d then
debug_print('get_commmands - to side_target x' .. side_target.position.x .. ' y' .. side_target.position.y)
2020-08-09 20:23:45 +02:00
debug_print('get_commmands - distance_to_target:' .. distance_to_target .. ' steps:' .. steps)
debug_print('get_commmands - vector ' .. vector[1] .. '_' .. vector[2])
end
2020-10-30 23:05:05 +02:00
for i = 1, steps, 1 do
local old_position = group_position
group_position.x = group_position.x + vector[1]
group_position.y = group_position.y + vector[2]
local obstacles =
group.surface.find_entities_filtered {
position = old_position,
radius = step_length,
type = {'simple-entity', 'tree'},
limit = 50
}
if obstacles then
shuffle_distance(obstacles, old_position)
for v = 1, #obstacles, 1 do
if obstacles[v].valid then
commands[#commands + 1] = {
type = defines.command.attack,
target = obstacles[v],
distraction = defines.distraction.by_enemy
}
end
end
end
2020-11-17 13:45:47 +02:00
local position = group.surface.find_non_colliding_position('behemoth-biter', group_position, step_length, 4)
2020-10-30 23:05:05 +02:00
if position then
commands[#commands + 1] = {
type = defines.command.attack_area,
destination = {x = position.x, y = position.y},
radius = 16,
distraction = defines.distraction.by_anything
}
else
local obst =
group.surface.find_entities_filtered {
position = group_position,
radius = step_length,
type = {'simple-entity', 'tree'},
limit = 50
}
if obst then
shuffle_distance(obst, old_position)
for v = 1, #obst, 1 do
if obst[v].valid then
commands[#commands + 1] = {
type = defines.command.attack,
target = obst[v],
distraction = defines.distraction.by_enemy
}
end
end
end
end
end
2020-08-09 20:23:45 +02:00
commands[#commands + 1] = {
type = defines.command.attack,
target = side_target,
distraction = defines.distraction.by_enemy
}
end
end
2020-11-17 13:45:47 +02:00
::continue::
local target = WD.get('target')
if not (target and target.valid) then
return
end
local target_position = target.position
2020-08-09 20:23:45 +02:00
2020-10-30 23:05:05 +02:00
for i = 1, 4, 1 do
2020-08-09 20:23:45 +02:00
local obstacles =
group.surface.find_entities_filtered {
2020-10-30 23:05:05 +02:00
position = group_position,
2020-08-09 20:23:45 +02:00
radius = step_length / 2,
type = {'simple-entity', 'tree'},
2020-10-22 13:32:18 +02:00
limit = 50
2020-08-09 20:23:45 +02:00
}
if obstacles then
2020-10-30 23:05:05 +02:00
shuffle_distance(obstacles, group_position)
for v = 1, #obstacles, 1 do
if obstacles[v].valid then
2020-08-09 20:23:45 +02:00
commands[#commands + 1] = {
type = defines.command.attack,
2020-10-30 23:05:05 +02:00
target = obstacles[v],
2020-08-09 20:23:45 +02:00
distraction = defines.distraction.by_enemy
}
end
end
end
2020-09-17 09:14:07 +02:00
local position = group.surface.find_non_colliding_position('behemoth-biter', group_position, step_length, 1)
2020-08-09 20:23:45 +02:00
if position then
commands[#commands + 1] = {
type = defines.command.attack_area,
destination = {x = position.x, y = position.y},
2020-10-30 23:05:05 +02:00
radius = step_length,
2020-08-09 20:23:45 +02:00
distraction = defines.distraction.by_anything
}
end
end
commands[#commands + 1] = {
type = defines.command.attack_area,
destination = {x = target_position.x, y = target_position.y},
2020-10-30 23:05:05 +02:00
radius = step_length,
2020-08-09 20:23:45 +02:00
distraction = defines.distraction.by_enemy
}
commands[#commands + 1] = {
type = defines.command.attack,
2020-11-17 13:45:47 +02:00
target = target,
2020-08-09 20:23:45 +02:00
distraction = defines.distraction.by_enemy
}
return commands
2019-10-08 01:17:00 +02:00
end
2020-08-21 13:56:01 +02:00
local function command_unit_group(group)
2020-11-17 13:45:47 +02:00
local unit_group_last_command = WD.get('unit_group_last_command')
local unit_group_command_delay = WD.get('unit_group_command_delay')
if not unit_group_last_command[group.group_number] then
unit_group_last_command[group.group_number] = game.tick - (unit_group_command_delay + 1)
2020-08-09 20:23:45 +02:00
end
2020-11-17 13:45:47 +02:00
if unit_group_last_command[group.group_number] then
if unit_group_last_command[group.group_number] + unit_group_command_delay > game.tick then
2020-08-09 20:23:45 +02:00
return
end
end
2020-08-09 20:23:45 +02:00
local tile = group.surface.get_tile(group.position)
if tile.valid and tile.collides_with('player-layer') then
group = reform_group(group)
end
group.set_command(
{
type = defines.command.compound,
2020-10-22 13:32:18 +02:00
structure_type = defines.compound_command.return_last,
2020-08-09 20:23:45 +02:00
commands = get_commmands(group)
}
)
2020-10-30 23:05:05 +02:00
2020-11-17 13:45:47 +02:00
unit_group_last_command[group.group_number] = game.tick
2019-10-07 22:40:05 +02:00
end
2019-10-15 04:20:40 +02:00
local function give_commands_to_unit_groups()
2020-11-17 13:45:47 +02:00
local index = WD.get('index')
if index == 0 then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
local target = WD.get('target')
if not (target and target.valid) then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
local unit_groups = WD.get('unit_groups')
for k, group in pairs(unit_groups) do
if not group.valid then
2020-11-17 13:45:47 +02:00
unit_groups[k] = nil
WD.set('index', index - 1)
index = WD.get('index')
if index <= 0 then
WD.set('index', 0)
end
2020-11-17 13:45:47 +02:00
local unit_group_last_command = WD.get('unit_group_last_command')
if unit_group_last_command[k] then
unit_group_last_command[k] = nil
end
end
if type(group) ~= 'number' then
if group.valid then
2020-11-17 13:45:47 +02:00
command_unit_group(group)
end
2020-08-09 20:23:45 +02:00
end
end
2019-10-07 04:37:23 +02:00
end
2019-10-27 20:26:55 +02:00
local function spawn_unit_group()
2020-08-09 20:23:45 +02:00
if not can_units_spawn() then
return
end
2020-11-17 13:45:47 +02:00
local target = WD.get('target')
if not (target and target.valid) then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
local max_active_unit_groups = WD.get('max_active_unit_groups')
if get_active_unit_groups_count() >= max_active_unit_groups then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
local surface_index = WD.get('surface_index')
local surface = game.surfaces[surface_index]
2020-08-09 20:23:45 +02:00
set_group_spawn_position(surface)
2020-11-17 13:45:47 +02:00
local spawn_position = WD.get('spawn_position')
local pos = spawn_position
if not surface.can_place_entity({name = 'behemoth-biter', position = pos}) then
2020-08-09 20:23:45 +02:00
return
end
local radius = 10
local area = {left_top = {pos.x - radius, pos.y - radius}, right_bottom = {pos.x + radius, pos.y + radius}}
for k, v in pairs(surface.find_entities_filtered {area = area, name = 'land-mine'}) do
if v and v.valid then
v.die()
end
end
2020-11-17 13:45:47 +02:00
local wave_number = WD.get('wave_number')
BiterRolls.wave_defense_set_unit_raffle(wave_number)
2020-08-09 20:23:45 +02:00
2020-11-17 13:45:47 +02:00
debug_print('Spawning unit group at x' .. spawn_position.x .. ' y' .. spawn_position.y)
local position = spawn_position
2020-08-09 20:23:45 +02:00
local unit_group = surface.create_unit_group({position = position, force = 'enemy'})
2020-11-17 13:45:47 +02:00
local average_unit_group_size = WD.get('average_unit_group_size')
local group_size = math_floor(average_unit_group_size * group_size_modifier_raffle[math_random(1, group_size_modifier_raffle_size)])
2020-08-09 20:23:45 +02:00
for _ = 1, group_size, 1 do
local biter = spawn_biter(surface)
if not biter then
break
end
unit_group.add_member(biter)
end
2020-11-17 13:45:47 +02:00
local boss_wave = WD.get('boss_wave')
if boss_wave then
local count = math_random(1, math_floor(wave_number * 0.01) + 2)
if count > 16 then
count = 16
end
if count <= 1 then
count = 4
2020-08-09 20:23:45 +02:00
end
for _ = 1, count, 1 do
local biter = spawn_biter(surface, true)
if not biter then
break
end
unit_group.add_member(biter)
end
2020-11-17 13:45:47 +02:00
WD.set('boss_wave', false)
end
if unit_group then
unit_group.start_moving()
2020-08-09 20:23:45 +02:00
end
2020-11-17 13:45:47 +02:00
local unit_groups = WD.get('unit_groups')
unit_groups[unit_group.group_number] = unit_group
if math_random(1, 2) == 1 then
2020-11-17 13:45:47 +02:00
WD.set('random_group', unit_group.group_number)
end
2020-11-17 13:45:47 +02:00
local index = WD.get('index')
WD.set('index', index + 1)
2020-08-09 20:23:45 +02:00
return true
2019-10-27 20:26:55 +02:00
end
2019-10-28 14:29:15 +02:00
local function log_threat()
2020-11-17 13:45:47 +02:00
local threat_log_index = WD.get('threat_log_index')
WD.set('threat_log_index', threat_log_index + 1)
local threat_log = WD.get('threat_log')
local threat = WD.get('threat')
threat_log_index = WD.get('threat_log_index')
threat_log[threat_log_index] = threat
if threat_log_index > 900 then
threat_log[threat_log_index - 901] = nil
2020-08-09 20:23:45 +02:00
end
end
2019-10-15 04:20:40 +02:00
local tick_tasks = {
2020-08-09 20:23:45 +02:00
[30] = set_main_target,
[60] = set_enemy_evolution,
[90] = spawn_unit_group,
[120] = give_commands_to_unit_groups,
[150] = ThreatEvent.build_nest,
[180] = ThreatEvent.build_worm,
[3600] = time_out_biters,
[7200] = refresh_active_unit_threat
2019-10-15 04:20:40 +02:00
}
2019-10-07 01:46:26 +02:00
local function on_tick()
2020-11-17 13:45:47 +02:00
local tick = game.tick
local game_lost = WD.get('game_lost')
if game_lost then
2020-08-09 20:23:45 +02:00
return
end
2020-11-17 13:45:47 +02:00
local next_wave = WD.get('next_wave')
if tick > next_wave then
2020-08-09 20:23:45 +02:00
set_next_wave()
end
2020-11-17 13:45:47 +02:00
local t = tick % 300
local t2 = tick % 18000
2020-08-09 20:23:45 +02:00
if tick_tasks[t] then
tick_tasks[t]()
end
if tick_tasks[t2] then
tick_tasks[t2]()
end
2020-11-17 13:45:47 +02:00
local enable_threat_log = WD.get('enable_threat_log')
if enable_threat_log then
if tick % 60 == 0 then
2020-08-09 20:23:45 +02:00
log_threat()
end
end
local players = game.connected_players
for _, player in pairs(players) do
2020-08-09 20:23:45 +02:00
update_gui(player)
end
2019-10-07 01:46:26 +02:00
end
2020-08-09 20:22:33 +02:00
Event.on_nth_tick(30, on_tick)
2019-10-07 01:46:26 +02:00
2020-04-08 20:28:02 +02:00
return Public