1
0
mirror of https://github.com/veden/Rampant.git synced 2024-12-24 20:14:35 +02:00
Rampant/libs/ChunkPropertyUtils.lua

631 lines
18 KiB
Lua

-- 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/>.
if ChunkPropertyUtilsG then
return ChunkPropertyUtilsG
end
local ChunkPropertyUtils = {}
--
local Universe
local Position
--
local Constants = require("Constants")
local MathUtils = require("MathUtils")
-- Constants
local DURATION_ACTIVE_NEST = Constants.DURATION_ACTIVE_NEST
local PLAYER_GENERATOR_PERSISTANCE = Constants.PLAYER_GENERATOR_PERSISTANCE
local PLAYER_PHEROMONE_GENERATOR_AMOUNT = Constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT
local COOLDOWN_DRAIN = Constants.COOLDOWN_DRAIN
local RAIDING_MINIMUM_BASE_THRESHOLD = Constants.RAIDING_MINIMUM_BASE_THRESHOLD
local PLAYER_PHEROMONE = Constants.PLAYER_PHEROMONE
local BASE_PHEROMONE = Constants.BASE_PHEROMONE
local MOVEMENT_GENERATOR_PERSISTANCE = Constants.MOVEMENT_GENERATOR_PERSISTANCE
local CHUNK_ALL_DIRECTIONS = Constants.CHUNK_ALL_DIRECTIONS
local MAGIC_MAXIMUM_NUMBER = Constants.MAGIC_MAXIMUM_NUMBER
-- imported functions
local activateMap
local euclideanDistancePoints = MathUtils.euclideanDistancePoints
local tableSize = table_size
local mMin = math.min
-- module code
local function getActiveTick(chunk)
return chunk.activeTick or 0
end
local function registerActiveSpawner(chunk, register, activeType, tick)
local chunkId = chunk.id
if Universe[register][chunkId] then
return
end
chunk.activeTick = tick + DURATION_ACTIVE_NEST
local base = chunk.base
base[activeType] = base[activeType] + 1
Universe[register][chunkId] = chunk
end
local function unregisterActiveSpawner(chunk, register, iterator, activeType)
local chunkId = chunk.id
if not Universe[register][chunkId] then
return
end
chunk.activeTick = nil
local base = chunk.base
base[activeType] = base[activeType] - 1
Universe[register][chunkId] = nil
if (Universe[iterator] == chunkId) then
Universe[iterator] = nil
end
end
local function registerActiveNest(chunk, tick)
registerActiveSpawner(chunk, "chunkToActiveNest", "activeNests", tick)
end
local function registerActiveRaidNest(chunk, tick)
registerActiveSpawner(chunk, "chunkToActiveRaidNest", "activeRaidNests", tick)
end
local function unregisterActiveNest(chunk)
unregisterActiveSpawner(
chunk,
"chunkToActiveNest",
"processActiveSpawnerIterator",
"activeNests"
)
end
local function unregisterActiveRaidNest(chunk)
unregisterActiveSpawner(
chunk,
"chunkToActiveRaidNest",
"processActiveRaidSpawnerIterator",
"activeRaidNests"
)
end
local function addEnemyStructure(chunk, unitNumber, ids, counts, register)
activateMap(chunk.map)
local chunkId = chunk.id
local entityIds = chunk[ids]
if not entityIds then
entityIds = {}
chunk[ids] = entityIds
end
if entityIds[unitNumber] then
return false
end
entityIds[unitNumber] = true
chunk[counts] = (chunk[counts] or 0) + 1
if register then
Universe[register][chunkId] = chunk
end
return true
end
local function removeEnemyStructure(chunk, unitNumber, ids, counts, register)
local chunkId = chunk.id
local entityIds = chunk[ids]
if not (entityIds and entityIds[unitNumber]) then
return false
end
entityIds[unitNumber] = nil
chunk[counts] = chunk[counts] - 1
if chunk[counts] > 0 then
return true
end
chunk[ids] = nil
chunk[counts] = nil
if register then
Universe[register][chunkId] = nil
end
if (ids == "nestIds") then
unregisterActiveNest(chunk)
unregisterActiveRaidNest(chunk)
if (Universe.processMigrationIterator == chunkId) then
Universe.processMigrationIterator = nil
end
if (Universe.processNestIterator == chunkId) then
Universe.processNestIterator = nil
end
end
return true
end
function ChunkPropertyUtils.addTurretCount(chunk, unitNumber)
return addEnemyStructure(chunk, unitNumber, "turretIds", "turretCount")
end
function ChunkPropertyUtils.removeTurretCount(chunk, unitNumber)
return removeEnemyStructure(chunk, unitNumber, "turretIds", "turretCount")
end
function ChunkPropertyUtils.addUtilitiesCount(chunk, unitNumber)
return addEnemyStructure(chunk, unitNumber, "utilityIds", "utilityCount", "chunkToUtilities")
end
function ChunkPropertyUtils.removeUtilitiesCount(chunk, unitNumber)
return removeEnemyStructure(chunk, unitNumber, "utilityIds", "utilityCount", "chunkToUtilities")
end
function ChunkPropertyUtils.addHiveCount(chunk, unitNumber)
return addEnemyStructure(chunk, unitNumber, "hiveIds", "hiveCount", "chunkToHives")
end
function ChunkPropertyUtils.removeHiveCount(chunk, unitNumber)
return removeEnemyStructure(chunk, unitNumber, "hiveIds", "hiveCount", "chunkToHives")
end
function ChunkPropertyUtils.addNestCount(chunk, unitNumber)
return addEnemyStructure(chunk, unitNumber, "nestIds", "nestCount", "chunkToNests")
end
function ChunkPropertyUtils.removeNestCount(chunk, unitNumber)
return removeEnemyStructure(chunk, unitNumber, "nestIds", "nestCount", "chunkToNests")
end
function ChunkPropertyUtils.isActiveNest(chunk)
return Universe.chunkToActiveNest[chunk.id] ~= nil
end
function ChunkPropertyUtils.isActiveRaidNest(chunk)
return Universe.chunkToActiveRaidNest[chunk.id] ~= nil
end
function ChunkPropertyUtils.addBaseResourceChunk(base, chunk)
if not chunk.resourceGenerator then
return
end
base.resourceChunkCount = base.resourceChunkCount + 1
base.resourceChunks[chunk.id] = true
end
function ChunkPropertyUtils.removeBaseResourceChunk(base, chunk)
if not base.resourceChunks[chunk.id] then
return
end
base.resourceChunkCount = base.resourceChunkCount - 1
base.resourceChunks[chunk.id] = nil
end
function ChunkPropertyUtils.removeChunkBase(chunk, base)
if not chunk.base then
return
end
base.chunkCount = base.chunkCount - 1
base.totalX = base.totalX - chunk.x
base.totalY = base.totalY - chunk.y
base.x = base.totalX / base.chunkCount
base.y = base.totalY / base.chunkCount
chunk.base = nil
end
function ChunkPropertyUtils.setChunkBase(chunk, base)
if chunk.base then
return
end
base.chunkCount = base.chunkCount + 1
base.totalX = base.totalX + chunk.x
base.totalY = base.totalY + chunk.y
base.x = base.totalX / base.chunkCount
base.y = base.totalY / base.chunkCount
chunk.base = base
end
function ChunkPropertyUtils.getEnemyStructureCount(chunk)
return (chunk.nestCount or 0)
+ (chunk.turretCount or 0)
+ (chunk.utilityCount or 0)
+ (chunk.hiveCount or 0)
end
function ChunkPropertyUtils.setDrainPylons(map, entity1, entity2)
local pair = {entity1, entity2}
map.drainPylons[entity1.unit_number] = pair
map.drainPylons[entity2.unit_number] = pair
end
function ChunkPropertyUtils.removeDrainPylons(map, unitNumber)
local pair = map.drainPylons[unitNumber]
if pair then
local target = pair[1]
local pole = pair[2]
if target.unit_number == unitNumber then
map.drainPylons[unitNumber] = nil
if pole.valid then
map.drainPylons[pole.unit_number] = nil
pole.destroy()
end
elseif (pole.unit_number == unitNumber) then
map.drainPylons[unitNumber] = nil
if target.valid then
map.drainPylons[target.unit_number] = nil
target.die()
end
end
end
end
function ChunkPropertyUtils.getDrainPylonPair(map, unitNumber)
return map.drainPylons[unitNumber]
end
function ChunkPropertyUtils.isDrained(chunk, tick)
local drainTick = Universe.chunkToDrained[chunk.id]
if not drainTick then
return false
end
return (tick - drainTick) < COOLDOWN_DRAIN
end
function ChunkPropertyUtils.setDrainedTick(chunk, tick)
Universe.chunkToDrained[chunk.id] = tick
end
function ChunkPropertyUtils.getRetreatTick(chunk)
return Universe.chunkToRetreats[chunk.id] or 0
end
function ChunkPropertyUtils.getRallyTick(chunk)
return Universe.chunkToRallys[chunk.id] or 0
end
function ChunkPropertyUtils.setRallyTick(chunk, tick)
Universe.chunkToRallys[chunk.id] = tick
end
function ChunkPropertyUtils.setRetreatTick(chunk, tick)
Universe.chunkToRetreats[chunk.id] = tick
end
function ChunkPropertyUtils.setResourceGenerator(chunk, resourceGenerator)
if (resourceGenerator <= 0) then
chunk.resourceGenerator = nil
else
chunk.resourceGenerator = resourceGenerator
end
end
function ChunkPropertyUtils.getResourceGenerator(chunk)
return chunk.resourceGenerator or 0
end
function ChunkPropertyUtils.addResourceGenerator(chunk, delta)
chunk.resourceGenerator = (chunk.resourceGenerator or 0) + delta
end
function ChunkPropertyUtils.getPassable(chunk)
return chunk.passable or CHUNK_ALL_DIRECTIONS
end
function ChunkPropertyUtils.setPassable(chunk, value)
if (value == CHUNK_ALL_DIRECTIONS) then
chunk.passable = nil
else
chunk.passable = value
end
end
function ChunkPropertyUtils.getPathRating(chunk)
return chunk.pathRating or 1
end
function ChunkPropertyUtils.setPathRating(chunk, value)
if (value == 1) then
chunk.pathRating = nil
else
chunk.pathRating = value
end
end
function ChunkPropertyUtils.getDeathGeneratorRating(chunk)
return 1 + (chunk.deathGenerator or 0)
end
function ChunkPropertyUtils.getCombinedDeathGeneratorRating(chunk)
local amount = 1 + ((chunk.deathGenerator or 0) + (chunk.permanentDeathGenerator or 0))
if (amount > 1) then
return 1
elseif (amount <= 0) then
return 0.001
else
return amount
end
end
function ChunkPropertyUtils.getDeathGenerator(chunk)
return chunk.deathGenerator or 0
end
function ChunkPropertyUtils.getPermanentDeathGeneratorRating(chunk)
return 1 + (chunk.permanentDeathGenerator or 0)
end
function ChunkPropertyUtils.getCombinedDeathGenerator(chunk)
local amount = (chunk.deathGenerator or 0) + (chunk.permanentDeathGenerator or 0)
if (amount > 1) then
return 1
elseif (amount < -1) then
return -1
else
return amount
end
end
function ChunkPropertyUtils.addPermanentDeathGenerator(chunk, amount)
local adjustedAmount = (amount * 0.25) + (chunk.permanentDeathGenerator or 0)
if (adjustedAmount > 0.75) then
chunk.permanentDeathGenerator = 0.75
elseif (adjustedAmount < -0.75) then
chunk.permanentDeathGenerator = -0.75
else
chunk.permanentDeathGenerator = adjustedAmount
end
end
function ChunkPropertyUtils.addDeathGenerator(chunk, value)
local currentAmount = (chunk.deathGenerator or 0) + value
if (currentAmount > 1) then
chunk.deathGenerator = 1
elseif (currentAmount < -1) then
chunk.deathGenerator = -1
else
chunk.deathGenerator = currentAmount
end
end
function ChunkPropertyUtils.setDeathGenerator(chunk, value)
if (value > 1) then
chunk.deathGenerator = 1
elseif (value < -1) then
chunk.deathGenerator = -1
else
chunk.deathGenerator = value
end
end
function ChunkPropertyUtils.addVictoryGenerator(chunk, value)
local cToV = Universe.chunkToVictory
local chunkId = chunk.id
if not cToV[chunkId] then
cToV[chunkId] = {
chunk = chunk,
v = 0
}
end
cToV[chunkId].v = cToV[chunkId].v + value
end
function ChunkPropertyUtils.decayDeathGenerator(chunk)
local gen = chunk.deathGenerator
if gen then
local v = gen * MOVEMENT_GENERATOR_PERSISTANCE
if (v < 0.0001) and (v > -0.0001) then
chunk.deathGenerator = nil
else
chunk.deathGenerator = v
end
end
end
function ChunkPropertyUtils.decayPlayerGenerator(chunk)
local gen = chunk.playerGenerator
if gen then
local v = gen * PLAYER_GENERATOR_PERSISTANCE
if (v < 0.0001) and (v > -0.0001) then
chunk.playerGenerator = nil
else
chunk.playerGenerator = v
end
end
end
function ChunkPropertyUtils.addPlayerGenerator(chunk, playerMaxGenerator)
local value = chunk.playerGenerator
if value then
chunk.playerGenerator = mMin(
value + PLAYER_PHEROMONE_GENERATOR_AMOUNT,
playerMaxGenerator
)
else
chunk.playerGenerator = PLAYER_PHEROMONE_GENERATOR_AMOUNT
end
end
function ChunkPropertyUtils.getPlayerGenerator(chunk)
return chunk.playerGenerator or 0
end
function ChunkPropertyUtils.getPlayerBaseGenerator(chunk)
return chunk.playerBaseGenerator or 0
end
function ChunkPropertyUtils.addSquadToChunk(chunk, squad)
if (chunk ~= -1)
and (
(squad.chunk == -1)
or (squad.chunk.id ~= chunk.id)
)
then
ChunkPropertyUtils.removeSquadFromChunk(squad)
local squads = chunk.squads
if not squads then
squads = {}
chunk.squads = squads
end
squads[squad.groupNumber] = squad
squad.chunk = chunk
end
end
function ChunkPropertyUtils.removeSquadFromChunk(squad)
local chunk = squad.chunk
if (chunk ~= -1) then
local squads = chunk.squads
if squads then
squads[squad.groupNumber] = nil
if (tableSize(squads) == 0) then
chunk.squads = nil
end
end
end
end
function ChunkPropertyUtils.setPlayerBaseGenerator(chunk, playerBaseGenerator)
if (playerBaseGenerator <= 0) then
chunk.playerBaseGenerator = nil
return 0
else
chunk.playerBaseGenerator = playerBaseGenerator
return playerBaseGenerator
end
end
function ChunkPropertyUtils.addPlayerBaseGenerator(chunk, playerBaseGenerator)
local amount = (chunk.playerBaseGenerator or 0) + playerBaseGenerator
if amount <= 0 then
chunk.playerBaseGenerator = nil
return 0
else
chunk.playerBaseGenerator = amount
return amount
end
end
function ChunkPropertyUtils.findNearbyBase(chunk)
local foundBase = chunk.base
if foundBase then
return foundBase
end
return ChunkPropertyUtils.findNearbyBaseByPosition(
chunk.map,
chunk.x,
chunk.y
)
end
function ChunkPropertyUtils.findNearbyBaseByPosition(map, x, y)
local foundBase
local closest = MAGIC_MAXIMUM_NUMBER
for _, base in pairs(map.bases) do
local distance = euclideanDistancePoints(base.x, base.y, x, y)
if (distance <= base.distanceThreshold) and (distance < closest) then
closest = distance
foundBase = base
end
end
return foundBase
end
function ChunkPropertyUtils.processNestActiveness(chunk, tick)
if getActiveTick(chunk) > tick then
return
end
if chunk.nestCount then
local surface = chunk.map.surface
if Universe.attackUsePlayer and (chunk[PLAYER_PHEROMONE] > Universe.attackPlayerThreshold) then
registerActiveNest(chunk, tick)
elseif (chunk[BASE_PHEROMONE] > 0) then
local getPollution = surface.get_pollution
if (getPollution(chunk) > 0) then
registerActiveNest(chunk, tick)
else
local x = chunk.x
local y = chunk.y
local pollutionThreshold = Universe.pollutionDiffuseMinimum
Position.x = x + 32
Position.y = y
if (getPollution(Position) > pollutionThreshold) then
registerActiveNest(chunk, tick)
else
Position.x = x - 32
if (getPollution(Position) > pollutionThreshold) then
registerActiveNest(chunk, tick)
else
Position.x = x
Position.y = y - 32
if (getPollution(Position) > pollutionThreshold) then
registerActiveNest(chunk, tick)
else
Position.y = y + 32
if (getPollution(Position) > pollutionThreshold) then
registerActiveNest(chunk, tick)
else
unregisterActiveNest(chunk)
if (chunk[BASE_PHEROMONE] > RAIDING_MINIMUM_BASE_THRESHOLD) then
registerActiveRaidNest(chunk, tick)
else
unregisterActiveRaidNest(chunk)
end
end
end
end
end
end
else
unregisterActiveNest(chunk)
unregisterActiveRaidNest(chunk)
end
else
unregisterActiveNest(chunk)
unregisterActiveRaidNest(chunk)
end
end
function ChunkPropertyUtils.init(universe, mapUtils)
Universe = universe
activateMap = mapUtils.activateMap
if universe.chunkPropertyUtilsQueries then
Position = universe.chunkPropertyUtilsQueries.position
end
end
ChunkPropertyUtilsG = ChunkPropertyUtils
return ChunkPropertyUtils