1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-05 22:53:24 +02:00
Rampant/libs/ChunkUtils.lua

494 lines
18 KiB
Lua
Raw Normal View History

2019-02-16 06:17:30 +02:00
if chunkUtilsG then
return chunkUtilsG
end
local chunkUtils = {}
-- imports
local stringUtils = require("StringUtils")
local baseUtils = require("BaseUtils")
local constants = require("Constants")
2017-11-21 09:27:03 +02:00
local mapUtils = require("MapUtils")
local chunkPropertyUtils = require("ChunkPropertyUtils")
2017-11-21 09:27:03 +02:00
-- constants
2017-05-12 06:50:06 +02:00
local CHUNK_SIZE_DIVIDER = constants.CHUNK_SIZE_DIVIDER
2017-11-21 09:27:03 +02:00
local DEFINES_WIRE_TYPE_RED = defines.wire_type.red
local DEFINES_WIRE_TYPE_GREEN = defines.wire_type.green
2017-06-08 02:57:24 +02:00
2019-03-09 02:42:20 +02:00
local CHUNK_PASS_THRESHOLD = constants.CHUNK_PASS_THRESHOLD
2017-11-21 09:27:03 +02:00
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
2019-02-11 08:14:17 +02:00
local AI_STATE_ONSLAUGHT = constants.AI_STATE_ONSLAUGHT
2016-10-15 02:00:18 +02:00
local BASE_PHEROMONE = constants.BASE_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
2017-06-08 02:57:24 +02:00
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local CHUNK_SIZE = constants.CHUNK_SIZE
local CHUNK_SIZE_DIVIDER = constants.CHUNK_SIZE_DIVIDER
2017-06-10 10:38:20 +02:00
local CHUNK_NORTH_SOUTH = constants.CHUNK_NORTH_SOUTH
local CHUNK_EAST_WEST = constants.CHUNK_EAST_WEST
2017-06-10 10:38:20 +02:00
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
local CHUNK_IMPASSABLE = constants.CHUNK_IMPASSABLE
local RESOURCE_NORMALIZER = constants.RESOURCE_NORMALIZER
2016-10-15 02:00:18 +02:00
local CHUNK_TICK = constants.CHUNK_TICK
2017-05-12 06:50:06 +02:00
-- imported functions
local isRampant = stringUtils.isRampant
local setNestCount = chunkPropertyUtils.setNestCount
local setPlayerBaseGenerator = chunkPropertyUtils.setPlayerBaseGenerator
local addPlayerBaseGenerator = chunkPropertyUtils.addPlayerBaseGenerator
local setResourceGenerator = chunkPropertyUtils.setResourceGenerator
local addResourceGenerator = chunkPropertyUtils.addResourceGenerator
local setWormCount = chunkPropertyUtils.setWormCount
local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator
local getNestCount = chunkPropertyUtils.getNestCount
2019-02-20 08:16:43 +02:00
local setRaidNestActiveness = chunkPropertyUtils.setRaidNestActiveness
local setNestActiveness = chunkPropertyUtils.setNestActiveness
local findNearbyBase = baseUtils.findNearbyBase
local createBase = baseUtils.createBase
2017-11-21 09:27:03 +02:00
local upgradeEntity = baseUtils.upgradeEntity
local setChunkBase = chunkPropertyUtils.setChunkBase
2018-09-24 06:56:45 +02:00
local setPassable = chunkPropertyUtils.setPassable
local setPathRating = chunkPropertyUtils.setPathRating
local getChunkByXY = mapUtils.getChunkByXY
2018-01-14 07:48:21 +02:00
2017-11-21 09:27:03 +02:00
local mFloor = math.floor
2017-05-12 06:50:06 +02:00
2019-02-13 07:50:25 +02:00
local mRandom = math.random
-- module code
2017-05-06 11:03:28 +02:00
2018-01-14 07:48:21 +02:00
local function getEntityOverlapChunks(map, entity)
local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box;
local overlapArray = map.chunkOverlapArray
2019-02-06 08:25:43 +02:00
overlapArray[1] = SENTINEL_IMPASSABLE_CHUNK --LeftTop
overlapArray[2] = SENTINEL_IMPASSABLE_CHUNK --RightTop
overlapArray[3] = SENTINEL_IMPASSABLE_CHUNK --LeftBottom
overlapArray[4] = SENTINEL_IMPASSABLE_CHUNK --RightBottom
2019-02-06 08:25:43 +02:00
if boundingBox then
2017-11-21 09:27:03 +02:00
local center = entity.position
local topXOffset
local topYOffset
2019-02-06 08:25:43 +02:00
2017-11-21 09:27:03 +02:00
local bottomXOffset
local bottomYOffset
2019-02-06 08:25:43 +02:00
2019-02-13 07:50:25 +02:00
topXOffset = boundingBox.left_top.x
topYOffset = boundingBox.left_top.y
bottomXOffset = boundingBox.right_bottom.x
bottomYOffset = boundingBox.right_bottom.y
2019-02-06 08:25:43 +02:00
local leftTopChunkX = mFloor((center.x + topXOffset) * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
local leftTopChunkY = mFloor((center.y + topYOffset) * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
2019-02-06 08:25:43 +02:00
local rightTopChunkX = mFloor((center.x + bottomXOffset) * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
local leftBottomChunkY = mFloor((center.y + bottomYOffset) * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
2019-02-06 08:25:43 +02:00
overlapArray[1] = getChunkByXY(map, leftTopChunkX, leftTopChunkY) -- LeftTop
2017-11-21 09:27:03 +02:00
if (leftTopChunkX ~= rightTopChunkX) then
overlapArray[2] = getChunkByXY(map, rightTopChunkX, leftTopChunkY) -- RightTop
2017-11-21 09:27:03 +02:00
end
if (leftTopChunkY ~= leftBottomChunkY) then
overlapArray[3] = getChunkByXY(map, leftTopChunkX, leftBottomChunkY) -- LeftBottom
2017-11-21 09:27:03 +02:00
end
if (leftTopChunkX ~= rightTopChunkX) and (leftTopChunkY ~= leftBottomChunkY) then
overlapArray[4] = getChunkByXY(map, rightTopChunkX, leftBottomChunkY) -- RightBottom
2017-11-21 09:27:03 +02:00
end
end
return overlapArray
2017-11-21 09:27:03 +02:00
end
local function scanPaths(chunk, surface, map)
2017-12-21 05:50:36 +02:00
local pass = CHUNK_IMPASSABLE
2019-02-06 08:25:43 +02:00
2019-03-08 05:40:55 +02:00
local x = chunk.x
local y = chunk.y
local filteredEntitiesCliffQuery = map.filteredEntitiesCliffQuery
local filteredTilesPathQuery = map.filteredTilesPathQuery
local count_entities_filtered = surface.count_entities_filtered
local count_tiles_filtered = surface.count_tiles_filtered
local passableNorthSouth = false
local passableEastWest = false
local topPosition = filteredEntitiesCliffQuery.area[1]
local bottomPosition = filteredEntitiesCliffQuery.area[2]
topPosition[2] = y
bottomPosition[2] = y + 32
for xi=x, x + 32 do
topPosition[1] = xi
2019-03-08 05:40:55 +02:00
bottomPosition[1] = xi + 1
if (count_entities_filtered(filteredEntitiesCliffQuery) == 0) and
2019-03-08 05:40:55 +02:00
(count_tiles_filtered(filteredTilesPathQuery) == 0)
then
passableNorthSouth = true
break
end
2019-03-08 05:40:55 +02:00
end
topPosition[1] = x
bottomPosition[1] = x + 32
for yi=y, y + 32 do
topPosition[2] = yi
2019-03-08 05:40:55 +02:00
bottomPosition[2] = yi + 1
if (count_entities_filtered(filteredEntitiesCliffQuery) == 0) and
2019-03-08 05:40:55 +02:00
(count_tiles_filtered(filteredTilesPathQuery) == 0)
then
passableEastWest = true
break
end
2019-03-08 05:40:55 +02:00
end
if passableEastWest and passableNorthSouth then
pass = CHUNK_ALL_DIRECTIONS
elseif passableEastWest then
pass = CHUNK_EAST_WEST
elseif passableNorthSouth then
pass = CHUNK_NORTH_SOUTH
end
return pass
end
2019-05-10 02:46:57 +02:00
local function scorePlayerBuildings(surface, map)
2019-05-16 07:11:43 +02:00
return (surface.count_entities_filtered(map.filteredEntitiesPlayerQuery50) * 25) +
(surface.count_entities_filtered(map.filteredEntitiesPlayerQuery200) * 100) +
(surface.count_entities_filtered(map.filteredEntitiesPlayerQuery1000) * 500) +
(surface.count_entities_filtered(map.filteredEntitiesPlayerQuery2000) * 1000) +
(surface.count_entities_filtered(map.filteredEntitiesPlayerQuery3500) * 1750) +
(surface.count_entities_filtered(map.filteredEntitiesPlayerQuery12000) * 6000)
end
function chunkUtils.initialScan(chunk, natives, surface, map, tick, evolutionFactor, rebuilding)
local passScore = 1 - (surface.count_tiles_filtered(map.filteredTilesQuery) * 0.0009765625)
2019-03-09 02:42:20 +02:00
if (passScore >= CHUNK_PASS_THRESHOLD) then
local pass = scanPaths(chunk, surface, map)
2019-02-06 08:25:43 +02:00
local playerObjects = scorePlayerBuildings(surface, map)
2019-03-08 05:40:55 +02:00
2019-03-06 08:18:03 +02:00
local nests = surface.find_entities_filtered(map.filteredEntitiesUnitSpawnereQuery)
if ((playerObjects > 0) or (#nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS
end
2019-02-21 08:31:47 +02:00
if (pass ~= CHUNK_IMPASSABLE) then
2019-05-10 02:46:57 +02:00
local worms = surface.find_entities_filtered(map.filteredEntitiesWormQuery)
2019-02-21 08:31:47 +02:00
local resources = surface.count_entities_filtered(map.countResourcesQuery) * RESOURCE_NORMALIZER
if natives.newEnemies and ((#nests > 0) or (#worms > 0)) then
local nestCount = 0
local wormCount = 0
local base = findNearbyBase(map, chunk, natives)
if base then
setChunkBase(map, chunk, base)
2019-02-21 08:31:47 +02:00
else
base = createBase(map, natives, evolutionFactor, chunk, tick, rebuilding)
2019-02-21 08:31:47 +02:00
end
local alignment = base.alignment
2019-04-07 06:41:00 +02:00
2019-04-08 07:22:02 +02:00
for _, unit in pairs(surface.find_entities_filtered(map.filteredEntitiesUnitQuery)) do
if (unit.valid) then
unit.destroy()
end
end
2019-04-07 06:41:00 +02:00
2019-02-21 08:31:47 +02:00
if (#nests > 0) then
for i = 1, #nests do
if rebuilding then
if not isRampant(nests[i].name) then
if upgradeEntity(nests[i], surface, alignment[mRandom(#alignment)], natives, evolutionFactor) then
nestCount = nestCount + 1
end
else
nestCount = nestCount + 1
end
else
if upgradeEntity(nests[i], surface, alignment[mRandom(#alignment)], natives, evolutionFactor) then
nestCount = nestCount + 1
end
end
end
end
if (#worms > 0) then
for i = 1, #worms do
if rebuilding then
if not isRampant(worms[i].name) then
if upgradeEntity(worms[i], surface, alignment[mRandom(#alignment)], natives, evolutionFactor) then
wormCount = wormCount + 1
end
else
wormCount = wormCount + 1
end
else
if upgradeEntity(worms[i], surface, alignment[mRandom(#alignment)], natives, evolutionFactor) then
wormCount = wormCount + 1
end
end
end
end
setNestCount(map, chunk, nestCount)
setWormCount(map, chunk, wormCount)
else
setNestCount(map, chunk, #nests)
setWormCount(map, chunk, #worms)
end
2019-02-06 08:25:43 +02:00
2019-02-21 08:31:47 +02:00
setPlayerBaseGenerator(map, chunk, playerObjects)
setResourceGenerator(map, chunk, resources)
2019-02-06 08:25:43 +02:00
2019-02-21 08:31:47 +02:00
setPassable(map, chunk, pass)
setPathRating(map, chunk, passScore)
2019-02-21 08:31:47 +02:00
return chunk
end
2017-06-09 07:18:59 +02:00
end
return SENTINEL_IMPASSABLE_CHUNK
end
2018-01-14 07:48:21 +02:00
function chunkUtils.chunkPassScan(chunk, surface, map)
local passScore = 1 - (surface.count_tiles_filtered(map.filteredTilesQuery) * 0.0009765625)
2019-03-09 02:42:20 +02:00
if (passScore >= CHUNK_PASS_THRESHOLD) then
local pass = scanPaths(chunk, surface, map)
2019-02-06 08:25:43 +02:00
local playerObjects = getPlayerBaseGenerator(map, chunk)
local nests = getNestCount(map, chunk)
if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS
end
setPassable(map, chunk, pass)
setPathRating(map, chunk, passScore)
return chunk
2017-11-21 09:27:03 +02:00
end
return SENTINEL_IMPASSABLE_CHUNK
end
2019-05-10 02:46:57 +02:00
function chunkUtils.mapScanChunk(chunk, surface, map)
local playerObjects = scorePlayerBuildings(surface, map)
setPlayerBaseGenerator(map, chunk, playerObjects)
local resources = surface.count_entities_filtered(map.countResourcesQuery) * RESOURCE_NORMALIZER
setResourceGenerator(map, chunk, resources)
2018-09-24 06:56:45 +02:00
local nests = surface.count_entities_filtered(map.filteredEntitiesUnitSpawnereQuery)
setNestCount(map, chunk, nests)
local worms = surface.count_entities_filtered(map.filteredEntitiesWormQuery)
setWormCount(map, chunk, worms)
end
2019-03-10 21:28:43 +02:00
function chunkUtils.entityForPassScan(map, entity)
local overlapArray = getEntityOverlapChunks(map, entity)
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
map.chunkToPassScan[chunk] = true
end
end
end
function chunkUtils.createChunk(topX, topY)
2016-10-15 02:00:18 +02:00
local chunk = {
x = topX,
y = topY
2016-10-15 02:00:18 +02:00
}
chunk[MOVEMENT_PHEROMONE] = 0
2016-10-15 02:00:18 +02:00
chunk[BASE_PHEROMONE] = 0
chunk[PLAYER_PHEROMONE] = 0
2017-06-08 02:57:24 +02:00
chunk[RESOURCE_PHEROMONE] = 0
2016-10-15 02:00:18 +02:00
chunk[CHUNK_TICK] = 0
2019-02-06 08:25:43 +02:00
return chunk
end
2017-12-31 21:36:23 +02:00
function chunkUtils.colorChunk(x, y, tileType, surface)
local tiles = {}
local lx = math.floor(x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
local ly = math.floor(y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
for xi=lx+5, lx + 27 do
for yi=ly+5, ly + 27 do
tiles[#tiles+1] = {name=tileType, position={xi, yi}}
end
2017-12-31 21:36:23 +02:00
end
surface.set_tiles(tiles, false)
end
function chunkUtils.registerEnemyBaseStructure(map, entity, base)
2017-11-21 09:27:03 +02:00
local entityType = entity.type
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
local overlapArray = getEntityOverlapChunks(map, entity)
local lookup
if (entityType == "unit-spawner") then
lookup = map.chunkToNests
elseif (entityType == "turret") then
lookup = map.chunkToWorms
end
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
lookup[chunk] = (lookup[chunk] or 0) + 1
setChunkBase(map, chunk, base)
end
end
2017-11-21 09:27:03 +02:00
end
2019-02-06 08:25:43 +02:00
2018-01-14 09:07:29 +02:00
return entity
2017-11-21 09:27:03 +02:00
end
2018-01-14 07:48:21 +02:00
function chunkUtils.unregisterEnemyBaseStructure(map, entity)
2017-11-21 09:27:03 +02:00
local entityType = entity.type
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
local overlapArray = getEntityOverlapChunks(map, entity)
local mainLookup
local secondaryLookup
if (entityType == "unit-spawner") then
mainLookup = map.chunkToNests
secondaryLookup = map.chunkToWorms
elseif (entity.type == "turret") then
mainLookup = map.chunkToWorms
secondaryLookup = map.chunkToNests
end
2019-02-06 08:25:43 +02:00
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local count = mainLookup[chunk]
if count then
if (count <= 1) then
if (entityType == "unit-spawner") then
setRaidNestActiveness(map, chunk, 0)
setNestActiveness(map, chunk, 0)
end
mainLookup[chunk] = nil
if not secondaryLookup[chunk] then
setChunkBase(map, chunk, nil)
end
else
mainLookup[chunk] = count - 1
end
end
end
end
2017-11-21 09:27:03 +02:00
end
end
function chunkUtils.accountPlayerEntity(map, entity, natives, addObject, creditNatives)
2018-05-24 02:25:08 +02:00
if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name ~= "enemy") then
local entityValue = BUILDING_PHEROMONES[entity.type]
2019-05-16 07:11:43 +02:00
local overlapArray = getEntityOverlapChunks(map, entity)
2017-11-21 09:27:03 +02:00
if not addObject then
if creditNatives then
2019-02-11 08:14:17 +02:00
if (natives.state == AI_STATE_ONSLAUGHT) then
natives.points = natives.points + entityValue
else
natives.points = natives.points + (entityValue * 0.12)
end
end
entityValue = -entityValue
end
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
addPlayerBaseGenerator(map, chunk, entityValue)
end
end
2017-11-21 09:27:03 +02:00
end
return entity
end
2018-01-14 07:48:21 +02:00
function chunkUtils.unregisterResource(entity, map)
if entity.prototype.infinite_resource then
return
end
local overlapArray = getEntityOverlapChunks(map, entity)
2019-02-06 08:25:43 +02:00
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
addResourceGenerator(map, chunk, -RESOURCE_NORMALIZER)
end
end
end
2019-05-16 07:11:43 +02:00
function chunkUtils.registerResource(entity, map)
local overlapArray = getEntityOverlapChunks(map, entity)
for i=1,#overlapArray do
local chunk = overlapArray[i]
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
addResourceGenerator(map, chunk, RESOURCE_NORMALIZER)
end
end
end
2017-11-21 09:27:03 +02:00
function chunkUtils.makeImmortalEntity(surface, entity)
local repairPosition = entity.position
local repairName = entity.name
local repairForce = entity.force
local repairDirection = entity.direction
local wires
if (entity.type == "electric-pole") then
wires = entity.neighbours
2017-11-21 09:27:03 +02:00
end
entity.destroy()
local newEntity = surface.create_entity({position=repairPosition,
name=repairName,
direction=repairDirection,
force=repairForce})
2017-11-21 09:27:03 +02:00
if wires then
for _,v in pairs(wires.copper) do
2019-02-19 02:43:01 +02:00
if (v.valid) then
newEntity.connect_neighbour(v);
end
2019-02-13 07:50:25 +02:00
end
for _,v in pairs(wires.red) do
2019-02-19 02:43:01 +02:00
if (v.valid) then
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_RED, target_entity = v});
end
2019-02-13 07:50:25 +02:00
end
for _,v in pairs(wires.green) do
2019-02-19 02:43:01 +02:00
if (v.valid) then
newEntity.connect_neighbour({wire = DEFINES_WIRE_TYPE_GREEN, target_entity = v});
end
2019-02-13 07:50:25 +02:00
end
2017-11-21 09:27:03 +02:00
end
newEntity.destructible = false
end
2019-02-16 06:17:30 +02:00
chunkUtilsG = chunkUtils
return chunkUtils