2022-01-15 00:08:58 +02:00
|
|
|
-- Copyright (C) 2022 veden
|
|
|
|
|
|
|
|
-- This program is free software: you can redistribute it and/or modify
|
|
|
|
-- it under the terms of the GNU General Public License as published by
|
|
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
|
|
|
-- (at your option) any later version.
|
|
|
|
|
|
|
|
-- This program is distributed in the hope that it will be useful,
|
|
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
-- GNU General Public License for more details.
|
|
|
|
|
|
|
|
-- You should have received a copy of the GNU General Public License
|
|
|
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
if ProcessorG then
|
|
|
|
return ProcessorG
|
2019-02-16 06:17:30 +02:00
|
|
|
end
|
2023-03-12 06:51:13 +02:00
|
|
|
local Processor = {}
|
2016-08-05 06:47:51 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
--
|
|
|
|
|
2023-04-08 06:07:13 +02:00
|
|
|
local TargetPosition
|
2023-03-11 22:53:06 +02:00
|
|
|
local Universe
|
2023-03-19 19:25:46 +02:00
|
|
|
local Queries
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
-- imports
|
2017-06-16 03:30:26 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
local Utils = require("Utils")
|
2023-03-11 22:53:06 +02:00
|
|
|
local MapUtils = require("MapUtils")
|
2023-03-12 06:51:13 +02:00
|
|
|
local Squad = require("Squad")
|
|
|
|
local Constants = require("Constants")
|
2023-03-11 22:53:06 +02:00
|
|
|
local ChunkUtils = require("ChunkUtils")
|
|
|
|
local ChunkPropertyUtils = require("ChunkPropertyUtils")
|
|
|
|
local BaseUtils = require("BaseUtils")
|
2023-03-12 06:51:13 +02:00
|
|
|
local MathUtils = require("MathUtils")
|
2016-09-14 13:16:33 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
-- Constants
|
2020-04-28 05:41:18 +02:00
|
|
|
|
2023-03-19 19:25:46 +02:00
|
|
|
local CHUNK_SIZE = Constants.CHUNK_SIZE
|
2023-03-22 08:09:51 +02:00
|
|
|
local EIGHTH_CHUNK_SIZE = Constants.EIGHTH_CHUNK_SIZE
|
2023-03-19 19:25:46 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local PLAYER_PHEROMONE_GENERATOR_AMOUNT = Constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
2016-11-04 09:26:19 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local PROCESS_QUEUE_SIZE = Constants.PROCESS_QUEUE_SIZE
|
|
|
|
local RESOURCE_QUEUE_SIZE = Constants.RESOURCE_QUEUE_SIZE
|
|
|
|
local ENEMY_QUEUE_SIZE = Constants.ENEMY_QUEUE_SIZE
|
|
|
|
local PLAYER_QUEUE_SIZE = Constants.PLAYER_QUEUE_SIZE
|
2016-09-14 13:16:33 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local CLEANUP_QUEUE_SIZE = Constants.CLEANUP_QUEUE_SIZE
|
2016-10-15 02:00:18 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local PROCESS_PLAYER_BOUND = Constants.PROCESS_PLAYER_BOUND
|
2020-05-22 20:45:05 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local AI_VENGENCE_SQUAD_COST = Constants.AI_VENGENCE_SQUAD_COST
|
2016-11-04 09:26:19 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local COOLDOWN_DRAIN = Constants.COOLDOWN_DRAIN
|
|
|
|
local COOLDOWN_RALLY = Constants.COOLDOWN_RALLY
|
|
|
|
local COOLDOWN_RETREAT = Constants.COOLDOWN_RETREAT
|
2023-03-22 08:09:51 +02:00
|
|
|
|
|
|
|
local BUILDING_HIVE_TYPE_LOOKUP = Constants.BUILDING_HIVE_TYPE_LOOKUP
|
|
|
|
|
|
|
|
local DEV_HIVE_TTL = Constants.DEV_HIVE_TTL
|
|
|
|
local MAX_HIVE_TTL = Constants.MAX_HIVE_TTL
|
|
|
|
local MIN_HIVE_TTL = Constants.MIN_HIVE_TTL
|
2023-03-12 06:51:13 +02:00
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- imported functions
|
|
|
|
|
2023-03-22 08:09:51 +02:00
|
|
|
local distortPositionConcentricCircles = MathUtils.distortPositionConcentricCircles
|
|
|
|
local linearInterpolation = MathUtils.linearInterpolation
|
|
|
|
local gaussianRandomRangeRG = MathUtils.gaussianRandomRangeRG
|
2023-03-12 06:51:13 +02:00
|
|
|
local findInsertionPoint = MapUtils.findInsertionPoint
|
|
|
|
|
|
|
|
local createChunk = ChunkUtils.createChunk
|
|
|
|
local initialScan = ChunkUtils.initialScan
|
|
|
|
|
|
|
|
local removeChunkFromMap = MapUtils.removeChunkFromMap
|
|
|
|
local chunkPassScan = ChunkUtils.chunkPassScan
|
|
|
|
|
|
|
|
local unregisterEnemyBaseStructure = ChunkUtils.unregisterEnemyBaseStructure
|
|
|
|
local setPositionInQuery = Utils.setPositionInQuery
|
2023-01-08 08:53:47 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local addPlayerGenerator = ChunkPropertyUtils.addPlayerGenerator
|
|
|
|
local findNearbyBase = ChunkPropertyUtils.findNearbyBase
|
2022-02-28 04:45:42 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local removeChunkToNest = MapUtils.removeChunkToNest
|
2022-01-14 21:17:33 +02:00
|
|
|
|
2023-03-22 08:09:51 +02:00
|
|
|
local queueCreation = BaseUtils.queueCreation
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
local processPheromone = MapUtils.processPheromone
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local getCombinedDeathGeneratorRating = ChunkPropertyUtils.getCombinedDeathGeneratorRating
|
|
|
|
local processBaseMutation = BaseUtils.processBaseMutation
|
2020-05-20 04:37:16 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local processNestActiveness = ChunkPropertyUtils.processNestActiveness
|
2020-05-20 04:37:16 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
local formSquads = Squad.formSquads
|
|
|
|
local formVengenceSquad = Squad.formVengenceSquad
|
|
|
|
local formVengenceSettler = Squad.formVengenceSettler
|
|
|
|
local formSettlers = Squad.formSettlers
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local getChunkByPosition = MapUtils.getChunkByPosition
|
|
|
|
local getChunkByXY = MapUtils.getChunkByXY
|
2016-10-15 02:00:18 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
local validPlayer = Utils.validPlayer
|
2017-11-21 09:27:03 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local mapScanEnemyChunk = ChunkUtils.mapScanEnemyChunk
|
|
|
|
local mapScanPlayerChunk = ChunkUtils.mapScanPlayerChunk
|
|
|
|
local mapScanResourceChunk = ChunkUtils.mapScanResourceChunk
|
2017-12-29 07:38:10 +02:00
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local getEnemyStructureCount = ChunkPropertyUtils.getEnemyStructureCount
|
2016-08-20 04:52:27 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
local canAttack = BaseUtils.canAttack
|
|
|
|
local canMigrate = BaseUtils.canMigrate
|
2017-05-14 00:32:16 +02:00
|
|
|
|
2021-02-14 06:49:54 +02:00
|
|
|
local tableSize = table_size
|
2017-05-28 06:50:37 +02:00
|
|
|
|
2016-08-29 02:05:28 +02:00
|
|
|
local mMin = math.min
|
2020-05-22 08:57:03 +02:00
|
|
|
local mMax = math.max
|
2023-03-12 06:51:13 +02:00
|
|
|
local tableInsert = table.insert
|
2016-08-29 02:05:28 +02:00
|
|
|
|
2020-05-20 04:37:16 +02:00
|
|
|
local next = next
|
2017-07-01 06:36:23 +02:00
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- module code
|
|
|
|
|
2016-10-15 02:00:18 +02:00
|
|
|
--[[
|
|
|
|
processing is not consistant as it depends on the number of chunks that have been generated
|
|
|
|
so if we process 400 chunks an iteration and 200 chunks have been generated than these are
|
|
|
|
processed 3 times a second and 1200 generated chunks would be processed once a second
|
2019-02-03 08:01:28 +02:00
|
|
|
In theory, this might be fine as smaller bases have less surface to attack and need to have
|
2016-10-15 02:00:18 +02:00
|
|
|
pheromone dissipate at a faster rate.
|
|
|
|
--]]
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processMap(map, tick)
|
2018-01-14 07:48:21 +02:00
|
|
|
local processQueue = map.processQueue
|
2020-05-22 08:57:03 +02:00
|
|
|
local processQueueLength = #processQueue
|
2018-10-20 07:17:37 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (processQueueLength == 0) then
|
|
|
|
return
|
|
|
|
end
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2023-03-11 21:10:15 +02:00
|
|
|
local startIndex = mMin(map.processIndex, processQueueLength)
|
2020-05-22 20:45:05 +02:00
|
|
|
local step
|
|
|
|
local endIndex
|
2023-03-11 21:10:15 +02:00
|
|
|
if map.outgoingScanWave then
|
2020-05-22 20:45:05 +02:00
|
|
|
step = 1
|
2023-03-11 21:10:15 +02:00
|
|
|
endIndex = mMin(startIndex + PROCESS_QUEUE_SIZE, processQueueLength)
|
|
|
|
if (endIndex == processQueueLength) then
|
|
|
|
map.outgoingScanWave = false
|
|
|
|
map.processIndex = processQueueLength
|
|
|
|
else
|
|
|
|
map.processIndex = endIndex + 1
|
|
|
|
end
|
2020-05-22 20:45:05 +02:00
|
|
|
else
|
|
|
|
step = -1
|
2023-03-11 21:10:15 +02:00
|
|
|
endIndex = mMax(startIndex - PROCESS_QUEUE_SIZE, 1)
|
|
|
|
if (endIndex == 1) then
|
|
|
|
map.outgoingScanWave = true
|
|
|
|
map.processIndex = 1
|
|
|
|
else
|
|
|
|
map.processIndex = endIndex - 1
|
|
|
|
end
|
2020-05-22 20:45:05 +02:00
|
|
|
end
|
2023-03-11 22:53:06 +02:00
|
|
|
Universe.processedChunks = Universe.processedChunks + ((startIndex - endIndex) * step)
|
2020-05-22 20:45:05 +02:00
|
|
|
|
2023-03-11 21:10:15 +02:00
|
|
|
for x=startIndex,endIndex,step do
|
2023-03-13 01:13:32 +02:00
|
|
|
processPheromone(processQueue[x], tick)
|
2020-05-22 20:45:05 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-15 02:00:18 +02:00
|
|
|
--[[
|
|
|
|
Localized player radius were processing takes place in realtime, doesn't store state
|
|
|
|
between calls.
|
2019-02-03 08:01:28 +02:00
|
|
|
vs
|
2016-10-15 02:00:18 +02:00
|
|
|
the slower passive version processing the entire map in multiple passes.
|
|
|
|
--]]
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processPlayers(players, tick)
|
2016-10-15 02:00:18 +02:00
|
|
|
-- put down player pheromone for player hunters
|
|
|
|
-- randomize player order to ensure a single player isn't singled out
|
2018-05-26 00:23:22 +02:00
|
|
|
-- not looping everyone because the cost is high enough already in multiplayer
|
2023-01-19 07:49:15 +02:00
|
|
|
local playerCount = #players
|
|
|
|
local playerMaxGenerator = playerCount * PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
|
|
|
for i=1,playerCount do
|
2023-01-08 03:59:21 +02:00
|
|
|
local player = players[i]
|
|
|
|
if validPlayer(player) then
|
|
|
|
local char = player.character
|
2023-03-11 22:53:06 +02:00
|
|
|
local map = Universe.maps[char.surface.index]
|
2023-01-08 03:59:21 +02:00
|
|
|
if map then
|
|
|
|
local playerChunk = getChunkByPosition(map, char.position)
|
|
|
|
|
|
|
|
if (playerChunk ~= -1) then
|
2023-03-12 03:21:22 +02:00
|
|
|
addPlayerGenerator(playerChunk, playerMaxGenerator)
|
2023-01-08 03:59:21 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-19 19:25:46 +02:00
|
|
|
if (#players == 0) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local player = players[Universe.random(#players)]
|
|
|
|
if not validPlayer(player) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local char = player.character
|
|
|
|
local map = Universe.maps[char.surface.index]
|
|
|
|
if not map then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local playerChunk = getChunkByPosition(map, char.position)
|
2021-12-06 03:16:14 +02:00
|
|
|
|
2023-03-19 19:25:46 +02:00
|
|
|
if (playerChunk == -1) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local base = findNearbyBase(playerChunk)
|
|
|
|
if not base then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local allowingAttacks = canAttack(base)
|
|
|
|
local vengence = allowingAttacks and
|
|
|
|
(base.unitPoints >= AI_VENGENCE_SQUAD_COST) and
|
|
|
|
((getEnemyStructureCount(playerChunk) > 0) or
|
|
|
|
(getCombinedDeathGeneratorRating(playerChunk) < Universe.retreatThreshold))
|
|
|
|
|
|
|
|
local quadrant = Universe.random(4)
|
|
|
|
|
|
|
|
local pX = playerChunk.x
|
|
|
|
local pY = playerChunk.y
|
|
|
|
local pXStart
|
|
|
|
local pYStart
|
|
|
|
local pXEnd
|
|
|
|
local pYEnd
|
|
|
|
|
|
|
|
if quadrant == 1 then
|
|
|
|
pXStart = pX - PROCESS_PLAYER_BOUND
|
|
|
|
pXEnd = pX
|
|
|
|
pYStart = pY - PROCESS_PLAYER_BOUND
|
|
|
|
pYEnd = pY
|
|
|
|
elseif quadrant == 2 then
|
|
|
|
pXStart = pX
|
|
|
|
pXEnd = pX + PROCESS_PLAYER_BOUND
|
|
|
|
pYStart = pY - PROCESS_PLAYER_BOUND
|
|
|
|
pYEnd = pY
|
|
|
|
elseif quadrant == 3 then
|
|
|
|
pXStart = pX - PROCESS_PLAYER_BOUND
|
|
|
|
pXEnd = pX
|
|
|
|
pYStart = pY
|
|
|
|
pYEnd = pY + PROCESS_PLAYER_BOUND
|
|
|
|
elseif quadrant == 4 then
|
|
|
|
pXStart = pX
|
|
|
|
pXEnd = pX + PROCESS_PLAYER_BOUND
|
|
|
|
pYStart = pY
|
|
|
|
pYEnd = pY + PROCESS_PLAYER_BOUND
|
|
|
|
end
|
|
|
|
|
|
|
|
for x=pXStart, pXEnd, CHUNK_SIZE do
|
|
|
|
for y=pYStart, pYEnd, CHUNK_SIZE do
|
|
|
|
local chunk = getChunkByXY(map, x, y)
|
|
|
|
|
|
|
|
if (chunk ~= -1) then
|
|
|
|
processPheromone(chunk, tick, true)
|
|
|
|
|
|
|
|
if chunk.nestCount then
|
|
|
|
processNestActiveness(chunk, tick)
|
|
|
|
|
|
|
|
if vengence then
|
|
|
|
Universe.vengenceQueue[chunk.id] = chunk
|
2019-10-19 21:13:48 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-10-15 02:00:18 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-12 04:14:42 +02:00
|
|
|
local function processCleanUp(chunks, tick, duration)
|
|
|
|
local chunkId, eventTick = next(chunks, nil)
|
2021-12-09 08:01:54 +02:00
|
|
|
if not chunkId then
|
2023-03-12 04:14:42 +02:00
|
|
|
return
|
2021-12-09 08:01:54 +02:00
|
|
|
end
|
2023-03-12 04:14:42 +02:00
|
|
|
if (tick - eventTick) > duration then
|
|
|
|
chunks[chunkId] = nil
|
2021-12-09 08:01:54 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.cleanUpMapTables(tick)
|
2023-03-11 22:53:06 +02:00
|
|
|
local retreats = Universe.chunkToRetreats
|
|
|
|
local rallys = Universe.chunkToRallys
|
|
|
|
local drained = Universe.chunkToDrained
|
2017-05-24 08:46:23 +02:00
|
|
|
|
2021-12-09 08:13:38 +02:00
|
|
|
for _=1,CLEANUP_QUEUE_SIZE do
|
2023-03-12 04:14:42 +02:00
|
|
|
processCleanUp(retreats, tick, COOLDOWN_RETREAT)
|
2018-02-12 05:21:28 +02:00
|
|
|
|
2023-03-12 04:14:42 +02:00
|
|
|
processCleanUp(rallys, tick, COOLDOWN_RALLY)
|
2018-02-12 05:21:28 +02:00
|
|
|
|
2023-03-12 04:14:42 +02:00
|
|
|
processCleanUp(drained, tick, COOLDOWN_DRAIN)
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[
|
|
|
|
Passive scan to find entities that have been generated outside the factorio event system
|
|
|
|
--]]
|
2023-03-13 01:13:32 +02:00
|
|
|
function Processor.scanPlayerMap(map)
|
2020-05-22 08:57:03 +02:00
|
|
|
local index = map.scanPlayerIndex
|
|
|
|
|
|
|
|
local processQueue = map.processQueue
|
2020-12-05 06:49:51 +02:00
|
|
|
local processQueueLength = #processQueue
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
local endIndex = mMin(index + PLAYER_QUEUE_SIZE, processQueueLength)
|
|
|
|
|
|
|
|
if (processQueueLength == 0) then
|
|
|
|
return
|
|
|
|
end
|
2020-05-22 08:57:03 +02:00
|
|
|
|
|
|
|
for x=index,endIndex do
|
2021-12-11 20:42:49 +02:00
|
|
|
mapScanPlayerChunk(processQueue[x], map)
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (endIndex == processQueueLength) then
|
2020-05-22 08:57:03 +02:00
|
|
|
map.scanPlayerIndex = 1
|
|
|
|
else
|
|
|
|
map.scanPlayerIndex = endIndex + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.scanEnemyMap(map, tick)
|
2020-05-22 08:57:03 +02:00
|
|
|
local index = map.scanEnemyIndex
|
|
|
|
|
|
|
|
local processQueue = map.processQueue
|
2020-12-05 06:49:51 +02:00
|
|
|
local processQueueLength = #processQueue
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2020-05-22 08:57:03 +02:00
|
|
|
local endIndex = mMin(index + ENEMY_QUEUE_SIZE, #processQueue)
|
2019-02-19 02:43:01 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (processQueueLength == 0) then
|
|
|
|
return
|
|
|
|
end
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2020-05-22 08:57:03 +02:00
|
|
|
for x=index,endIndex do
|
2021-12-05 02:46:29 +02:00
|
|
|
mapScanEnemyChunk(processQueue[x], map, tick)
|
2016-08-05 06:47:51 +02:00
|
|
|
end
|
2017-04-22 01:14:04 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (endIndex == processQueueLength) then
|
2020-05-22 08:57:03 +02:00
|
|
|
map.scanEnemyIndex = 1
|
2016-08-29 02:05:28 +02:00
|
|
|
else
|
2020-05-22 08:57:03 +02:00
|
|
|
map.scanEnemyIndex = endIndex + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-13 01:13:32 +02:00
|
|
|
function Processor.scanResourceMap(map)
|
2020-05-22 08:57:03 +02:00
|
|
|
local index = map.scanResourceIndex
|
|
|
|
|
2021-02-14 06:49:54 +02:00
|
|
|
local processQueue = map.processQueue
|
2020-12-05 06:49:51 +02:00
|
|
|
local processQueueLength = #processQueue
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
local endIndex = mMin(index + RESOURCE_QUEUE_SIZE, processQueueLength)
|
2020-05-22 08:57:03 +02:00
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (processQueueLength == 0) then
|
|
|
|
return
|
|
|
|
end
|
2021-02-14 06:49:54 +02:00
|
|
|
|
2020-05-22 08:57:03 +02:00
|
|
|
for x=index,endIndex do
|
2021-12-11 20:42:49 +02:00
|
|
|
mapScanResourceChunk(processQueue[x], map)
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
|
|
|
|
2020-12-05 06:49:51 +02:00
|
|
|
if (endIndex == processQueueLength) then
|
2020-05-22 08:57:03 +02:00
|
|
|
map.scanResourceIndex = 1
|
|
|
|
else
|
|
|
|
map.scanResourceIndex = endIndex + 1
|
2016-08-20 04:52:27 +02:00
|
|
|
end
|
2016-08-05 06:47:51 +02:00
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processVengence()
|
2023-03-11 22:53:06 +02:00
|
|
|
local vengenceQueue = Universe.vengenceQueue
|
2023-03-12 04:14:42 +02:00
|
|
|
local chunkId, chunk = next(vengenceQueue, nil)
|
2021-12-05 20:19:04 +02:00
|
|
|
if not chunkId then
|
2021-12-06 05:40:39 +02:00
|
|
|
if (tableSize(vengenceQueue) == 0) then
|
2023-03-11 22:53:06 +02:00
|
|
|
Universe.vengenceQueue = {}
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
2023-03-12 04:14:42 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
vengenceQueue[chunkId] = nil
|
|
|
|
local map = chunk.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local base = chunk.base
|
2023-04-01 19:52:51 +02:00
|
|
|
if base then
|
|
|
|
if canMigrate(base) and (Universe.random() < 0.075) then
|
|
|
|
formVengenceSettler(chunk)
|
|
|
|
else
|
|
|
|
formVengenceSquad(chunk)
|
|
|
|
end
|
2020-05-20 04:37:16 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processNests(tick)
|
2023-03-11 22:53:06 +02:00
|
|
|
local chunkId = Universe.processNestIterator
|
2023-03-12 22:02:31 +02:00
|
|
|
local chunk
|
2021-12-08 08:13:32 +02:00
|
|
|
if not chunkId then
|
2023-03-12 22:02:31 +02:00
|
|
|
chunkId,chunk = next(Universe.chunkToNests, nil)
|
2021-12-08 08:13:32 +02:00
|
|
|
else
|
2023-03-12 22:02:31 +02:00
|
|
|
chunk = Universe.chunkToNests[chunkId]
|
2021-12-08 08:13:32 +02:00
|
|
|
end
|
|
|
|
if not chunkId then
|
2023-03-11 22:53:06 +02:00
|
|
|
Universe.processNestIterator = nil
|
2023-03-12 22:02:31 +02:00
|
|
|
return
|
|
|
|
end
|
2020-05-20 04:37:16 +02:00
|
|
|
|
2023-03-12 22:02:31 +02:00
|
|
|
Universe.processNestIterator = next(Universe.chunkToNests, chunkId)
|
|
|
|
local map = chunk.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
removeChunkToNest(chunkId)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
processNestActiveness(chunk, tick)
|
|
|
|
|
|
|
|
if Universe.NEW_ENEMIES then
|
|
|
|
processBaseMutation(chunk,
|
|
|
|
map,
|
|
|
|
chunk.base)
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-11 22:53:06 +02:00
|
|
|
local function processSpawnersBody(iterator, chunks)
|
|
|
|
local chunkId = Universe[iterator]
|
2023-03-12 22:02:31 +02:00
|
|
|
local chunk
|
2021-12-08 08:13:32 +02:00
|
|
|
if not chunkId then
|
2023-03-12 22:02:31 +02:00
|
|
|
chunkId,chunk = next(chunks, nil)
|
2021-12-08 08:13:32 +02:00
|
|
|
else
|
2023-03-12 22:02:31 +02:00
|
|
|
chunk = chunks[chunkId]
|
2021-12-08 08:13:32 +02:00
|
|
|
end
|
|
|
|
if not chunkId then
|
2023-03-11 22:53:06 +02:00
|
|
|
Universe[iterator] = nil
|
2023-03-12 22:02:31 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
Universe[iterator] = next(chunks, chunkId)
|
|
|
|
local map = chunk.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
if (iterator == "processMigrationIterator") then
|
|
|
|
removeChunkToNest(chunkId)
|
|
|
|
else
|
|
|
|
chunks[chunkId] = nil
|
2020-05-22 08:57:03 +02:00
|
|
|
end
|
2023-03-12 22:02:31 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
local base = chunk.base
|
|
|
|
local migrate = canMigrate(base)
|
|
|
|
local attack = canAttack(base)
|
|
|
|
if migrate then
|
|
|
|
formSettlers(chunk)
|
|
|
|
end
|
|
|
|
if attack then
|
|
|
|
formSquads(chunk)
|
2020-05-20 04:37:16 +02:00
|
|
|
end
|
|
|
|
end
|
2020-04-28 05:41:18 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processAttackWaves()
|
2023-03-12 22:02:31 +02:00
|
|
|
processSpawnersBody(
|
|
|
|
"processActiveSpawnerIterator",
|
|
|
|
Universe.chunkToActiveNest
|
|
|
|
)
|
|
|
|
processSpawnersBody(
|
|
|
|
"processActiveRaidSpawnerIterator",
|
|
|
|
Universe.chunkToActiveRaidNest
|
|
|
|
)
|
|
|
|
processSpawnersBody(
|
|
|
|
"processMigrationIterator",
|
|
|
|
Universe.chunkToNests
|
|
|
|
)
|
2020-05-20 04:37:16 +02:00
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processClouds(tick)
|
2023-03-12 04:14:42 +02:00
|
|
|
local eventId, builderPack = next(Universe.settlePurpleCloud, nil)
|
2023-03-12 22:02:31 +02:00
|
|
|
if not builderPack or (builderPack.tick > tick) then
|
|
|
|
return
|
2023-01-08 08:53:47 +02:00
|
|
|
end
|
2023-03-12 22:02:31 +02:00
|
|
|
|
|
|
|
Universe.settlePurpleCloud[eventId] = nil
|
|
|
|
local map = builderPack.map
|
|
|
|
if not builderPack.group.valid or not map.surface.valid then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
setPositionInQuery(
|
|
|
|
Universe.obaCreateBuildCloudQuery,
|
|
|
|
builderPack.group.position
|
|
|
|
)
|
|
|
|
map.surface.create_entity(Universe.obaCreateBuildCloudQuery)
|
2023-01-08 08:53:47 +02:00
|
|
|
end
|
|
|
|
|
2023-03-22 08:09:51 +02:00
|
|
|
function Processor.processHives(tick)
|
|
|
|
local entityId = Universe.hiveIterator
|
|
|
|
local hiveData
|
|
|
|
if not entityId then
|
|
|
|
entityId, hiveData = next(Universe.activeHives, nil)
|
|
|
|
else
|
|
|
|
hiveData = Universe.activeHives[entityId]
|
|
|
|
end
|
|
|
|
if not entityId then
|
|
|
|
Universe.hiveIterator = nil
|
|
|
|
return
|
|
|
|
end
|
|
|
|
if tick < hiveData.tick then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
Universe.hiveIterator = next(Universe.activeHives, entityId)
|
|
|
|
local base = hiveData.base
|
|
|
|
local map = base.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
Universe.activeHives[entityId] = nil
|
|
|
|
return
|
|
|
|
end
|
2023-04-08 06:07:13 +02:00
|
|
|
if not hiveData.e.valid then
|
|
|
|
Universe.activeHives[entityId] = nil
|
|
|
|
Universe.hives[entityId] = nil
|
|
|
|
return
|
|
|
|
end
|
2023-03-22 08:09:51 +02:00
|
|
|
hiveData.tick = tick +
|
|
|
|
gaussianRandomRangeRG(
|
|
|
|
linearInterpolation(Universe.evolutionLevel, MAX_HIVE_TTL, MIN_HIVE_TTL),
|
|
|
|
DEV_HIVE_TTL,
|
|
|
|
MIN_HIVE_TTL,
|
|
|
|
MAX_HIVE_TTL,
|
|
|
|
Universe.random
|
|
|
|
)
|
|
|
|
|
|
|
|
local timeDelay = 0
|
|
|
|
|
2023-04-08 06:07:13 +02:00
|
|
|
TargetPosition.x = hiveData.position.x
|
|
|
|
TargetPosition.y = hiveData.position.y
|
|
|
|
|
|
|
|
distortPositionConcentricCircles(
|
2023-03-22 08:09:51 +02:00
|
|
|
Universe.random,
|
2023-04-08 06:07:13 +02:00
|
|
|
TargetPosition,
|
2023-03-22 08:09:51 +02:00
|
|
|
EIGHTH_CHUNK_SIZE * hiveData.tier,
|
|
|
|
EIGHTH_CHUNK_SIZE
|
|
|
|
)
|
|
|
|
|
|
|
|
if hiveData.nest < hiveData.maxNests then
|
|
|
|
local entityType = "biter-spawner"
|
|
|
|
if Universe.random() < 0.5 then
|
|
|
|
entityType = "spitter-spawner"
|
|
|
|
end
|
2023-04-08 06:07:13 +02:00
|
|
|
queueCreation(base, TargetPosition, entityType, timeDelay, hiveData)
|
2023-03-22 08:09:51 +02:00
|
|
|
elseif hiveData.turret < hiveData.maxTurrets then
|
2023-04-08 06:07:13 +02:00
|
|
|
queueCreation(base, TargetPosition, "turret", timeDelay, hiveData)
|
2023-03-22 08:09:51 +02:00
|
|
|
elseif hiveData.hive < hiveData.maxHives then
|
2023-04-08 06:07:13 +02:00
|
|
|
queueCreation(base, TargetPosition, "hive", timeDelay, hiveData)
|
2023-03-22 08:09:51 +02:00
|
|
|
else
|
|
|
|
Universe.activeHives[entityId] = nil
|
|
|
|
end
|
|
|
|
end
|
2023-03-12 06:51:13 +02:00
|
|
|
|
2023-04-07 04:49:09 +02:00
|
|
|
function Processor.cleanHivesData()
|
|
|
|
local entityId = Universe.hiveDataIterator
|
|
|
|
local hiveData
|
|
|
|
if not entityId then
|
|
|
|
entityId, hiveData = next(Universe.hiveData, nil)
|
|
|
|
else
|
|
|
|
hiveData = Universe.hiveData[entityId]
|
|
|
|
end
|
|
|
|
if not entityId then
|
|
|
|
Universe.hiveDataIterator = nil
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
Universe.hiveDataIterator = next(Universe.hiveData, entityId)
|
2023-04-08 02:54:56 +02:00
|
|
|
if not Universe.hives[hiveData.hiveId] then
|
2023-04-07 04:49:09 +02:00
|
|
|
Universe.hiveData[entityId] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
function Processor.processPendingChunks(tick, flush)
|
|
|
|
local pendingChunks = Universe.pendingChunks
|
|
|
|
local eventId, event = next(pendingChunks, nil)
|
|
|
|
|
|
|
|
if not eventId then
|
|
|
|
if (tableSize(pendingChunks) == 0) then
|
|
|
|
-- this is needed as the next command remembers the max length a table has been
|
|
|
|
Universe.pendingChunks = {}
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local endCount = 1
|
2023-03-13 04:36:01 +02:00
|
|
|
local flushAllChunks = flush or Universe.flushPendingChunks
|
|
|
|
if flushAllChunks then
|
2023-03-12 06:51:13 +02:00
|
|
|
endCount = tableSize(pendingChunks)
|
2023-03-13 04:36:01 +02:00
|
|
|
Universe.flushPendingChunks = false
|
2023-03-12 06:51:13 +02:00
|
|
|
end
|
|
|
|
for _=1,endCount do
|
2023-03-13 04:36:01 +02:00
|
|
|
if not flushAllChunks and (event.tick > tick) then
|
2023-03-12 06:51:13 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
local newEventId, newEvent = next(pendingChunks, eventId)
|
|
|
|
pendingChunks[eventId] = nil
|
|
|
|
local map = event.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local topLeft = event.area.left_top
|
|
|
|
local x = topLeft.x
|
|
|
|
local y = topLeft.y
|
|
|
|
|
|
|
|
if not map[x] then
|
|
|
|
map[x] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
if map[x][y] then
|
|
|
|
local oldChunk = map[x][y]
|
|
|
|
local chunk = initialScan(oldChunk, map, tick)
|
|
|
|
if (chunk == -1) then
|
|
|
|
removeChunkFromMap(map, oldChunk)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local initialChunk = createChunk(map, x, y)
|
|
|
|
map[x][y] = initialChunk
|
|
|
|
local chunk = initialScan(initialChunk, map, tick)
|
|
|
|
if (chunk ~= -1) then
|
|
|
|
tableInsert(
|
|
|
|
map.processQueue,
|
|
|
|
findInsertionPoint(map.processQueue, chunk),
|
|
|
|
chunk
|
|
|
|
)
|
|
|
|
else
|
|
|
|
map[x][y] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
eventId = newEventId
|
|
|
|
event = newEvent
|
|
|
|
if not eventId then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Processor.processPendingUpgrades(tick)
|
2023-03-22 08:09:51 +02:00
|
|
|
local upgradeId, entityData = next(Universe.pendingUpgrades, nil)
|
|
|
|
if not upgradeId then
|
|
|
|
if Universe.pendingUpgradesLength == 0 then
|
2023-03-12 06:51:13 +02:00
|
|
|
Universe.pendingUpgrades = {}
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local entity = entityData.entity
|
2023-03-22 08:09:51 +02:00
|
|
|
if (entityData.state ~= 2) and not entity.valid then
|
|
|
|
Universe.pendingUpgrades[upgradeId] = nil
|
|
|
|
Universe.pendingUpgradesLength = Universe.pendingUpgradesLength - 1
|
2023-03-12 23:21:24 +02:00
|
|
|
return
|
2023-03-12 06:51:13 +02:00
|
|
|
end
|
2023-03-12 23:21:24 +02:00
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
if entityData.delayTLL and tick < entityData.delayTLL then
|
|
|
|
return
|
|
|
|
end
|
2023-03-22 08:09:51 +02:00
|
|
|
|
2023-03-19 19:25:46 +02:00
|
|
|
local state = entityData.state
|
|
|
|
if state == 1 then
|
|
|
|
local map = entityData.map
|
|
|
|
unregisterEnemyBaseStructure(map, entity, nil, true)
|
2023-03-12 06:51:13 +02:00
|
|
|
entity.destroy()
|
2023-03-19 19:25:46 +02:00
|
|
|
if not entityData.name or not entityData.position then
|
2023-03-22 08:09:51 +02:00
|
|
|
Universe.pendingUpgrades[upgradeId] = nil
|
|
|
|
Universe.pendingUpgradesLength = Universe.pendingUpgradesLength - 1
|
2023-03-19 19:25:46 +02:00
|
|
|
return
|
2023-03-12 06:51:13 +02:00
|
|
|
end
|
2023-03-22 08:09:51 +02:00
|
|
|
entityData.state = 2
|
|
|
|
else
|
|
|
|
Universe.pendingUpgrades[upgradeId] = nil
|
|
|
|
Universe.pendingUpgradesLength = Universe.pendingUpgradesLength - 1
|
2023-03-19 19:25:46 +02:00
|
|
|
local query = Queries.createEntityQuery
|
|
|
|
local name = entityData.name
|
|
|
|
query.name = name
|
|
|
|
local position = entityData.position
|
|
|
|
setPositionInQuery(query, position)
|
|
|
|
local surface = entityData.map.surface
|
2023-03-22 08:09:51 +02:00
|
|
|
local newEntity = surface.create_entity(query)
|
|
|
|
if newEntity and newEntity.valid then
|
|
|
|
local hiveType = BUILDING_HIVE_TYPE_LOOKUP[name]
|
|
|
|
if hiveType == "hive" then
|
|
|
|
Universe.hives[newEntity.unit_number] = entityData.hive
|
|
|
|
else
|
|
|
|
local hiveData = entityData.hive
|
|
|
|
if hiveData then
|
|
|
|
Universe.hiveData[newEntity.unit_number] = entityData.hive
|
|
|
|
local adjustedHiveType = (
|
|
|
|
(
|
|
|
|
(hiveType == "spitter-spawner")
|
|
|
|
or (hiveType == "biter-spawner")
|
|
|
|
)
|
|
|
|
and "nest"
|
|
|
|
) or hiveType
|
|
|
|
hiveData[adjustedHiveType] = hiveData[adjustedHiveType] + 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-03-12 06:51:13 +02:00
|
|
|
if remote.interfaces["kr-creep"] then
|
2023-03-19 19:25:46 +02:00
|
|
|
remote.call(
|
|
|
|
"kr-creep",
|
|
|
|
"spawn_creep_at_position",
|
|
|
|
surface,
|
|
|
|
position,
|
|
|
|
false,
|
|
|
|
name
|
|
|
|
)
|
2023-03-12 06:51:13 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function Processor.processScanChunks()
|
|
|
|
local chunkId, chunk = next(Universe.chunkToPassScan, nil)
|
|
|
|
if not chunkId then
|
|
|
|
if (tableSize(Universe.chunkToPassScan) == 0) then
|
|
|
|
-- this is needed as the next command remembers the max length a table has been
|
|
|
|
Universe.chunkToPassScan = {}
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
Universe.chunkToPassScan[chunkId] = nil
|
|
|
|
local map = chunk.map
|
|
|
|
if not map.surface.valid then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
if (chunkPassScan(chunk, map) == -1) then
|
|
|
|
removeChunkFromMap(map, chunk)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Processor.init(universe)
|
2023-03-11 22:53:06 +02:00
|
|
|
Universe = universe
|
2023-04-08 06:07:13 +02:00
|
|
|
Queries = universe.processorQueries
|
|
|
|
if Queries then
|
|
|
|
TargetPosition = Queries.targetPosition
|
|
|
|
end
|
2023-03-11 22:53:06 +02:00
|
|
|
end
|
|
|
|
|
2023-03-12 06:51:13 +02:00
|
|
|
ProcessorG = Processor
|
|
|
|
return Processor
|