1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-08 00:39:30 +02:00
ComfyFactorio/modules/towny/biters.lua
MewMew e3e476a06a update
no biter attacks for new towns at high evo
clear spawn of biters for outlanders
clear units that are out of the current evolution range
prevent outlanders from building close to towns centers
2019-12-28 14:56:04 +01:00

196 lines
6.1 KiB
Lua

local Public = {}
local math_random = math.random
local math_floor = math.floor
local math_sqrt = math.sqrt
local math_round = math.round
local table_insert = table.insert
local table_remove = table.remove
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 i = 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_anything
}
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_enemy,
}
return commands
end
local function roll_market()
local r_max = 0
local town_centers = global.towny.town_centers
--Skip Towns that are too low in reserach for the current biter evolution.
local research_threshold = game.forces.enemy.evolution_factor * #game.technology_prototypes * 0.175
for k, town_center in pairs(town_centers) do
if town_center.research_counter >= research_threshold then
r_max = r_max + town_center.research_counter
end
end
if r_max == 0 then return end
local r = math_random(0, r_max)
local chance = 0
for k, town_center in pairs(town_centers) do
if town_center.research_counter >= research_threshold then
chance = chance + town_center.research_counter
if r <= chance then return town_center end
end
end
end
local function get_random_close_spawner(surface, market)
local spawners = surface.find_entities_filtered({type = "unit-spawner"})
if not spawners[1] then return false end
local size_of_spawners = #spawners
local center = market.position
local spawner = spawners[math_random(1, size_of_spawners)]
for i = 1, 64, 1 do
local spawner_2 = spawners[math_random(1, size_of_spawners)]
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
return spawner
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()
for k, swarm in pairs(global.towny.swarms) do
if not is_swarm_valid(swarm) then
table_remove(global.towny.swarms, k)
end
end
end
--Destroy biters that are out of the current evolution range.
function Public.wipe_units_out_of_evo_range()
local units_to_wipe = {}
local evo = game.forces.enemy.evolution_factor
if evo > 0.80 then return end
units_to_wipe[#units_to_wipe + 1] = "behemoth-biter"
units_to_wipe[#units_to_wipe + 1] = "behemoth-spitter"
if evo < 0.40 then
units_to_wipe[#units_to_wipe + 1] = "big-biter"
units_to_wipe[#units_to_wipe + 1] = "big-spitter"
end
if evo < 0.10 then
units_to_wipe[#units_to_wipe + 1] = "medium-biter"
units_to_wipe[#units_to_wipe + 1] = "medium-spitter"
end
for k, surface in pairs(game.surfaces) do
for k2, unit in pairs(surface.find_entities_filtered({name = units_to_wipe, force = "enemy"})) do
unit.destroy()
end
end
end
function Public.clear_spawn_for_player(player)
local area = {{player.position.x - 64, player.position.y - 64}, {player.position.x + 64, player.position.y + 64}}
for _, e in pairs(player.surface.find_entities_filtered({force = "enemy", type = {"unit-spawner", "unit", "turret"}, area = area})) do
e.destroy()
end
end
function Public.unit_groups_start_moving()
for k, swarm in pairs(global.towny.swarms) do
if swarm.group then
if swarm.group.valid then
swarm.group.start_moving()
end
end
end
end
function Public.swarm()
local count = 0
for k, swarm in pairs(global.towny.swarms) do
count = count + 1
end
if count > 6 then return end
local town_center = roll_market()
if not town_center then return end
local market = town_center.market
local surface = market.surface
local spawner = get_random_close_spawner(surface, market)
if not spawner then return end
local units = spawner.surface.find_enemy_units(spawner.position, 160, market.force)
if not units[1] then return end
local unit_group_position = surface.find_non_colliding_position("market", 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})
local count = (town_center.research_counter * 1.5) + 4
for key, unit in pairs(units) do
if key > count 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(global.towny.swarms, {group = unit_group, timeout = game.tick + 36000})
end
function Public.set_evolution()
local town_center_count = global.towny.size_of_town_centers
if town_center_count == 0 then
game.forces.enemy.evolution_factor = 0
return
end
local max_research_count = math_floor(#game.technology_prototypes * 0.30)
local evo = 0
for _, town_center in pairs(global.towny.town_centers) do
evo = evo + town_center.research_counter
end
evo = evo / town_center_count
evo = evo / max_research_count
if evo > 1 then evo = 1 end
game.forces.enemy.evolution_factor = evo
end
return Public