1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2025-01-24 03:16:22 +02:00

163 lines
7.2 KiB
Lua

-- oarc_enemies.lua
-- Feb 2020
-- This is my second attempt at modifying the normal enemy experience. The
-- first attempt ended up in a wave attack system which wasn't well received.
-- 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.
-- TODO:
-- Add options for modifying the default waves or spawning additional special waves.
-- Add option to disable attacks completely for a given spawn.
-- Generic Utility Includes
require("lib/oarc_utils")
function OarcModifyEnemyGroup(group)
-- Check validity
if ((group == nil) or (group.command == nil) or (group.force.name ~= "enemy")) then
log("OarcModifyEnemyGroup ignoring INVALID group/command")
return
end
-- Make sure the attack is of a TYPE that we care about.
if ((group.command.type == defines.command.attack) or
(group.command.type == defines.command.attack_area) or
(group.command.type == defines.command.build_base)) then
log("OarcModifyEnemyGroup MODIFYING command TYPE=" .. group.command.type)
else
log("OarcModifyEnemyGroup ignoring command TYPE=" .. group.command.type)
return
end
-- defines.command.attack --> target --> target.position
if (group.command.type == defines.command.attack) then
log("OarcModifyEnemyGroup defines.command.attack NOT IMPLEMENTED YET!")
return
-- defines.command.attack_area --> destination --> closest enemy (within 3 chunk radius?)
-- defines.command.build_base --> destination --> closest enemy (expansion chunk distance?)
else
local destination = group.command.destination
local distance = CHUNK_SIZE*3
if (group.command.type == defines.command.build_base) then
distance = CHUNK_SIZE*(game.map_settings.enemy_expansion.max_expansion_distance)
end
-- Find some enemies near the attack point.
local target_entities = group.surface.find_entities_filtered{
position=destination,
radius=distance,
force={"enemy", "neutral"},
limit=50,
invert=true}
-- Search through them all to find anything with a 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 enemies nearby?
if (target_entity == nil) then
if (group.command.type == defines.command.attack_area) then
if (global.enable_oe_debug) then
SendBroadcastMsg("OarcModifyEnemyGroup find_nearest_enemy attack_area FAILED!?!? " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(destination))
end
log("OarcModifyEnemyGroup UNEXPECTED find_nearest_enemy did not find anything!")
for _,member in pairs(group.members) do
member.destroy()
end
else
log("OarcModifyEnemyGroup find_nearest_enemy did not find anything!")
end
return
end
-- Probably don't need this I hope?
if (target_entity.force == "neutral") then
log("OarcModifyEnemyGroup UNEXPECTED find_nearest_enemy found neutral target?")
for _,member in pairs(group.members) do
member.destroy()
end
return
end
-- Most common target will be a built entity with a "last_user"
local target_player = target_entity.last_user
-- Target could also be a player character (more rare)
if (target_player == nil) and (target_entity.type == "character") then
target_player = target_entity.player
end
-- I don't think this should happen...
if ((target_player == nil) or (not target_player.valid)) then
if (global.enable_oe_debug) then
SendBroadcastMsg("ERROR?? target_player nil/invalid " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(target_entity.position))
end
log("OarcModifyEnemyGroup ERROR?? target_player nil/invalid")
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
if (global.enable_oe_debug) then
SendBroadcastMsg("Enemy group released (player): " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(target_entity.position) .. " " .. target_player.name)
end
log("OarcModifyEnemyGroup RELEASING enemy group since player is ONLINE")
return
end
-- Find the shared spawn that the player is part of.
-- This could be the own player's spawn (quite likely)
local sharedSpawnOwnerName = FindPlayerSharedSpawn(target_player.name)
-- Is someone in the shared spawn online?
if (sharedSpawnOwnerName ~= nil) then
if (GetOnlinePlayersAtSharedSpawn(sharedSpawnOwnerName) > 0) then
if (global.enable_oe_debug) then
SendBroadcastMsg("Enemy group released (shared): " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(target_entity.position) .. " " .. target_player.name)
end
log("OarcModifyEnemyGroup RELEASING enemy group since someone in the group is ONLINE")
return
end
end
-- Is there a buddy spawn and is the buddy online?
local buddyName = global.ocore.buddyPairs[sharedSpawnOwnerName]
if (buddyName ~= nil) and (game.players[buddyName] ~= nil) then
if (game.players[buddyName].connected or (GetOnlinePlayersAtSharedSpawn(buddyName) > 0)) then
if (global.enable_oe_debug) then
SendBroadcastMsg("Enemy group released (buddy): " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(target_entity.position) .. " " .. target_player.name)
end
log("OarcModifyEnemyGroup RELEASING enemy group since someone in the BUDDY PAIR is ONLINE")
return
end
end
-- Otherwise, we delete the group.
if (global.enable_oe_debug) then
SendBroadcastMsg("Enemy group deleted: " .. GetGPStext(group.position) .. " Target: " .. GetGPStext(target_entity.position) .. " " .. target_player.name)
end
for _,member in pairs(group.members) do
member.destroy()
end
log("OarcModifyEnemyGroup REMOVED enemy group since nobody was online?")
end
end