1
0
mirror of https://github.com/veden/Rampant.git synced 2024-12-28 21:08:22 +02:00

swiched tile, cliff, resource scans to events. Added artillery turret

to pheromones. Lowered pass score cutoff. added surface checks
This commit is contained in:
Aaron Veden 2018-01-01 22:05:21 -08:00
parent ed5739906d
commit b6d0ac9d3a
7 changed files with 260 additions and 80 deletions

View File

@ -45,6 +45,7 @@ local roundToNearest = mathUtils.roundToNearest
local getChunkByPosition = mapUtils.getChunkByPosition
local processPendingChunks = chunkProcessor.processPendingChunks
local processScanChunks = chunkProcessor.processScanChunks
local processMap = mapProcessor.processMap
local processPlayers = mapProcessor.processPlayers
@ -144,6 +145,7 @@ local function rebuildRegionMap()
regionMap.chunkToRallys = {}
regionMap.chunkToPlayerBase = {}
regionMap.chunkToResource = {}
regionMap.chunkToPassScan = {}
-- preallocating memory to be used in code, making it fast by reducing garbage generated.
regionMap.neighbors = { SENTINEL_IMPASSABLE_CHUNK,
@ -273,13 +275,15 @@ local function onTick(event)
processPendingChunks(natives, regionMap, surface, pendingChunks, tick)
scanMap(regionMap, surface, natives)
regionMap.chunkToPassScan = processScanChunks(regionMap, surface)
end
if (tick == regionMap.logicTick) then
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC
local gameRef = game
local surface = gameRef.surfaces[1]
planning(natives,
gameRef.forces.enemy.evolution_factor,
tick,
@ -304,16 +308,22 @@ end
local function onBuild(event)
local entity = event.created_entity
addRemovePlayerEntity(regionMap, entity, natives, true, false)
if natives.safeBuildings then
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
entity.destructible = false
if (entity.surface.index == 1) then
addRemovePlayerEntity(regionMap, entity, natives, true, false)
if natives.safeBuildings then
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
entity.destructible = false
end
end
end
end
local function onMine(event)
addRemovePlayerEntity(regionMap, event.entity, natives, false, false)
local entity = event.entity
local surface = entity.surface
if (surface.index == 1) then
addRemovePlayerEntity(regionMap, entity, natives, false, false)
end
end
local function onDeath(event)
@ -351,10 +361,10 @@ local function onDeath(event)
end
end
elseif (entity.type == "unit-spawner") or (entity.type == "turret") then
elseif event.force and (event.force.name == "player") and (entity.type == "unit-spawner") or (entity.type == "turret") then
local tick = event.tick
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
unregisterEnemyBaseStructure(regionMap, entity)
rallyUnits(chunk, regionMap, surface, natives, tick)
@ -388,14 +398,64 @@ local function onDeath(event)
end
local function onEnemyBaseBuild(event)
registerEnemyBaseStructure(regionMap, event.entity, nil)
local entity = event.entity
local surface = entity.surface
if (surface.index == 1) then
registerEnemyBaseStructure(regionMap, entity, nil)
end
end
local function onSurfaceTileChange(event)
-- local player = game.players[event.player_index]
-- if (player.surface.index == 1) then
-- aiAttackWave.fillTunnel(regionMap, player.surface, natives, event.positions)
-- end
local surfaceIndex = event.surface_index or event.robot.surface.index
if (event.item.name == "landfill") and (surfaceIndex == 1) then
local chunks = {}
local positions = event.positions
for i=1,#positions do
local position = positions[i]
local chunk = mapUtils.getChunkByPosition(regionMap, position, true)
-- weird bug with table pointer equality using name instead pointer comparison
if not chunk.name then
regionMap.chunkToPassScan[chunk] = true
else
local x,y = mapUtils.positionToChunkXY(position)
local addMe = true
for ci=1,#chunks do
local c = chunks[ci]
if (c.x == x) and (c.y == y) then
addMe = false
break
end
end
if addMe then
chunks[#chunks+1] = {x=x,y=y}
end
end
end
for i=1,#chunks do
onChunkGenerated({area = { left_top = chunks[i] },
surface = game.surfaces[surfaceIndex]})
end
end
end
local function onResourceDepleted(event)
local entity = event.entity
if (entity.surface.index == 1) then
chunkUtils.unregisterResource(entity, regionMap)
end
end
local function onUsedCapsule(event)
local surface = game.players[event.player_index].surface
if (event.item.name == "cliff-explosives") and (surface.index == 1) then
local cliffs = surface.find_entities_filtered({area={{event.position.x-0.75,event.position.y-0.75},
{event.position.x+0.75,event.position.y+0.75}},
type="cliff"})
for i=1,#cliffs do
chunkUtils.queueChunkForPassScan(regionMap, cliffs[i])
end
end
end
local function onInit()
@ -418,7 +478,11 @@ script.on_load(onLoad)
script.on_event(defines.events.on_runtime_mod_setting_changed, onModSettingsChange)
script.on_configuration_changed(onConfigChanged)
script.on_event(defines.events.on_player_built_tile, onSurfaceTileChange)
script.on_event(defines.events.on_resource_depleted, onResourceDepleted)
script.on_event({defines.events.on_player_built_tile,
defines.events.on_robot_built_tile}, onSurfaceTileChange)
script.on_event(defines.events.on_player_used_capsule, onUsedCapsule)
script.on_event(defines.events.on_biter_base_built, onEnemyBaseBuild)
script.on_event({defines.events.on_player_mined_entity,

View File

@ -4,7 +4,6 @@ local chunkProcessor = {}
local chunkUtils = require("ChunkUtils")
local constants = require("Constants")
local squadDefense = require("SquadDefense")
-- constants
@ -15,7 +14,8 @@ local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
-- imported functions
local createChunk = chunkUtils.createChunk
local analyzeChunk = chunkUtils.analyzeChunk
local initialScan = chunkUtils.initialScan
local chunkPassScan = chunkUtils.chunkPassScan
-- module code
@ -41,9 +41,9 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin
bottomOffset[1] = x + CHUNK_SIZE
bottomOffset[2] = y + CHUNK_SIZE
chunk = analyzeChunk(chunk, natives, surface, regionMap)
chunk = initialScan(chunk, natives, surface, regionMap)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local chunkX = chunk.x
if regionMap[chunkX] == nil then
@ -56,4 +56,37 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin
end
end
function chunkProcessor.processScanChunks(regionMap, surface)
local area = regionMap.area
local topOffset = area[1]
local bottomOffset = area[2]
local removals = {}
for chunk,_ in pairs(regionMap.chunkToPassScan) do
local x = chunk.x
local y = chunk.y
topOffset[1] = x
topOffset[2] = y
bottomOffset[1] = x + CHUNK_SIZE
bottomOffset[2] = y + CHUNK_SIZE
chunk = chunkPassScan(chunk, surface, regionMap)
if (chunk == SENTINEL_IMPASSABLE_CHUNK) then
regionMap[x][y] = nil
removals[#removals+1] = chunk
end
end
for i=#removals,1,-1 do
table.remove(regionMap.processQueue, i)
end
return {}
end
return chunkProcessor

View File

@ -33,6 +33,8 @@ local PATH_RATING = constants.PATH_RATING
local PASSABLE = constants.PASSABLE
local RESOURCE_GENERATOR_INCREMENT = constants.RESOURCE_GENERATOR_INCREMENT
-- imported functions
local getChunkByUnalignedXY = mapUtils.getChunkByUnalignedXY
@ -193,7 +195,7 @@ end
-- external functions
function chunkUtils.analyzeChunk(chunk, natives, surface, regionMap)
function chunkUtils.calculatePassScore(surface, regionMap)
local count_tiles_filtered = surface.count_tiles_filtered
local filteredTilesQuery = regionMap.filteredTilesQuery
@ -203,72 +205,120 @@ function chunkUtils.analyzeChunk(chunk, natives, surface, regionMap)
passScore = passScore + count_tiles_filtered(filteredTilesQuery)
end
passScore = 1 - (passScore * 0.0009765625)
return 1 - (passScore * 0.0009765625)
end
function chunkUtils.scanChunkPaths(chunk, surface, regionMap)
local pass = CHUNK_IMPASSABLE
if (passScore >= 0.60) then
local passableNorthSouth, passableEastWest = fullScan(chunk,
surface.can_place_entity,
regionMap.canPlaceQuery)
local passableNorthSouth, passableEastWest = fullScan(chunk,
surface.can_place_entity,
regionMap.canPlaceQuery)
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
if passableEastWest and passableNorthSouth then
pass = CHUNK_ALL_DIRECTIONS
elseif passableEastWest then
pass = CHUNK_EAST_WEST
elseif passableNorthSouth then
pass = CHUNK_NORTH_SOUTH
end
local entities = surface.find_entities_filtered(regionMap.filteredEntitiesPlayerQuery)
function chunkUtils.scorePlayerBuildings(surface, regionMap, natives)
local entities = surface.find_entities_filtered(regionMap.filteredEntitiesPlayerQuery)
local playerObjects = 0
local safeBuildings = natives.safeBuildings
local safeEntities = natives.safeEntities
local safeEntityName = natives.safeEntityName
if safeBuildings then
for i=1, #entities do
local entity = entities[i]
local entityType = entity.type
local playerObjects = 0
local safeBuildings = natives.safeBuildings
local safeEntities = natives.safeEntities
local safeEntityName = natives.safeEntityName
if safeBuildings then
for i=1, #entities do
local entity = entities[i]
local entityType = entity.type
if safeEntities[entityType] or safeEntityName[entity.name] then
entity.destructible = false
end
playerObjects = playerObjects + (BUILDING_PHEROMONES[entityType] or 0)
if safeEntities[entityType] or safeEntityName[entity.name] then
entity.destructible = false
end
else
for i=1, #entities do
playerObjects = playerObjects + (BUILDING_PHEROMONES[entities[i].type] or 0)
end
end
local query = regionMap.filteredEntitiesEnemyTypeQuery
playerObjects = playerObjects + (BUILDING_PHEROMONES[entityType] or 0)
end
else
for i=1, #entities do
playerObjects = playerObjects + (BUILDING_PHEROMONES[entities[i].type] or 0)
end
end
return playerObjects
end
function chunkUtils.scoreEnemyBuildings(surface, regionMap)
local query = regionMap.filteredEntitiesEnemyTypeQuery
query.type = "unit-spawner"
local nests = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery)
query.type = "turret"
local worms = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery)
return nests, worms
end
function chunkUtils.initialScan(chunk, natives, surface, regionMap)
local passScore = chunkUtils.calculatePassScore(surface, regionMap)
if (passScore >= 0.40) then
local pass = chunkUtils.scanChunkPaths(chunk, surface, regionMap)
query.type = "unit-spawner"
local nests = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery)
chunkUtils.setNestCount(regionMap, chunk, nests)
query.type = "turret"
local worms = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery)
chunkUtils.setWormCount(regionMap, chunk, worms)
local playerObjects = chunkUtils.scorePlayerBuildings(surface, regionMap, natives)
local nests, worms = chunkUtils.scoreEnemyBuildings(surface, regionMap)
local resources = surface.count_entities_filtered(regionMap.countResourcesQuery) * 0.001
if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS
end
chunkUtils.setNestCount(regionMap, chunk, nests)
chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects)
chunkUtils.setResourceGenerator(regionMap, chunk, resources)
end
chunkUtils.setWormCount(regionMap, chunk, worms)
if (pass == CHUNK_IMPASSABLE) then
return SENTINEL_IMPASSABLE_CHUNK
else
chunk[PASSABLE] = pass
chunk[PATH_RATING] = passScore
return chunk
end
return SENTINEL_IMPASSABLE_CHUNK
end
function chunkUtils.chunkPassScan(chunk, surface, regionMap)
local passScore = chunkUtils.calculatePassScore(surface, regionMap)
if (passScore >= 0.40) then
local pass = chunkUtils.scanChunkPaths(chunk, surface, regionMap)
local playerObjects = chunkUtils.getPlayerBaseGenerator(regionMap, chunk)
local nests = chunkUtils.getNestCount(regionMap, chunk)
if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS
end
chunk[PASSABLE] = pass
chunk[PATH_RATING] = passScore
return chunk
end
return SENTINEL_IMPASSABLE_CHUNK
end
function chunkUtils.analyzeChunk(chunk, natives, surface, regionMap)
local playerObjects = chunkUtils.scorePlayerBuildings(surface, regionMap, natives)
chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects)
end
-- function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQuery)
@ -360,6 +410,10 @@ function chunkUtils.getResourceGenerator(regionMap, chunk)
return regionMap.chunkToResource[chunk] or 0
end
function chunkUtils.addResourceGenerator(regionMap, chunk, delta)
regionMap.chunkToResource[chunk] = (regionMap.chunkToResource[chunk] or 0) + delta
end
function chunkUtils.getPlayerBaseGenerator(regionMap, chunk)
return regionMap.chunkToPlayerBase[chunk] or 0
end
@ -373,7 +427,7 @@ function chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerGenerator)
end
function chunkUtils.addPlayerBaseGenerator(regionMap, chunk, playerGenerator)
regionMap.chunkToPlayerBase[chunk] = regionMap.chunkToPlayerBase[chunk] + playerGenerator
regionMap.chunkToPlayerBase[chunk] = (regionMap.chunkToPlayerBase[chunk] or 0) + playerGenerator
end
function chunkUtils.createChunk(topX, topY)
@ -402,6 +456,23 @@ function chunkUtils.colorChunk(x, y, tileType, surface)
surface.set_tiles(tiles, false)
end
function chunkUtils.entityForPassScan(regionMap, entity)
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[leftTop] = true
end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[rightTop] = true
end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[leftBottom] = true
end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[rightBottom] = true
end
end
function chunkUtils.registerEnemyBaseStructure(regionMap, entity, base)
local entityType = entity.type
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
@ -471,6 +542,26 @@ function chunkUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject,
return entity
end
function chunkUtils.unregisterResource(entity, regionMap)
if entity.prototype.infinite_resource then
return
end
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, leftTop, -RESOURCE_GENERATOR_INCREMENT)
end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, rightTop, -RESOURCE_GENERATOR_INCREMENT)
end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, leftBottom, -RESOURCE_GENERATOR_INCREMENT)
end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, rightBottom, -RESOURCE_GENERATOR_INCREMENT)
end
end
function chunkUtils.makeImmortalEntity(surface, entity)
local repairPosition = entity.position
local repairName = entity.name

View File

@ -42,6 +42,7 @@ constants.INTERVAL_CHUNK = 17
constants.INTERVAL_LOGIC = 61
constants.INTERVAL_SQUAD = 41
constants.RESOURCE_GENERATOR_INCREMENT = 0.001
constants.PLAYER_PHEROMONE_MULTIPLER = 100
@ -174,7 +175,7 @@ constants.BUILDING_PHEROMONES["beacon"] = 10
constants.BUILDING_PHEROMONES["furnace"] = 12
constants.BUILDING_PHEROMONES["programmable-speaker"] = 8
constants.BUILDING_PHEROMONES["mining-drill"] = 35
constants.BUILDING_PHEROMONES["rocket-silo"] = 18
constants.BUILDING_PHEROMONES["rocket-silo"] = 120
constants.BUILDING_PHEROMONES["lamp"] = 4
constants.BUILDING_PHEROMONES["radar"] = 20
constants.BUILDING_PHEROMONES["lab"] = 15
@ -186,6 +187,7 @@ constants.BUILDING_PHEROMONES["wall"] = 0.5
constants.BUILDING_PHEROMONES["electric-turret"] = 20
constants.BUILDING_PHEROMONES["fluid-turret"] = 28
constants.BUILDING_PHEROMONES["turret"] = 10
constants.BUILDING_PHEROMONES["artillery-turret"] = 100
constants.retreatFilter = {}
constants.retreatFilter[constants.SQUAD_RETREATING] = true
@ -211,6 +213,7 @@ constants.UNIT_GROUP_SLOWDOWN_FACTOR = 0.9
constants.SENTINEL_IMPASSABLE_CHUNK = {}
constants.SENTINEL_IMPASSABLE_CHUNK.name = "ImpassableChunk"
constants.SENTINEL_IMPASSABLE_CHUNK[constants.MOVEMENT_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
constants.SENTINEL_IMPASSABLE_CHUNK[constants.BASE_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PLAYER_PHEROMONE] = constants.IMPASSABLE_TERRAIN_GENERATOR_AMOUNT

View File

@ -31,7 +31,6 @@ 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 BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
-- imported functions

View File

@ -87,7 +87,7 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
if newSquad then
if enemiesToSquad then
membersToSquad(newSquad, enemiesToSquad, (radius == RETREAT_SPAWNER_GRAB_RADIUS))
membersToSquad(newSquad, enemiesToSquad, force)
else
membersToSquad(newSquad, squad.group.members, true)
newSquad.penalties = squad.penalties

View File

@ -105,17 +105,7 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
return squad
end
end
local returnSquad = { group = unitGroup,
status = SQUAD_GUARDING,
penalties = {},
rabid = false,
frenzy = false,
kamikaze = false,
frenzyPosition = {x = 0,
y = 0},
cycles = 0 }
squads[#squads+1] = returnSquad
return returnSquad
return nil
end
function unitGroupUtils.calculateKamikazeThreshold(squad, natives)