mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-10 00:43:27 +02:00
242 lines
6.8 KiB
Lua
242 lines
6.8 KiB
Lua
--luacheck: ignore
|
|
local Public = {}
|
|
local math_random = math.random
|
|
local math_floor = math.floor
|
|
local math_sqrt = math.sqrt
|
|
local math_round = math.round
|
|
local table_size = table.size
|
|
local table_insert = table.insert
|
|
local table_remove = table.remove
|
|
local table_shuffle = table.shuffle_table
|
|
|
|
local Global = require 'utils.global'
|
|
|
|
local tick_schedule = {}
|
|
Global.register(
|
|
tick_schedule,
|
|
function(t)
|
|
tick_schedule = t
|
|
end
|
|
)
|
|
|
|
local Table = require 'modules.scrap_towny_ffa.table'
|
|
local Evolution = require 'modules.scrap_towny_ffa.evolution'
|
|
|
|
local function get_commmands(target, group)
|
|
local commands = {}
|
|
local group_position = {x = group.position.x, y = group.position.y}
|
|
local step_length = 128
|
|
|
|
local target_position = target.position
|
|
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)}
|
|
|
|
for _ = 1, steps, 1 do
|
|
group_position.x = group_position.x + vector[1]
|
|
group_position.y = group_position.y + vector[2]
|
|
local position = group.surface.find_non_colliding_position('small-biter', group_position, step_length, 2)
|
|
if position then
|
|
commands[#commands + 1] = {
|
|
type = defines.command.attack_area,
|
|
destination = {x = position.x, y = position.y},
|
|
radius = 16,
|
|
distraction = defines.distraction.by_damage
|
|
}
|
|
end
|
|
end
|
|
|
|
commands[#commands + 1] = {
|
|
type = defines.command.attack_area,
|
|
destination = target.position,
|
|
radius = 12,
|
|
distraction = defines.distraction.by_enemy
|
|
}
|
|
commands[#commands + 1] = {
|
|
type = defines.command.attack,
|
|
target = target,
|
|
distraction = defines.distraction.by_anything
|
|
}
|
|
|
|
return commands
|
|
end
|
|
|
|
local function roll_market()
|
|
local ffatable = Table.get_table()
|
|
local town_centers = ffatable.town_centers
|
|
if town_centers == nil or table_size(town_centers) == 0 then
|
|
return
|
|
end
|
|
local keyset = {}
|
|
for town_name, _ in pairs(town_centers) do
|
|
table_insert(keyset, town_name)
|
|
end
|
|
local tc = math_random(1, #keyset)
|
|
return town_centers[keyset[tc]]
|
|
end
|
|
|
|
local function get_random_close_spawner(surface, market, radius)
|
|
local units = surface.find_enemy_units(market.position, radius, market.force)
|
|
if units ~= nil and #units > 0 then
|
|
-- found units, shuffle the list
|
|
table_shuffle(units)
|
|
while units[1] do
|
|
local unit = units[1]
|
|
if unit.spawner then
|
|
return unit.spawner
|
|
end
|
|
table_remove(units, 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function is_swarm_valid(swarm)
|
|
local group = swarm.group
|
|
if not group then
|
|
return
|
|
end
|
|
if not group.valid then
|
|
return
|
|
end
|
|
if game.tick >= swarm.timeout then
|
|
group.destroy()
|
|
return
|
|
end
|
|
return true
|
|
end
|
|
|
|
function Public.validate_swarms()
|
|
local ffatable = Table.get_table()
|
|
for k, swarm in pairs(ffatable.swarms) do
|
|
if not is_swarm_valid(swarm) then
|
|
table_remove(ffatable.swarms, k)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Public.unit_groups_start_moving()
|
|
local ffatable = Table.get_table()
|
|
for _, swarm in pairs(ffatable.swarms) do
|
|
if swarm.group then
|
|
if swarm.group.valid then
|
|
swarm.group.start_moving()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Public.swarm(town_center, radius)
|
|
if town_center == nil then
|
|
return
|
|
end
|
|
local ffatable = Table.get_table()
|
|
local r = radius or 32
|
|
local tc = town_center or roll_market()
|
|
if not tc or r > 512 then
|
|
return
|
|
end
|
|
|
|
-- skip if town evolution < 0.25
|
|
if town_center.get_biter_evolution < 0.25 then
|
|
return
|
|
end
|
|
|
|
-- skip if we have to many swarms already
|
|
local count = table_size(ffatable.swarms)
|
|
local towns = table_size(ffatable.town_centers)
|
|
if count > 3 * towns then
|
|
return
|
|
end
|
|
|
|
local market = tc.market
|
|
local surface = market.surface
|
|
|
|
-- find a spawner
|
|
local spawner = get_random_close_spawner(surface, market, r)
|
|
if not spawner then
|
|
r = r + 16
|
|
local future = game.tick + 1
|
|
-- schedule to run this method again with a higher radius on next tick
|
|
if not tick_schedule[future] then
|
|
tick_schedule[future] = {}
|
|
end
|
|
tick_schedule[future][#tick_schedule[future] + 1] = {
|
|
callback = 'swarm',
|
|
params = {tc, r}
|
|
}
|
|
return
|
|
end
|
|
|
|
-- get our evolution
|
|
local evolution = 0
|
|
if spawner.name == 'spitter-spawner' then
|
|
evolution = Evolution.get_biter_evolution(spawner)
|
|
else
|
|
evolution = Evolution.get_spitter_evolution(spawner)
|
|
end
|
|
|
|
-- get our target amount of enemies
|
|
local count2 = (evolution * 124) + 4
|
|
|
|
local units = spawner.surface.find_enemy_units(spawner.position, 16, market.force)
|
|
if #units < count2 then
|
|
units = spawner.surface.find_enemy_units(spawner.position, 32, market.force)
|
|
end
|
|
if #units < count2 then
|
|
units = spawner.surface.find_enemy_units(spawner.position, 64, market.force)
|
|
end
|
|
if #units < count2 then
|
|
units = spawner.surface.find_enemy_units(spawner.position, 128, market.force)
|
|
end
|
|
if not units[1] then
|
|
return
|
|
end
|
|
|
|
local unit_group_position = surface.find_non_colliding_position('biter-spawner', units[1].position, 256, 1)
|
|
if not unit_group_position then
|
|
return
|
|
end
|
|
local unit_group = surface.create_unit_group({position = unit_group_position, force = units[1].force})
|
|
|
|
for key, unit in pairs(units) do
|
|
if key > count2 then
|
|
break
|
|
end
|
|
unit_group.add_member(unit)
|
|
end
|
|
|
|
unit_group.set_command(
|
|
{
|
|
type = defines.command.compound,
|
|
structure_type = defines.compound_command.return_last,
|
|
commands = get_commmands(market, unit_group)
|
|
}
|
|
)
|
|
table_insert(ffatable.swarms, {group = unit_group, timeout = game.tick + 36000})
|
|
end
|
|
|
|
local function on_tick()
|
|
if not tick_schedule[game.tick] then
|
|
return
|
|
end
|
|
for _, token in pairs(tick_schedule[game.tick]) do
|
|
local callback = token.callback
|
|
local params = token.params
|
|
if callback == 'swarm' then
|
|
Public.swarm(params[1], params[2])
|
|
end
|
|
end
|
|
tick_schedule[game.tick] = nil
|
|
end
|
|
|
|
local on_init = function()
|
|
local ffatable = Table.get_table()
|
|
ffatable.swarms = {}
|
|
end
|
|
|
|
local Event = require 'utils.event'
|
|
Event.on_init(on_init)
|
|
Event.add(defines.events.on_tick, on_tick)
|
|
|
|
return Public
|