1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-14 02:23:01 +02:00

FACTO-59: Finished independent regional base ais

This commit is contained in:
Aaron Veden 2022-03-19 16:29:12 -07:00
parent 52139e1e3a
commit 12ffd0b2f3
No known key found for this signature in database
GPG Key ID: FF5990B1C6DD3F84
17 changed files with 503 additions and 538 deletions

View File

@ -46,8 +46,6 @@ local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
-- imported functions
local addBasesToAllEnemyStructures = chunkUtils.addBasesToAllEnemyStructures
local sFind = string.find
local queueGeneratedChunk = mapUtils.queueGeneratedChunk
local processPendingChunks = chunkProcessor.processPendingChunks
@ -433,13 +431,14 @@ end
function upgrade.attempt(universe)
local starting = global.version
if not global.version or global.version < 114 then
global.version = 114
if not global.version or global.version < 300 then
global.version = 300
if not universe then
universe = {}
global.universe = universe
end
game.forces.enemy.kill_all_units()
universe.safeEntities = {}
@ -476,6 +475,12 @@ function upgrade.attempt(universe)
universe.expansionMinSize = game.map_settings.enemy_expansion.settler_group_min_size
universe.expansionMaxSize = game.map_settings.enemy_expansion.settler_group_max_size
universe.expansionMaxDistanceDerivation = nil
universe.expansionLowTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.33
universe.expansionMediumTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.50
universe.expansionHighTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.75
universe.expansionDistanceDeviation = universe.expansionMediumTargetDistance * 0.33
universe.settlerCooldown = 0
universe.settlerWaveDeviation = 0
universe.settlerWaveSize = 0
@ -500,17 +505,9 @@ function upgrade.attempt(universe)
game.forces.enemy.ai_controllable = true
universe.evolutionLevel = game.forces.enemy.evolution_factor
global.pendingChunks = nil
global.natives = nil
global.map = nil
end
if global.version < 116 then
global.version = 116
universe.maxPoints = 0
end
if global.version < 204 then
global.version = 204
global.pendingChunks = nil -- removes old pendingChunks
global.natives = nil -- removes old natives
global.map = nil -- removes old map
universe.eventId = 0
universe.chunkId = 0
@ -551,39 +548,9 @@ function upgrade.attempt(universe)
universe.chunkToPassScanIterator = nil
universe.baseId = 0
universe.awake = false
end
if global.version < 205 then
global.version = 205
addCommandSet(universe)
end
if global.version < 207 then
global.version = 207
for mapId,map in pairs(universe.maps) do
local toBeRemoved = not map.surface.valid or isExcludedSurface(map.surface.name)
if toBeRemoved then
if universe.mapIterator == mapId then
universe.mapIterator, universe.activeMap = next(universe.maps, universe.mapIterator)
end
if universe.processMapAIIterator == mapId then
universe.processMapAIIterator = nil
end
universe.maps[mapId] = nil
end
end
end
if global.version < 208 then
global.version = 208
universe.expansionMaxDistanceDerivation = nil
universe.expansionLowTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.33
universe.expansionMediumTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.50
universe.expansionHighTargetDistance = (universe.expansionMaxDistance + MINIMUM_EXPANSION_DISTANCE) * 0.75
universe.expansionDistanceDeviation = universe.expansionMediumTargetDistance * 0.33
end
if global.version < 209 then
global.version = 209
universe.maxPoints = 0
universe.maxOverflowPoints = 0
if not universe.random then
local combinedSeed = settings.startup["rampant--enemySeed"].value+game.default_map_gen_settings.seed
@ -594,6 +561,19 @@ function upgrade.attempt(universe)
end
end
universe.proxyEntityLookup = {}
universe.vanillaEntityLookups = {}
addCommandSet(universe)
local evoToTierMapping = {}
universe.evoToTierMapping = evoToTierMapping
universe.bases = {}
for i=1,10 do
evoToTierMapping[#evoToTierMapping+1] = (((i - 1) * 0.1) ^ 0.5) - 0.05
end
for _,map in pairs(universe.maps) do
if (map.surface.valid) then
local entities = map.surface.find_entities_filtered({type="land-mine"})
@ -606,26 +586,20 @@ function upgrade.attempt(universe)
end
end
universe.proxyEntityLookup = {}
universe.vanillaEntityLookups = {}
end
if global.version < 210 then
global.version = 210
addBasesToAllEnemyStructures(universe, game.tick)
local evoToTierMapping = {}
universe.evoToTierMapping = evoToTierMapping
for i=1,10 do
evoToTierMapping[#evoToTierMapping+1] = (((i - 1) * 0.1) ^ 0.5) - 0.05
for mapId,map in pairs(universe.maps) do
local toBeRemoved = not map.surface.valid or isExcludedSurface(map.surface.name)
if toBeRemoved then
if universe.mapIterator == mapId then
universe.mapIterator, universe.activeMap = next(universe.maps, universe.mapIterator)
end
if universe.processMapAIIterator == mapId then
universe.processMapAIIterator = nil
end
universe.maps[mapId] = nil
end
end
for chunkId in pairs(universe.vengenceQueue) do
universe.vengenceQueue[chunkId] = nil
end
game.print("Rampant - Version 2.3.0")
game.print("Rampant - Version 3.0.0")
end
return (starting ~= global.version) and global.version
@ -650,10 +624,6 @@ function upgrade.prepMap(universe, surface)
map.activatedMap = false
-- map.sentSiegeGroups = 0
-- map.maxSiegeGroups = 2
-- map.maxAggressiveGroups = 1
-- map.sentAggressiveGroups = 0
map.processedChunks = 0
map.processQueue = {}
map.processIndex = 1
@ -674,6 +644,7 @@ function upgrade.prepMap(universe, surface)
map.chunkToTrapIds = {}
map.chunkToTurretIds = {}
map.chunkToUtilityIds = {}
map.drainPylons = {}
map.chunkToPlayerBase = {}
map.chunkToResource = {}
@ -700,28 +671,6 @@ function upgrade.prepMap(universe, surface)
map.pendingAttack = nil
map.building = nil
-- map.baseIndex = 1
-- map.baseIncrement = 0
-- map.points = 0
-- map.state = constants.AI_STATE_PEACEFUL
-- map.evolutionLevel = game.forces.enemy.evolution_factor
-- map.canAttackTick = 0
-- map.drainPylons = {}
-- map.activeRaidNests = 0
-- map.activeNests = 0
-- map.destroyPlayerBuildings = 0
-- map.lostEnemyUnits = 0
-- map.lostEnemyBuilding = 0
-- map.rocketLaunched = 0
-- map.builtEnemyBuilding = 0
-- map.ionCannonBlasts = 0
-- map.artilleryBlasts = 0
-- map.temperament = 0.5
-- map.temperamentScore = 0
-- map.stateTick = 0
map.random = universe.random
-- queue all current chunks that wont be generated during play

View File

@ -1,13 +1,16 @@
---------------------------------------------------------------------------------------------------
Version: 2.3.0
Version: 3.0.0
improvement:
- Modified death pheromone squad path scoring
- AI is now per regional base
- Regional bases now have there own aggressive and siege squad counter
Tweaks:
- Added surface minime_dummy_dungeon and minime-preview-character to exclusion list
- Increased unit spawner cooldown by 2x
- Added point loss on unit death
Bugfixes:
- Fixed Krastorio2 on_force_created playerforces being nil
- Fixed enemy map scan creating bases unnecessarily
---------------------------------------------------------------------------------------------------
Version: 2.2.0

View File

@ -54,6 +54,8 @@ local UNIT_DEATH_POINT_COST = constants.UNIT_DEATH_POINT_COST
-- imported functions
local planning = aiPlanning.planning
local addBasesToAllEnemyStructures = chunkUtils.addBasesToAllEnemyStructures
local setPointAreaInQuery = queryUtils.setPointAreaInQuery
@ -112,7 +114,7 @@ local victoryScent = pheromoneUtils.victoryScent
local createSquad = unitGroupUtils.createSquad
local createBase = baseUtils.createBase
local findNearbyBase = baseUtils.findNearbyBase
local findNearbyBase = chunkPropertyUtils.findNearbyBase
local processActiveNests = mapProcessor.processActiveNests
@ -167,7 +169,7 @@ local function onIonCannonFired(event)
base.unitPoints = base.unitPoints + 4000
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. 4000 .. ". [Ion Cannon] Total: " ..
string.format("%.2f", base.points))
string.format("%.2f", base.unitPoints))
end
end
end
@ -410,10 +412,10 @@ local function onDeath(event)
base.lostEnemyUnits = base.lostEnemyUnits + 1
base.damagedBy[damageTypeName] = (base.damagedBy[damageTypeName] or 0) + 0.01
base.deathEvents = base.deathEvents + 1
-- base.points = base.points - UNIT_DEATH_POINT_COST
-- if universe.aiPointsPrintSpendingToChat then
-- game.print(map.surface.name .. ": Points: -" .. UNIT_DEATH_POINT_COST .. ". [Unit Lost] Total: " .. string.format("%.2f", base.points))
-- end
base.unitPoints = base.unitPoints - UNIT_DEATH_POINT_COST
if universe.aiPointsPrintSpendingToChat then
game.print(map.surface.name .. ": Points: -" .. UNIT_DEATH_POINT_COST .. ". [Unit Lost] Total: " .. string.format("%.2f", base.unitPoints))
end
if (universe.random() < universe.rallyThreshold) and not surface.peaceful_mode then
rallyUnits(chunk, map, tick, base)
end
@ -435,16 +437,16 @@ local function onDeath(event)
then
if base then
if (entityType == "unit-spawner") then
base.points = base.points + RECOVER_NEST_COST
base.unitPoints = base.unitPoints + RECOVER_NEST_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. RECOVER_NEST_COST ..
". [Nest Lost] Total: " .. string.format("%.2f", base.points))
". [Nest Lost] Total: " .. string.format("%.2f", base.unitPoints))
end
elseif (entityType == "turret") then
base.points = base.points + RECOVER_WORM_COST
base.unitPoints = base.unitPoints + RECOVER_WORM_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. RECOVER_WORM_COST ..
". [Worm Lost] Total: " .. string.format("%.2f", base.points))
". [Worm Lost] Total: " .. string.format("%.2f", base.unitPoints))
end
end
rallyUnits(chunk, map, tick, base)
@ -514,7 +516,7 @@ local function onEnemyBaseBuild(event)
event.tick)
end
registerEnemyBaseStructure(map, entity, event.tick, base)
registerEnemyBaseStructure(map, entity, base)
if universe.NEW_ENEMIES then
upgradeEntity(entity,
@ -644,9 +646,9 @@ local function onRocketLaunch(event)
if (chunk ~= -1) then
local base = findNearbyBase(map, chunk)
base.rocketLaunched = base.rocketLaunched + 1
base.points = base.points + 5000
base.unitPoints = base.unitPoints + 5000
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. 5000 .. ". [Rocket Launch] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. 5000 .. ". [Rocket Launch] Total: " .. string.format("%.2f", base.unitPoints))
end
end
end
@ -706,7 +708,7 @@ local function onEntitySpawned(event)
event.tick)
end
registerEnemyBaseStructure(map, entity, event.tick, base, true)
registerEnemyBaseStructure(map, entity, base, true)
upgradeEntity(entity,
base,
@ -763,14 +765,14 @@ local function onUnitGroupCreated(event)
if not settler and (universe.squadCount > universe.AI_MAX_SQUAD_COUNT) then
group.destroy()
base.points = base.points + AI_SQUAD_COST
base.unitPoints = base.unitPoints + AI_SQUAD_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.unitPoints))
end
return
end
squad = createSquad(nil, map, group, settler)
squad = createSquad(nil, map, group, settler, base)
universe.groupNumberToSquad[group.group_number] = squad
squad.base = base
@ -792,14 +794,14 @@ local function onUnitGroupCreated(event)
if not settler and (universe.squadCount > universe.AI_MAX_SQUAD_COUNT) then
group.destroy()
base.points = base.points + AI_SQUAD_COST
base.unitPoints = base.unitPoints + AI_SQUAD_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.unitPoints))
end
return
end
squad = createSquad(nil, map, group, settler)
squad = createSquad(nil, map, group, settler, base)
universe.groupNumberToSquad[group.group_number] = squad
squad.base = base
@ -830,9 +832,9 @@ local function onGroupFinishedGathering(event)
squadDispatch(map, squad, event.tick)
else
group.destroy()
base.points = base.points + AI_SETTLER_COST
base.unitPoints = base.unitPoints + AI_SETTLER_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. AI_SETTLER_COST .. ". [Settler Refund] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. AI_SETTLER_COST .. ". [Settler Refund] Total: " .. string.format("%.2f", base.unitPoints))
end
end
else
@ -840,9 +842,9 @@ local function onGroupFinishedGathering(event)
squadDispatch(map, squad, event.tick)
else
group.destroy()
base.points = base.points + AI_SQUAD_COST
base.unitPoints = base.unitPoints + AI_SQUAD_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.unitPoints))
end
end
end
@ -855,14 +857,14 @@ local function onGroupFinishedGathering(event)
if not settler and (universe.squadCount > universe.AI_MAX_SQUAD_COUNT) then
group.destroy()
base.points = base.points + AI_SQUAD_COST
base.unitPoints = base.unitPoints + AI_SQUAD_COST
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. AI_SQUAD_COST .. ". [Squad Refund] Total: " .. string.format("%.2f", base.unitPoints))
end
return
end
squad = createSquad(nil, map, group, settler)
squad = createSquad(nil, map, group, settler, base)
universe.groupNumberToSquad[group.group_number] = squad
if settler then
universe.builderCount = universe.builderCount + 1
@ -985,12 +987,13 @@ script.on_event(defines.events.on_tick,
elseif (pick == 7) then
processPendingChunks(universe, tick)
processScanChunks(universe)
planning(universe, gameRef.forces.enemy.evolution_factor)
end
processBaseAIs(universe, gameRef.forces.enemy.evolution_factor, tick)
processBaseAIs(universe, tick)
processActiveNests(universe, tick)
processPendingUpgrades(universe, tick)
processPendingUpgrades(universe, tick)
processPendingUpgrades(universe)
processPendingUpgrades(universe)
cleanSquads(universe, tick)
-- game.print({"", "--dispatch4 ", profiler, ", ", pick, ", ", game.tick, " ", universe.random()})

View File

@ -1,7 +1,7 @@
{
"name" : "Rampant",
"factorio_version" : "1.1",
"version" : "2.3.0",
"version" : "3.0.0",
"title" : "Rampant",
"author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",

View File

@ -54,8 +54,6 @@ local BASE_AI_STATE_AGGRESSIVE = constants.BASE_AI_STATE_AGGRESSIVE
-- imported functions
local findNearbyBase = baseUtils.findNearbyBase
local calculateKamikazeSettlerThreshold = unitGroupUtils.calculateKamikazeSettlerThreshold
local calculateKamikazeSquadThreshold = unitGroupUtils.calculateKamikazeSquadThreshold
@ -99,7 +97,10 @@ end
local function attackWaveValidCandidate(chunk, map, base)
local isValid = getNestActiveness(map, chunk)
if (base.stateAI == BASE_AI_STATE_RAIDING) or (base.stateAI == BASE_AI_STATE_SIEGE) or (base.stateAI == BASE_AI_STATE_ONSLAUGHT) then
if (base.stateAI == BASE_AI_STATE_RAIDING) or
(base.stateAI == BASE_AI_STATE_SIEGE) or
(base.stateAI == BASE_AI_STATE_ONSLAUGHT)
then
isValid = isValid + getRaidNestActiveness(map, chunk)
end
return (isValid > 0)
@ -216,7 +217,7 @@ function aiAttackWave.formSettlers(map, chunk, base)
then
local surface = map.surface
local squadPath, squadDirection
if (map.state == BASE_AI_STATE_SIEGE) then
if (base.stateAI == BASE_AI_STATE_SIEGE) then
squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
validSiegeSettlerLocation,
scoreSiegeSettlerLocation,
@ -238,7 +239,7 @@ function aiAttackWave.formSettlers(map, chunk, base)
4,
true)
if squadPosition then
local squad = createSquad(squadPosition, map, nil, true)
local squad = createSquad(squadPosition, map, nil, true, base)
local scaledWaveSize = settlerWaveScaling(universe)
universe.formGroupCommand.group = squad.group
@ -294,7 +295,7 @@ function aiAttackWave.formVengenceSquad(map, chunk, base)
4,
true)
if squadPosition then
local squad = createSquad(squadPosition, map)
local squad = createSquad(squadPosition, map, nil, false, base)
squad.rabid = map.random() < 0.03
@ -342,7 +343,7 @@ function aiAttackWave.formVengenceSettler(map, chunk, base)
4,
true)
if squadPosition then
local squad = createSquad(squadPosition, map, nil, true)
local squad = createSquad(squadPosition, map, nil, true, base)
squad.rabid = map.random() < 0.03
@ -391,7 +392,7 @@ function aiAttackWave.formSquads(map, chunk, base)
4,
true)
if squadPosition then
local squad = createSquad(squadPosition, map)
local squad = createSquad(squadPosition, map, nil, false, base)
squad.rabid = map.random() < 0.03

View File

@ -23,32 +23,27 @@ local aiPlanning = {}
local constants = require("Constants")
local mathUtils = require("MathUtils")
local baseUtils = require("BaseUtils")
-- constants
local BASE_PROCESS_INTERVAL = constants.BASE_PROCESS_INTERVAL
local BASE_GENERATION_STATE_ACTIVE = constants.BASE_GENERATION_STATE_ACTIVE
local BASE_GENERATION_STATE_DORMANT = constants.BASE_GENERATION_STATE_DORMANT
local BASE_GENERATION_MIN_STATE_DURATION = constants.BASE_GENERATION_MIN_STATE_DURATION
local BASE_GENERATION_MAX_STATE_DURATION = constants.BASE_GENERATION_MAX_STATE_DURATION
local TEMPERAMENT_RANGE_MAX = constants.TEMPERAMENT_RANGE_MAX
local TEMPERAMENT_RANGE_MIN = constants.TEMPERAMENT_RANGE_MIN
local TEMPERAMENT_DIVIDER = constants.TEMPERAMENT_DIVIDER
local AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION
local AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION
local ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS = constants.ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS
local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT
local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX
local BASE_AI_STATE_PEACEFUL = constants.BASE_AI_STATE_PEACEFUL
local BASE_AI_STATE_AGGRESSIVE = constants.BASE_AI_STATE_AGGRESSIVE
local BASE_AI_STATE_RAIDING = constants.BASE_AI_STATE_RAIDING
local BASE_AI_STATE_MIGRATING = constants.BASE_AI_STATE_MIGRATING
local BASE_AI_STATE_ONSLAUGHT = constants.BASE_AI_STATE_ONSLAUGHT
local BASE_AI_STATE_SIEGE = constants.BASE_AI_STATE_SIEGE
local AI_UNIT_REFUND = constants.AI_UNIT_REFUND
local AI_MAX_POINTS = constants.AI_MAX_POINTS
local AI_POINT_GENERATOR_AMOUNT = constants.AI_POINT_GENERATOR_AMOUNT
local AI_MIN_STATE_DURATION = constants.AI_MIN_STATE_DURATION
local AI_MAX_STATE_DURATION = constants.AI_MAX_STATE_DURATION
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
local BONUS_RALLY_CHANCE = constants.BONUS_RALLY_CHANCE
@ -57,18 +52,37 @@ local RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN = constants.RETREAT_MOVEMENT_PHEROMON
local RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX
local MINIMUM_AI_POINTS = constants.MINIMUM_AI_POINTS
local AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION
local AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION = constants.AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION
local ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS = constants.ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS
local BASE_AI_STATE_PEACEFUL = constants.BASE_AI_STATE_PEACEFUL
local BASE_AI_STATE_AGGRESSIVE = constants.BASE_AI_STATE_AGGRESSIVE
local BASE_AI_STATE_RAIDING = constants.BASE_AI_STATE_RAIDING
local BASE_AI_STATE_MIGRATING = constants.BASE_AI_STATE_MIGRATING
local BASE_AI_STATE_ONSLAUGHT = constants.BASE_AI_STATE_ONSLAUGHT
local BASE_AI_STATE_SIEGE = constants.BASE_AI_STATE_SIEGE
local AI_POINT_GENERATOR_AMOUNT = constants.AI_POINT_GENERATOR_AMOUNT
local BASE_AI_MIN_STATE_DURATION = constants.BASE_AI_MIN_STATE_DURATION
local BASE_AI_MAX_STATE_DURATION = constants.BASE_AI_MAX_STATE_DURATION
-- imported functions
local randomTickEvent = mathUtils.randomTickEvent
local upgradeBaseBasedOnDamage = baseUtils.upgradeBaseBasedOnDamage
local linearInterpolation = mathUtils.linearInterpolation
local mFloor = math.floor
local mCeil = math.ceil
local mMax = math.max
local mMin = math.min
local mCeil = math.ceil
-- module code
local function getTimeStringFromTick(tick)
@ -82,8 +96,8 @@ local function getTimeStringFromTick(tick)
return days .. "d " .. hours .. "h " .. minutes .. "m " .. seconds .. "s"
end
local function planning(universe, base, evolutionLevel, tick)
function aiPlanning.planning(universe, evolutionLevel)
universe.evolutionLevel = evolutionLevel
local maxPoints = mMax(AI_MAX_POINTS * evolutionLevel, MINIMUM_AI_POINTS)
universe.maxPoints = maxPoints
@ -101,15 +115,6 @@ local function planning(universe, base, evolutionLevel, tick)
universe.attackWaveDeviation = (universe.attackWaveSize * 0.333)
universe.attackWaveUpperBound = universe.attackWaveSize + (universe.attackWaveSize * 0.35)
if (base.canAttackTick < tick) then
base.maxAggressiveGroups = mCeil(base.activeNests / ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS)
base.sentAggressiveGroups = 0
base.canAttackTick = randomTickEvent(universe.random,
tick,
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
end
if (universe.attackWaveSize < 1) then
universe.attackWaveSize = 2
universe.attackWaveDeviation = 1
@ -127,18 +132,31 @@ local function planning(universe, base, evolutionLevel, tick)
universe.unitRefundAmount = AI_UNIT_REFUND * evolutionLevel
universe.kamikazeThreshold = NO_RETREAT_BASE_PERCENT + (evolutionLevel * NO_RETREAT_EVOLUTION_BONUS_MAX)
end
local points = ((AI_POINT_GENERATOR_AMOUNT * universe.random()) + (base.activeNests * 0.003) +
(AI_POINT_GENERATOR_AMOUNT * mMax(evolutionLevel ^ 2.5, 0.1)))
local function processBase(universe, base, tick)
if (base.canAttackTick < tick) then
base.maxAggressiveGroups = mCeil(base.activeNests / ACTIVE_NESTS_PER_AGGRESSIVE_GROUPS)
base.sentAggressiveGroups = 0
base.canAttackTick = randomTickEvent(universe.random,
tick,
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
end
local points = (AI_POINT_GENERATOR_AMOUNT * universe.random()) +
(base.activeNests * 0.144) +
(AI_POINT_GENERATOR_AMOUNT * mMax(universe.evolutionLevel ^ 2.5, 0.1))
if (base.temperament == 0) or (base.temperament == 1) then
points = points + 0.5
points = points + 24
elseif (base.temperament < 0.20) or (base.temperament > 0.80) then
points = points + 0.3
points = points + 14.4
elseif (base.temperament < 0.35) or (base.temperament > 0.65) then
points = points + 0.2
points = points + 9.6
elseif (base.temperament < 0.45) or (base.temperament > 0.55) then
points = points + 0.1
points = points + 4.8
end
if (base.stateAI == BASE_AI_STATE_ONSLAUGHT) then
@ -147,23 +165,199 @@ local function planning(universe, base, evolutionLevel, tick)
points = points * universe.aiPointsScaler
base.points = points * 30
base.unitPoints = points * 30
local currentPoints = base.points
local currentPoints = base.unitPoints
if (currentPoints <= 0) then
currentPoints = 0
end
if (currentPoints < maxPoints) then
base.points = currentPoints + points
if (currentPoints < universe.maxPoints) then
base.unitPoints = currentPoints + points
elseif currentPoints > universe.maxOverflowPoints then
base.unitPoints = universe.maxOverflowPoints
end
if (currentPoints > maxOverflowPoints) then
base.points = maxOverflowPoints
if (base.points < universe.maxPoints) then
base.points = base.points + (points * 0.75)
else
base.points = universe.maxPoints
end
local deathThreshold
local evolutionLevel = universe.evolutionLevel
if (evolutionLevel < 0.5) then
deathThreshold = 4500
elseif (evolutionLevel < 0.7) then
deathThreshold = 7500
elseif (evolutionLevel < 0.9) then
deathThreshold = 11000
else
deathThreshold = 16000
end
deathThreshold = universe.adaptationModifier * deathThreshold
if ((base.deathEvents > deathThreshold) and (universe.random() > 0.95)) then
if (base.mutations < universe.MAX_BASE_MUTATIONS) then
base.mutations = base.mutations + 1
upgradeBaseBasedOnDamage(universe, base)
elseif (base.mutations == universe.MAX_BASE_MUTATIONS) then
local roll = universe.random()
if (roll < 0.001) then
base.mutations = 0
if (universe.printBaseAdaptation) then
game.print({"description.rampant--adaptationResetDebugMessage",
base.x,
base.y,
base.mutations,
universe.MAX_BASE_MUTATIONS})
end
elseif (roll > 0.999) then
base.mutations = base.mutations + 1
if (universe.printBaseAdaptation) then
game.print({"description.rampant--adaptationFrozenDebugMessage",
base.x,
base.y})
end
end
end
base.damagedBy = {}
base.deathEvents = 0
end
if (base.stateGenerationTick <= tick) then
local roll = universe.random()
if (roll < 0.85) then
base.stateGeneration = BASE_GENERATION_STATE_ACTIVE
else
base.stateGeneration = BASE_GENERATION_STATE_DORMANT
end
base.stateGenerationTick = randomTickEvent(universe.random,
tick,
BASE_GENERATION_MIN_STATE_DURATION,
BASE_GENERATION_MAX_STATE_DURATION)
end
base.tick = tick
end
local function temperamentPlanner(base, evolutionLevel)
local destroyPlayerBuildings = base.destroyPlayerBuildings
local lostEnemyUnits = base.lostEnemyUnits
local lostEnemyBuilding = base.lostEnemyBuilding
local rocketLaunched = base.rocketLaunched
local builtEnemyBuilding = base.builtEnemyBuilding
local ionCannonBlasts = base.ionCannonBlasts
local artilleryBlasts = base.artilleryBlasts
local activeNests = base.activeNests
local activeRaidNests = base.activeRaidNests
local currentTemperament = base.temperamentScore
local delta = 0
if activeNests > 0 then
local val = (5.76 * activeNests)
delta = delta + val
else
delta = delta - 5.553792
end
if destroyPlayerBuildings > 0 then
if currentTemperament > 0 then
delta = delta - (5.553792 * destroyPlayerBuildings)
else
delta = delta + (5.553792 * destroyPlayerBuildings)
end
end
if activeRaidNests > 0 then
local val = (0.2304 * activeRaidNests)
delta = delta - val
else
delta = delta - 3.84
end
if lostEnemyUnits > 0 then
local multipler
if evolutionLevel < 0.3 then
multipler = 0.083328
elseif evolutionLevel < 0.5 then
multipler = 0.041472
elseif evolutionLevel < 0.7 then
multipler = 0.020736
elseif evolutionLevel < 0.9 then
multipler = 0.010368
elseif evolutionLevel < 0.9 then
multipler = 0.005184
else
multipler = 0.002592
end
local val = (multipler * lostEnemyUnits)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
end
if lostEnemyBuilding > 0 then
local val = (0.576 * lostEnemyBuilding)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
end
if builtEnemyBuilding > 0 then
local val = (0.261952 * builtEnemyBuilding)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
else
delta = delta - 2.777088
end
if (rocketLaunched > 0) then
local val = (27.76 * rocketLaunched)
delta = delta + val
end
if (ionCannonBlasts > 0) then
local val = (13.924864 * ionCannonBlasts)
delta = delta + val
end
if (artilleryBlasts > 0) then
local val = (13.924864 * artilleryBlasts)
delta = delta + val
end
local universe = base.universe
delta = delta * universe.temperamentRateModifier
base.temperamentScore = mMin(TEMPERAMENT_RANGE_MAX, mMax(TEMPERAMENT_RANGE_MIN, currentTemperament + delta))
base.temperament = ((base.temperamentScore + TEMPERAMENT_RANGE_MAX) * TEMPERAMENT_DIVIDER)
if universe.debugTemperament then
game.print("Rampant Stats:\naN:" .. base.activeNests .. ", aRN:" .. base.activeRaidNests .. ", dPB:" ..
base.destroyPlayerBuildings .. ", lEU:" .. base.lostEnemyUnits .. ", lEB:" ..
base.lostEnemyBuilding .. ", rL:" .. base.rocketLaunched .. ", bEB:" ..
base.builtEnemyBuilding .. ", iCB:" .. base.ionCannonBlasts .. ", aB:" ..
base.artilleryBlasts .. ", temp:" .. base.temperament .. ", tempScore:" .. base.temperamentScore ..
", points:" .. base.points .. ", unitPoints:" .. base.unitPoints .. ", state:" ..
constants.stateEnglish[base.stateAI] .. ", surface:" .. base.surface.index .. " [" ..
base.surface.name .. "]" .. ", aS:" .. universe.squadCount .. ", aB:" .. universe.builderCount ..
", atkSize:" .. universe.attackWaveSize .. ", stlSize:" .. universe.settlerWaveSize ..
", formGroup:" .. universe.formSquadThreshold .. ", sAgg:".. base.sentAggressiveGroups ..
", mAgg:" .. base.maxAggressiveGroups .. ", baseState:" .. base.generationState ..
", baseId:".. base.id)
end
end
local function processState(universe, base, tick)
if (base.stateAITick > tick) or not universe.awake then
if (not universe.awake) and (tick >= universe.initialPeaceTime) then
universe.awake = true
@ -339,129 +533,17 @@ local function planning(universe, base, evolutionLevel, tick)
base.ionCannonBlasts = 0
base.artilleryBlasts = 0
base.stateAITick = randomTickEvent(universe.random, tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION)
base.stateAITick = randomTickEvent(universe.random, tick, BASE_AI_MIN_STATE_DURATION, BASE_AI_MAX_STATE_DURATION)
if universe.printAIStateChanges then
game.print(base.index .. ": AI is now: " .. constants.stateEnglish[base.stateAI] .. ", Next state change is in "
.. string.format("%.2f", (base.stateAITick - tick) / (60*60)) .. " minutes @ " ..
getTimeStringFromTick(base.stateAITick) .. " playtime")
end
end
local function temperamentPlanner(base, evolutionLevel)
local destroyPlayerBuildings = base.destroyPlayerBuildings
local lostEnemyUnits = base.lostEnemyUnits
local lostEnemyBuilding = base.lostEnemyBuilding
local rocketLaunched = base.rocketLaunched
local builtEnemyBuilding = base.builtEnemyBuilding
local ionCannonBlasts = base.ionCannonBlasts
local artilleryBlasts = base.artilleryBlasts
local activeNests = base.activeNests
local activeRaidNests = base.activeRaidNests
local currentTemperament = base.temperamentScore
local delta = 0
if activeNests > 0 then
local val = (0.015 * activeNests)
delta = delta + val
else
delta = delta - 0.014463
end
if destroyPlayerBuildings > 0 then
if currentTemperament > 0 then
delta = delta - (0.014463 * destroyPlayerBuildings)
else
delta = delta + (0.014463 * destroyPlayerBuildings)
end
end
if activeRaidNests > 0 then
local val = (0.0006 * activeRaidNests)
delta = delta - val
else
delta = delta - 0.01
end
if lostEnemyUnits > 0 then
local multipler
if evolutionLevel < 0.3 then
multipler = 0.000217
elseif evolutionLevel < 0.5 then
multipler = 0.000108
elseif evolutionLevel < 0.7 then
multipler = 0.000054
elseif evolutionLevel < 0.9 then
multipler = 0.000027
elseif evolutionLevel < 0.9 then
multipler = 0.0000135
else
multipler = 0.00000675
end
local val = (multipler * lostEnemyUnits)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
end
if lostEnemyBuilding > 0 then
local val = (0.0015 * lostEnemyBuilding)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
end
if builtEnemyBuilding > 0 then
local val = (0.0006818 * builtEnemyBuilding)
if (currentTemperament > 0) then
delta = delta - val
else
delta = delta + val
end
else
delta = delta - 0.007232
end
if (rocketLaunched > 0) then
local val = (0.289268 * rocketLaunched)
delta = delta + val
end
if (ionCannonBlasts > 0) then
local val = (0.144634 * ionCannonBlasts)
delta = delta + val
end
if (artilleryBlasts > 0) then
local val = (0.144634 * artilleryBlasts)
delta = delta + val
end
local universe = base.universe
delta = delta * universe.temperamentRateModifier
base.temperamentScore = mMin(TEMPERAMENT_RANGE_MAX, mMax(TEMPERAMENT_RANGE_MIN, currentTemperament + delta))
base.temperament = ((base.temperamentScore + TEMPERAMENT_RANGE_MAX) * TEMPERAMENT_DIVIDER)
if universe.debugTemperament then
if game.tick % 243 == 0 then
game.print("Rampant Stats:")
game.print("aN:" .. base.activeNests .. ", aRN:" .. base.activeRaidNests .. ", dPB:" .. base.destroyPlayerBuildings ..
", lEU:" .. base.lostEnemyUnits .. ", lEB:" .. base.lostEnemyBuilding .. ", rL:" .. base.rocketLaunched .. ", bEB:" .. base.builtEnemyBuilding ..
", iCB:" .. base.ionCannonBlasts .. ", aB:" .. base.artilleryBlasts)
game.print("temp: " .. base.temperament .. ", tempScore:" .. base.temperamentScore .. ", points:" .. base.points .. ", state:" .. constants.stateEnglish[base.state] .. ", surface:" .. base.surface.index .. " [" .. base.surface.name .. "]")
game.print("aS:" .. universe.squadCount .. ", aB:" .. universe.builderCount .. ", atkSize:" .. universe.attackWaveSize .. ", stlSize:" .. universe.settlerWaveSize .. ", formGroup:" .. universe.formSquadThreshold)
game.print("sAgg:".. base.sentAggressiveGroups .. ", mAgg:" .. base.maxAggressiveGroups)
end
end
end
function aiPlanning.processBaseAIs(universe, evo, tick)
function aiPlanning.processBaseAIs(universe, tick)
local baseId = universe.processBaseAIIterator
local base
if not baseId then
@ -474,12 +556,12 @@ function aiPlanning.processBaseAIs(universe, evo, tick)
return
else
universe.processBaseAIIterator = next(universe.bases, baseId)
universe.evolutionLevel = evo
planning(universe, base, evo, tick)
temperamentPlanner(base, evo)
if not universe.processBaseAIIterator then
if (tick - base.tick) <= BASE_PROCESS_INTERVAL then
return
end
temperamentPlanner(base, universe.evolutionLevel)
processState(universe, base, tick)
processBase(universe, base, tick)
end
end

View File

@ -37,7 +37,7 @@ local BASE_AI_STATE_ONSLAUGHT = constants.BASE_AI_STATE_ONSLAUGHT
function aiPredicates.canAttack(map, base)
local surface = map.surface
local goodAI = (((base.stateAI == BASE_AI_STATE_AGGRESSIVE) and (map.sentAggressiveGroups < map.maxAggressiveGroups)) or
local goodAI = (((base.stateAI == BASE_AI_STATE_AGGRESSIVE) and (base.sentAggressiveGroups < base.maxAggressiveGroups)) or
(base.stateAI == BASE_AI_STATE_RAIDING) or
(base.stateAI == BASE_AI_STATE_ONSLAUGHT) or
(map.universe.raidAIToggle and (base.stateAI == BASE_AI_STATE_SIEGE) and (base.sentSiegeGroups >= base.maxSiegeGroups)))

View File

@ -37,13 +37,9 @@ local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local FACTIONS_BY_DAMAGE_TYPE = constants.FACTIONS_BY_DAMAGE_TYPE
local BASE_GENERATION_STATE_ACTIVE = constants.BASE_GENERATION_STATE_ACTIVE
local BASE_GENERATION_STATE_DORMANT = constants.BASE_GENERATION_STATE_DORMANT
local FACTION_SET = constants.FACTION_SET
local BASE_GENERATION_MIN_STATE_DURATION = constants.BASE_GENERATION_MIN_STATE_DURATION
local BASE_GENERATION_MAX_STATE_DURATION = constants.BASE_GENERATION_MAX_STATE_DURATION
local HIVE_BUILDINGS_COST = constants.HIVE_BUILDINGS_COST
local BASE_DISTANCE_THRESHOLD = constants.BASE_DISTANCE_THRESHOLD
@ -52,17 +48,13 @@ local BASE_DISTANCE_TO_EVO_INDEX = constants.BASE_DISTANCE_TO_EVO_INDEX
local CHUNK_SIZE = constants.CHUNK_SIZE
local BASE_PROCESS_INTERVAL = constants.BASE_PROCESS_INTERVAL
local BASE_AI_STATE_PEACEFUL = constants.BASE_AI_STATE_PEACEFUL
-- imported functions
local setPositionXYInQuery = queryUtils.setPositionXYInQuery
local randomTickEvent = mathUtils.randomTickEvent
local euclideanDistancePoints = mathUtils.euclideanDistancePoints
local manhattenDistancePoints = mathUtils.manhattenDistancePoints
local getChunkByPosition = mapUtils.getChunkByPosition
@ -76,8 +68,6 @@ local mMin = math.min
local mMax = math.max
local distort = mathUtils.distort
local getChunkBase = chunkPropertyUtils.getChunkBase
local getResourceGenerator = chunkPropertyUtils.getResourceGenerator
local next = next
@ -99,34 +89,11 @@ local function evoToTier(universe, evolutionFactor, maxSkips)
return v
end
function baseUtils.findNearbyBase(map, chunk)
local x = chunk.x
local y = chunk.y
local foundBase = getChunkBase(map, chunk)
if foundBase then
return foundBase
end
local bases = map.bases
local closest = MAGIC_MAXIMUM_NUMBER
for _, base in pairs(bases) do
local distance = manhattenDistancePoints(base.x, base.y, x, y)
if (distance <= base.distanceThreshold) and (distance < closest) then
closest = distance
foundBase = base
end
end
return foundBase
end
local function findBaseMutation(map, targetEvolution)
local universe = map.universe
local function findBaseMutation(universe, targetEvolution)
local tier = evoToTier(universe, targetEvolution or universe.evolutionLevel, 2)
local alignments = universe.evolutionTableAlignment[tier]
local roll = map.random()
local roll = universe.random()
for i=1,#alignments do
local alignment = alignments[i]
@ -274,15 +241,15 @@ local function findEntityUpgrade(baseAlignment, currentEvo, evoIndex, originalEn
end
end
local function findBaseInitialAlignment(map, evoIndex)
local function findBaseInitialAlignment(universe, evoIndex)
local dev = evoIndex * 0.15
local evoTop = gaussianRandomRangeRG(evoIndex - (evoIndex * 0.075), dev, 0, evoIndex, map.random)
local evoTop = gaussianRandomRangeRG(evoIndex - (evoIndex * 0.075), dev, 0, evoIndex, universe.random)
local result
if map.random() < 0.05 then
result = {findBaseMutation(map, evoTop), findBaseMutation(map, evoTop)}
if universe.random() < 0.05 then
result = {findBaseMutation(universe, evoTop), findBaseMutation(universe, evoTop)}
else
result = {findBaseMutation(map, evoTop)}
result = {findBaseMutation(universe, evoTop)}
end
return result
@ -303,6 +270,7 @@ function baseUtils.recycleBases(map)
map.recycleBaseIterator = next(bases, id)
if base.chunkCount == 0 then
bases[id] = nil
map.universe.bases[id] = nil
end
end
end
@ -353,14 +321,14 @@ function baseUtils.upgradeEntity(entity, base, map, disPos, evolve, register)
return nil
end
local function pickMutationFromDamageType(map, damageType, roll, base)
local function pickMutationFromDamageType(universe, damageType, roll, base)
local baseAlignment = base.alignment
local damageFactions = FACTIONS_BY_DAMAGE_TYPE[damageType]
local mutation
if (damageFactions and (#damageFactions > 0)) then
mutation = damageFactions[map.random(#damageFactions)]
mutation = damageFactions[universe.random(#damageFactions)]
if baseAlignment[2] then
if (roll < 0.05) then
baseAlignment[2] = nil
@ -378,7 +346,7 @@ local function pickMutationFromDamageType(map, damageType, roll, base)
end
end
else
mutation = findBaseMutation(map)
mutation = findBaseMutation(universe)
if baseAlignment[2] then
if (roll < 0.05) then
baseAlignment[2] = nil
@ -396,7 +364,7 @@ local function pickMutationFromDamageType(map, damageType, roll, base)
end
end
end
if (map.universe.printBaseAdaptation) then
if (universe.printBaseAdaptation) then
if baseAlignment[2] then
game.print({"description.rampant--adaptation2DebugMessage",
damageType,
@ -405,7 +373,7 @@ local function pickMutationFromDamageType(map, damageType, roll, base)
base.x,
base.y,
base.mutations,
map.universe.MAX_BASE_MUTATIONS})
universe.MAX_BASE_MUTATIONS})
else
game.print({"description.rampant--adaptation1DebugMessage",
damageType,
@ -413,12 +381,12 @@ local function pickMutationFromDamageType(map, damageType, roll, base)
base.x,
base.y,
base.mutations,
map.universe.MAX_BASE_MUTATIONS})
universe.MAX_BASE_MUTATIONS})
end
end
end
local function upgradeBaseBasedOnDamage(map, base)
function baseUtils.upgradeBaseBasedOnDamage(universe, base)
local total = 0
@ -429,7 +397,7 @@ local function upgradeBaseBasedOnDamage(map, base)
base.damagedBy["RandomMutation"] = mutationAmount
total = total + mutationAmount
local pickedDamage
local roll = map.random()
local roll = universe.random()
for damageTypeName,amount in pairs(base.damagedBy) do
base.damagedBy[damageTypeName] = amount / total
end
@ -441,37 +409,30 @@ local function upgradeBaseBasedOnDamage(map, base)
end
end
pickMutationFromDamageType(map, pickedDamage, roll, base)
pickMutationFromDamageType(universe, pickedDamage, roll, base)
end
function baseUtils.processBase(chunk, map, tick, base)
if ((tick - base.generationTick) <= BASE_PROCESS_INTERVAL) then
return
end
if not base.alignment[1] then
return
end
local surface = map.surface
local universe = map.universe
setPositionXYInQuery(universe.pbFilteredEntitiesPointQueryLimited,
chunk.x + (CHUNK_SIZE * map.random()),
chunk.y + (CHUNK_SIZE * map.random()))
local upgradeRoll = map.random()
if (base.generationState == BASE_GENERATION_STATE_ACTIVE) and
(base.points >= MINIMUM_BUILDING_COST) and
(upgradeRoll < 0.30)
function baseUtils.processBaseMutation(chunk, map, base)
if not base.alignment[1] or
(base.stateGeneration ~= BASE_GENERATION_STATE_ACTIVE) or
(map.random() >= 0.30)
then
return
end
if (base.points >= MINIMUM_BUILDING_COST) then
local surface = map.surface
local universe = map.universe
setPositionXYInQuery(universe.pbFilteredEntitiesPointQueryLimited,
chunk.x + (CHUNK_SIZE * map.random()),
chunk.y + (CHUNK_SIZE * map.random()))
local entities = surface.find_entities_filtered(universe.pbFilteredEntitiesPointQueryLimited)
if #entities ~= 0 then
local entity = entities[1]
local cost = (universe.costLookup[entity.name] or MAGIC_MAXIMUM_NUMBER)
if (base.points >= cost) then
local newEntity = baseUtils.upgradeEntity(entity,
base,
map)
local newEntity = baseUtils.upgradeEntity(entity, base, map)
if newEntity then
if universe.printBaseUpgrades then
surface.print("[gps=".. entity.position.x ..",".. entity.position.y .."] " .. "Scheduled upgrade for ".. entity.name .. " to " .. newEntity)
@ -481,73 +442,6 @@ function baseUtils.processBase(chunk, map, tick, base)
end
end
end
local deathThreshold
local evolutionLevel = map.universe.evolutionLevel
if (evolutionLevel < 0.5) then
deathThreshold = 4500
elseif (evolutionLevel < 0.7) then
deathThreshold = 7500
elseif (evolutionLevel < 0.9) then
deathThreshold = 11000
else
deathThreshold = 16000
end
deathThreshold = universe.adaptationModifier * deathThreshold
if ((base.deathEvents > deathThreshold) and (upgradeRoll > 0.95)) then
if (base.mutations < universe.MAX_BASE_MUTATIONS) then
base.mutations = base.mutations + 1
upgradeBaseBasedOnDamage(map, base)
elseif (base.mutations == universe.MAX_BASE_MUTATIONS) then
local roll = map.random()
if (roll < 0.001) then
base.mutations = 0
if (map.universe.printBaseAdaptation) then
game.print({"description.rampant--adaptationResetDebugMessage",
base.x,
base.y,
base.mutations,
map.universe.MAX_BASE_MUTATIONS})
end
elseif (roll > 0.999) then
base.mutations = base.mutations + 1
if (map.universe.printBaseAdaptation) then
game.print({"description.rampant--adaptationFrozenDebugMessage",
base.x,
base.y})
end
end
end
base.damagedBy = {}
base.deathEvents = 0
end
base.points = base.points + map.baseIncrement
base.unitPoints = base.unitPoints + map.baseIncrement
if (base.points > universe.maxPoints) then
base.points = universe.maxPoints
end
if (base.unitPoints > universe.maxPoints) then
base.unitPoints = universe.unitPoints
end
if (base.stateGenerationTick <= tick) then
local roll = map.random()
if (roll < 0.85) then
base.generationState = BASE_GENERATION_STATE_ACTIVE
else
base.generationState = BASE_GENERATION_STATE_DORMANT
end
base.stateGenerationTick = randomTickEvent(map.random,
tick,
BASE_GENERATION_MIN_STATE_DURATION,
BASE_GENERATION_MAX_STATE_DURATION)
end
base.generationTick = tick
end
function baseUtils.createBase(map, chunk, tick)
@ -557,40 +451,46 @@ function baseUtils.createBase(map, chunk, tick)
local meanLevel = mFloor(distance * 0.005)
local universe = map.universe
local distanceIndex = mMin(1, distance * BASE_DISTANCE_TO_EVO_INDEX)
local evoIndex = mMax(distanceIndex, map.universe.evolutionLevel)
local evoIndex = mMax(distanceIndex, universe.evolutionLevel)
local baseTick = tick
local alignment = (universe.NEW_ENEMIES and findBaseInitialAlignment(universe, evoIndex)) or {"neutral"}
local alignment = findBaseInitialAlignment(map, evoIndex) or {"neutral"}
local baseLevel = gaussianRandomRangeRG(meanLevel, meanLevel * 0.3, meanLevel * 0.50, meanLevel * 1.50, map.random)
local baseLevel = gaussianRandomRangeRG(meanLevel,
meanLevel * 0.3,
meanLevel * 0.50,
meanLevel * 1.50,
universe.random)
local baseDistanceThreshold = gaussianRandomRangeRG(BASE_DISTANCE_THRESHOLD,
BASE_DISTANCE_THRESHOLD * 0.2,
BASE_DISTANCE_THRESHOLD * 0.75,
BASE_DISTANCE_THRESHOLD * 1.50,
map.random)
universe.random)
local distanceThreshold = (baseLevel * BASE_DISTANCE_LEVEL_BONUS) + baseDistanceThreshold
local universe = map.universe
local base = {
x = x,
y = y,
distanceThreshold = distanceThreshold * map.universe.baseDistanceModifier,
tick = baseTick,
distanceThreshold = distanceThreshold * universe.baseDistanceModifier,
tick = tick,
alignment = alignment,
state = BASE_GENERATION_STATE_ACTIVE,
damagedBy = {},
deathEvents = 0,
mutations = 0,
stateGeneration = BASE_GENERATION_STATE_ACTIVE,
stateGenerationTick = 0,
chunkCount = 0,
createdTick = tick,
points = 0,
unitPoints = 0,
stateAI = BASE_AI_STATE_PEACEFUL,
stateAITick = 0,
canAttackTick = 0,
drainPylons = {},
maxAggressiveGroups = 0,
sentAggressiveGroups = 0,
maxSiegeGroups = 0,
sentSiegeGroups = 0,
activeRaidNests = 0,
activeNests = 0,
destroyPlayerBuildings = 0,
@ -602,7 +502,8 @@ function baseUtils.createBase(map, chunk, tick)
artilleryBlasts = 0,
temperament = 0.5,
temperamentScore = 0,
stateAITick = 0,
universe = universe,
surface = map.surface,
id = universe.baseId
}
universe.baseId = universe.baseId + 1
@ -766,18 +667,16 @@ function baseUtils.rebuildNativeTables(universe, rg)
local evoIndex = evoToTier(universe, universe.evolutionLevel, 2)
if universe.maps then
for _,map in pairs(universe.maps) do
for _,base in pairs(map.bases) do
for x=1,2 do
local alignment = base.alignment[x]
if alignment and not universe.buildingEvolveLookup[alignment] then
base.alignment = findBaseInitialAlignment(map, evoIndex)
break
elseif not alignment and (x == 1) then
base.alignment = findBaseInitialAlignment(map, evoIndex)
break
end
if universe.bases then
for _,base in pairs(universe.bases) do
for x=1,2 do
local alignment = base.alignment[x]
if alignment and not universe.buildingEvolveLookup[alignment] then
base.alignment = findBaseInitialAlignment(universe, evoIndex)
break
elseif not alignment and (x == 1) then
base.alignment = findBaseInitialAlignment(universe, evoIndex)
break
end
end
end

View File

@ -159,7 +159,7 @@ function chunkProcessor.processPendingChunks(universe, tick, flush)
universe.chunkProcessorIterator = eventId
end
function chunkProcessor.processPendingUpgrades(universe, tick)
function chunkProcessor.processPendingUpgrades(universe)
local entityId = universe.pendingUpgradeIterator
local entityData
if not entityId then
@ -191,7 +191,7 @@ function chunkProcessor.processPendingUpgrades(universe, tick)
setPositionInQuery(query, foundPosition or position)
local createdEntity = surface.create_entity(query)
if createdEntity and createdEntity.valid then
registerEnemyBaseStructure(entityData.map, createdEntity, tick, entityData.base, true)
registerEnemyBaseStructure(entityData.map, createdEntity, entityData.base, true)
if remote.interfaces["kr-creep"] then
remote.call("kr-creep", "spawn_creep_at_position", surface, foundPosition or position)
end

View File

@ -20,6 +20,7 @@ end
local chunkPropertyUtils = {}
local constants = require("Constants")
local mathUtils = require("MathUtils")
-- constants
@ -33,8 +34,12 @@ 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 manhattenDistancePoints = mathUtils.manhattenDistancePoints
local mMin = math.min
-- module code
@ -369,11 +374,11 @@ function chunkPropertyUtils.getRaidNestActiveness(map, chunk)
return activeness.v or 0
end
function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value)
function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value, base)
local universe = map.universe
if (value <= 0) then
if universe.chunkToActiveRaidNest[chunk.id] then
map.activeRaidNests = map.activeRaidNests - 1
base.activeRaidNests = base.activeRaidNests - 1
end
if (universe.processActiveRaidSpawnerIterator == chunk.id) then
universe.processActiveRaidSpawnerIterator = nil
@ -381,7 +386,7 @@ function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value)
universe.chunkToActiveRaidNest[chunk.id] = nil
else
if not universe.chunkToActiveRaidNest[chunk.id] then
map.activeRaidNests = map.activeRaidNests + 1
base.activeRaidNests = base.activeRaidNests + 1
universe.chunkToActiveRaidNest[chunk.id] = {
map = map,
v = 0
@ -399,11 +404,11 @@ function chunkPropertyUtils.getNestActiveness(map, chunk)
return activeness.v or 0
end
function chunkPropertyUtils.setNestActiveness(map, chunk, value)
function chunkPropertyUtils.setNestActiveness(map, chunk, value, base)
local universe = map.universe
if (value <= 0) then
if universe.chunkToActiveNest[chunk.id] then
map.activeNests = map.activeNests - 1
base.activeNests = base.activeNests - 1
end
if (universe.processActiveSpawnerIterator == chunk.id) then
universe.processActiveSpawnerIterator = nil
@ -411,7 +416,7 @@ function chunkPropertyUtils.setNestActiveness(map, chunk, value)
universe.chunkToActiveNest[chunk.id] = nil
else
if not universe.chunkToActiveNest[chunk.id] then
map.activeNests = map.activeNests + 1
base.activeNests = base.activeNests + 1
universe.chunkToActiveNest[chunk.id] = {
map = map,
v = 0
@ -568,18 +573,40 @@ function chunkPropertyUtils.addPlayerBaseGenerator(map, chunk, playerGenerator)
map.chunkToPlayerBase[chunk.id] = (map.chunkToPlayerBase[chunk.id] or 0) + playerGenerator
end
function chunkPropertyUtils.findNearbyBase(map, chunk)
local x = chunk.x
local y = chunk.y
local foundBase = chunkPropertyUtils.getChunkBase(map, chunk)
if foundBase then
return foundBase
end
local closest = MAGIC_MAXIMUM_NUMBER
for _, base in pairs(map.bases) do
local distance = manhattenDistancePoints(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(map, chunk)
local nests = chunkPropertyUtils.getNestCount(map, chunk)
local base = chunkPropertyUtils.findNearbyBase(map, chunk)
if (nests > 0) then
local surface = map.surface
local activeness = chunkPropertyUtils.getNestActiveness(map, chunk)
local universe = map.universe
local raidActiveness = chunkPropertyUtils.getRaidNestActiveness(map, chunk)
if universe.attackUsePlayer and (chunk[PLAYER_PHEROMONE] > universe.attackPlayerThreshold) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
elseif (chunk[BASE_PHEROMONE] > 0) then
if (surface.get_pollution(chunk) > 0) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
else
local x = chunk.x
local y = chunk.y
@ -587,26 +614,26 @@ function chunkPropertyUtils.processNestActiveness(map, chunk)
position.x = x + 32
position.y = y
if (surface.get_pollution(position) > 0) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
else
position.x = x - 32
if (surface.get_pollution(position) > 0) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
else
position.x = x
position.y = y - 32
if (surface.get_pollution(position) > 0) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
else
position.y = y + 32
if (surface.get_pollution(position) > 0) then
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20))
chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20), base)
else
chunkPropertyUtils.setNestActiveness(map, chunk, activeness - 2)
chunkPropertyUtils.setNestActiveness(map, chunk, activeness - 2, base)
if (chunk[BASE_PHEROMONE] > RAIDING_MINIMUM_BASE_THRESHOLD) then
chunkPropertyUtils.setRaidNestActiveness(map, chunk, mMin(raidActiveness + 3, 20))
chunkPropertyUtils.setRaidNestActiveness(map, chunk, mMin(raidActiveness + 3, 20), base)
else
chunkPropertyUtils.setRaidNestActiveness(map, chunk, raidActiveness - 1)
chunkPropertyUtils.setRaidNestActiveness(map, chunk, raidActiveness - 1, base)
end
end
end
@ -614,12 +641,12 @@ function chunkPropertyUtils.processNestActiveness(map, chunk)
end
end
else
chunkPropertyUtils.setNestActiveness(map, chunk, activeness - 5)
chunkPropertyUtils.setRaidNestActiveness(map, chunk, raidActiveness - 5)
chunkPropertyUtils.setNestActiveness(map, chunk, activeness - 5, base)
chunkPropertyUtils.setRaidNestActiveness(map, chunk, raidActiveness - 5, base)
end
else
chunkPropertyUtils.setNestActiveness(map, chunk, 0)
chunkPropertyUtils.setRaidNestActiveness(map, chunk, 0)
elseif base then
chunkPropertyUtils.setNestActiveness(map, chunk, 0, base)
chunkPropertyUtils.setRaidNestActiveness(map, chunk, 0, base)
end
end

View File

@ -94,7 +94,7 @@ local processNestActiveness = chunkPropertyUtils.processNestActiveness
local removeChunkBase = chunkPropertyUtils.removeChunkBase
local getEnemyStructureCount = chunkPropertyUtils.getEnemyStructureCount
local findNearbyBase = baseUtils.findNearbyBase
local findNearbyBase = chunkPropertyUtils.findNearbyBase
local createBase = baseUtils.createBase
local upgradeEntity = baseUtils.upgradeEntity
@ -261,7 +261,7 @@ function chunkUtils.initialScan(chunk, map, tick)
for i = 1, #enemyBuildings do
local enemyBuilding = enemyBuildings[i]
chunkUtils.registerEnemyBaseStructure(map, enemyBuilding, tick, base)
chunkUtils.registerEnemyBaseStructure(map, enemyBuilding, base)
local entityName = enemyBuilding.name
local isVanilla = vanillaEntityTypeLookup[entityName]
if isVanilla or (not isVanilla and not buildingHiveTypeLookup[entityName]) then
@ -271,7 +271,7 @@ function chunkUtils.initialScan(chunk, map, tick)
else
for i=1,#enemyBuildings do
local building = enemyBuildings[i]
chunkUtils.registerEnemyBaseStructure(map, building, tick, base)
chunkUtils.registerEnemyBaseStructure(map, building, base)
end
end
end
@ -347,14 +347,16 @@ function chunkUtils.mapScanEnemyChunk(chunk, map, tick)
for i=1,#HIVE_BUILDINGS_TYPES do
counts[HIVE_BUILDINGS_TYPES[i]] = 0
end
local base = findNearbyBase(map, chunk)
if not base then
base = createBase(map, chunk, tick)
end
for i=1,#buildings do
local building = buildings[i]
if (#buildings > 0) then
local base = findNearbyBase(map, chunk)
if not base then
base = createBase(map, chunk, tick)
end
for i=1,#buildings do
local building = buildings[i]
chunkUtils.registerEnemyBaseStructure(map, building, tick, base)
chunkUtils.registerEnemyBaseStructure(map, building, base)
end
end
end
@ -477,7 +479,7 @@ function chunkUtils.colorXY(x, y, surface, color)
})
end
function chunkUtils.registerEnemyBaseStructure(map, entity, tick, incomingBase, skipCount)
function chunkUtils.registerEnemyBaseStructure(map, entity, base, skipCount)
local entityType = entity.type
local addFunc
@ -510,13 +512,6 @@ function chunkUtils.registerEnemyBaseStructure(map, entity, tick, incomingBase,
if (chunk ~= -1) then
if addFunc(map, chunk, entityUnitNumber) then
added = true
local base = incomingBase
if not base then
base = findNearbyBase(map, chunk)
if not base then
base = createBase(map, chunk, tick)
end
end
setChunkBase(map, chunk, base)
end
if (hiveType == "spitter-spawner") or (hiveType == "biter-spawner") then
@ -525,7 +520,7 @@ function chunkUtils.registerEnemyBaseStructure(map, entity, tick, incomingBase,
end
end
if added and (not skipCount) then
map.builtEnemyBuilding = map.builtEnemyBuilding + 1
base.builtEnemyBuilding = base.builtEnemyBuilding + 1
end
end
@ -554,24 +549,27 @@ function chunkUtils.unregisterEnemyBaseStructure(map, entity, damageTypeName, sk
end
end
local removed = false
local entityUnitNumber = entity.unit_number
local usedBases = {}
local chunks = getEntityOverlapChunks(map, entity)
for i=1,#chunks do
local chunk = chunks[i]
if (chunk ~= -1) then
local base = getChunkBase(map, chunk)
if (hiveType == "spitter-spawner") or (hiveType == "biter-spawner") then
setRaidNestActiveness(map, chunk, 0)
setNestActiveness(map, chunk, 0)
setRaidNestActiveness(map, chunk, 0, base)
setNestActiveness(map, chunk, 0, base)
end
if removeFunc(map, chunk, entityUnitNumber) then
removed = true
local base = getChunkBase(map, chunk)
if damageTypeName and not usedBases[base.id] then
if not usedBases[base.id] then
usedBases[base.id] = true
base.damagedBy[damageTypeName] = (base.damagedBy[damageTypeName] or 0) + 3
base.deathEvents = base.deathEvents + 3
if damageTypeName then
base.damagedBy[damageTypeName] = (base.damagedBy[damageTypeName] or 0) + 3
base.deathEvents = base.deathEvents + 3
end
if (not skipCount) and (hiveType ~= "trap") then
base.lostEnemyBuilding = base.lostEnemyBuilding + 1
end
end
if (getEnemyStructureCount(map, chunk) <= 0) then
removeChunkBase(map, chunk, base)
@ -579,9 +577,6 @@ function chunkUtils.unregisterEnemyBaseStructure(map, entity, damageTypeName, sk
end
end
end
if removed and (not skipCount) and (hiveType ~= "trap") then
map.lostEnemyBuilding = map.lostEnemyBuilding + 1
end
end
function chunkUtils.accountPlayerEntity(entity, map, addObject, base)
@ -592,15 +587,15 @@ function chunkUtils.accountPlayerEntity(entity, map, addObject, base)
if not addObject then
if base then
base.destroyPlayerBuildings = base.destroyPlayerBuildings + 1
if (base.state == BASE_AI_STATE_ONSLAUGHT) then
base.points = base.points + entityValue
if (base.stateAI == BASE_AI_STATE_ONSLAUGHT) then
base.unitPoints = base.unitPoints + entityValue
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. math.floor(entityValue) .. ". [Structure Kill] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. math.floor(entityValue) .. ". [Structure Kill] Total: " .. string.format("%.2f", base.unitPoints))
end
else
base.points = base.points + (entityValue * 0.12)
base.unitPoints = base.unitPoints + (entityValue * 0.12)
if universe.aiPointsPrintGainsToChat then
game.print(map.surface.name .. ": Points: +" .. math.floor(entityValue * 0.12) .. ". [Structure Kill] Total: " .. string.format("%.2f", base.points))
game.print(map.surface.name .. ": Points: +" .. math.floor(entityValue * 0.12) .. ". [Structure Kill] Total: " .. string.format("%.2f", base.unitPoints))
end
end
end

View File

@ -118,7 +118,7 @@ constants.DIVISOR_DEATH_TRAIL_TABLE = { 0.75, 0.65, 0.55, 0.45, 0.35 }
constants.RESOURCE_MINIMUM_FORMATION_DELTA = 15
constants.MINIMUM_AI_POINTS = 400
constants.AI_POINT_GENERATOR_AMOUNT = 0.17721
constants.AI_POINT_GENERATOR_AMOUNT = 15
constants.AI_SQUAD_COST = 175
constants.RECOVER_NEST_COST = constants.AI_SQUAD_COST
constants.RECOVER_WORM_COST = constants.AI_SQUAD_COST * 0.5
@ -187,7 +187,7 @@ constants.BASE_UPGRADE = 1500
constants.BASE_DISTANCE_THRESHOLD = 30 * constants.CHUNK_SIZE
constants.BASE_DISTANCE_LEVEL_BONUS = 15
constants.BASE_PROCESS_INTERVAL = constants.TICKS_A_SECOND
constants.BASE_PROCESS_INTERVAL = constants.TICKS_A_SECOND * 20
-- ai retreat
@ -1579,7 +1579,7 @@ constants.HIVE_BUILDINGS_COST["spitter-spawner"] = constants.BASE_SPAWNER_UPGRAD
constants.HIVE_BUILDINGS_COST["biter-spawner"] = constants.BASE_SPAWNER_UPGRADE
constants.HIVE_BUILDINGS_COST["hive"] = constants.BASE_SPAWNER_UPGRADE * 2
constants.UNIT_DEATH_POINT_COST = 1
constants.UNIT_DEATH_POINT_COST = 0.5
constants.MINIMUM_BUILDING_COST = constants.MAGIC_MAXIMUM_NUMBER
for _,cost in pairs(constants.HIVE_BUILDINGS_COST) do

View File

@ -60,7 +60,7 @@ local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
-- imported functions
local findNearbyBase = baseUtils.findNearbyBase
local findNearbyBase = chunkPropertyUtils.findNearbyBase
local removeChunkToNest = mapUtils.removeChunkToNest
@ -68,7 +68,7 @@ local processStaticPheromone = pheromoneUtils.processStaticPheromone
local processPheromone = pheromoneUtils.processPheromone
local getDeathGeneratorRating = chunkPropertyUtils.getDeathGeneratorRating
local processBase = baseUtils.processBase
local processBaseMutation = baseUtils.processBaseMutation
local processNestActiveness = chunkPropertyUtils.processNestActiveness
local getChunkBase = chunkPropertyUtils.getChunkBase
@ -221,13 +221,16 @@ function mapProcessor.processPlayers(players, universe, tick)
local char = player.character
local map = universe.maps[char.surface.index]
if map then
local allowingAttacks = canAttack(map, base)
local playerChunk = getChunkByPosition(map, char.position)
if (playerChunk ~= -1) then
local base = findNearbyBase(map, playerChunk)
if not base then
return
end
local allowingAttacks = canAttack(map, base)
local vengence = allowingAttacks and
(base.points >= AI_VENGENCE_SQUAD_COST) and
(base.unitPoints >= AI_VENGENCE_SQUAD_COST) and
((getEnemyStructureCount(map, playerChunk) > 0) or
(getDeathGeneratorRating(map, playerChunk) < universe.retreatThreshold))
@ -479,10 +482,11 @@ function mapProcessor.processNests(universe, tick)
processNestActiveness(map, chunk)
queueNestSpawners(map, chunk, tick)
processBase(chunk,
map,
tick,
getChunkBase(map, chunk))
if universe.NEW_ENEMIES then
processBaseMutation(chunk,
map,
getChunkBase(map, chunk))
end
end
end
@ -507,25 +511,25 @@ local function processSpawnersBody(universe, iterator, chunks)
end
return
end
local state = chunkPack.map.state
if base.state == BASE_AI_STATE_PEACEFUL then
local chunk = getChunkById(map, chunkId)
local base = findNearbyBase(map, chunk)
if base.stateAI == BASE_AI_STATE_PEACEFUL then
return
end
if iterator == "processMigrationIterator" then
if (base.state ~= BASE_AI_STATE_MIGRATING) and (state ~= BASE_AI_STATE_SIEGE) then
if (base.stateAI ~= BASE_AI_STATE_MIGRATING) and (base.stateAI ~= BASE_AI_STATE_SIEGE) then
return
end
elseif iterator == "processActiveRaidSpawnerIterator" then
if (base.state == BASE_AI_STATE_AGGRESSIVE) or (base.state == BASE_AI_STATE_MIGRATING) then
if (base.stateAI == BASE_AI_STATE_AGGRESSIVE) or (base.stateAI == BASE_AI_STATE_MIGRATING) then
return
end
elseif iterator == "processActiveSpawnerIterator" then
if (base.state == BASE_AI_STATE_MIGRATING) then
if (base.stateAI == BASE_AI_STATE_MIGRATING) then
return
end
end
local chunk = getChunkById(map, chunkId)
local migrate = canMigrate(map, base)
local attack = canAttack(map, base)
if migrate then

View File

@ -137,9 +137,7 @@ function mathUtils.euclideanDistancePoints(x1, y1, x2, y2)
end
function mathUtils.manhattenDistancePoints(x1, y1, x2, y2)
local xs = x1 - x2
local ys = y1 - y2
return mAbs(xs + ys)
return mAbs((x1 - x2) + (y1 - y2))
end
function mathUtils.euclideanDistanceArray(p1, p2)

View File

@ -129,7 +129,7 @@ local function settleMove(map, squad)
local x, y = positionToChunkXY(groupPosition)
local chunk = getChunkByXY(map, x, y)
local scoreFunction = scoreResourceLocation
if (base.state == BASE_AI_STATE_SIEGE) then
if (squad.type == BASE_AI_STATE_SIEGE) then
if squad.kamikaze then
scoreFunction = scoreSiegeLocationKamikaze
else
@ -200,7 +200,7 @@ local function settleMove(map, squad)
local attackPlayerThreshold = universe.attackPlayerThreshold
if (nextAttackChunk ~= -1) then
if (getPlayerBaseGenerator(map,nextAttackChunk) == 0) or (base.state ~= BASE_AI_STATE_SIEGE) then
if (getPlayerBaseGenerator(map,nextAttackChunk) == 0) or (squad.type ~= BASE_AI_STATE_SIEGE) then
attackChunk = nextAttackChunk
position = findMovementPosition(
surface,
@ -257,7 +257,7 @@ local function settleMove(map, squad)
end
if (nextAttackChunk ~= -1) and
(base.state == BASE_AI_STATE_SIEGE) and
(squad.type == BASE_AI_STATE_SIEGE) and
(getPlayerBaseGenerator(map, nextAttackChunk) ~= 0)
then
cmd = universe.settleCommand

View File

@ -41,7 +41,7 @@ local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
-- imported functions
local findNearbyBase = baseUtils.findNearbyBase
local findNearbyBase = chunkPropertyUtils.findNearbyBase
local addSquadToChunk = chunkPropertyUtils.addSquadToChunk
@ -122,7 +122,11 @@ function aiDefense.retreatUnits(chunk, cause, map, tick, radius)
if not newSquad then
if (universe.squadCount < universe.AI_MAX_SQUAD_COUNT) then
created = true
newSquad = createSquad(position, map)
local base = findNearbyBase(map, chunk)
if not base then
return
end
newSquad = createSquad(position, map, nil, false, base)
else
return
end
@ -143,7 +147,6 @@ function aiDefense.retreatUnits(chunk, cause, map, tick, radius)
end
if created then
newSquad.base = findNearbyBase(map, chunk)
universe.groupNumberToSquad[newSquad.groupNumber] = newSquad
universe.squadCount = universe.squadCount + 1
end

View File

@ -114,7 +114,7 @@ function unitGroupUtils.calculateSettlerMaxDistance(universe)
universe.random)
end
function unitGroupUtils.createSquad(position, map, group, settlers)
function unitGroupUtils.createSquad(position, map, group, settlers, base)
local unitGroup = group or map.surface.create_unit_group({position=position})
local squad = {
@ -122,7 +122,8 @@ function unitGroupUtils.createSquad(position, map, group, settlers)
status = SQUAD_GUARDING,
rabid = false,
penalties = {},
base = nil,
base = base,
type = base.stateAI,
frenzy = false,
map = map,
wanders = 0,