1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-12 10:13:58 +02:00
FactorioScenarioMultiplayer.../lib/offline_protection.lua

109 lines
4.5 KiB
Lua

-- This attempt will try to intercept normal vanilla enemy groups and modify them based on player activity.
-- Basic logic:
-- on_unit_group_finished_gathering we check what command is given.
-- find destination position
-- check for closest "player" using find_nearest_enemy function
-- if a player is found, check if player is part of a shared spawn
-- Remove the enemy group if no player in the shared spawn is online.
-- Generic Utility Includes
require("lib/oarc_utils")
---This function is called when a unit group finishes gathering.
---@param event EventData.on_unit_group_finished_gathering
---@return nil
function OarcModifyEnemyGroup(event)
local group = event.group
-- Check validity
if ((group.command == nil) or (group.force.name ~= "enemy")) then
log("WARN - OarcModifyEnemyGroup ignoring INVALID group/command " .. serpent.block(group))
return
end
-- Make sure the attack is of a TYPE that we care about.
if ((group.command.type ~= defines.command.attack_area) and
(group.command.type ~= defines.command.build_base)) then
-- log("OarcModifyEnemyGroup ignoring command TYPE=" .. group.command.type)
return
end
-- For these 2 commands, we look around to find the nearest player.
-- defines.command.attack_area --> destination --> closest player (within 3 chunk radius?)
-- defines.command.build_base --> destination --> closest player (expansion chunk distance?)
local destination = group.command.destination
local search_radius = CHUNK_SIZE * 3 -- Just a reasonable default search size I think?
if (group.command.type == defines.command.build_base) then
search_radius = CHUNK_SIZE * (game.map_settings.enemy_expansion.max_expansion_distance)
end
-- Look for any player force targets near the destination point.
local target_entities = group.surface.find_entities_filtered{
position=destination,
radius=search_radius,
force=ENEMY_FORCES_NAMES_INCL_NEUTRAL,
limit=50,
invert=true}
-- Search through them all to find anything with a non-nil last_user.
local target_entity = nil
for _,target in ipairs(target_entities) do
if (target.last_user ~= nil) then
target_entity = target
break
end
end
-- No targets found with a last_user
if (target_entity == nil) then
-- This is unexpected, not sure under which conditions this would happen.
if (group.command.type == defines.command.attack_area) then
-- SendBroadcastMsg("OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!? " .. GetGPStext(group.surface.name, group.position) .. " Target: " .. GetGPStext(group.surface.name, group.command.destination))
log("ERROR - OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!?" .. serpent.block(group))
-- This is fine, as the enemy group is just expanding / building bases
else
-- log("OarcModifyEnemyGroup find_nearest_enemy did not find anything!")
end
return
end
-- Most common target will be a built entity with a "last_user"
local target_player = target_entity.last_user
-- I don't think this should happen ever...
if ((target_player == nil) or (not target_player.valid)) then
log("ERROR - OarcModifyEnemyGroup target_player nil/invalid?" .. serpent.block(group))
-- for _,member in pairs(group.members) do
-- member.destroy()
-- end
return
end
-- Is the target player online? Then the attack can go through.
if (target_player.connected) then
-- log("OarcModifyEnemyGroup RELEASING enemy group since player is ONLINE " .. target_player.name)
return
end
-- Find the shared spawn that the player is part of.
-- This could be the own player's spawn (quite likely)
local online_players = GetPlayersFromSameSpawn(target_player.name, false)
-- Is someone in the group online?
if (#online_players > 0) then
-- log("OarcModifyEnemyGroup RELEASING enemy group since someone in the group is ONLINE " .. target_player.name)
return
end
-- Otherwise, we delete the group.
for _,member in pairs(group.members) do
member.destroy()
end
-- log("OarcModifyEnemyGroup REMOVED enemy group since nobody was online? " .. target_player.name)
end