2019-11-09 16:46:18 +02:00
|
|
|
local BiterHealthBooster = require "modules.biter_health_booster"
|
2019-10-28 18:38:36 +02:00
|
|
|
local BiterRolls = require "modules.wave_defense.biter_rolls"
|
2019-10-29 12:26:59 +02:00
|
|
|
local SideTargets = require "modules.wave_defense.side_targets"
|
2019-10-28 18:38:36 +02:00
|
|
|
local ThreatEvent = require "modules.wave_defense.threat_events"
|
2019-10-22 10:18:28 +02:00
|
|
|
local update_gui = require "modules.wave_defense.gui"
|
2019-10-08 17:41:15 +02:00
|
|
|
local threat_values = require "modules.wave_defense.threat_values"
|
2019-10-28 18:38:36 +02:00
|
|
|
local WD = require "modules.wave_defense.table"
|
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
|
|
|
local event = require 'utils.event'
|
|
|
|
local Public = {}
|
|
|
|
|
2019-11-09 14:18:30 +02:00
|
|
|
local group_size_modifier_raffle = {}
|
|
|
|
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}}
|
|
|
|
for _, v in pairs(group_size_chances) do
|
|
|
|
for c = 1, v[1], 1 do
|
|
|
|
table_insert(group_size_modifier_raffle, v[2])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local group_size_modifier_raffle_size = #group_size_modifier_raffle
|
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
local function debug_print(msg)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if not wave_defense_table.debug then return end
|
|
|
|
print("WaveDefense: " .. msg)
|
2019-10-08 01:17:00 +02:00
|
|
|
end
|
|
|
|
|
2020-04-08 20:28:02 +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
|
|
|
|
|
2019-10-15 04:20:40 +02:00
|
|
|
local function is_unit_valid(biter)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-10-08 17:41:15 +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
|
2019-10-28 18:38:36 +02:00
|
|
|
if biter.spawn_tick + wave_defense_table.max_biter_age < game.tick then debug_print("is_unit_valid - unit destroyed - timed out") return false end
|
2019-10-07 22:40:05 +02:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-10-25 08:09:39 +02:00
|
|
|
local function refresh_active_unit_threat()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
debug_print("refresh_active_unit_threat - current value " .. wave_defense_table.active_biter_threat)
|
2019-10-25 08:09:39 +02:00
|
|
|
local active_biter_threat = 0
|
2019-10-28 18:38:36 +02:00
|
|
|
for k, biter in pairs(wave_defense_table.active_biters) do
|
2019-10-25 08:09:39 +02:00
|
|
|
if biter.entity then
|
|
|
|
if biter.entity.valid then
|
|
|
|
active_biter_threat = active_biter_threat + threat_values[biter.entity.name]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-11-09 14:18:30 +02:00
|
|
|
wave_defense_table.active_biter_threat = math_round(active_biter_threat * global.biter_health_boost, 2)
|
2019-10-28 18:38:36 +02:00
|
|
|
debug_print("refresh_active_unit_threat - new value " .. wave_defense_table.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()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
for k, biter in pairs(wave_defense_table.active_biters) do
|
2019-10-07 22:40:05 +02:00
|
|
|
if not is_unit_valid(biter) then
|
2019-10-28 18:38:36 +02:00
|
|
|
wave_defense_table.active_biter_count = wave_defense_table.active_biter_count - 1
|
2019-10-07 22:40:05 +02:00
|
|
|
if biter.entity then
|
|
|
|
if biter.entity.valid then
|
2019-11-09 14:18:30 +02:00
|
|
|
wave_defense_table.active_biter_threat = wave_defense_table.active_biter_threat - math_round(threat_values[biter.entity.name] * global.biter_health_boost, 2)
|
2019-10-14 06:52:17 +02:00
|
|
|
if biter.entity.force.index == 2 then
|
|
|
|
biter.entity.destroy()
|
|
|
|
end
|
2019-10-07 22:40:05 +02:00
|
|
|
end
|
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
wave_defense_table.active_biters[k] = nil
|
2019-10-07 04:37:23 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-10-12 04:06:48 +02:00
|
|
|
local function get_random_close_spawner(surface)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
local spawners = surface.find_entities_filtered({type = "unit-spawner"})
|
2019-10-07 01:46:26 +02:00
|
|
|
if not spawners[1] then return false end
|
2019-10-28 18:38:36 +02:00
|
|
|
local center = wave_defense_table.target.position
|
2019-11-09 14:18:30 +02:00
|
|
|
local spawner = spawners[math_random(1,#spawners)]
|
2019-10-28 18:38:36 +02:00
|
|
|
for i = 1, wave_defense_table.get_random_close_spawner_attempts, 1 do
|
2019-11-09 14:18:30 +02:00
|
|
|
local spawner_2 = spawners[math_random(1,#spawners)]
|
2019-10-28 18:38:36 +02:00
|
|
|
if (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 then spawner = spawner_2 end
|
|
|
|
end
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("get_random_close_spawner - Found at x" .. spawner.position.x .. " y" .. spawner.position.y)
|
2019-10-07 01:46:26 +02:00
|
|
|
return spawner
|
|
|
|
end
|
|
|
|
|
2020-01-01 15:05:49 +02:00
|
|
|
local function get_random_character(wave_defense_table)
|
|
|
|
local characters = {}
|
|
|
|
for _, player in pairs(game.connected_players) do
|
|
|
|
if player.character then
|
|
|
|
if player.character.valid then
|
|
|
|
if player.character.surface.index == wave_defense_table.surface_index then
|
|
|
|
characters[#characters + 1] = player.character
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not characters[1] then return end
|
|
|
|
return characters[math_random(1, #characters)]
|
|
|
|
end
|
|
|
|
|
2019-10-25 08:09:39 +02:00
|
|
|
local function set_main_target()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if wave_defense_table.target then
|
|
|
|
if wave_defense_table.target.valid then return end
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2020-01-01 15:05:49 +02:00
|
|
|
local target = SideTargets.get_side_target()
|
|
|
|
if not target then target = get_random_character(wave_defense_table) end
|
2019-10-25 08:09:39 +02:00
|
|
|
if not target then return end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
|
|
|
wave_defense_table.target = target
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("set_main_target -- New main target " .. target.name .. " at position x" .. target.position.x .. " y" .. target.position.y .. " selected.")
|
|
|
|
end
|
|
|
|
|
2019-10-12 04:06:48 +02:00
|
|
|
local function set_group_spawn_position(surface)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-10-12 04:06:48 +02:00
|
|
|
local spawner = get_random_close_spawner(surface)
|
2019-10-07 01:46:26 +02:00
|
|
|
if not spawner then return end
|
2020-01-01 15:05:49 +02:00
|
|
|
local position = surface.find_non_colliding_position("behemoth-biter", spawner.position, 64, 1)
|
2019-10-28 18:38:36 +02:00
|
|
|
if not position then return end
|
2019-11-01 17:24:44 +02:00
|
|
|
wave_defense_table.spawn_position = {x = position.x, y = position.y}
|
2019-10-28 18:38:36 +02:00
|
|
|
debug_print("set_group_spawn_position -- Changed position to x" .. wave_defense_table.spawn_position.x .. " y" .. wave_defense_table.spawn_position.y .. ".")
|
2019-10-07 01:46:26 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
local function set_enemy_evolution()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
local evolution_factor = wave_defense_table.wave_number * 0.001
|
2019-10-23 21:17:15 +02:00
|
|
|
local biter_health_boost = 1
|
2019-10-26 11:47:46 +02:00
|
|
|
--local damage_increase = 0
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-13 05:24:29 +02:00
|
|
|
if evolution_factor > 1 then
|
2019-10-26 11:47:46 +02:00
|
|
|
--damage_increase = damage_increase + (evolution_factor - 1)
|
2019-10-26 13:56:02 +02:00
|
|
|
--biter_health_boost = biter_health_boost + (evolution_factor - 1) * 2
|
2019-10-13 05:24:29 +02:00
|
|
|
evolution_factor = 1
|
|
|
|
end
|
2019-10-23 21:17:15 +02:00
|
|
|
|
2019-11-01 12:46:28 +02:00
|
|
|
if wave_defense_table.threat > 50000 then
|
2019-11-09 14:18:30 +02:00
|
|
|
biter_health_boost = math_round(biter_health_boost + (wave_defense_table.threat - 50000) * 0.000033, 3)
|
|
|
|
--damage_increase = math_round(damage_increase + wave_defense_table.threat * 0.0000025, 3)
|
2019-10-07 09:48:17 +02:00
|
|
|
end
|
2019-10-13 05:24:29 +02:00
|
|
|
|
2019-10-23 21:17:15 +02:00
|
|
|
global.biter_health_boost = biter_health_boost
|
2019-10-26 11:47:46 +02:00
|
|
|
--game.forces.enemy.set_ammo_damage_modifier("melee", damage_increase)
|
|
|
|
--game.forces.enemy.set_ammo_damage_modifier("biological", damage_increase)
|
2019-10-13 05:24:29 +02:00
|
|
|
game.forces.enemy.evolution_factor = evolution_factor
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
local function can_units_spawn()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if wave_defense_table.threat <= 0 then
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("can_units_spawn - threat too low")
|
2019-10-28 18:38:36 +02:00
|
|
|
return false
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
if wave_defense_table.active_biter_count >= wave_defense_table.max_active_biters then
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("can_units_spawn - active biter count too high")
|
2019-10-28 18:38:36 +02:00
|
|
|
return false
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
if wave_defense_table.active_biter_threat >= wave_defense_table.threat then
|
|
|
|
debug_print("can_units_spawn - active biter threat too high (" .. wave_defense_table.active_biter_threat .. ")")
|
|
|
|
return false
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
local function get_active_unit_groups_count()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-10-25 08:09:39 +02:00
|
|
|
local count = 0
|
2019-10-28 18:38:36 +02:00
|
|
|
for _, g in pairs(wave_defense_table.unit_groups) do
|
2019-10-25 08:09:39 +02:00
|
|
|
if g.valid then
|
2019-10-26 11:47:46 +02:00
|
|
|
if #g.members > 0 then
|
|
|
|
count = count + 1
|
|
|
|
else
|
|
|
|
g.destroy()
|
|
|
|
end
|
2019-10-25 08:09:39 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
debug_print("Active unit group count: " .. count)
|
|
|
|
return count
|
2019-10-07 01:46:26 +02:00
|
|
|
end
|
|
|
|
|
2019-11-09 16:46:18 +02:00
|
|
|
local function spawn_biter(surface, is_boss_biter)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-11-09 16:46:18 +02:00
|
|
|
if not is_boss_biter then
|
|
|
|
if not can_units_spawn() then return end
|
|
|
|
end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-12 04:06:48 +02:00
|
|
|
local name
|
2019-11-09 14:18:30 +02:00
|
|
|
if math_random(1,100) > 73 then
|
2019-10-28 18:38:36 +02:00
|
|
|
name = BiterRolls.wave_defense_roll_spitter_name()
|
2019-10-12 04:06:48 +02:00
|
|
|
else
|
2019-10-28 18:38:36 +02:00
|
|
|
name = BiterRolls.wave_defense_roll_biter_name()
|
2019-10-12 04:06:48 +02:00
|
|
|
end
|
2019-11-01 17:24:44 +02:00
|
|
|
--local position = surface.find_non_colliding_position(name, wave_defense_table.spawn_position, 48, 2)
|
|
|
|
--if not position then return false end
|
|
|
|
local biter = surface.create_entity({name = name, position = wave_defense_table.spawn_position, force = "enemy"})
|
2019-10-07 01:46:26 +02:00
|
|
|
biter.ai_settings.allow_destroy_when_commands_fail = false
|
|
|
|
biter.ai_settings.allow_try_return_to_spawner = false
|
2019-11-09 16:46:18 +02:00
|
|
|
if is_boss_biter then BiterHealthBooster.add_boss_unit(biter, global.biter_health_boost * 5, 0.35) end
|
2019-10-28 18:38:36 +02:00
|
|
|
wave_defense_table.active_biters[biter.unit_number] = {entity = biter, spawn_tick = game.tick}
|
|
|
|
wave_defense_table.active_biter_count = wave_defense_table.active_biter_count + 1
|
2019-11-09 14:18:30 +02:00
|
|
|
wave_defense_table.active_biter_threat = wave_defense_table.active_biter_threat + math_round(threat_values[name] * global.biter_health_boost, 2)
|
2019-10-14 06:52:17 +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()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
wave_defense_table.wave_number = wave_defense_table.wave_number + 1
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-30 18:29:15 +02:00
|
|
|
local threat_gain = wave_defense_table.wave_number * wave_defense_table.threat_gain_multiplier
|
2019-11-01 12:46:28 +02:00
|
|
|
if wave_defense_table.wave_number > 1000 then
|
|
|
|
threat_gain = threat_gain * (wave_defense_table.wave_number * 0.001)
|
|
|
|
end
|
2019-11-09 16:46:18 +02:00
|
|
|
if wave_defense_table.wave_number % 25 == 0 then
|
|
|
|
wave_defense_table.boss_wave = true
|
2020-04-08 20:28:02 +02:00
|
|
|
threat_gain = threat_gain * 2
|
2019-11-09 16:46:18 +02:00
|
|
|
end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
|
|
|
wave_defense_table.threat = wave_defense_table.threat + math_floor(threat_gain)
|
2019-10-28 18:38:36 +02:00
|
|
|
wave_defense_table.last_wave = wave_defense_table.next_wave
|
|
|
|
wave_defense_table.next_wave = game.tick + wave_defense_table.wave_interval
|
2019-10-07 22:40:05 +02:00
|
|
|
end
|
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
local function get_commmands(group)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-10-08 01:17:00 +02:00
|
|
|
local commands = {}
|
|
|
|
local group_position = {x = group.position.x, y = group.position.y}
|
2019-10-28 18:38:36 +02:00
|
|
|
local step_length = wave_defense_table.unit_group_command_step_length
|
|
|
|
|
2019-11-09 14:18:30 +02:00
|
|
|
if math_random(1,2) == 1 then
|
2019-10-29 12:26:59 +02:00
|
|
|
local side_target = SideTargets.get_side_target()
|
2019-10-11 21:52:32 +02:00
|
|
|
if side_target then
|
2019-10-28 18:38:36 +02:00
|
|
|
local target_position = side_target.position
|
2019-11-09 14:18:30 +02:00
|
|
|
local distance_to_target = math_floor(math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2))
|
|
|
|
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)}
|
2019-10-28 18:38:36 +02:00
|
|
|
|
|
|
|
if wave_defense_table.debug then
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("get_commmands - to side_target x" .. side_target.position.x .. " y" .. side_target.position.y)
|
|
|
|
debug_print("get_commmands - distance_to_target:" .. distance_to_target .. " steps:" .. steps)
|
|
|
|
debug_print("get_commmands - vector " .. vector[1] .. "_" .. vector[2])
|
2019-10-15 04:20:40 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-11 21:52:32 +02:00
|
|
|
for i = 1, steps, 1 do
|
2020-04-08 20:28:02 +02:00
|
|
|
local old_position = group_position
|
2019-10-11 21:52:32 +02:00
|
|
|
group_position.x = group_position.x + vector[1]
|
2020-04-08 20:28:02 +02:00
|
|
|
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 i = 1, #obstacles, 1 do
|
|
|
|
if obstacles[i].valid then
|
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack,
|
|
|
|
target = obstacles[i],
|
|
|
|
distraction = defines.distraction.by_enemy
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local position = group.surface.find_non_colliding_position("rocket-silo", group_position, step_length, 4)
|
2019-10-11 21:52:32 +02:00
|
|
|
if position then
|
2020-04-08 20:28:02 +02:00
|
|
|
-- commands[#commands + 1] = {
|
|
|
|
-- type = defines.command.go_to_location,
|
|
|
|
-- destination = {x = position.x, y = position.y},
|
|
|
|
-- distraction = defines.distraction.by_anything
|
|
|
|
-- }
|
2019-10-11 21:52:32 +02:00
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack_area,
|
|
|
|
destination = {x = position.x, y = position.y},
|
|
|
|
radius = 16,
|
|
|
|
distraction = defines.distraction.by_anything
|
|
|
|
}
|
2020-04-08 20:28:02 +02:00
|
|
|
else
|
|
|
|
local obstacles = group.surface.find_entities_filtered{position = group_position, radius = step_length, type = {"simple-entity", "tree"}, limit = 50}
|
|
|
|
if obstacles then
|
|
|
|
shuffle_distance(obstacles, old_position)
|
|
|
|
for i = 1, #obstacles, 1 do
|
|
|
|
if obstacles[i].valid then
|
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack,
|
|
|
|
target = obstacles[i],
|
|
|
|
distraction = defines.distraction.by_enemy
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
end
|
2019-10-11 21:52:32 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-11 21:52:32 +02:00
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack,
|
|
|
|
target = side_target,
|
|
|
|
distraction = defines.distraction.by_enemy,
|
2019-10-28 18:38:36 +02:00
|
|
|
}
|
2019-10-10 01:42:38 +02:00
|
|
|
end
|
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
|
|
|
|
local target_position = wave_defense_table.target.position
|
2019-11-09 14:18:30 +02:00
|
|
|
local distance_to_target = math_floor(math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2))
|
|
|
|
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)}
|
2019-10-28 18:38:36 +02:00
|
|
|
|
|
|
|
if wave_defense_table.debug then
|
2019-10-25 08:09:39 +02:00
|
|
|
debug_print("get_commmands - to main target x" .. target_position.x .. " y" .. target_position.y)
|
|
|
|
debug_print("get_commmands - distance_to_target:" .. distance_to_target .. " steps:" .. steps)
|
|
|
|
debug_print("get_commmands - vector " .. vector[1] .. "_" .. vector[2])
|
2019-10-15 04:20:40 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
for i = 1, steps, 1 do
|
2020-04-08 20:28:02 +02:00
|
|
|
local old_position = group_position
|
2019-10-08 01:17:00 +02:00
|
|
|
group_position.x = group_position.x + vector[1]
|
2019-10-28 18:38:36 +02:00
|
|
|
group_position.y = group_position.y + vector[2]
|
2020-04-08 20:28:02 +02:00
|
|
|
local obstacles = group.surface.find_entities_filtered{position = old_position, radius = step_length / 2, type = {"simple-entity", "tree"}, limit = 50}
|
|
|
|
if obstacles then
|
|
|
|
shuffle_distance(obstacles, old_position)
|
|
|
|
for i = 1, #obstacles, 1 do
|
|
|
|
if obstacles[i].valid then
|
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack,
|
|
|
|
target = obstacles[i],
|
|
|
|
distraction = defines.distraction.by_enemy
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local position = group.surface.find_non_colliding_position("rocket-silo", group_position, step_length, 1)
|
2019-10-08 01:17:00 +02:00
|
|
|
if position then
|
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack_area,
|
|
|
|
destination = {x = position.x, y = position.y},
|
|
|
|
radius = 16,
|
2019-10-08 05:50:32 +02:00
|
|
|
distraction = defines.distraction.by_anything
|
2019-10-08 01:17:00 +02:00
|
|
|
}
|
2019-10-28 18:38:36 +02:00
|
|
|
end
|
2019-10-08 01:17:00 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack_area,
|
2019-10-18 07:01:14 +02:00
|
|
|
destination = {x = target_position.x, y = target_position.y},
|
2019-10-08 01:17:00 +02:00
|
|
|
radius = 8,
|
|
|
|
distraction = defines.distraction.by_enemy
|
|
|
|
}
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
commands[#commands + 1] = {
|
|
|
|
type = defines.command.attack,
|
2019-10-28 18:38:36 +02:00
|
|
|
target = wave_defense_table.target,
|
2019-10-08 01:17:00 +02:00
|
|
|
distraction = defines.distraction.by_enemy,
|
|
|
|
}
|
2019-10-28 18:38:36 +02:00
|
|
|
|
2019-10-08 01:17:00 +02:00
|
|
|
return commands
|
|
|
|
end
|
|
|
|
|
2019-10-07 22:40:05 +02:00
|
|
|
local function command_unit_group(group)
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if not wave_defense_table.unit_group_last_command[group.group_number] then
|
|
|
|
wave_defense_table.unit_group_last_command[group.group_number] = game.tick - (wave_defense_table.unit_group_command_delay + 1)
|
|
|
|
end
|
|
|
|
if wave_defense_table.unit_group_last_command[group.group_number] then
|
2020-04-08 20:28:02 +02:00
|
|
|
if wave_defense_table.unit_group_last_command[group.group_number] + wave_defense_table.unit_group_command_delay > game.tick then return end
|
2019-10-16 00:23:54 +02:00
|
|
|
end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-07 22:40:05 +02:00
|
|
|
group.set_command({
|
|
|
|
type = defines.command.compound,
|
|
|
|
structure_type = defines.compound_command.return_last,
|
2019-10-08 01:17:00 +02:00
|
|
|
commands = get_commmands(group)
|
2019-10-07 22:40:05 +02:00
|
|
|
})
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-28 18:38:36 +02:00
|
|
|
wave_defense_table.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()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if #wave_defense_table.unit_groups == 0 then return end
|
|
|
|
if not wave_defense_table.target then return end
|
|
|
|
if not wave_defense_table.target.valid then return end
|
|
|
|
for k, group in pairs(wave_defense_table.unit_groups) do
|
2019-10-15 04:20:40 +02:00
|
|
|
if group.valid then
|
|
|
|
command_unit_group(group)
|
|
|
|
else
|
2019-10-28 18:38:36 +02:00
|
|
|
table.remove(wave_defense_table.unit_groups, k)
|
2019-10-15 04:20:40 +02:00
|
|
|
end
|
2019-10-28 18:38:36 +02:00
|
|
|
end
|
2019-10-07 04:37:23 +02:00
|
|
|
end
|
|
|
|
|
2019-10-27 20:26:55 +02:00
|
|
|
local function spawn_unit_group()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
2019-10-27 20:26:55 +02:00
|
|
|
if not can_units_spawn() then return end
|
2019-10-28 18:38:36 +02:00
|
|
|
if not wave_defense_table.target then return end
|
|
|
|
if not wave_defense_table.target.valid then return end
|
|
|
|
if get_active_unit_groups_count() >= wave_defense_table.max_active_unit_groups then return end
|
2019-11-14 19:48:03 +02:00
|
|
|
local surface = game.surfaces[wave_defense_table.surface_index]
|
|
|
|
set_group_spawn_position(surface)
|
2019-11-09 12:24:39 +02:00
|
|
|
local pos = wave_defense_table.spawn_position
|
2019-11-14 19:48:03 +02:00
|
|
|
if not surface.can_place_entity({name = "small-biter", position = pos}) then return end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-11-14 21:08:53 +02:00
|
|
|
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-04-08 20:28:02 +02:00
|
|
|
|
2019-10-28 18:38:36 +02:00
|
|
|
BiterRolls.wave_defense_set_unit_raffle(wave_defense_table.wave_number)
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-28 18:38:36 +02:00
|
|
|
debug_print("Spawning unit group at x" .. wave_defense_table.spawn_position.x .." y" .. wave_defense_table.spawn_position.y)
|
2020-04-08 20:28:02 +02:00
|
|
|
local unit_group = surface.create_unit_group({position = wave_defense_table.spawn_position, force = "enemy"})
|
2019-11-09 14:18:30 +02:00
|
|
|
local group_size = math_floor(wave_defense_table.average_unit_group_size * group_size_modifier_raffle[math_random(1, group_size_modifier_raffle_size)])
|
2019-11-09 16:46:18 +02:00
|
|
|
for _ = 1, group_size, 1 do
|
2019-10-27 20:26:55 +02:00
|
|
|
local biter = spawn_biter(surface)
|
|
|
|
if not biter then break end
|
|
|
|
unit_group.add_member(biter)
|
2019-11-09 16:46:18 +02:00
|
|
|
end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-11-09 16:46:18 +02:00
|
|
|
if wave_defense_table.boss_wave then
|
|
|
|
local count = math_random(1, math_floor(wave_defense_table.wave_number * 0.01) + 2)
|
|
|
|
if count > 8 then count = 8 end
|
|
|
|
for _ = 1, count, 1 do
|
|
|
|
local biter = spawn_biter(surface, true)
|
|
|
|
if not biter then break end
|
|
|
|
unit_group.add_member(biter)
|
|
|
|
end
|
|
|
|
wave_defense_table.boss_wave = false
|
|
|
|
end
|
|
|
|
|
2020-04-08 20:28:02 +02:00
|
|
|
table_insert(wave_defense_table.unit_groups, unit_group)
|
2019-10-27 20:26:55 +02:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2019-10-28 14:29:15 +02:00
|
|
|
local function log_threat()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
wave_defense_table.threat_log_index = wave_defense_table.threat_log_index + 1
|
|
|
|
wave_defense_table.threat_log[wave_defense_table.threat_log_index] = wave_defense_table.threat
|
2020-04-08 20:28:02 +02:00
|
|
|
if wave_defense_table.threat_log_index > 900 then wave_defense_table.threat_log[wave_defense_table.threat_log_index - 901] = nil end
|
2019-10-28 14:29:15 +02:00
|
|
|
end
|
|
|
|
|
2019-10-15 04:20:40 +02:00
|
|
|
local tick_tasks = {
|
|
|
|
[30] = set_main_target,
|
|
|
|
[60] = set_enemy_evolution,
|
2019-10-25 08:09:39 +02:00
|
|
|
[90] = spawn_unit_group,
|
2019-10-15 04:20:40 +02:00
|
|
|
[120] = give_commands_to_unit_groups,
|
2019-10-28 18:38:36 +02:00
|
|
|
[150] = ThreatEvent.build_nest,
|
|
|
|
[180] = ThreatEvent.build_worm,
|
2019-10-25 08:09:39 +02:00
|
|
|
[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()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
if wave_defense_table.game_lost then return end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-28 18:38:36 +02:00
|
|
|
if game.tick > wave_defense_table.next_wave then set_next_wave() end
|
2019-10-15 04:20:40 +02:00
|
|
|
|
|
|
|
local t = game.tick % 300
|
2019-10-25 08:09:39 +02:00
|
|
|
local t2 = game.tick % 18000
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-15 04:20:40 +02:00
|
|
|
if tick_tasks[t] then tick_tasks[t]() end
|
2019-10-25 08:09:39 +02:00
|
|
|
if tick_tasks[t2] then tick_tasks[t2]() end
|
2020-04-08 20:28:02 +02:00
|
|
|
|
2019-10-28 14:29:15 +02:00
|
|
|
if game.tick % 60 == 0 then log_threat() end
|
|
|
|
for _, player in pairs(game.connected_players) do update_gui(player) end
|
2019-10-07 01:46:26 +02:00
|
|
|
end
|
|
|
|
|
2019-10-07 16:40:52 +02:00
|
|
|
local function on_init()
|
2019-10-28 18:38:36 +02:00
|
|
|
local wave_defense_table = WD.get_table()
|
|
|
|
wave_defense_table.reset_wave_defense()
|
2019-10-07 16:40:52 +02:00
|
|
|
end
|
2019-10-07 01:46:26 +02:00
|
|
|
|
2019-10-07 04:37:23 +02:00
|
|
|
event.on_nth_tick(30, on_tick)
|
2020-04-08 20:28:02 +02:00
|
|
|
return Public
|