1
0
mirror of https://github.com/veden/Rampant.git synced 2024-12-26 20:54:12 +02:00
Rampant/libs/MapProcessor.lua

263 lines
8.0 KiB
Lua
Raw Normal View History

local mapProcessor = {}
-- imports
2016-08-21 23:48:55 +02:00
local pheromoneUtils = require("PheromoneUtils")
local aiBuilding = require("AIBuilding")
2017-05-19 09:47:24 +02:00
local aiPredicates = require("AIPredicates")
2016-08-29 02:05:28 +02:00
local constants = require("Constants")
2016-10-15 02:00:18 +02:00
local mapUtils = require("MapUtils")
2017-05-19 09:47:24 +02:00
local playerUtils = require("PlayerUtils")
2016-09-14 13:16:33 +02:00
-- constants
local PROCESS_QUEUE_SIZE = constants.PROCESS_QUEUE_SIZE
2016-11-04 09:26:19 +02:00
local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
2016-09-14 13:16:33 +02:00
local SCAN_QUEUE_SIZE = constants.SCAN_QUEUE_SIZE
2017-04-22 01:14:04 +02:00
local AI_UNIT_REFUND = constants.AI_UNIT_REFUND
2016-09-14 13:16:33 +02:00
local CHUNK_SIZE = constants.CHUNK_SIZE
2016-10-15 02:00:18 +02:00
local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND
local CHUNK_TICK = constants.CHUNK_TICK
2017-05-19 09:47:24 +02:00
local NEST_BASE = constants.NEST_BASE
2017-05-12 06:50:06 +02:00
2017-04-22 01:14:04 +02:00
local AI_MAX_POINTS = constants.AI_MAX_POINTS
2016-11-04 09:26:19 +02:00
local AI_SQUAD_COST = constants.AI_SQUAD_COST
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
2016-11-04 09:26:19 +02:00
-- imported functions
2016-08-21 23:48:55 +02:00
local scents = pheromoneUtils.scents
local processPheromone = pheromoneUtils.processPheromone
2016-08-21 23:48:55 +02:00
local formSquads = aiBuilding.formSquads
2016-10-15 02:00:18 +02:00
local getChunkByIndex = mapUtils.getChunkByIndex
local getChunkByPosition = mapUtils.getChunkByPosition
local playerScent = pheromoneUtils.playerScent
2017-05-19 09:47:24 +02:00
local canAttack = aiPredicates.canAttack
2017-05-14 00:32:16 +02:00
2016-08-29 02:05:28 +02:00
local mMin = math.min
2017-05-19 09:47:24 +02:00
local validPlayer = playerUtils.validPlayer
-- module code
2016-10-15 02:00:18 +02:00
local function nonRepeatingRandom(players)
local ordering = {}
for _,player in pairs(players) do
ordering[#ordering+1] = player.index
end
for i=#ordering,1,-1 do
local s = math.random(i)
local t = ordering[i]
ordering[i] = ordering[s]
ordering[s] = t
end
return ordering
end
--[[
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
In theory, this might be fine as smaller bases have less surface to attack and need to have
pheromone dissipate at a faster rate.
--]]
function mapProcessor.processMap(regionMap, surface, natives, evolution_factor)
2016-08-29 02:05:28 +02:00
local roll = regionMap.processRoll
local index = regionMap.processPointer
2016-08-29 02:05:28 +02:00
if (index == 1) then
2016-08-26 00:20:06 +02:00
roll = math.random()
2016-08-29 02:05:28 +02:00
regionMap.processRoll = roll
2016-08-26 00:20:06 +02:00
end
2017-05-14 00:32:16 +02:00
2017-05-19 09:47:24 +02:00
local squads = canAttack(natives, surface) and (0.11 <= roll) and (roll <= 0.35)
2016-08-29 02:05:28 +02:00
local processQueue = regionMap.processQueue
2016-09-14 13:16:33 +02:00
local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue)
2016-08-29 02:05:28 +02:00
for x=index,endIndex do
local chunk = processQueue[x]
2017-04-22 01:14:04 +02:00
processPheromone(regionMap, chunk)
2016-08-26 00:20:06 +02:00
if squads then
2016-11-04 09:26:19 +02:00
formSquads(regionMap, surface, natives, chunk, evolution_factor, AI_SQUAD_COST)
2017-04-22 01:14:04 +02:00
end
scents(chunk)
2016-08-29 02:05:28 +02:00
end
if (endIndex == #processQueue) then
regionMap.processPointer = 1
else
regionMap.processPointer = endIndex + 1
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.
vs
the slower passive version processing the entire map in multiple passes.
--]]
function mapProcessor.processPlayers(players, regionMap, surface, natives, evolution_factor, tick)
-- put down player pheromone for player hunters
-- randomize player order to ensure a single player isn't singled out
local playerOrdering = nonRepeatingRandom(players)
2016-11-04 09:26:19 +02:00
local vengenceThreshold = -(evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)
2016-10-15 02:00:18 +02:00
local roll = math.random()
2017-05-19 09:47:24 +02:00
local squads = canAttack(natives, surface) and (0.11 <= roll) and (roll <= 0.20)
2016-10-15 02:00:18 +02:00
for i=1,#playerOrdering do
local player = players[playerOrdering[i]]
2017-05-19 09:47:24 +02:00
if validPlayer(player) then
2016-10-15 02:00:18 +02:00
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
2017-05-27 02:58:33 +02:00
if playerChunk then
2016-10-15 02:00:18 +02:00
playerScent(playerChunk)
end
end
end
for i=1,#playerOrdering do
local player = players[playerOrdering[i]]
2017-05-19 09:47:24 +02:00
if validPlayer(player) then
2016-10-15 02:00:18 +02:00
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
2017-05-27 02:58:33 +02:00
if playerChunk then
2017-05-19 09:47:24 +02:00
local vengence = canAttack(natives, surface) and ((#playerChunk[NEST_BASE] ~= 0) or (playerChunk[MOVEMENT_PHEROMONE] < vengenceThreshold))
2017-05-27 07:56:45 +02:00
2016-10-15 02:00:18 +02:00
for x=playerChunk.cX - PROCESS_PLAYER_BOUND, playerChunk.cX + PROCESS_PLAYER_BOUND do
for y=playerChunk.cY - PROCESS_PLAYER_BOUND, playerChunk.cY + PROCESS_PLAYER_BOUND do
local chunk = getChunkByIndex(regionMap, x, y)
2016-11-04 09:26:19 +02:00
2017-05-27 02:58:33 +02:00
if chunk and (chunk[CHUNK_TICK] ~= tick) then
2016-10-15 02:00:18 +02:00
chunk[CHUNK_TICK] = tick
2017-04-22 01:14:04 +02:00
processPheromone(regionMap, chunk)
2016-11-04 09:26:19 +02:00
2016-10-15 02:00:18 +02:00
if squads then
2016-11-04 09:26:19 +02:00
formSquads(regionMap, surface, natives, chunk, evolution_factor, AI_SQUAD_COST)
end
if vengence then
formSquads(regionMap, surface, natives, chunk, evolution_factor, AI_VENGENCE_SQUAD_COST)
2016-10-15 02:00:18 +02:00
end
2017-04-22 01:14:04 +02:00
scents(chunk)
2016-10-15 02:00:18 +02:00
end
end
end
end
end
end
end
2016-11-04 01:51:35 +02:00
--[[
Passive scan to find entities that have been generated outside the factorio event system
2016-11-04 01:51:35 +02:00
--]]
function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
2017-05-19 09:47:24 +02:00
-- local index = regionMap.scanPointer
local chunkPosition = {x=0,y=0}
local chunkBox = {chunkPosition,
{x=chunkPosition.x + CHUNK_SIZE, y=chunkPosition.y + CHUNK_SIZE}}
local playerQuery = {area = chunkBox,
force = "player"}
local spawnerQuery = {area = chunkBox,
type = "unit-spawner",
force = "enemy"}
local wormsQuery = {area = chunkBox,
type = "turret",
force = "enemy"}
local unitCountQuery = {area = chunkBox,
type = "unit",
force = "enemy"}
2016-08-29 02:05:28 +02:00
local processQueue = regionMap.processQueue
2016-09-14 13:16:33 +02:00
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
2016-08-29 02:05:28 +02:00
for x=index,endIndex do
2016-10-15 02:00:18 +02:00
local chunk = processQueue[x]
chunkPosition.x = chunk.pX
chunkPosition.y = chunk.pY
chunkBox[2].x = chunkPosition.x + CHUNK_SIZE
chunkBox[2].y = chunkPosition.y + CHUNK_SIZE
local entities = surface.find_entities_filtered(playerQuery)
2017-04-22 01:14:04 +02:00
local spawners = surface.count_entities_filtered(spawnerQuery)
2017-04-22 01:14:04 +02:00
local worms = surface.count_entities_filtered(wormsQuery)
local unitCount = surface.count_entities_filtered(unitCountQuery)
local closeBy = false
if (unitCount > 300) then
for i=1,#natives.squads do
local squadGroup = natives.squads[i].group
2017-05-27 02:58:33 +02:00
if squadGroup.valid and (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then
closeBy = true
end
end
end
if (unitCount > 300) and not closeBy then
2017-04-22 01:14:04 +02:00
local weight = AI_UNIT_REFUND * evolution_factor
local units = surface.find_enemy_units(chunkPosition, CHUNK_SIZE * 3)
2017-04-22 01:14:04 +02:00
for i=1,#units do
units[i].destroy()
natives.points = natives.points + weight
end
if (natives.points > (AI_MAX_POINTS * 3)) then
natives.points = (AI_MAX_POINTS * 3)
end
end
local playerBaseGenerator = 0
local safeBuildings = natives.safeBuildings
for i=1,#entities do
local entity = entities[i]
local value = BUILDING_PHEROMONES[entity.type]
if safeBuildings then
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
entity.destructible = false
end
end
if (value ~= nil) then
playerBaseGenerator = playerBaseGenerator + value
end
end
2017-04-16 08:04:22 +02:00
chunk[ENEMY_BASE_GENERATOR] = (spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT) + worms
chunk[PLAYER_BASE_GENERATOR] = playerBaseGenerator
end
2017-04-22 01:14:04 +02:00
2016-08-29 02:05:28 +02:00
if (endIndex == #processQueue) then
2016-10-15 02:00:18 +02:00
regionMap.scanPointer = 1
2016-08-29 02:05:28 +02:00
else
2016-10-15 02:00:18 +02:00
regionMap.scanPointer = endIndex + 1
end
end
2016-09-08 22:02:23 +02:00
return mapProcessor