cleanup + optimizations + indestructible

This commit is contained in:
Aaron Veden
2017-05-23 23:46:23 -07:00
parent c9c878babb
commit 49a82fcff4
15 changed files with 270 additions and 214 deletions
+22 -6
View File
@@ -56,9 +56,6 @@ function upgrade.attempt(natives, regionMap)
if (global.version < constants.VERSION_11) then
natives.state = constants.AI_STATE_AGGRESSIVE
natives.temperament = 0
-- needs to be on inner logic tick loop interval
natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
global.version = constants.VERSION_11
end
@@ -74,9 +71,6 @@ function upgrade.attempt(natives, regionMap)
global.version = constants.VERSION_12
end
if (global.version < constants.VERSION_13) then
-- switched over to tick event
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
-- used to rate limit the number of rally cries during a period of time
natives.rallyCries = MAX_RALLY_CRIES
@@ -124,6 +118,28 @@ function upgrade.attempt(natives, regionMap)
game.surfaces[1].print("Rampant - Version 0.15.9")
global.version = constants.VERSION_21
end
if (global.version < constants.VERSION_22) then
-- been made redundant
natives.rallyCries = nil
-- switched over to tick event
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
-- needs to be on inner logic tick loop interval
natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
game.map_settings.path_finder.short_request_ratio = 0.8
game.map_settings.path_finder.short_cache_size = 25
game.map_settings.path_finder.long_cache_size = 5
game.map_settings.path_finder.min_steps_to_check_path_find_termination = 300
game.map_settings.max_failed_behavior_count = 6
game.surfaces[1].print("Rampant - Version 0.15.10")
global.version = constants.VERSION_22
end
return starting ~= global.version
end
+22 -23
View File
@@ -12,7 +12,6 @@ local aiDefense = require("libs/AIDefense")
local aiAttack = require("libs/AIAttack")
local aiBuilding = require("libs/AIBuilding")
local aiPlanning = require("libs/AIPlanning")
local mathUtils = require("libs/MathUtils")
local interop = require("libs/Interop")
local tests = require("tests")
@@ -21,8 +20,6 @@ local tests = require("tests")
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
@@ -47,6 +44,7 @@ local rallyUnits = aiBuilding.rallyUnits
local deathScent = pheromoneUtils.deathScent
local victoryScent = pheromoneUtils.victoryScent
local cleanSquads = unitGroupUtils.cleanSquads
local regroupSquads = unitGroupUtils.regroupSquads
local convertUnitGroupToSquad = unitGroupUtils.convertUnitGroupToSquad
@@ -55,11 +53,9 @@ local squadBeginAttack = aiAttack.squadBeginAttack
local retreatUnits = aiDefense.retreatUnits
local regenerateEntity = entityUtils.regenerateEntity
-- local regenerateEntity = entityUtils.regenerateEntity
local addRemoveEntity = entityUtils.addRemoveEntity
--local makeImmortalEntity = entityUtils.makeImmortalEntity
local roundToNearest = mathUtils.roundToNearest
local makeImmortalEntity = entityUtils.makeImmortalEntity
-- local references to global
@@ -102,7 +98,7 @@ local function onModSettingsChange(event)
natives.safeEntityName["big-electric-pole-2"] = poles
natives.safeEntityName["big-electric-pole-3"] = poles
natives.safeEntityName["big-electric-pole-4"] = poles
natives.attackUsePlayer = settings.global["rampant-attackWaveGenerationUsePlayerProximity"].value
natives.attackUsePollution = settings.global["rampant-attackWaveGenerationUsePollution"].value
@@ -147,17 +143,16 @@ local function onTick(event)
local evolutionFactor = game.forces.enemy.evolution_factor
local players = game.players
processPendingChunks(regionMap, surface, pendingChunks)
processPendingChunks(natives, regionMap, surface, pendingChunks)
scanMap(regionMap, surface, natives, evolutionFactor)
if (tick == regionMap.logicTick) then
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC
natives.rallyCries = MAX_RALLY_CRIES
planning(natives, evolutionFactor, tick, surface)
regroupSquads(natives, evolutionFactor)
cleanSquads(natives, evolutionFactor)
-- regroupSquads(natives, evolutionFactor)
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
@@ -170,7 +165,13 @@ local function onTick(event)
end
local function onBuild(event)
addRemoveEntity(regionMap, event.created_entity, natives, true, false)
local entity = event.created_entity
addRemoveEntity(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
local function onPickUp(event)
@@ -185,13 +186,14 @@ local function onDeath(event)
if (entity.type == "unit") then
local entityPosition = entity.position
local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
if (deathChunk ~= nil) then
-- drop death pheromone where unit died
deathScent(deathChunk)
if ((event.force ~= nil) and (event.force.name == "player")) then
local evolutionFactor = game.forces.enemy.evolution_factor
local tick = event.tick
if (deathChunk[MOVEMENT_PHEROMONE] < -(evolutionFactor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
retreatUnits(deathChunk,
@@ -200,15 +202,15 @@ local function onDeath(event)
regionMap,
surface,
natives,
event.tick)
tick)
local rallyThreshold = BASE_RALLY_CHANCE + (evolutionFactor * BONUS_RALLY_CHANCE)
if (natives.rallyCries >= 0) and (math.random() < rallyThreshold) then
natives.rallyCries = natives.rallyCries - 1
if (math.random() < rallyThreshold) then
rallyUnits(deathChunk,
regionMap,
surface,
natives,
evolutionFactor)
evolutionFactor,
tick)
end
end
end
@@ -227,10 +229,7 @@ local function onDeath(event)
victoryScent(victoryChunk, entity.type)
end
if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then
-- makeImmortalEntity(surface, entity)
-- hack version
regenerateEntity(entity, entityPosition, surface)
makeImmortalEntity(surface, entity)
else
addRemoveEntity(regionMap, entity, natives, false, creditNatives)
end
+6 -5
View File
@@ -62,8 +62,9 @@ function aiAttack.squadAttack(regionMap, surface, natives)
for i=1,#squads do
local squad = squads[i]
local group = squad.group
if group.valid and (squad.status == SQUAD_RAIDING) then
if (group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering) or ((group.state == defines.group_state.moving) and (squad.cycles == 0)) then
if group.valid and (squad.status == SQUAD_RAIDING) then
local groupState = group.state
if (groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering) or ((groupState == defines.group_state.moving) and (squad.cycles == 0)) then
local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y)
if (chunk ~= nil) then
local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk,
@@ -75,9 +76,9 @@ function aiAttack.squadAttack(regionMap, surface, natives)
attackPosition,
true)
addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
if (attackChunk ~= nil) then
if attackChunk then
if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
((groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering)) then
positionFromDirectionAndChunk(attackDirection, squad.group.position, attackPosition)
@@ -100,7 +101,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
group.set_command(attackCmd)
group.start_moving()
elseif not squad.frenzy and not squad.rabid and
((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_target) or
((groupState == defines.group_state.attacking_distraction) or (groupState == defines.group_state.attacking_target) or
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
squad.frenzy = true
squad.frenzyPosition.x = squad.group.position.x
+13 -9
View File
@@ -23,7 +23,8 @@ local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
local AI_SQUAD_COST = constants.AI_SQUAD_COST
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local CHUNK_SIZE = constants.CHUNK_SIZE
@@ -123,14 +124,17 @@ end
-- --]]
-- end
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor)
local cX = chunk.cX
local cY = chunk.cY
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
local rallyChunk = getChunkByIndex(regionMap, x, y)
if (rallyChunk ~= nil) and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor, tick)
if (tick - chunk[RALLY_TRIGGERED] > INTERVAL_LOGIC) then
chunk[RALLY_TRIGGERED] = tick
local cX = chunk.cX
local cY = chunk.cY
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
local rallyChunk = getChunkByIndex(regionMap, x, y)
if (rallyChunk ~= nil) and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
end
end
end
end
+5 -9
View File
@@ -53,19 +53,15 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[ENEMY_BASE_GENERATOR] == 0) then
local performRetreat = false
local enemiesToSquad
if (squad == nil) then
enemiesToSquad = surface.find_enemy_units({x=chunk.pX,
y=chunk.pY}, RETREAT_GRAB_RADIUS)
if (#enemiesToSquad > 0) then
performRetreat = true
end
performRetreat = #enemiesToSquad > 0
elseif squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then
if (#squad.group.members > 1) then
performRetreat = true
end
performRetreat = #squad.group.members > 1
end
if performRetreat then
chunk[RETREAT_TRIGGERED] = tick
local retreatPosition = {x=0, y=0}
@@ -77,7 +73,7 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
surface,
retreatPosition,
false)
if (exitPath ~= nil) then
if exitPath then
retreatPosition.x = exitPath.pX + HALF_CHUNK_SIZE
retreatPosition.y = exitPath.pY + HALF_CHUNK_SIZE
+2 -2
View File
@@ -12,7 +12,7 @@ local scoreChunk = chunkUtils.scoreChunk
-- module code
function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendingStack)
local processQueue = regionMap.processQueue
for _=#pendingStack, 1, -1 do
@@ -29,7 +29,7 @@ function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
regionMap[chunkX][chunk.cY] = chunk
checkChunkPassability(chunk, surface)
scoreChunk(chunk, surface)
scoreChunk(natives, chunk, surface)
processQueue[#processQueue+1] = chunk
end
end
+14 -4
View File
@@ -25,6 +25,7 @@ local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GEN
local CHUNK_TICK = constants.CHUNK_TICK
local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
-- module code
@@ -68,7 +69,7 @@ function chunkUtils.checkChunkPassability(chunk, surface)
chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
end
function chunkUtils.scoreChunk(chunk, surface)
function chunkUtils.scoreChunk(natives, chunk, surface)
local x = chunk.pX
local y = chunk.pY
@@ -92,10 +93,18 @@ function chunkUtils.scoreChunk(chunk, surface)
chunk[ENEMY_BASE_GENERATOR] = (entities * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT) + worms
entities = surface.find_entities_filtered(playerChunkQuery)
local safeBuildings = natives.safeBuildings
for i=1, #entities do
local entityType = entities[i].type
local entity = entities[i]
local entityType = entity.type
if safeBuildings then
if natives.safeEntities[entityType] or natives.safeEntityName[entity.name] then
entity.destructible = false
end
end
local entityScore = BUILDING_PHEROMONES[entityType]
if (entityScore ~= nil) then
playerObjects = playerObjects + entityScore
@@ -121,6 +130,7 @@ function chunkUtils.createChunk(topX, topY)
chunk[EAST_WEST_PASSABLE] = false
chunk[CHUNK_TICK] = 0
chunk[RETREAT_TRIGGERED] = 0
chunk[RALLY_TRIGGERED] = 0
return chunk
end
+4 -2
View File
@@ -16,6 +16,7 @@ constants.VERSION_18 = 18
constants.VERSION_19 = 19
constants.VERSION_20 = 20
constants.VERSION_21 = 21
constants.VERSION_22 = 22
-- misc
@@ -29,8 +30,8 @@ constants.PROCESS_PLAYER_BOUND = 4
constants.TICKS_A_SECOND = 60
constants.TICKS_A_MINUTE = constants.TICKS_A_SECOND * 60
constants.INTERVAL_PROCESS = 20
constants.INTERVAL_LOGIC = 40
constants.INTERVAL_PROCESS = 19
constants.INTERVAL_LOGIC = 38
-- ai
@@ -100,6 +101,7 @@ constants.EAST_WEST_PASSABLE = 7
constants.CHUNK_TICK = 8
constants.RETREAT_TRIGGERED = 9
constants.RALLY_TRIGGERED = 10
-- Squad status
+3 -21
View File
@@ -117,9 +117,8 @@ function entityUtils.addRemoveEntity(regionMap, entity, natives, addObject, cred
end
end
function entityUtils.regenerateEntity(entity, entityPosition, surface)
local repairPosition = entityPosition
function entityUtils.makeImmortalEntity(surface, entity)
local repairPosition = entity.position
local repairName = entity.name
local repairForce = entity.force
local repairDirection = entity.direction
@@ -150,25 +149,8 @@ function entityUtils.regenerateEntity(entity, entityPosition, surface)
end
end
end
-- forces enemy to disperse
local enemies = surface.find_enemy_units({repairPosition.x, repairPosition.y}, CHUNK_SIZE)
for i=1, #enemies do
enemies[i].set_command({type=defines.command.wander,
distraction=defines.distraction.by_enemy})
end
end
function entityUtils.makeImmortalEntity(surface, entity)
local repairPosition = entity.position
local repairName = entity.name
local repairForce = entity.force
local repairDirection = entity.direction
entity.destroy()
local entityRepaired = surface.create_entity({position=repairPosition,
name=repairName,
direction=repairDirection,
force=repairForce})
entityRepaired.destructible = false
newEntity.destructible = false
end
return entityUtils
+47 -19
View File
@@ -46,6 +46,8 @@ local getChunkByPosition = mapUtils.getChunkByPosition
local playerScent = pheromoneUtils.playerScent
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
local canAttackNocturnal = nocturnalUtils.canAttack
local mMin = math.min
@@ -182,34 +184,54 @@ end
function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
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"}
local processQueue = regionMap.processQueue
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
for x=index,endIndex do
local chunk = processQueue[x]
local entities = surface.find_entities_filtered({area = {{chunk.pX, chunk.pY},
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
force = "player"})
local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
type = "unit-spawner",
force = "enemy"})
chunkPosition.x = chunk.pX
chunkPosition.y = chunk.pY
local worms = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
type = "turret",
force = "enemy"})
chunkBox[2].x = chunkPosition.x + CHUNK_SIZE
chunkBox[2].y = chunkPosition.y + CHUNK_SIZE
local unitCount = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
type = "unit",
force = "enemy"})
local entities = surface.find_entities_filtered(playerQuery)
local spawners = surface.count_entities_filtered(spawnerQuery)
if (unitCount > 550) then
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
if (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then
closeBy = true
end
end
end
if (unitCount > 300) and not closeBy then
local weight = AI_UNIT_REFUND * evolution_factor
local units = surface.find_enemy_units({chunk.pX, chunk.pY},
CHUNK_SIZE * 3)
local units = surface.find_enemy_units(chunkPosition, CHUNK_SIZE * 3)
for i=1,#units do
units[i].destroy()
@@ -222,9 +244,15 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
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
+27 -40
View File
@@ -45,36 +45,27 @@ end
6 7 8
]]--
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY)
local neighbors = {1,2,3,4,5,6,7,8}
local neighbors = {false,false,false,false,false,false,false,false}
local chunkYRow1 = chunkY - 1
local chunkYRow3 = chunkY + 1
local xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then
neighbors[1] = xChunks[chunkY-1]
neighbors[1] = xChunks[chunkYRow1]
neighbors[4] = xChunks[chunkY]
neighbors[6] = xChunks[chunkY+1]
else
neighbors[1] = nil
neighbors[4] = nil
neighbors[6] = nil
neighbors[6] = xChunks[chunkYRow3]
end
xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then
neighbors[3] = xChunks[chunkY-1]
neighbors[3] = xChunks[chunkYRow1]
neighbors[5] = xChunks[chunkY]
neighbors[8] = xChunks[chunkY+1]
else
neighbors[3] = nil
neighbors[5] = nil
neighbors[8] = nil
neighbors[8] = xChunks[chunkYRow3]
end
xChunks = regionMap[chunkX]
if (xChunks ~= nil) then
neighbors[2] = xChunks[chunkY-1]
neighbors[7] = xChunks[chunkY+1]
else
neighbors[2] = nil
neighbors[7] = nil
neighbors[2] = xChunks[chunkYRow1]
neighbors[7] = xChunks[chunkYRow3]
end
return neighbors
end
@@ -93,25 +84,28 @@ function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk)
end
function mapUtils.getNeighborChunksWithDirection(regionMap, chunkX, chunkY)
local neighbors = {{d=1},{d=2},{d=3},{d=4},{d=5},{d=6},{d=7},{d=8}}
local neighbors = {false,false,false,false,false,false,false,false}
local chunkYRow1 = chunkY - 1
local chunkYRow3 = chunkY + 1
local xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then
neighbors[1].c = xChunks[chunkY-1]
neighbors[4].c = xChunks[chunkY]
neighbors[6].c = xChunks[chunkY+1]
neighbors[1] = xChunks[chunkYRow1]
neighbors[4] = xChunks[chunkY]
neighbors[6] = xChunks[chunkYRow3]
end
xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then
neighbors[3].c = xChunks[chunkY-1]
neighbors[5].c = xChunks[chunkY]
neighbors[8].c = xChunks[chunkY+1]
neighbors[3] = xChunks[chunkYRow1]
neighbors[5] = xChunks[chunkY]
neighbors[8] = xChunks[chunkYRow3]
end
xChunks = regionMap[chunkX]
if (xChunks ~= nil) then
neighbors[2].c = xChunks[chunkY-1]
neighbors[7].c = xChunks[chunkY+1]
neighbors[2] = xChunks[chunkYRow1]
neighbors[7] = xChunks[chunkYRow3]
end
return neighbors
end
@@ -124,48 +118,41 @@ end
4
]]--
function mapUtils.getCardinalChunksWithDirection(regionMap, chunkX, chunkY)
local neighbors = {{d=1},{d=2},{d=3},{d=4}}
local neighbors = {false, false, false, false}
local xChunks = regionMap[chunkX]
if (xChunks ~= nil) then
neighbors[1].c = xChunks[chunkY-1]
neighbors[4].c = xChunks[chunkY+1]
neighbors[1] = xChunks[chunkY-1]
neighbors[4] = xChunks[chunkY+1]
end
xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then
neighbors[2].c = xChunks[chunkY]
neighbors[2] = xChunks[chunkY]
end
xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then
neighbors[3].c = xChunks[chunkY]
neighbors[3] = xChunks[chunkY]
end
return neighbors
end
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
local neighbors = {1,2,3,4}
local neighbors = {false,false,false,false}
local xChunks = regionMap[chunkX]
if (xChunks ~= nil) then
neighbors[1] = xChunks[chunkY-1]
neighbors[4] = xChunks[chunkY+1]
else
neighbors[1] = nil
neighbors[4] = nil
end
xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then
neighbors[2] = xChunks[chunkY]
else
neighbors[2] = nil
end
xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then
neighbors[3] = xChunks[chunkY]
else
neighbors[3] = nil
end
return neighbors
end
+15 -7
View File
@@ -10,21 +10,25 @@ local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
-- module code
--[[
Expects all neighbors adjacent to a chunk
--]]
function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf)
local highestChunk
local highestScore = -MAGIC_MAXIMUM_NUMBER
local highestDirection
for x=1,#neighborDirectionChunks do
local neighborDirectionChunk = neighborDirectionChunks[x]
local neighborChunk = neighborDirectionChunk.c
if (neighborChunk ~= nil) and validFunction(x, chunk, neighborChunk) then
for x=1,8 do
local neighborChunk = neighborDirectionChunks[x]
if neighborChunk and validFunction(x, chunk, neighborChunk) then
position.x = neighborChunk.pX
position.y = neighborChunk.pY
local score = scoreFunction(position, squad, neighborChunk, surface)
if (score > highestScore) then
highestScore = score
highestChunk = neighborChunk
highestDirection = neighborDirectionChunk.d
highestDirection = x
end
end
end
@@ -36,12 +40,16 @@ function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunk
return highestChunk, highestDirection
end
--[[
Expects all neighbors adjacent to a chunk
--]]
function neighborUtils.scoreNeighbors(chunk, neighborChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf)
local highestChunk
local highestScore = -MAGIC_MAXIMUM_NUMBER
for x=1,#neighborChunks do
for x=1,8 do
local neighborChunk = neighborChunks[x]
if (neighborChunk ~= nil) and validFunction(x, chunk, neighborChunk) then
if neighborChunk and validFunction(x, chunk, neighborChunk) then
position.x = neighborChunk.pX
position.y = neighborChunk.pY
local score = scoreFunction(position, squad, neighborChunk, surface)
+14 -9
View File
@@ -64,21 +64,26 @@ function pheromoneUtils.processPheromone(regionMap, chunk)
return
end
local neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
local chunkMovement = chunk[MOVEMENT_PHEROMONE]
local chunkBase = chunk[BASE_PHEROMONE]
local chunkPlayer = chunk[PLAYER_PHEROMONE]
local totalMovement = 0
local totalBase = 0
local totalPlayer = 0
local neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
for i=1,#neighbors do
for i=1,4 do
local neighborChunk = neighbors[i]
if (neighborChunk ~= nil) then
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunk[MOVEMENT_PHEROMONE])
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunk[BASE_PHEROMONE])
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunk[PLAYER_PHEROMONE])
if neighborChunk then
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
end
end
chunk[MOVEMENT_PHEROMONE] = (chunk[MOVEMENT_PHEROMONE] + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE
chunk[BASE_PHEROMONE] = (chunk[BASE_PHEROMONE] + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE
chunk[PLAYER_PHEROMONE] = (chunk[PLAYER_PHEROMONE] + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE
chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE
chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE
chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE
end
return pheromoneUtils
+75 -57
View File
@@ -4,7 +4,6 @@ local unitGroupUtils = {}
local mapUtils = require("MapUtils")
local constants = require("Constants")
local nocturnalUtils = require("NocturnalUtils")
-- constants
@@ -22,12 +21,16 @@ local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT
local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX
local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX
local AI_MAX_POINTS = constants.AI_MAX_POINTS
local AI_UNIT_REFUND = constants.AI_UNIT_REFUND
local AI_MAX_BITER_GROUP_SIZE = constants.AI_MAX_BITER_GROUP_SIZE
-- imported functions
local mLog = math.log10
local tableRemove = table.remove
local tableInsert = table.insert
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
@@ -142,40 +145,78 @@ local function isAttacking(group)
return (state == GROUP_STATE_ATTACKING_TARGET) or (state == GROUP_STATE_ATTACKING_DISTRACTION)
end
function unitGroupUtils.regroupSquads(natives, evolution_factor)
function unitGroupUtils.cleanSquads(natives, evolution_factor)
local squads = natives.squads
local squadCount = #squads
for i=1,squadCount do
local squad = squads[i]
local group = squad.group
if group.valid then
local memberCount = #group.members
if (memberCount == 0) or (memberCount > AI_MAX_BITER_GROUP_SIZE) then
group.destroy()
end
end
end
local weight = AI_UNIT_REFUND * evolution_factor
local groupThreshold = AI_MAX_BITER_GROUP_SIZE * 0.75
local cleanSquads = {}
for i=1,squadCount do
local squad = squads[i]
local group = squad.group
if group.valid then
local status = squad.status
local memberCount = #group.members
local squadPosition = group.position
if not isAttacking(group) and (memberCount < groupThreshold) then
if (memberCount == 0) then
group.destroy()
elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
local members = group.members
for x=1,memberCount do
members[x].destroy()
natives.points = natives.points + weight
end
if (natives.points > (AI_MAX_POINTS * 3)) then
natives.points = (AI_MAX_POINTS * 3)
end
group.destroy()
else
local status = squad.status
local squadPosition = group.position
local cycles = squad.cycles
if (status == SQUAD_RETREATING) and (cycles == 0) then
squad.status = SQUAD_GUARDING
squad.frenzy = true
squad.frenzyPosition.x = squadPosition.x
squad.frenzyPosition.y = squadPosition.y
elseif (group.state == GROUP_STATE_FINISHED) then
squad.status = SQUAD_GUARDING
elseif (cycles > 0) then
squad.cycles = cycles - 1
end
cleanSquads[#cleanSquads+1] = squad
end
end
end
natives.squads = cleanSquads
end
function unitGroupUtils.regroupSquads(natives, evolution_factor)
local groupThreshold = AI_MAX_BITER_GROUP_SIZE * 0.75
local squads = natives.squads
local squadCount = #squads
for i=1,squadCount do
local squad = squads[i]
local group = squad.group
if group.valid and not isAttacking(group) then
local status = squad.status
local memberCount = #group.members
if (memberCount < groupThreshold) then
local squadPosition = group.position
local mergedSquads = false
for x=i+1,squadCount do
local mergeSquad = squads[x]
local mergeGroup = mergeSquad.group
if mergeGroup.valid then
local mergeMembers = mergeGroup.members
local mergeCount = #mergeMembers
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) and (mergeSquad.status == status) and not isAttacking(mergeGroup) then
local mergeSquad = squads[x]
local mergeGroup = mergeSquad.group
if mergeGroup.valid and (mergeSquad.status == status) and not isAttacking(mergeGroup) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) then
local mergeMembers = mergeGroup.members
local mergeCount = #mergeMembers
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then
for memberIndex=1, mergeCount do
group.add_member(mergeMembers[memberIndex])
end
@@ -184,45 +225,22 @@ function unitGroupUtils.regroupSquads(natives, evolution_factor)
end
mergedSquads = true
mergeGroup.destroy()
end
memberCount = memberCount + mergeCount
if (memberCount > groupThreshold) then
break
end
end
end
memberCount = memberCount + mergeCount
if (memberCount > groupThreshold) then
break
end
end
end
if mergedSquads and not squad.kamikaze then
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor)
if (math.random() < kamikazeThreshold) then
squad.kamikaze = true
end
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor)
if (math.random() < kamikazeThreshold) then
squad.kamikaze = true
end
end
end
local cycles = squad.cycles
if (status == SQUAD_RETREATING) and (cycles == 0) then
squad.status = SQUAD_GUARDING
squad.frenzy = true
squad.frenzyPosition.x = squadPosition.x
squad.frenzyPosition.y = squadPosition.y
elseif (group.state == GROUP_STATE_FINISHED) then
squad.status = SQUAD_GUARDING
elseif (cycles > 0) then
squad.cycles = cycles - 1
end
end
end
local cleanSquads = {}
for i=1,squadCount do
local squad = squads[i]
if squad.group.valid then
cleanSquads[#cleanSquads+1] = squad
end
end
natives.squads = cleanSquads
end
end
return unitGroupUtils
+1 -1
View File
@@ -47,7 +47,7 @@ rampant-attackWaveGenerationUsePlayerProximity=Include player pheromones amount
rampant-attackWaveGenerationThresholdMax=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (starting threshold @ 0.0 evolution)
rampant-attackWaveGenerationThresholdMin=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (ending threshold @ 100.0 evolution)
rampant-attackWaveMaxSize=If you wish to change how the attack wave scales with evolution you will need to modify the config.lua in the zip file.
rampant-safeBuildings=This needs to be toggle for the safe building toggles to work. Understand this can cause weird behavior due to the fact that this is a stopgap until a bug is fixed in factorio.
rampant-safeBuildings=This needs to be toggle for the safe building toggles to work. This will cause entities made safe to regenerate with the destructible flag set to false, which causes them to never be targeted or damaged again.
rampant-safeBuildings-curvedRail=Make curved rails safe from biters
rampant-safeBuildings-straightRail=Make straight rails safe from biters
rampant-safeBuildings-bigElectricPole=Make big electric poles safe from biters