mirror of
https://github.com/veden/Rampant.git
synced 2024-12-26 20:54:12 +02:00
currently stuck at factorio crash
This commit is contained in:
parent
ed66822afa
commit
fcd52cf91d
22
Upgrade.lua
22
Upgrade.lua
@ -35,6 +35,7 @@ function upgrade.attempt(natives, setNewSurface, gameSurfaces)
|
||||
natives.state = constants.AI_STATE_AGGRESSIVE
|
||||
|
||||
natives.safeEntities = {}
|
||||
natives.vengenceQueue = {}
|
||||
|
||||
natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value
|
||||
natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value
|
||||
@ -150,15 +151,30 @@ function upgrade.attempt(natives, setNewSurface, gameSurfaces)
|
||||
end
|
||||
end
|
||||
|
||||
natives.remainingSquads = 0
|
||||
natives.groupNumberToSquad = {}
|
||||
game.forces.enemy.kill_all_units()
|
||||
natives.squads = nil
|
||||
natives.pendingAttack = nil
|
||||
natives.building = nil
|
||||
end
|
||||
if (global.version < 112) then
|
||||
global.version = 112
|
||||
if (global.version < 113) then
|
||||
global.version = 113
|
||||
|
||||
natives.baseId = 0
|
||||
|
||||
local newBases = {}
|
||||
for i=1,#natives.bases do
|
||||
local base = natives.bases
|
||||
base.id = natives.baseId
|
||||
newBases[base.id] = base
|
||||
natives.baseId = natives.baseId + 1
|
||||
end
|
||||
natives.bases = newBases
|
||||
global.pendingChunks = nil
|
||||
|
||||
natives.vengenceQueue = {}
|
||||
|
||||
game.forces.enemy.ai_controllable = true
|
||||
|
||||
if not setNewSurface then
|
||||
game.get_surface(natives.activeSurface).print("Rampant - Version 0.18.12")
|
||||
|
@ -1,10 +1,22 @@
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Version: 0.18.12
|
||||
Date: 16. 4 2020
|
||||
Improvements:
|
||||
- Swapped to ai command completed for unit movements
|
||||
- When squads reach a movement threshold for being in the same spots to much they switch to kamikaze mode
|
||||
- Added effect when spawners build to destroy build site
|
||||
- Integrated vanilla AI into Rampant for pollution management
|
||||
Tweaks:
|
||||
- Changed ai credits per rocket launched to 5000
|
||||
Bugfixes:
|
||||
- fixed add movement penalty not using squad chunk
|
||||
- fixed landfill and waterfill getting registered properly
|
||||
Optimizations:
|
||||
- Cleaned up regroup squads
|
||||
- Cleaned up invalid group detection
|
||||
- Minimized use of group.members
|
||||
- Changed how settlers remove entities around build sites
|
||||
- Split map processing and unit group creation
|
||||
|
||||
---------------------------------------------------------------------------------------------------
|
||||
Version: 0.18.11
|
||||
|
288
control.lua
288
control.lua
@ -22,9 +22,9 @@ local upgrade = require("Upgrade")
|
||||
local config = require("config")
|
||||
local aiPredicates = require("libs/AIPredicates")
|
||||
|
||||
|
||||
-- constants
|
||||
|
||||
local DIVISOR_DEATH_TRAIL_TABLE = constants.DIVISOR_DEATH_TRAIL_TABLE
|
||||
local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
local INTERVAL_PLAYER_PROCESS = constants.INTERVAL_PLAYER_PROCESS
|
||||
@ -32,8 +32,9 @@ local INTERVAL_MAP_PROCESS = constants.INTERVAL_MAP_PROCESS
|
||||
local INTERVAL_SCAN = constants.INTERVAL_SCAN
|
||||
local INTERVAL_SQUAD = constants.INTERVAL_SQUAD
|
||||
local INTERVAL_RESQUAD = constants.INTERVAL_RESQUAD
|
||||
local INTERVAL_BUILDERS = constants.INTERVAL_BUILDERS
|
||||
-- local INTERVAL_BUILDERS = constants.INTERVAL_BUILDERS
|
||||
local INTERVAL_TEMPERAMENT = constants.INTERVAL_TEMPERAMENT
|
||||
local INTERVAL_SPAWNER = constants.INTERVAL_SPAWNER
|
||||
|
||||
local HIVE_BUILDINGS = constants.HIVE_BUILDINGS
|
||||
|
||||
@ -52,6 +53,7 @@ local RETREAT_GRAB_RADIUS = constants.RETREAT_GRAB_RADIUS
|
||||
|
||||
local RETREAT_SPAWNER_GRAB_RADIUS = constants.RETREAT_SPAWNER_GRAB_RADIUS
|
||||
|
||||
local DEFINES_BEHAVIOR_RESULT_FAIL = defines.behavior_result.fail
|
||||
local DEFINES_COMMAND_GROUP = defines.command.group
|
||||
local DEFINES_COMMAND_WANDER = defines.command.wander
|
||||
local DEFINES_COMMAND_BUILD_BASE = defines.command.build_base
|
||||
@ -91,6 +93,9 @@ local positionToChunkXY = mapUtils.positionToChunkXY
|
||||
|
||||
local temperamentPlanner = aiPlanning.temperamentPlanner
|
||||
|
||||
local processVengence = mapProcessor.processVengence
|
||||
local processSpawners = mapProcessor.processSpawners
|
||||
|
||||
local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
@ -122,6 +127,10 @@ local findNearbyBase = baseUtils.findNearbyBase
|
||||
|
||||
local processActiveNests = mapProcessor.processActiveNests
|
||||
|
||||
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
|
||||
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
|
||||
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
|
||||
|
||||
local retreatUnits = squadDefense.retreatUnits
|
||||
|
||||
local accountPlayerEntity = chunkUtils.accountPlayerEntity
|
||||
@ -137,16 +146,18 @@ local cleanSquads = unitGroupUtils.cleanSquads
|
||||
local upgradeEntity = baseUtils.upgradeEntity
|
||||
local rebuildNativeTables = baseUtils.rebuildNativeTables
|
||||
|
||||
local mMin = math.min
|
||||
local mRandom = math.random
|
||||
|
||||
local tRemove = table.remove
|
||||
|
||||
local sFind = string.find
|
||||
|
||||
-- local references to global
|
||||
|
||||
local gameSurfaces -- used for manage which surfaces have been visited
|
||||
local map -- manages the chunks that make up the game world
|
||||
local natives -- manages the enemy units, structures, and ai
|
||||
local pendingChunks -- chunks that have yet to be processed by the mod
|
||||
|
||||
-- hook functions
|
||||
|
||||
@ -175,17 +186,17 @@ end
|
||||
local function onLoad()
|
||||
map = global.map
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
gameSurfaces = global.gameSurfaces
|
||||
|
||||
hookEvents()
|
||||
end
|
||||
|
||||
local function onChunkGenerated(event)
|
||||
print("1", game.tick)
|
||||
-- queue generated chunk for delayed processing, queuing is required because some mods (RSO) mess with chunk as they
|
||||
-- are generated, which messes up the scoring.
|
||||
if (event.surface.name == natives.activeSurface) then
|
||||
pendingChunks[#pendingChunks+1] = event
|
||||
map.pendingChunks[event] = true
|
||||
end
|
||||
end
|
||||
|
||||
@ -201,6 +212,7 @@ local function rebuildMap()
|
||||
map.processIndex = 1
|
||||
map.scanIndex = 1
|
||||
|
||||
map.pendingChunks = {}
|
||||
map.chunkToBase = {}
|
||||
map.chunkToNests = {}
|
||||
map.chunkToTurrets = {}
|
||||
@ -215,7 +227,6 @@ local function rebuildMap()
|
||||
|
||||
map.chunkToRetreats = {}
|
||||
map.chunkToRallys = {}
|
||||
map.chunkToSettler = {}
|
||||
|
||||
map.chunkToPassable = {}
|
||||
map.chunkToPathRating = {}
|
||||
@ -229,6 +240,11 @@ local function rebuildMap()
|
||||
|
||||
map.squadIterator = nil
|
||||
map.regroupIterator = nil
|
||||
map.deployVengenceIterator = nil
|
||||
map.recycleBaseIterator = nil
|
||||
map.processActiveSpawnerIterator = nil
|
||||
map.processActiveRaidSpawnerIterator = nil
|
||||
map.processMigrationIterator = nil
|
||||
|
||||
-- preallocating memory to be used in code, making it fast by reducing garbage generated.
|
||||
map.neighbors = {
|
||||
@ -306,6 +322,10 @@ local function rebuildMap()
|
||||
"turret"
|
||||
}
|
||||
}
|
||||
map.createBuildCloudQuery = {
|
||||
name = "build-clear-cloud-rampant",
|
||||
position = map.position
|
||||
}
|
||||
|
||||
map.activePlayerForces = {"player"}
|
||||
|
||||
@ -434,6 +454,13 @@ local function rebuildMap()
|
||||
use_group_distraction = false
|
||||
}
|
||||
|
||||
map.mergeGroupCommand = {
|
||||
type = DEFINES_COMMAND_GROUP,
|
||||
group = nil,
|
||||
distraction = DEFINES_DISTRACTION_NONE,
|
||||
use_group_distraction = false
|
||||
}
|
||||
|
||||
map.fleeCommand = {
|
||||
type = DEFINES_COMMAND_FLEE,
|
||||
from = nil,
|
||||
@ -507,14 +534,10 @@ local function onModSettingsChange(event)
|
||||
upgrade.compareTable(natives, "newEnemies", settings.startup["rampant-newEnemies"].value)
|
||||
upgrade.compareTable(natives, "enemySeed", settings.startup["rampant-enemySeed"].value)
|
||||
|
||||
upgrade.compareTable(natives, "disableVanillaAI", settings.global["rampant-disableVanillaAI"].value)
|
||||
|
||||
natives.enabledMigration = natives.expansion and settings.global["rampant-enableMigration"].value
|
||||
|
||||
upgrade.compareTable(natives, "ENEMY_VARIATIONS", settings.startup["rampant-newEnemyVariations"].value)
|
||||
|
||||
game.forces.enemy.ai_controllable = not natives.disableVanillaAI
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -548,10 +571,6 @@ local function prepWorld(rebuild, surfaceName)
|
||||
map.natives = natives
|
||||
natives.map = map
|
||||
|
||||
-- clear pending chunks, will be added when loop runs below
|
||||
global.pendingChunks = {}
|
||||
pendingChunks = global.pendingChunks
|
||||
|
||||
-- queue all current chunks that wont be generated during play
|
||||
local surface = game.get_surface(natives.activeSurface)
|
||||
local tick = game.tick
|
||||
@ -569,7 +588,7 @@ local function prepWorld(rebuild, surfaceName)
|
||||
end
|
||||
end
|
||||
|
||||
processPendingChunks(map, surface, pendingChunks, tick, rebuild)
|
||||
processPendingChunks(map, surface, tick, rebuild, true)
|
||||
end
|
||||
end
|
||||
|
||||
@ -578,6 +597,7 @@ local function onConfigChanged()
|
||||
end
|
||||
|
||||
local function onBuild(event)
|
||||
print("2", game.tick)
|
||||
local entity = event.created_entity or event.entity
|
||||
if (entity.surface.name == natives.activeSurface) then
|
||||
if (entity.type == "resource") and (entity.force.name == "neutral") then
|
||||
@ -594,6 +614,7 @@ local function onBuild(event)
|
||||
end
|
||||
|
||||
local function onMine(event)
|
||||
print("3", game.tick)
|
||||
local entity = event.entity
|
||||
local surface = entity.surface
|
||||
if (surface.name == natives.activeSurface) then
|
||||
@ -608,6 +629,7 @@ local function onMine(event)
|
||||
end
|
||||
|
||||
local function onDeath(event)
|
||||
print("4", game.tick)
|
||||
local entity = event.entity
|
||||
if entity.valid then
|
||||
local surface = entity.surface
|
||||
@ -634,14 +656,15 @@ local function onDeath(event)
|
||||
|
||||
natives.lostEnemyUnits = natives.lostEnemyUnits + 1
|
||||
|
||||
retreatUnits(chunk,
|
||||
entityPosition,
|
||||
entity.unit_group,
|
||||
map,
|
||||
surface,
|
||||
tick,
|
||||
(artilleryBlast and RETREAT_SPAWNER_GRAB_RADIUS) or RETREAT_GRAB_RADIUS,
|
||||
artilleryBlast)
|
||||
-- retreatUnits(chunk,
|
||||
-- entityPosition,
|
||||
-- entity.unit_group,
|
||||
-- map,
|
||||
-- surface,
|
||||
-- tick,
|
||||
-- (artilleryBlast and RETREAT_SPAWNER_GRAB_RADIUS) or RETREAT_GRAB_RADIUS-- ,
|
||||
-- -- artilleryBlast
|
||||
-- )
|
||||
|
||||
if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then
|
||||
rallyUnits(chunk, map, surface, tick)
|
||||
@ -653,19 +676,20 @@ local function onDeath(event)
|
||||
|
||||
natives.points = natives.points + (((entityType == "unit-spawner") and RECOVER_NEST_COST) or RECOVER_WORM_COST)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
unregisterEnemyBaseStructure(map, entity)
|
||||
unregisterEnemyBaseStructure(map, entity)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
rallyUnits(chunk, map, surface, tick)
|
||||
|
||||
retreatUnits(chunk,
|
||||
entityPosition,
|
||||
nil,
|
||||
map,
|
||||
surface,
|
||||
tick,
|
||||
RETREAT_SPAWNER_GRAB_RADIUS,
|
||||
(cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret"))))
|
||||
-- retreatUnits(chunk,
|
||||
-- entityPosition,
|
||||
-- nil,
|
||||
-- map,
|
||||
-- surface,
|
||||
-- tick,
|
||||
-- RETREAT_SPAWNER_GRAB_RADIUS-- ,
|
||||
-- -- (cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret")))
|
||||
-- )
|
||||
end
|
||||
end
|
||||
|
||||
@ -751,6 +775,7 @@ local function onDeath(event)
|
||||
end
|
||||
|
||||
local function onEnemyBaseBuild(event)
|
||||
print("5", game.tick)
|
||||
local entity = event.entity
|
||||
if entity.valid then
|
||||
local surface = entity.surface
|
||||
@ -782,36 +807,35 @@ local function onEnemyBaseBuild(event)
|
||||
end
|
||||
|
||||
local function onSurfaceTileChange(event)
|
||||
print("6", game.tick)
|
||||
local surfaceIndex = event.surface_index or (event.robot and event.robot.surface and event.robot.surface.index)
|
||||
local surfaceName = game.surfaces[surfaceIndex].name
|
||||
if (surfaceName == natives.activeSurface) and
|
||||
((event.item.name == "landfill") or (event.item.name == "waterfill")) and
|
||||
event.item
|
||||
then
|
||||
local surface = game.get_surface(natives.activeSurface)
|
||||
local surface = game.get_surface(natives.activeSurface)
|
||||
if (surface.index == surfaceIndex) then
|
||||
local chunks = {}
|
||||
local tiles = event.tiles
|
||||
for i=1,#tiles do
|
||||
local position = tiles[i].position
|
||||
local chunk = getChunkByPosition(map, position)
|
||||
if (event.tile.name == "landfill") or sFind(event.tile.name, "water") then
|
||||
for i=1,#tiles do
|
||||
local position = tiles[i].position
|
||||
local chunk = getChunkByPosition(map, position)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
map.chunkToPassScan[chunk] = true
|
||||
else
|
||||
local x,y = positionToChunkXY(position)
|
||||
local addMe = true
|
||||
for ci=1,#chunks do
|
||||
local c = chunks[ci]
|
||||
if (c.x == x) and (c.y == y) then
|
||||
addMe = false
|
||||
break
|
||||
if (chunk ~= -1) then
|
||||
map.chunkToPassScan[chunk] = true
|
||||
else
|
||||
local x,y = positionToChunkXY(position)
|
||||
local addMe = true
|
||||
for ci=1,#chunks do
|
||||
local c = chunks[ci]
|
||||
if (c.x == x) and (c.y == y) then
|
||||
addMe = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if addMe then
|
||||
local chunkXY = {x=x,y=y}
|
||||
chunks[#chunks+1] = chunkXY
|
||||
onChunkGenerated({area = { left_top = chunkXY },
|
||||
surface = surface})
|
||||
end
|
||||
end
|
||||
if addMe then
|
||||
local chunkXY = {x=x,y=y}
|
||||
chunks[#chunks+1] = chunkXY
|
||||
onChunkGenerated({area = { left_top = chunkXY },
|
||||
surface = surface})
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -819,6 +843,7 @@ local function onSurfaceTileChange(event)
|
||||
end
|
||||
|
||||
local function onResourceDepleted(event)
|
||||
print("7", game.tick)
|
||||
local entity = event.entity
|
||||
if (entity.surface.name == natives.activeSurface) then
|
||||
unregisterResource(entity, map)
|
||||
@ -826,7 +851,7 @@ local function onResourceDepleted(event)
|
||||
end
|
||||
|
||||
local function onRobotCliff(event)
|
||||
|
||||
print("8", game.tick)
|
||||
local surface = event.robot.surface
|
||||
if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then
|
||||
entityForPassScan(map, event.cliff)
|
||||
@ -834,6 +859,7 @@ local function onRobotCliff(event)
|
||||
end
|
||||
|
||||
local function onUsedCapsule(event)
|
||||
print("9", game.tick)
|
||||
local surface = game.players[event.player_index].surface
|
||||
if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then
|
||||
map.position2Top.x = event.position.x-0.75
|
||||
@ -848,6 +874,7 @@ local function onUsedCapsule(event)
|
||||
end
|
||||
|
||||
local function onRocketLaunch(event)
|
||||
print("10", game.tick)
|
||||
local entity = event.rocket_silo or event.rocket
|
||||
if entity and entity.valid and (entity.surface.name == natives.activeSurface) then
|
||||
natives.rocketLaunched = natives.rocketLaunched + 1
|
||||
@ -856,6 +883,7 @@ local function onRocketLaunch(event)
|
||||
end
|
||||
|
||||
local function onTriggerEntityCreated(event)
|
||||
print("11", game.tick)
|
||||
local entity = event.entity
|
||||
if entity.valid and (entity.surface.name == natives.activeSurface) and (entity.name == "drain-trigger-rampant") then
|
||||
local chunk = getChunkByPosition(map, entity.position)
|
||||
@ -868,13 +896,11 @@ end
|
||||
|
||||
local function onInit()
|
||||
global.map = {}
|
||||
global.pendingChunks = {}
|
||||
global.natives = {}
|
||||
global.gameSurfaces = {}
|
||||
|
||||
map = global.map
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
gameSurfaces = global.gameSurfaces
|
||||
|
||||
prepWorld(false, "nauvis")
|
||||
@ -882,6 +908,7 @@ local function onInit()
|
||||
end
|
||||
|
||||
local function onEntitySpawned(event)
|
||||
print("12", game.tick)
|
||||
local entity = event.entity
|
||||
if natives.newEnemies and entity.valid then
|
||||
local surface = entity.surface
|
||||
@ -921,41 +948,76 @@ local function onEntitySpawned(event)
|
||||
end
|
||||
|
||||
local function onUnitGroupCreated(event)
|
||||
print("13", game.tick)
|
||||
local group = event.group
|
||||
if (group.surface.name == natives.activeSurface) and (group.force.name == "enemy") then
|
||||
local surface = group.surface
|
||||
if (surface.name == natives.activeSurface) and (group.force.name == "enemy") then
|
||||
if not group.is_script_driven then
|
||||
squad = createSquad(nil,
|
||||
nil,
|
||||
group,
|
||||
mRandom() < 0.75 and canMigrate(natives, game.get_surface(natives.activeSurface)))
|
||||
natives.groupNumberToSquad[group.group_number] = squad
|
||||
if not natives.aiNocturnalMode then
|
||||
squad = createSquad(nil,
|
||||
nil,
|
||||
group,
|
||||
mRandom() < 0.25 and canMigrate(natives, group.surface))
|
||||
natives.groupNumberToSquad[group.group_number] = squad
|
||||
elseif not (surface.darkness > 0.65) then
|
||||
group.destroy()
|
||||
else
|
||||
squad = createSquad(nil,
|
||||
nil,
|
||||
group,
|
||||
mRandom() < 0.25 and canMigrate(natives, group.surface))
|
||||
natives.groupNumberToSquad[group.group_number] = squad
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onCommandComplete(event)
|
||||
-- local msg
|
||||
-- if (event.result == defines.behavior_result.in_progress) then
|
||||
-- msg = "progress"
|
||||
-- elseif (event.result == defines.behavior_result.fail) then
|
||||
-- msg = "fail"
|
||||
-- elseif (event.result == defines.behavior_result.success) then
|
||||
-- msg = "success"
|
||||
-- elseif (event.result == defines.behavior_result.deleted) then
|
||||
-- msg = "deleted"
|
||||
-- end
|
||||
|
||||
print("14", game.tick)
|
||||
local unitNumber = event.unit_number
|
||||
local squad = natives.groupNumberToSquad[unitNumber]
|
||||
if squad then
|
||||
-- local result = event.result
|
||||
-- local msg
|
||||
-- if (result == defines.behavior_result.in_progress) then
|
||||
-- msg = "progress"
|
||||
-- elseif (result == defines.behavior_result.fail) then
|
||||
-- msg = "fail"
|
||||
-- elseif (result == defines.behavior_result.success) then
|
||||
-- msg = "success"
|
||||
-- elseif (result == defines.behavior_result.deleted) then
|
||||
-- msg = "deleted"
|
||||
-- end
|
||||
-- print(msg)
|
||||
|
||||
local group = squad.group
|
||||
if group and group.valid and (group.surface.name == natives.activeSurface) then
|
||||
squadDispatch(map, group.surface, squad, unitNumber)
|
||||
|
||||
if (event.result == DEFINES_BEHAVIOR_RESULT_FAIL) then
|
||||
print("count", #group.members)
|
||||
if (#group.members == 0) then
|
||||
print("dropping")
|
||||
local deathGen = getDeathGenerator(map, squad.chunk)
|
||||
local penalties = squad.penalties
|
||||
for xc=1,mMin(#squad.penalties,5) do
|
||||
addDeathGenerator(map,
|
||||
penalties[xc].c,
|
||||
deathGen * DIVISOR_DEATH_TRAIL_TABLE[xc])
|
||||
end
|
||||
removeSquadFromChunk(map, squad)
|
||||
group.destroy()
|
||||
else
|
||||
squadDispatch(map, group.surface, squad, unitNumber)
|
||||
end
|
||||
else
|
||||
squadDispatch(map, group.surface, squad, unitNumber)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onGroupFinishedGathering(event)
|
||||
print("15", game.tick)
|
||||
local group = event.group
|
||||
if group.valid then
|
||||
local unitNumber = group.group_number
|
||||
@ -967,10 +1029,12 @@ local function onGroupFinishedGathering(event)
|
||||
end
|
||||
|
||||
local function onForceCreated(event)
|
||||
print("16", game.tick)
|
||||
map.activePlayerForces[#map.activePlayerForces+1] = event.force.name
|
||||
end
|
||||
|
||||
local function onForceMerged(event)
|
||||
print("17", game.tick)
|
||||
for i=#map.activePlayerForces,1,-1 do
|
||||
if (map.activePlayerForces[i] == event.source_name) then
|
||||
tRemove(map.activePlayerForces, i)
|
||||
@ -980,6 +1044,7 @@ local function onForceMerged(event)
|
||||
end
|
||||
|
||||
local function onSurfaceRenamed(event)
|
||||
print("18", game.tick)
|
||||
if event.old_name == natives.activeSurface then
|
||||
natives.activeSurface = event.new_name
|
||||
end
|
||||
@ -990,6 +1055,7 @@ local function onSurfaceRenamed(event)
|
||||
end
|
||||
|
||||
local function onSurfaceCleared(event)
|
||||
print("19", game.tick)
|
||||
local surface = game.get_surface(event.surface_index)
|
||||
if surface and surface.valid and (surface.name == natives.activeSurface) then
|
||||
prepWorld(true, natives.activeSurface)
|
||||
@ -997,6 +1063,7 @@ local function onSurfaceCleared(event)
|
||||
end
|
||||
|
||||
local function onPlayerChangedSurface(event)
|
||||
print("20", game.tick)
|
||||
local player = game.players[event.player_index]
|
||||
local surface
|
||||
if player and player.valid and not settings.get_player_settings(player)["rampant-suppress-surface-change-warnings"].value
|
||||
@ -1020,6 +1087,7 @@ local function onPlayerChangedSurface(event)
|
||||
end
|
||||
|
||||
local function onSurfaceDeleted(event)
|
||||
print("21", game.tick)
|
||||
local surface = game.get_surface(event.surface_index)
|
||||
if surface and surface.valid then
|
||||
if (surface.name == natives.activeSurface) then
|
||||
@ -1035,68 +1103,106 @@ end
|
||||
|
||||
script.on_nth_tick(INTERVAL_PLAYER_PROCESS,
|
||||
function (event)
|
||||
|
||||
print("22", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
local gameRef = game
|
||||
|
||||
processPlayers(gameRef.connected_players,
|
||||
map,
|
||||
gameRef.get_surface(natives.activeSurface),
|
||||
event.tick)
|
||||
game.print({"", "player", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_MAP_PROCESS,
|
||||
function (event)
|
||||
|
||||
print("23", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
local gameRef = game
|
||||
|
||||
processMap(map,
|
||||
gameRef.get_surface(natives.activeSurface),
|
||||
event.tick)
|
||||
-- processMap(map,
|
||||
-- gameRef.get_surface(natives.activeSurface),
|
||||
-- event.tick)
|
||||
game.print({"", "map", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_SCAN,
|
||||
function (event)
|
||||
print("24", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
local tick = event.tick
|
||||
local gameRef = game
|
||||
local surface = gameRef.get_surface(natives.activeSurface)
|
||||
|
||||
processPendingChunks(map, surface, pendingChunks, tick)
|
||||
processPendingChunks(map, surface, tick)
|
||||
|
||||
scanMap(map, surface, tick)
|
||||
|
||||
processScanChunks(map, surface)
|
||||
game.print({"", "scan", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_LOGIC,
|
||||
function (event)
|
||||
print("25", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
local tick = event.tick
|
||||
|
||||
planning(natives,
|
||||
game.forces.enemy.evolution_factor,
|
||||
tick)
|
||||
|
||||
map.squadIterator = cleanSquads(natives, map.squadIterator)
|
||||
cleanSquads(natives, map.squadIterator)
|
||||
|
||||
if natives.newEnemies then
|
||||
recycleBases(natives, tick)
|
||||
end
|
||||
game.print({"", "logic", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_SPAWNER,
|
||||
function (event)
|
||||
print("26", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
processSpawners(map,
|
||||
game.get_surface(natives.activeSurface),
|
||||
event.tick)
|
||||
game.print({"", "spawners", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_SQUAD,
|
||||
function (event)
|
||||
print("27", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
processVengence(map,
|
||||
game.get_surface(natives.activeSurface),
|
||||
event.tick)
|
||||
game.print({"", "vengence", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_TEMPERAMENT,
|
||||
function (event)
|
||||
print("28", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
temperamentPlanner(natives)
|
||||
game.print({"", "temperament", profiler})
|
||||
end)
|
||||
|
||||
script.on_nth_tick(INTERVAL_RESQUAD,
|
||||
function ()
|
||||
function ()
|
||||
print("29", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
map.regroupIterator = regroupSquads(natives, map.regroupIterator)
|
||||
game.print({"", "regroup", profiler})
|
||||
end)
|
||||
|
||||
script.on_event(defines.events.on_tick,
|
||||
function (event)
|
||||
processActiveNests(map,
|
||||
game.get_surface(natives.activeSurface),
|
||||
event.tick)
|
||||
print("30", game.tick)
|
||||
local profiler = game.create_profiler()
|
||||
-- processActiveNests(map,
|
||||
-- game.get_surface(natives.activeSurface),
|
||||
-- event.tick)
|
||||
game.print({"", "processActiveNests", profiler})
|
||||
end)
|
||||
|
||||
script.on_event(defines.events.on_surface_cleared, onSurfaceCleared)
|
||||
|
@ -5,6 +5,6 @@
|
||||
"title" : "Rampant",
|
||||
"author" : "Veden",
|
||||
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
|
||||
"description" : "Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies (disabled by default). Can completely replace the vanilla AI. Difficulty setting in mod options menu.",
|
||||
"description" : "Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies (disabled by default). Difficulty setting in mod options menu.",
|
||||
"dependencies" : ["base >= 0.18.22", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Orbital Ion Cannon", "? RampantArsenal", "? RampantResources", "? ArmouredBiters"]
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
|
||||
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
|
||||
|
||||
local INTERVAL_RALLY = constants.INTERVAL_RALLY
|
||||
local COOLDOWN_RALLY = constants.COOLDOWN_RALLY
|
||||
|
||||
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
||||
|
||||
@ -52,16 +52,12 @@ local randomTickEvent = mathUtils.randomTickEvent
|
||||
|
||||
local mRandom = math.random
|
||||
|
||||
local createSpawnerProxies = baseUtils.createSpawnerProxies
|
||||
|
||||
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
||||
|
||||
local getPassable = chunkPropertyUtils.getPassable
|
||||
local getNestCount = chunkPropertyUtils.getNestCount
|
||||
local getChunkSettlerTick = chunkPropertyUtils.getChunkSettlerTick
|
||||
local getRaidNestActiveness = chunkPropertyUtils.getRaidNestActiveness
|
||||
local getNestActiveness = chunkPropertyUtils.getNestActiveness
|
||||
local setChunkSettlerTick = chunkPropertyUtils.setChunkSettlerTick
|
||||
local getRallyTick = chunkPropertyUtils.getRallyTick
|
||||
local setRallyTick = chunkPropertyUtils.setRallyTick
|
||||
|
||||
@ -121,68 +117,76 @@ local function validUnitGroupLocation(map, neighborChunk)
|
||||
(getNestCount(map, neighborChunk) == 0)
|
||||
end
|
||||
|
||||
local function visitPattern(o, cX, cY, distance)
|
||||
local startX
|
||||
local endX
|
||||
local stepX
|
||||
local startY
|
||||
local endY
|
||||
local stepY
|
||||
if (o == 0) then
|
||||
startX = cX - RALLY_CRY_DISTANCE
|
||||
endX = cX + RALLY_CRY_DISTANCE
|
||||
stepX = 32
|
||||
startY = cY - RALLY_CRY_DISTANCE
|
||||
endY = cY + RALLY_CRY_DISTANCE
|
||||
stepY = 32
|
||||
elseif (o == 1) then
|
||||
startX = cX + RALLY_CRY_DISTANCE
|
||||
endX = cX - RALLY_CRY_DISTANCE
|
||||
stepX = -32
|
||||
startY = cY + RALLY_CRY_DISTANCE
|
||||
endY = cY - RALLY_CRY_DISTANCE
|
||||
stepY = -32
|
||||
elseif (o == 2) then
|
||||
startX = cX - RALLY_CRY_DISTANCE
|
||||
endX = cX + RALLY_CRY_DISTANCE
|
||||
stepX = 32
|
||||
startY = cY + RALLY_CRY_DISTANCE
|
||||
endY = cY - RALLY_CRY_DISTANCE
|
||||
stepY = -32
|
||||
elseif (o == 3) then
|
||||
startX = cX + RALLY_CRY_DISTANCE
|
||||
endX = cX - RALLY_CRY_DISTANCE
|
||||
stepX = -32
|
||||
startY = cY - RALLY_CRY_DISTANCE
|
||||
endY = cY + RALLY_CRY_DISTANCE
|
||||
stepY = 32
|
||||
end
|
||||
return startX, endX, stepX, startY, endY, stepY
|
||||
end
|
||||
|
||||
function aiAttackWave.rallyUnits(chunk, map, surface, tick)
|
||||
if ((tick - getRallyTick(map, chunk) > INTERVAL_RALLY) and (map.natives.points >= AI_VENGENCE_SQUAD_COST)) then
|
||||
if ((tick - getRallyTick(map, chunk) > COOLDOWN_RALLY) and (map.natives.points >= AI_VENGENCE_SQUAD_COST)) then
|
||||
setRallyTick(map, chunk, tick)
|
||||
local cX = chunk.x
|
||||
local cY = chunk.y
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do
|
||||
local startX, endX, stepX, startY, endY, stepY = visitPattern(tick % 4, cX, cY, RALLY_CRY_DISTANCE)
|
||||
local vengenceQueue = map.natives.vengenceQueue
|
||||
for x=startX, endX, stepX do
|
||||
for y=startY, endY, stepY do
|
||||
if (x ~= cX) and (y ~= cY) then
|
||||
local rallyChunk = getChunkByXY(map, x, y)
|
||||
if (rallyChunk ~= -1) and (getNestCount(map, rallyChunk) > 0) then
|
||||
if not aiAttackWave.formVengenceSquad(map, surface, rallyChunk) then
|
||||
return false
|
||||
local count = vengenceQueue[rallyChunk]
|
||||
if not count then
|
||||
count = 0
|
||||
vengenceQueue[rallyChunk] = count
|
||||
end
|
||||
vengenceQueue[rallyChunk] = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function aiAttackWave.formAttackWave(chunk, map, surface, tick)
|
||||
if (map.natives.points >= AI_SQUAD_COST) then
|
||||
local cX = chunk.x
|
||||
local cY = chunk.y
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do
|
||||
if (x ~= cX) and (y ~= cY) then
|
||||
local rallyChunk = getChunkByXY(map, x, y)
|
||||
if (rallyChunk ~= -1) and (getNestCount(map, rallyChunk) > 0) then
|
||||
if not aiAttackWave.formSquads(map, surface, rallyChunk, tick) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function noNearbySettlers(map, chunk, tick)
|
||||
local cX = chunk.x
|
||||
local cY = chunk.y
|
||||
for x=cX - SETTLER_DISTANCE, cX + SETTLER_DISTANCE, 32 do
|
||||
for y=cY - SETTLER_DISTANCE, cY + SETTLER_DISTANCE, 32 do
|
||||
if (x ~= cX) and (y ~= cY) then
|
||||
local c = getChunkByXY(map, x, y)
|
||||
if (c ~= -1) and ((tick - getChunkSettlerTick(map, c)) < 0) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function aiAttackWave.formSettlers(map, surface, chunk, tick)
|
||||
local natives = map.natives
|
||||
if (mRandom() < natives.formSquadThreshold) and (natives.remainingSquads > 0) then
|
||||
|
||||
local natives = map.natives
|
||||
if (mRandom() < natives.formSquadThreshold) and ((natives.points - AI_SETTLER_COST) > 0) then
|
||||
local squadPath, squadDirection
|
||||
if (natives.state == AI_STATE_SIEGE) then
|
||||
squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
|
||||
@ -197,7 +201,7 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
|
||||
map)
|
||||
end
|
||||
|
||||
if (squadPath ~= -1) and noNearbySettlers(map, chunk, tick) then
|
||||
if (squadPath ~= -1) then
|
||||
local squadPosition = surface.find_non_colliding_position("chunk-scanner-squad-rampant",
|
||||
positionFromDirectionAndChunk(squadDirection,
|
||||
chunk,
|
||||
@ -214,14 +218,12 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
|
||||
10,
|
||||
natives.expansionMaxDistance)
|
||||
|
||||
|
||||
local scaledWaveSize = settlerWaveScaling(natives)
|
||||
map.formGroupCommand.group = squad.group
|
||||
map.formCommand.unit_count = scaledWaveSize
|
||||
local foundUnits = surface.set_multi_command(map.formCommand)
|
||||
if (foundUnits > 0) then
|
||||
createSpawnerProxies(map, surface, chunk, foundUnits)
|
||||
setChunkSettlerTick(map, squadPath, tick + natives.settlerCooldown)
|
||||
natives.remainingSquads = natives.remainingSquads - 1
|
||||
natives.points = natives.points - AI_SETTLER_COST
|
||||
natives.groupNumberToSquad[squad.groupNumber] = squad
|
||||
else
|
||||
@ -232,13 +234,11 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ((natives.points - AI_SETTLER_COST) > 0) and (natives.remainingSquads > 0)
|
||||
end
|
||||
|
||||
function aiAttackWave.formVengenceSquad(map, surface, chunk)
|
||||
local natives = map.natives
|
||||
if (mRandom() < natives.formSquadThreshold) then
|
||||
if (mRandom() < natives.formSquadThreshold) and ((natives.points - AI_VENGENCE_SQUAD_COST) > 0) then
|
||||
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
|
||||
validUnitGroupLocation,
|
||||
scoreUnitGroupLocation,
|
||||
@ -262,7 +262,6 @@ function aiAttackWave.formVengenceSquad(map, surface, chunk)
|
||||
map.formCommand.unit_count = scaledWaveSize
|
||||
local foundUnits = surface.set_multi_command(map.formCommand)
|
||||
if (foundUnits > 0) then
|
||||
createSpawnerProxies(map, surface, chunk, foundUnits)
|
||||
natives.groupNumberToSquad[squad.groupNumber] = squad
|
||||
natives.points = natives.points - AI_VENGENCE_SQUAD_COST
|
||||
else
|
||||
@ -273,15 +272,13 @@ function aiAttackWave.formVengenceSquad(map, surface, chunk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return (natives.points - AI_VENGENCE_SQUAD_COST) > 0
|
||||
end
|
||||
|
||||
function aiAttackWave.formSquads(map, surface, chunk, tick)
|
||||
local natives = map.natives
|
||||
if attackWaveValidCandidate(chunk, natives, map) and
|
||||
(mRandom() < natives.formSquadThreshold) and
|
||||
(natives.remainingSquads > 0)
|
||||
((natives.points - AI_SQUAD_COST) > 0)
|
||||
then
|
||||
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
|
||||
validUnitGroupLocation,
|
||||
@ -308,13 +305,11 @@ function aiAttackWave.formSquads(map, surface, chunk, tick)
|
||||
if (foundUnits > 0) then
|
||||
createSpawnerProxies(map, surface, chunk, foundUnits)
|
||||
natives.points = natives.points - AI_SQUAD_COST
|
||||
natives.remainingSquads = natives.remainingSquads - 1
|
||||
natives.groupNumberToSquad[squad.groupNumber] = squad
|
||||
if tick and (natives.state == AI_STATE_AGGRESSIVE) then
|
||||
natives.canAttackTick = randomTickEvent(tick,
|
||||
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
|
||||
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
|
||||
return false
|
||||
end
|
||||
else
|
||||
if (squad.group.valid) then
|
||||
@ -324,8 +319,6 @@ function aiAttackWave.formSquads(map, surface, chunk, tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ((natives.points - AI_SQUAD_COST) > 0) and (natives.remainingSquads > 0)
|
||||
end
|
||||
|
||||
|
||||
|
@ -71,7 +71,7 @@ function aiPlanning.planning(natives, evolution_factor, tick)
|
||||
local attackWaveMaxSize = natives.attackWaveMaxSize
|
||||
natives.retreatThreshold = linearInterpolation(evolution_factor, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX)
|
||||
natives.rallyThreshold = BASE_RALLY_CHANCE + (evolution_factor * BONUS_RALLY_CHANCE)
|
||||
natives.formSquadThreshold = mMax((0.25 * evolution_factor), 0.10)
|
||||
natives.formSquadThreshold = mMax((0.20 * evolution_factor), 0.05)
|
||||
|
||||
natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.15)
|
||||
natives.attackWaveDeviation = (natives.attackWaveSize * 0.333)
|
||||
|
@ -19,8 +19,10 @@ local AI_STATE_ONSLAUGHT = constants.AI_STATE_ONSLAUGHT
|
||||
|
||||
-- module code
|
||||
|
||||
function aiPredicates.canAttack(natives, surface)
|
||||
local goodAI = ((natives.state == AI_STATE_AGGRESSIVE) or (natives.state == AI_STATE_RAIDING) or (natives.state == AI_STATE_ONSLAUGHT))
|
||||
function aiPredicates.canAttack(natives, surface, tick)
|
||||
local goodAI = (((natives.state == AI_STATE_AGGRESSIVE) and (natives.canAttackTick > tick)) or
|
||||
(natives.state == AI_STATE_RAIDING) or
|
||||
(natives.state == AI_STATE_ONSLAUGHT))
|
||||
local notPeaceful = not surface.peaceful_mode
|
||||
local noctural = (not natives.aiNocturnalMode) or (natives.aiNocturnalMode and surface.darkness > 0.65)
|
||||
return goodAI and notPeaceful and noctural
|
||||
|
@ -76,6 +76,8 @@ local setChunkBase = chunkPropertyUtils.setChunkBase
|
||||
|
||||
local getResourceGenerator = chunkPropertyUtils.getResourceGenerator
|
||||
|
||||
local next = next
|
||||
|
||||
local tRemove = table.remove
|
||||
|
||||
local mRandom = math.random
|
||||
@ -95,50 +97,6 @@ local function evoToTier(natives, evolutionFactor)
|
||||
return v
|
||||
end
|
||||
|
||||
function baseUtils.createSpawnerProxies(map, surface, chunk, foundUnits)
|
||||
local query = map.placeSpawnerProxyQuery
|
||||
if (foundUnits >= 60) then
|
||||
query.name = "spawner-proxy-2-rampant"
|
||||
elseif (foundUnits >= 120) then
|
||||
query.name = "spawner-proxy-3-rampant"
|
||||
else
|
||||
query.name = "spawner-proxy-1-rampant"
|
||||
end
|
||||
local position3 = map.position3
|
||||
local chunkX = chunk.x + 5
|
||||
local chunkY = chunk.y + 5
|
||||
position3.x = chunkX
|
||||
position3.y = chunkY
|
||||
local entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
position3.x = chunkX+CHUNK_SIZE
|
||||
position3.y = chunkY
|
||||
entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
position3.x = chunkX-CHUNK_SIZE
|
||||
position3.y = chunkY
|
||||
entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
position3.x = chunkX
|
||||
position3.y = chunkY-CHUNK_SIZE
|
||||
entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
position3.x = chunkX
|
||||
position3.y = chunkY+CHUNK_SIZE
|
||||
entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
end
|
||||
|
||||
function baseUtils.createSpawnerProxy(map, surface, chunk)
|
||||
local query = map.placeSpawnerProxyQuery
|
||||
query.name = "spawner-proxy-1-rampant"
|
||||
local position3 = map.position3
|
||||
position3.x = chunk.x + 5
|
||||
position3.y = chunk.y + 5
|
||||
local entity = surface.create_entity(query)
|
||||
entity.destructible = false
|
||||
end
|
||||
|
||||
function baseUtils.findNearbyBase(map, chunk)
|
||||
local x = chunk.x
|
||||
local y = chunk.y
|
||||
@ -150,8 +108,7 @@ function baseUtils.findNearbyBase(map, chunk)
|
||||
|
||||
local bases = map.natives.bases
|
||||
local closet = MAGIC_MAXIMUM_NUMBER
|
||||
for i=1, #bases do
|
||||
local base = bases[i]
|
||||
for _, base in pairs(bases) do
|
||||
local distance = euclideanDistancePoints(base.x, base.y, x, y)
|
||||
if (distance <= base.distanceThreshold) and (distance < closet) then
|
||||
closet = distance
|
||||
@ -283,7 +240,8 @@ local function findEntityUpgrade(baseAlignment, currentEvo, evoIndex, originalEn
|
||||
end
|
||||
|
||||
local function findBaseInitialAlignment(natives, evoIndex)
|
||||
local evoTop = gaussianRandomRange(evoIndex, evoIndex * 0.3, 0, evoIndex)
|
||||
local dev = evoIndex * 0.3
|
||||
local evoTop = gaussianRandomRange(evoIndex - dev, dev, 0, evoIndex)
|
||||
|
||||
local result
|
||||
if mRandom() < 0.05 then
|
||||
@ -298,21 +256,23 @@ end
|
||||
function baseUtils.recycleBases(natives, tick)
|
||||
local baseIndex = natives.baseIndex
|
||||
local bases = natives.bases
|
||||
|
||||
local endIndex = mMin(baseIndex+BASE_QUEUE_SIZE, #bases)
|
||||
for index = endIndex, baseIndex, -1 do
|
||||
local base = bases[index]
|
||||
|
||||
if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then
|
||||
tRemove(bases, index)
|
||||
local id, base = next(bases, natives.map.recycleBaseIterator)
|
||||
for i=1,2 do
|
||||
if not id then
|
||||
natives.map.recycleBaseIterator = nil
|
||||
return
|
||||
else
|
||||
if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then
|
||||
local nextId
|
||||
nextId, base = next(bases, id)
|
||||
bases[id] = nil
|
||||
id = nextId
|
||||
else
|
||||
id, base = next(bases, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (endIndex == #bases) then
|
||||
natives.baseIndex = 1
|
||||
else
|
||||
natives.baseIndex = endIndex + 1
|
||||
end
|
||||
natives.map.recycleBaseIterator = id
|
||||
end
|
||||
|
||||
|
||||
@ -495,12 +455,14 @@ function baseUtils.createBase(natives, chunk, tick, rebuilding)
|
||||
temperamentTick = 0,
|
||||
createdTick = tick,
|
||||
temperament = 0,
|
||||
points = 0
|
||||
points = 0,
|
||||
id = natives.baseId
|
||||
}
|
||||
natives.baseId = natives.baseId + 1
|
||||
|
||||
setChunkBase(natives.map, chunk, base)
|
||||
|
||||
natives.bases[#natives.bases+1] = base
|
||||
natives.bases[base.id] = base
|
||||
|
||||
return base
|
||||
end
|
||||
@ -653,8 +615,7 @@ function baseUtils.rebuildNativeTables(natives, surface, rg)
|
||||
|
||||
local evoIndex = evoToTier(natives, natives.evolutionLevel)
|
||||
|
||||
for i=1,#natives.bases do
|
||||
local base = natives.bases[i]
|
||||
for id,base in pairs(natives.bases) do
|
||||
for x=1,#base.alignment do
|
||||
local alignment = base.alignment[x]
|
||||
if not natives.buildingEvolveLookup[alignment] then
|
||||
|
@ -27,6 +27,8 @@ local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
|
||||
local tSort = table.sort
|
||||
|
||||
local abs = math.abs
|
||||
local next = next
|
||||
local table_size = table_size
|
||||
|
||||
local tRemove = table.remove
|
||||
|
||||
@ -49,49 +51,67 @@ local function sorter(a, b)
|
||||
return (aDistance < bDistance)
|
||||
end
|
||||
|
||||
function chunkProcessor.processPendingChunks(map, surface, pendingStack, tick, rebuilding)
|
||||
function chunkProcessor.processPendingChunks(map, surface, tick, rebuilding, flush)
|
||||
local profiler = game.create_profiler()
|
||||
local processQueue = map.processQueue
|
||||
local pendingChunks = map.pendingChunks
|
||||
|
||||
local area = map.area
|
||||
|
||||
local topOffset = area[1]
|
||||
local bottomOffset = area[2]
|
||||
|
||||
for i=#pendingStack, 1, -1 do
|
||||
local event = pendingStack[i]
|
||||
pendingStack[i] = nil
|
||||
|
||||
local topLeft = event.area.left_top
|
||||
local x = topLeft.x
|
||||
local y = topLeft.y
|
||||
|
||||
topOffset[1] = x
|
||||
topOffset[2] = y
|
||||
bottomOffset[1] = x + CHUNK_SIZE
|
||||
bottomOffset[2] = y + CHUNK_SIZE
|
||||
|
||||
if map[x] and map[x][y] then
|
||||
mapScanChunk(map[x][y], surface, map)
|
||||
local event = next(pendingChunks, map.chunkProcessorIterator)
|
||||
local endCount = 5
|
||||
if flush then
|
||||
endCount = table_size(pendingChunks)
|
||||
end
|
||||
for i=1,endCount do
|
||||
if not event then
|
||||
map.chunkProcessorIterator = nil
|
||||
if (table_size(pendingChunks) == 0) then
|
||||
-- this is needed as the next command remembers the max length a table has been
|
||||
map.pendingChunks = {}
|
||||
end
|
||||
break
|
||||
else
|
||||
if map[x] == nil then
|
||||
map[x] = {}
|
||||
end
|
||||
|
||||
local chunk = createChunk(x, y)
|
||||
|
||||
chunk = initialScan(chunk, surface, map, tick, rebuilding)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
map[x][y] = chunk
|
||||
processQueue[#processQueue+1] = chunk
|
||||
local topLeft = event.area.left_top
|
||||
local x = topLeft.x
|
||||
local y = topLeft.y
|
||||
|
||||
topOffset[1] = x
|
||||
topOffset[2] = y
|
||||
bottomOffset[1] = x + CHUNK_SIZE
|
||||
bottomOffset[2] = y + CHUNK_SIZE
|
||||
|
||||
if map[x] and map[x][y] then
|
||||
mapScanChunk(map[x][y], surface, map)
|
||||
else
|
||||
if map[x] == nil then
|
||||
map[x] = {}
|
||||
end
|
||||
|
||||
local chunk = createChunk(x, y)
|
||||
|
||||
chunk = initialScan(chunk, surface, map, tick, rebuilding)
|
||||
|
||||
if (chunk ~= -1) then
|
||||
map[x][y] = chunk
|
||||
processQueue[#processQueue+1] = chunk
|
||||
end
|
||||
end
|
||||
local newEvent,_ = next(pendingChunks, event)
|
||||
pendingChunks[event] = nil
|
||||
event = newEvent
|
||||
end
|
||||
end
|
||||
map.chunkProcessorIterator = event
|
||||
|
||||
if (#processQueue > map.nextChunkSort) or
|
||||
(((tick - map.nextChunkSortTick) > MAX_TICKS_BEFORE_SORT_CHUNKS) and ((map.nextChunkSort - 75) ~= #processQueue))
|
||||
(((tick - map.nextChunkSortTick) > MAX_TICKS_BEFORE_SORT_CHUNKS) and
|
||||
((map.nextChunkSort - 150) < #processQueue))
|
||||
then
|
||||
map.nextChunkSort = #processQueue + 75
|
||||
map.nextChunkSort = #processQueue + 150
|
||||
map.nextChunkSortTick = tick
|
||||
tSort(processQueue, sorter)
|
||||
end
|
||||
|
@ -79,23 +79,14 @@ end
|
||||
function chunkPropertyUtils.setNestCount(map, chunk, count)
|
||||
if (count <= 0) then
|
||||
map.chunkToNests[chunk] = nil
|
||||
if (map.processMigrationIterator == chunk) then
|
||||
map.processMigrationIterator = nil
|
||||
end
|
||||
else
|
||||
map.chunkToNests[chunk] = count
|
||||
end
|
||||
end
|
||||
|
||||
function chunkPropertyUtils.getChunkSettlerTick(map, chunk)
|
||||
return map.chunkToSettler[chunk] or 0
|
||||
end
|
||||
|
||||
function chunkPropertyUtils.setChunkSettlerTick(map, chunk, tick)
|
||||
if (tick <= 0) then
|
||||
map.chunkToSettler[chunk] = nil
|
||||
else
|
||||
map.chunkToSettler[chunk] = tick
|
||||
end
|
||||
end
|
||||
|
||||
function chunkPropertyUtils.getNestCount(map, chunk)
|
||||
return map.chunkToNests[chunk] or 0
|
||||
end
|
||||
@ -163,6 +154,9 @@ function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value)
|
||||
if (map.chunkToActiveRaidNest[chunk] ~= nil) then
|
||||
map.natives.activeRaidNests = map.natives.activeRaidNests - 1
|
||||
end
|
||||
if (map.processActiveRaidSpawnerIterator == chunk) then
|
||||
map.processActiveRaidSpawnerIterator = nil
|
||||
end
|
||||
map.chunkToActiveRaidNest[chunk] = nil
|
||||
else
|
||||
if (map.chunkToActiveRaidNest[chunk] == nil) then
|
||||
@ -193,6 +187,9 @@ function chunkPropertyUtils.setNestActiveness(map, chunk, value)
|
||||
if (map.chunkToActiveNest[chunk] ~= nil) then
|
||||
map.natives.activeNests = map.natives.activeNests - 1
|
||||
end
|
||||
if (map.processActiveSpawnerIterator == chunk) then
|
||||
map.processActiveSpawnerIterator = nil
|
||||
end
|
||||
map.chunkToActiveNest[chunk] = nil
|
||||
else
|
||||
if (map.chunkToActiveNest[chunk] == nil) then
|
||||
|
@ -58,15 +58,15 @@ constants.CHUNK_PASS_THRESHOLD = 0.25
|
||||
constants.INTERVAL_PLAYER_PROCESS = (settings.startup["rampant-liteMode"].value and 124) or 62
|
||||
constants.INTERVAL_MAP_PROCESS = (settings.startup["rampant-liteMode"].value and 8) or 5
|
||||
constants.INTERVAL_SCAN = (settings.startup["rampant-liteMode"].value and 42) or 21
|
||||
constants.INTERVAL_CHUNK = 17
|
||||
constants.INTERVAL_LOGIC = 60
|
||||
constants.INTERVAL_TEMPERAMENT = 121
|
||||
constants.INTERVAL_SQUAD = 41
|
||||
constants.INTERVAL_SQUAD = 17
|
||||
constants.INTERVAL_RESQUAD = 101
|
||||
constants.INTERVAL_SPAWNER = 31
|
||||
constants.INTERVAL_BUILDERS = 300
|
||||
constants.INTERVAL_SPAWNER = constants.TICKS_A_SECOND * 10
|
||||
constants.INTERVAL_RALLY = constants.TICKS_A_SECOND * 10
|
||||
constants.INTERVAL_RETREAT = constants.TICKS_A_SECOND * 10
|
||||
|
||||
constants.COOLDOWN_RALLY = constants.TICKS_A_SECOND * 10
|
||||
constants.COOLDOWN_RETREAT = constants.TICKS_A_SECOND * 10
|
||||
|
||||
constants.RESOURCE_NORMALIZER = 1 / 1024
|
||||
|
||||
|
@ -36,15 +36,12 @@ local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
local AI_SETTLER_COST = constants.AI_SETTLER_COST
|
||||
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
|
||||
|
||||
local processNestActiveness = chunkPropertyUtils.processNestActiveness
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
|
||||
local INTERVAL_RALLY = constants.INTERVAL_RALLY
|
||||
local INTERVAL_RETREAT = constants.INTERVAL_RETREAT
|
||||
local INTERVAL_SPAWNER = constants.INTERVAL_SPAWNER
|
||||
local COOLDOWN_RALLY = constants.COOLDOWN_RALLY
|
||||
local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
|
||||
|
||||
local BASE_PROCESS_INTERVAL = constants.BASE_PROCESS_INTERVAL
|
||||
|
||||
@ -52,15 +49,17 @@ local AI_MAX_SQUADS_PER_CYCLE = constants.AI_MAX_SQUADS_PER_CYCLE
|
||||
|
||||
-- imported functions
|
||||
|
||||
-- local scents = pheromoneUtils.scents
|
||||
local processPheromone = pheromoneUtils.processPheromone
|
||||
local commitPheromone = pheromoneUtils.commitPheromone
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
|
||||
local processBase = baseUtils.processBase
|
||||
|
||||
local processNestActiveness = chunkPropertyUtils.processNestActiveness
|
||||
|
||||
local formSquads = aiAttackWave.formSquads
|
||||
local formAttackWave = aiAttackWave.formAttackWave
|
||||
local formSettlers = aiAttackWave.formSettlers
|
||||
local formVengenceSquad = aiAttackWave.formVengenceSquad
|
||||
local formSettlers = aiAttackWave.formSettlers
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local getChunkByXY = mapUtils.getChunkByXY
|
||||
@ -89,11 +88,9 @@ local canMigrate = aiPredicates.canMigrate
|
||||
|
||||
local findNearbySquad = unitGroupUtils.findNearbySquad
|
||||
|
||||
local processBase = baseUtils.processBase
|
||||
|
||||
local mMin = math.min
|
||||
-- local mMax = math.max
|
||||
|
||||
local next = next
|
||||
local mRandom = math.random
|
||||
|
||||
-- module code
|
||||
@ -109,47 +106,21 @@ function mapProcessor.processMap(map, surface, tick)
|
||||
local roll = map.processRoll
|
||||
local index = map.processIndex
|
||||
|
||||
local chunkToBase = map.chunkToBase
|
||||
|
||||
local natives = map.natives
|
||||
|
||||
if (index == 1) then
|
||||
roll = mRandom()
|
||||
map.processRoll = roll
|
||||
natives.remainingSquads = AI_MAX_SQUADS_PER_CYCLE
|
||||
end
|
||||
|
||||
local newEnemies = natives.newEnemies
|
||||
local scentStaging = map.scentStaging
|
||||
|
||||
local squads = canAttack(natives, surface) and (roll <= 0.45) and (natives.points >= AI_SQUAD_COST)
|
||||
if squads and (natives.state == AI_STATE_AGGRESSIVE) and (tick < natives.canAttackTick) then
|
||||
squads = false
|
||||
end
|
||||
local settlers = canMigrate(natives, surface) and (roll <= 0.45) and (natives.points >= AI_SETTLER_COST)
|
||||
|
||||
local processQueue = map.processQueue
|
||||
local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue)
|
||||
local i = 1
|
||||
|
||||
for x=index,endIndex do
|
||||
local chunk = processQueue[x]
|
||||
|
||||
if (chunk[CHUNK_TICK] ~= tick) then
|
||||
processPheromone(map, chunk, scentStaging[i])
|
||||
|
||||
if settlers and (getNestCount(map, chunk) > 0) then
|
||||
settlers = formSettlers(map, surface, chunk, tick)
|
||||
end
|
||||
if squads then
|
||||
squads = formAttackWave(chunk, map, surface, tick)
|
||||
end
|
||||
|
||||
if newEnemies then
|
||||
local base = chunkToBase[chunk]
|
||||
if base and ((tick - base.tick) > BASE_PROCESS_INTERVAL) then
|
||||
processBase(chunk, surface, natives, tick, base)
|
||||
end
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
@ -170,12 +141,11 @@ function mapProcessor.processMap(map, surface, tick)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function queueNestSpawners(map, chunk, tick)
|
||||
local limitPerActiveChunkTick = map.natives.activeNests * DURATION_ACTIVE_NEST_DIVIDER
|
||||
|
||||
local processActiveNest = map.processActiveNest
|
||||
|
||||
|
||||
if ((getNestActiveness(map, chunk) > 0) and (getNestActiveTick(map, chunk) == 0)) then
|
||||
local nextTick = tick + DURATION_ACTIVE_NEST
|
||||
local slot = processActiveNest[nextTick]
|
||||
@ -223,8 +193,6 @@ function mapProcessor.processPlayers(players, map, surface, tick)
|
||||
|
||||
local scentStaging = map.scentStaging
|
||||
|
||||
local squads = allowingAttacks and (0.11 <= roll) and (roll <= 0.20) and (natives.points >= AI_SQUAD_COST)
|
||||
|
||||
-- not looping everyone because the cost is high enough already in multiplayer
|
||||
if (#players > 0) then
|
||||
local player = players[mRandom(#players)]
|
||||
@ -233,9 +201,10 @@ function mapProcessor.processPlayers(players, map, surface, tick)
|
||||
|
||||
if (playerChunk ~= -1) then
|
||||
local i = 1
|
||||
local vengence = (allowingAttacks and
|
||||
(natives.points >= AI_VENGENCE_SQUAD_COST) and
|
||||
((getEnemyStructureCount(map, playerChunk) > 0) or (playerChunk[MOVEMENT_PHEROMONE] < -natives.retreatThreshold)))
|
||||
local vengence = allowingAttacks and
|
||||
(natives.points >= AI_VENGENCE_SQUAD_COST) and
|
||||
((getEnemyStructureCount(map, playerChunk) > 0) or
|
||||
(playerChunk[MOVEMENT_PHEROMONE] < -natives.retreatThreshold))
|
||||
|
||||
for x=playerChunk.x - PROCESS_PLAYER_BOUND, playerChunk.x + PROCESS_PLAYER_BOUND, 32 do
|
||||
for y=playerChunk.y - PROCESS_PLAYER_BOUND, playerChunk.y + PROCESS_PLAYER_BOUND, 32 do
|
||||
@ -246,9 +215,14 @@ function mapProcessor.processPlayers(players, map, surface, tick)
|
||||
|
||||
processNestActiveness(map, chunk, natives, surface)
|
||||
queueNestSpawners(map, chunk, tick)
|
||||
|
||||
|
||||
if vengence and (getNestCount(map, chunk) > 0) then
|
||||
vengence = formVengenceSquad(map, surface, chunk)
|
||||
local count = natives.vengenceQueue[chunk]
|
||||
if not count then
|
||||
count = 0
|
||||
natives.vengenceQueue[chunk] = count
|
||||
end
|
||||
natives.vengenceQueue[chunk] = count + 1
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
@ -293,8 +267,6 @@ function mapProcessor.scanMap(map, surface, tick)
|
||||
|
||||
local retreats = map.chunkToRetreats
|
||||
local rallys = map.chunkToRallys
|
||||
-- local spawners = map.chunkToSpawner
|
||||
local settlers = map.chunkToSettler
|
||||
local drained = map.chunkToDrained
|
||||
|
||||
local processQueue = map.processQueue
|
||||
@ -314,20 +286,15 @@ function mapProcessor.scanMap(map, surface, tick)
|
||||
offset[2] = chunk.y + CHUNK_SIZE
|
||||
|
||||
local retreatTick = retreats[chunk]
|
||||
if retreatTick and ((tick - retreatTick) > INTERVAL_RETREAT) then
|
||||
if retreatTick and ((tick - retreatTick) > COOLDOWN_RETREAT) then
|
||||
retreats[chunk] = nil
|
||||
end
|
||||
|
||||
local rallyTick = rallys[chunk]
|
||||
if rallyTick and ((tick - rallyTick) > INTERVAL_RALLY) then
|
||||
if rallyTick and ((tick - rallyTick) > COOLDOWN_RALLY) then
|
||||
rallys[chunk] = nil
|
||||
end
|
||||
|
||||
local settlerTick = settlers[chunk]
|
||||
if settlerTick and ((tick - settlerTick) > 0) then
|
||||
settlers[chunk] = nil
|
||||
end
|
||||
|
||||
local drainTick = drained[chunk]
|
||||
if drainTick and ((tick - drainTick) > 0) then
|
||||
drained[chunk] = nil
|
||||
@ -362,11 +329,11 @@ function mapProcessor.processActiveNests(map, surface, tick)
|
||||
local processActiveNest = map.processActiveNest
|
||||
local slot = processActiveNest[tick]
|
||||
if slot then
|
||||
local natives = map.natives
|
||||
for i=1,#slot do
|
||||
local chunk = slot[i]
|
||||
if (getNestActiveness(map, chunk) > 0) then
|
||||
createSpawnerProxy(map, surface, chunk)
|
||||
-- setNestActiveTick(map, chunk, tick)
|
||||
processNestActiveness(map, chunk, natives, surface)
|
||||
local nextTick = tick + DURATION_ACTIVE_NEST
|
||||
local nextSlot = processActiveNest[nextTick]
|
||||
if not nextSlot then
|
||||
@ -382,7 +349,75 @@ function mapProcessor.processActiveNests(map, surface, tick)
|
||||
end
|
||||
end
|
||||
|
||||
function mapProcessor.processVengence(map, surface, tick)
|
||||
local natives = map.natives
|
||||
local ss = natives.vengenceQueue
|
||||
-- local generated = 0
|
||||
local chunk, count = next(ss, map.deployVengenceIterator)
|
||||
-- for i=1,3 do
|
||||
if not chunk then
|
||||
map.deployVengenceIterator = nil
|
||||
-- break
|
||||
else
|
||||
-- generated = generated + 1
|
||||
formVengenceSquad(map, surface, chunk)
|
||||
local nextChunk
|
||||
nextChunk, count = next(ss, chunk)
|
||||
ss[chunk] = nil
|
||||
chunk = nextChunk
|
||||
end
|
||||
-- end
|
||||
map.deployVengenceIterator = chunk
|
||||
end
|
||||
|
||||
local function processSpawners(map, surface, tick, natives, iteration, iterator, chunks)
|
||||
|
||||
local bases = map.chunkToBase
|
||||
local chunk, count = next(chunks, map[iterator])
|
||||
for i=1,iteration do
|
||||
if not chunk then
|
||||
map[iterator] = nil
|
||||
return
|
||||
else
|
||||
if canMigrate(natives, surface) then
|
||||
formSettlers(map, surface, chunk, tick)
|
||||
elseif (canAttack(natives, surface, tick)) then
|
||||
formSquads(map, surface, chunk, tick)
|
||||
end
|
||||
|
||||
|
||||
if (natives.newEnemies) then
|
||||
local base = bases[chunk]
|
||||
if base and ((tick - base.tick) > BASE_PROCESS_INTERVAL) then
|
||||
processBase(chunk, surface, natives, tick, base)
|
||||
end
|
||||
end
|
||||
|
||||
chunk, count = next(chunks, chunk)
|
||||
end
|
||||
end
|
||||
map[iterator] = chunk
|
||||
end
|
||||
|
||||
function mapProcessor.processSpawners(map, surface, tick)
|
||||
local chunks
|
||||
local natives = map.natives
|
||||
|
||||
if (natives.state ~= AI_STATE_PEACEFUL) then
|
||||
if (natives.state == AI_STATE_MIGRATING) or
|
||||
((natives.state == AI_STATE_SIEGE) and natives.temperament <= 0.5)
|
||||
then
|
||||
processSpawners(map, surface, tick, natives, 2, "processMigrationIterator", map.chunkToNests)
|
||||
else
|
||||
if (natives.state ~= AI_STATE_AGGRESSIVE) then
|
||||
processSpawners(map, surface, tick, natives, 1, "processActiveSpawnerIterator", map.chunkToActiveNest)
|
||||
processSpawners(map, surface, tick, natives, 1, "processActiveRaidSpawnerIterator", map.chunkToActiveRaidNest)
|
||||
else
|
||||
processSpawners(map, surface, tick, natives, 2, "processActiveSpawnerIterator", map.chunkToActiveNest)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mapProcessorG = mapProcessor
|
||||
return mapProcessor
|
||||
|
||||
|
||||
|
@ -31,25 +31,25 @@ local distortPosition = mathUtils.distortPosition
|
||||
|
||||
function movementUtils.findMovementPosition(surface, position)
|
||||
local pos = position
|
||||
if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then
|
||||
pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 15, 2, true)
|
||||
end
|
||||
-- if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then
|
||||
pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 10, 2, false)
|
||||
-- end
|
||||
return pos
|
||||
end
|
||||
|
||||
function movementUtils.findMovementPositionEntity(entityName, surface, position)
|
||||
local pos = position
|
||||
if not surface.can_place_entity({name=entityName, position=pos}) then
|
||||
-- if not surface.can_place_entity({name=entityName, position=pos}) then
|
||||
pos = surface.find_non_colliding_position(entityName, pos, 5, 4, true)
|
||||
end
|
||||
-- end
|
||||
return pos
|
||||
end
|
||||
|
||||
function movementUtils.findMovementPositionDistort(surface, position)
|
||||
local pos = position
|
||||
if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then
|
||||
pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 15, 2, true)
|
||||
end
|
||||
-- if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then
|
||||
pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 10, 2, false)
|
||||
-- end
|
||||
return distortPosition(pos, 8)
|
||||
end
|
||||
|
||||
@ -176,7 +176,6 @@ function movementUtils.scoreNeighborsForSettling(map, chunk, neighborDirectionCh
|
||||
neighborDirectionChunks = getNeighborChunks(map, highestChunk.x, highestChunk.y)
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
|
||||
if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and
|
||||
canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then
|
||||
local score = scoreFunction(squad, neighborChunk)
|
||||
|
@ -104,7 +104,7 @@ function pheromoneUtils.processPheromone(map, chunk, staging)
|
||||
local baseTotal = 0
|
||||
local playerTotal = 0
|
||||
local resourceTotal = 0
|
||||
|
||||
|
||||
local neighborCount = 0
|
||||
|
||||
local neighbor
|
||||
@ -113,151 +113,175 @@ function pheromoneUtils.processPheromone(map, chunk, staging)
|
||||
local chunkPass = getPassable(map, chunk)
|
||||
|
||||
if (chunkPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighbor = tempNeighbors[2]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
neighbor = tempNeighbors[2]
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
|
||||
neighborCount = neighborCount + 1
|
||||
-- movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
-- baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
-- playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
-- resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[7]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[4]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[5]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[1]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[3]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[6]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[8]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if (neighborPass == CHUNK_ALL_DIRECTIONS) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
elseif (chunkPass == CHUNK_EAST_WEST) then
|
||||
|
||||
neighbor = tempNeighbors[4]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[5]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
elseif (chunkPass == CHUNK_NORTH_SOUTH) then
|
||||
|
||||
neighbor = tempNeighbors[2]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
|
||||
neighbor = tempNeighbors[7]
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighbor ~= -1) and
|
||||
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
|
||||
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource)
|
||||
if (neighbor ~= -1) then
|
||||
neighborPass = getPassable(map, neighbor)
|
||||
if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
|
||||
neighborCount = neighborCount + 1
|
||||
movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
|
||||
baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
|
||||
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
|
||||
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local neighborDiv = 0
|
||||
if neighborCount ~= 0 then
|
||||
neighborDiv = NEIGHBOR_DIVIDER[neighborCount]
|
||||
chunkMovement = chunkMovement + (neighborDiv * (movementTotal - (chunkMovement * neighborCount)))
|
||||
chunkBase = chunkBase + (neighborDiv * (baseTotal - (chunkBase * neighborCount)))
|
||||
chunkPlayer = chunkPlayer + (neighborDiv * (playerTotal - (chunkPlayer * neighborCount)))
|
||||
chunkResource = chunkResource + (neighborDiv * (resourceTotal - (chunkResource * neighborCount)))
|
||||
end
|
||||
|
||||
staging[MOVEMENT_PHEROMONE] = (chunkMovement + (neighborDiv * movementTotal)) * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[BASE_PHEROMONE] = (chunkBase + (neighborDiv * baseTotal)) * BASE_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[PLAYER_PHEROMONE] = (chunkPlayer + (neighborDiv * playerTotal)) * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[MOVEMENT_PHEROMONE] = chunkMovement * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[BASE_PHEROMONE] = chunkBase * BASE_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[PLAYER_PHEROMONE] = chunkPlayer * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
if clear then
|
||||
staging[RESOURCE_PHEROMONE] = (chunkResource + (neighborDiv * resourceTotal)) * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
staging[RESOURCE_PHEROMONE] = chunkResource * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating
|
||||
else
|
||||
staging[RESOURCE_PHEROMONE] = (chunkResource + (neighborDiv * resourceTotal)) * 0.01
|
||||
staging[RESOURCE_PHEROMONE] = chunkResource * 0.01
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -76,7 +76,6 @@ local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
||||
local positionFromDirectionAndFlat = mapUtils.positionFromDirectionAndFlat
|
||||
|
||||
local createSquad = unitGroupUtils.createSquad
|
||||
local membersToSquad = unitGroupUtils.membersToSquad
|
||||
|
||||
local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
|
||||
|
||||
@ -108,14 +107,14 @@ local function scoreAttackLocation(natives, squad, neighborChunk)
|
||||
if (movementPheromone >= 0) then
|
||||
damage = movementPheromone + (neighborChunk[BASE_PHEROMONE]) + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
|
||||
else
|
||||
damage = (neighborChunk[BASE_PHEROMONE] * (1 - (movementPheromone / -natives.retreatThreshold))) + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
|
||||
damage = (neighborChunk[BASE_PHEROMONE] * (1 - (movementPheromone / -natives.retreatThreshold))) + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER) + (getPlayerBaseGenerator(natives.map, neighborChunk) * PLAYER_PHEROMONE_MULTIPLER)
|
||||
end
|
||||
|
||||
return damage -- - lookupMovementPenalty(squad, neighborChunk)
|
||||
end
|
||||
|
||||
local function scoreAttackKamikazeLocation(natives, squad, neighborChunk)
|
||||
local damage = neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
|
||||
local damage = neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER) + (getPlayerBaseGenerator(natives.map, neighborChunk) * PLAYER_PHEROMONE_MULTIPLER)
|
||||
return damage -- - lookupMovementPenalty(squad, neighborChunk)
|
||||
end
|
||||
|
||||
@ -140,7 +139,6 @@ local function settleMove(map, squad, surface)
|
||||
groupPosition.y,
|
||||
squad.originPosition.x,
|
||||
squad.originPosition.y)
|
||||
|
||||
local cmd
|
||||
local position
|
||||
local position2
|
||||
@ -165,18 +163,7 @@ local function settleMove(map, squad, surface)
|
||||
|
||||
squad.status = SQUAD_BUILDING
|
||||
|
||||
map.buildPositionTop.x = position.x - BASE_CLEAN_DISTANCE
|
||||
map.buildPositionTop.y = position.y - BASE_CLEAN_DISTANCE
|
||||
map.buildPositionBottom.x = position.x + BASE_CLEAN_DISTANCE
|
||||
map.buildPositionBottom.y = position.y + BASE_CLEAN_DISTANCE
|
||||
|
||||
local entities = surface.find_entities_filtered(map.filteredEntitiesClearBuildingQuery)
|
||||
for i=1,#entities do
|
||||
local entity = entities[i]
|
||||
if entity.valid and (entity.type ~= "cliff") then
|
||||
entity.die()
|
||||
end
|
||||
end
|
||||
surface.create_entity(map.createBuildCloudQuery)
|
||||
|
||||
group.set_command(cmd)
|
||||
else
|
||||
@ -186,70 +173,52 @@ local function settleMove(map, squad, surface)
|
||||
scoreFunction,
|
||||
squad)
|
||||
|
||||
|
||||
if (attackChunk == -1) then
|
||||
cmd = map.wonderCommand
|
||||
group.set_command(cmd)
|
||||
return
|
||||
else
|
||||
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
|
||||
position = findMovementPosition(surface, targetPosition)
|
||||
|
||||
elseif (attackDirection ~= 0) then
|
||||
local attackPlayerThreshold = natives.attackPlayerThreshold
|
||||
|
||||
if not position then
|
||||
if (nextAttackChunk ~= -1) then
|
||||
attackChunk = nextAttackChunk
|
||||
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
|
||||
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
|
||||
position = findMovementPosition(surface, targetPosition2)
|
||||
else
|
||||
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
|
||||
position = findMovementPosition(surface, targetPosition)
|
||||
end
|
||||
|
||||
if position then
|
||||
targetPosition.x = position.x
|
||||
targetPosition.y = position.y
|
||||
else
|
||||
cmd = map.wonderCommand
|
||||
group.set_command(cmd)
|
||||
return
|
||||
end
|
||||
|
||||
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) or
|
||||
(attackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold)
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
else
|
||||
targetPosition.x = position.x
|
||||
targetPosition.y = position.y
|
||||
|
||||
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) or
|
||||
(attackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold)
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
cmd = map.moveCommand
|
||||
if squad.rabid or squad.kamikaze then
|
||||
cmd.distraction = DEFINES_DISTRACTION_NONE
|
||||
else
|
||||
cmd = map.moveCommand
|
||||
if squad.rabid or squad.kamikaze then
|
||||
cmd.distraction = DEFINES_DISTRACTION_NONE
|
||||
else
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
end
|
||||
|
||||
if (nextAttackChunk ~= -1) then
|
||||
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
|
||||
|
||||
position2 = findMovementPosition(surface, targetPosition2)
|
||||
|
||||
if position2 then
|
||||
targetPosition.x = position2.x
|
||||
targetPosition.y = position2.y
|
||||
|
||||
if ((cmd ~= map.attackCommand) and
|
||||
((getPlayerBaseGenerator(map, nextAttackChunk) ~= 0) or
|
||||
(nextAttackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold)))
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (attackDirection == 0) then
|
||||
else
|
||||
cmd = map.settleCommand
|
||||
if squad.kamikaze then
|
||||
cmd.distraction = DEFINES_DISTRACTION_NONE
|
||||
@ -259,32 +228,21 @@ local function settleMove(map, squad, surface)
|
||||
|
||||
squad.status = SQUAD_BUILDING
|
||||
|
||||
map.buildPositionTop.x = targetPosition.x - BASE_CLEAN_DISTANCE
|
||||
map.buildPositionTop.y = targetPosition.y - BASE_CLEAN_DISTANCE
|
||||
map.buildPositionBottom.x = targetPosition.x + BASE_CLEAN_DISTANCE
|
||||
map.buildPositionBottom.y = targetPosition.y + BASE_CLEAN_DISTANCE
|
||||
|
||||
local entities = surface.find_entities_filtered(map.filteredEntitiesClearBuildingQuery)
|
||||
for i=1,#entities do
|
||||
local entity = entities[i]
|
||||
if entity.valid and (entity.type ~= "cliff") then
|
||||
entity.die()
|
||||
end
|
||||
end
|
||||
|
||||
group.set_command(cmd)
|
||||
else
|
||||
group.set_command(cmd)
|
||||
surface.create_entity(map.createBuildCloudQuery)
|
||||
end
|
||||
|
||||
group.set_command(cmd)
|
||||
end
|
||||
end
|
||||
|
||||
local function attackMove(map, squad, surface)
|
||||
|
||||
local targetPosition = map.position
|
||||
local targetPosition2 = map.position2
|
||||
|
||||
local group = squad.group
|
||||
|
||||
local position
|
||||
local groupPosition = group.position
|
||||
local x, y = positionToChunkXY(groupPosition)
|
||||
local chunk = getChunkByXY(map, x, y)
|
||||
@ -305,68 +263,45 @@ local function attackMove(map, squad, surface)
|
||||
cmd = map.wonderCommand
|
||||
group.set_command(cmd)
|
||||
return
|
||||
elseif (nextAttackChunk ~= -1) then
|
||||
attackChunk = nextAttackChunk
|
||||
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
|
||||
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
|
||||
position = findMovementPosition(surface, targetPosition2)
|
||||
else
|
||||
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
|
||||
|
||||
local attackPlayerThreshold = map.natives.attackPlayerThreshold
|
||||
local position = findMovementPosition(surface, targetPosition)
|
||||
|
||||
if not position then
|
||||
cmd = map.wonderCommand
|
||||
group.set_command(cmd)
|
||||
return
|
||||
else
|
||||
targetPosition.x = position.x
|
||||
targetPosition.y = position.y
|
||||
|
||||
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) and
|
||||
(attackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold)
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
else
|
||||
cmd = map.moveCommand
|
||||
if squad.rabid or squad.frenzy then
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING
|
||||
else
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local position2
|
||||
|
||||
if (nextAttackChunk ~= -1) then
|
||||
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
|
||||
|
||||
position2 = findMovementPosition(surface, targetPosition2)
|
||||
|
||||
if position2 then
|
||||
targetPosition.x = position2.x
|
||||
targetPosition.y = position2.y
|
||||
|
||||
if (cmd ~= map.attackCommand) and
|
||||
((getPlayerBaseGenerator(map, nextAttackChunk) ~= 0) or
|
||||
(nextAttackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold))
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
group.set_command(cmd)
|
||||
position = findMovementPosition(surface, targetPosition)
|
||||
end
|
||||
|
||||
if not position then
|
||||
cmd = map.wonderCommand
|
||||
group.set_command(cmd)
|
||||
return
|
||||
else
|
||||
targetPosition.x = position.x
|
||||
targetPosition.y = position.y
|
||||
end
|
||||
|
||||
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) and
|
||||
(attackChunk[PLAYER_PHEROMONE] >= map.natives.attackPlayerThreshold)
|
||||
then
|
||||
cmd = map.attackCommand
|
||||
|
||||
if not squad.rabid then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = groupPosition.x
|
||||
squad.frenzyPosition.y = groupPosition.y
|
||||
end
|
||||
else
|
||||
cmd = map.moveCommand
|
||||
if squad.rabid or squad.frenzy then
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING
|
||||
else
|
||||
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
|
||||
end
|
||||
end
|
||||
|
||||
group.set_command(cmd)
|
||||
end
|
||||
|
||||
local function buildMove(map, squad, surface)
|
||||
@ -385,53 +320,36 @@ local function buildMove(map, squad, surface)
|
||||
end
|
||||
|
||||
function squadAttack.squadDispatch(map, surface, squad)
|
||||
-- local profiler = game.create_profiler()
|
||||
local group = squad.group
|
||||
if group and group.valid then
|
||||
local memberCount = #group.members
|
||||
if (memberCount == 0) then
|
||||
removeSquadFromChunk(map, squad)
|
||||
local deathGen = getDeathGenerator(map, squad.chunk)
|
||||
local penalties = squad.penalties
|
||||
for xc=1,mMin(#squad.penalties,5) do
|
||||
addDeathGenerator(map,
|
||||
penalties[xc].c,
|
||||
deathGen * DIVISOR_DEATH_TRAIL_TABLE[xc])
|
||||
end
|
||||
group.destroy()
|
||||
elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
|
||||
local members = group.members
|
||||
unitGroupUtils.recycleBiters(natives, members)
|
||||
removeSquadFromChunk(map, squad)
|
||||
group.destroy()
|
||||
else
|
||||
local status = squad.status
|
||||
|
||||
if (status == SQUAD_RAIDING) then
|
||||
attackMove(map, squad, surface)
|
||||
elseif (status == SQUAD_SETTLING) then
|
||||
local status = squad.status
|
||||
if (status == SQUAD_RAIDING) then
|
||||
attackMove(map, squad, surface)
|
||||
elseif (status == SQUAD_SETTLING) then
|
||||
settleMove(map, squad, surface)
|
||||
elseif (status == SQUAD_RETREATING) then
|
||||
if squad.settlers then
|
||||
squad.status = SQUAD_SETTLING
|
||||
settleMove(map, squad, surface)
|
||||
elseif (status == SQUAD_RETREATING) then
|
||||
if squad.settlers then
|
||||
squad.status = SQUAD_SETTLING
|
||||
settleMove(map, squad, surface)
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
attackMove(map, squad, surface)
|
||||
end
|
||||
elseif (status == SQUAD_BUILDING) then
|
||||
removeSquadFromChunk(map, squad)
|
||||
buildMove(map, squad, surface)
|
||||
elseif (status == SQUAD_GUARDING) then
|
||||
if squad.settlers then
|
||||
squad.status = SQUAD_SETTLING
|
||||
settleMove(map, squad, surface)
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
attackMove(map, squad, surface)
|
||||
end
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
attackMove(map, squad, surface)
|
||||
end
|
||||
elseif (status == SQUAD_BUILDING) then
|
||||
removeSquadFromChunk(map, squad)
|
||||
buildMove(map, squad, surface)
|
||||
elseif (status == SQUAD_GUARDING) then
|
||||
if squad.settlers then
|
||||
squad.status = SQUAD_SETTLING
|
||||
settleMove(map, squad, surface)
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
attackMove(map, squad, surface)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- game.print({"", "--dispatch4 ", profiler})
|
||||
end
|
||||
|
||||
squadAttackG = squadAttack
|
||||
|
@ -21,7 +21,7 @@ local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER
|
||||
|
||||
local SQUAD_RETREATING = constants.SQUAD_RETREATING
|
||||
|
||||
local INTERVAL_RETREAT = constants.INTERVAL_RETREAT
|
||||
local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
|
||||
|
||||
-- imported functions
|
||||
|
||||
@ -54,23 +54,24 @@ local function scoreRetreatLocation(map, neighborChunk)
|
||||
-(getPlayerBaseGenerator(map, neighborChunk) * 1000))
|
||||
end
|
||||
|
||||
function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radius, artilleryBlast)
|
||||
if (tick - getRetreatTick(map, chunk) > INTERVAL_RETREAT) and
|
||||
((getEnemyStructureCount(map, chunk) == 0) or artilleryBlast)
|
||||
then
|
||||
function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radius)
|
||||
if (tick - getRetreatTick(map, chunk) > COOLDOWN_RETREAT) and (getEnemyStructureCount(map, chunk) == 0) then
|
||||
local performRetreat = false
|
||||
local enemiesToSquad = nil
|
||||
|
||||
local squad
|
||||
local groupMembers
|
||||
if group and group.valid then
|
||||
squad = map.natives.groupNumberToSquad[group.group_number]
|
||||
if not squad then
|
||||
squad = createSquad(position, surface, group)
|
||||
squad.kamikaze = mRandom() < calculateKamikazeThreshold(group.members, natives)
|
||||
groupMembers = group.members
|
||||
squad.kamikaze = mRandom() < calculateKamikazeThreshold(#groupMembers, natives)
|
||||
end
|
||||
end
|
||||
|
||||
if not squad then
|
||||
print("grabbing people", position.x, position.y)
|
||||
enemiesToSquad = map.enemiesToSquad
|
||||
local unitCount = 0
|
||||
local units = surface.find_enemy_units(position, radius)
|
||||
@ -83,16 +84,16 @@ function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radi
|
||||
end
|
||||
enemiesToSquad.len = unitCount
|
||||
if (mRandom() < calculateKamikazeThreshold(unitCount, map.natives)) then
|
||||
setRetreatTick(map, chunk, tick)
|
||||
return
|
||||
end
|
||||
performRetreat = unitCount > 6
|
||||
performRetreat = false
|
||||
else
|
||||
performRetreat = unitCount > 6
|
||||
end
|
||||
elseif squad.group and squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then
|
||||
performRetreat = #squad.group.members > 6
|
||||
performRetreat = #groupMembers > 6
|
||||
end
|
||||
|
||||
setRetreatTick(map, chunk, tick)
|
||||
if performRetreat then
|
||||
setRetreatTick(map, chunk, tick)
|
||||
local exitPath,exitDirection,nextExitPath,nextExitDirection = scoreNeighborsForRetreat(chunk,
|
||||
getNeighborChunks(map,
|
||||
chunk.x,
|
||||
@ -140,7 +141,7 @@ function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radi
|
||||
if enemiesToSquad then
|
||||
membersToSquad(cmd, enemiesToSquad.len, enemiesToSquad, artilleryBlast)
|
||||
else
|
||||
membersToSquad(cmd, #squad.group.members, squad.group.members, true)
|
||||
membersToSquad(cmd, #groupMembers, groupMembers, true)
|
||||
if squad.rabid then
|
||||
newSquad.rabid = true
|
||||
end
|
||||
|
@ -15,6 +15,7 @@ local movementUtils = require("MovementUtils")
|
||||
|
||||
local DEFINES_GROUP_FINISHED = defines.group_state.finished
|
||||
|
||||
local DIVISOR_DEATH_TRAIL_TABLE = constants.DIVISOR_DEATH_TRAIL_TABLE
|
||||
local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE
|
||||
|
||||
local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
|
||||
@ -36,6 +37,11 @@ local mRandom = math.random
|
||||
|
||||
local findMovementPosition = movementUtils.findMovementPosition
|
||||
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
|
||||
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
|
||||
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
|
||||
|
||||
local next = next
|
||||
local table_size = table_size
|
||||
|
||||
local mLog = math.log10
|
||||
|
||||
@ -139,15 +145,21 @@ function unitGroupUtils.createSquad(position, surface, group, settlers)
|
||||
end
|
||||
|
||||
function unitGroupUtils.cleanSquads(natives, iterator)
|
||||
local profiler = game.create_profiler()
|
||||
local squads = natives.groupNumberToSquad
|
||||
local map = natives.map
|
||||
|
||||
local k, squad = next(squads, iterator)
|
||||
local nextK
|
||||
for i=1,2 do
|
||||
if not k then
|
||||
return nil
|
||||
elseif not squad.group.valid then
|
||||
-- for i=1,2 do
|
||||
if not k then
|
||||
if (table_size(squads) == 0) then
|
||||
-- this is needed as the next command remembers the max length a table has been
|
||||
natives.groupNumberToSquad = {}
|
||||
end
|
||||
else
|
||||
local group = squad.group
|
||||
if not group.valid then
|
||||
removeSquadFromChunk(map, squad)
|
||||
if (map.regroupIterator == k) then
|
||||
map.regroupIterator = nil
|
||||
@ -155,9 +167,39 @@ function unitGroupUtils.cleanSquads(natives, iterator)
|
||||
nextK,squad = next(squads, k)
|
||||
squads[k] = nil
|
||||
k = nextK
|
||||
-- else
|
||||
-- game.print({"", "3b", profiler})
|
||||
-- profiler.restart()
|
||||
-- local members = group.members
|
||||
-- local memberCount = #members
|
||||
-- if (memberCount == 0) then
|
||||
-- game.print({"", "4a", profiler})
|
||||
-- profiler.restart()
|
||||
-- local deathGen = getDeathGenerator(map, squad.chunk)
|
||||
-- local penalties = squad.penalties
|
||||
-- for xc=1,mMin(#squad.penalties,5) do
|
||||
-- addDeathGenerator(map,
|
||||
-- penalties[xc].c,
|
||||
-- deathGen * DIVISOR_DEATH_TRAIL_TABLE[xc])
|
||||
-- end
|
||||
-- removeSquadFromChunk(map, squad)
|
||||
-- group.destroy()
|
||||
-- game.print({"", "4ea", profiler})
|
||||
-- profiler.restart()
|
||||
-- elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
|
||||
-- game.print({"", "4b", profiler})
|
||||
-- profiler.restart()
|
||||
-- unitGroupUtils.recycleBiters(natives, members)
|
||||
-- removeSquadFromChunk(map, squad)
|
||||
-- group.destroy()
|
||||
-- game.print({"", "4eb", profiler})
|
||||
-- profiler.restart()
|
||||
-- end
|
||||
-- game.print({"", "3be", profiler})
|
||||
end
|
||||
end
|
||||
return k
|
||||
-- end
|
||||
map.squadIterator = k
|
||||
end
|
||||
|
||||
function unitGroupUtils.membersToSquad(cmd, size, members, overwriteGroup)
|
||||
@ -185,6 +227,7 @@ end
|
||||
function unitGroupUtils.regroupSquads(natives, iterator)
|
||||
local map = natives.map
|
||||
local squads = natives.groupNumberToSquad
|
||||
local cmd = map.mergeGroupCommand
|
||||
|
||||
local k, squad = iterator, nil
|
||||
for i=1,SQUAD_QUEUE_SIZE do
|
||||
@ -194,42 +237,45 @@ function unitGroupUtils.regroupSquads(natives, iterator)
|
||||
else
|
||||
local group = squad.group
|
||||
if group and group.valid then
|
||||
cmd.group = group
|
||||
local groupState = group.state
|
||||
if (groupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
|
||||
(groupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
|
||||
then
|
||||
local memberCount = #group.members
|
||||
if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
|
||||
local status = squad.status
|
||||
local chunk = squad.chunk
|
||||
-- local memberCount = #group.members
|
||||
-- if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
|
||||
local status = squad.status
|
||||
local chunk = squad.chunk
|
||||
|
||||
if (chunk ~= -1) then
|
||||
for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do
|
||||
if (mergeSquad ~= squad) then
|
||||
local mergeGroup = mergeSquad.group
|
||||
if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then
|
||||
local mergeGroupState = mergeGroup.state
|
||||
if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
|
||||
(mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
|
||||
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
|
||||
mergeGroup.destroy()
|
||||
end
|
||||
squad.status = SQUAD_GUARDING
|
||||
memberCount = memberCount + mergeCount
|
||||
if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
|
||||
break
|
||||
end
|
||||
end
|
||||
if (chunk ~= -1) then
|
||||
for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do
|
||||
if (mergeSquad ~= squad) then
|
||||
local mergeGroup = mergeSquad.group
|
||||
if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then
|
||||
local mergeGroupState = mergeGroup.state
|
||||
if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
|
||||
(mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
|
||||
then
|
||||
print("merging group")
|
||||
mergeGroup.set_command(cmd)
|
||||
-- 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
|
||||
-- mergeGroup.destroy()
|
||||
-- end
|
||||
squad.status = SQUAD_GUARDING
|
||||
-- memberCount = memberCount + mergeCount
|
||||
-- if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
|
||||
-- break
|
||||
-- end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -18710,7 +18710,6 @@ rampant-enableNEUnits=World: Enable NE as a faction
|
||||
rampant-disallowFriendlyFire=Safety: Disallow Friendly Fire Splash Damage
|
||||
rampant-tierStart=World: Beginning enemy level
|
||||
rampant-tierEnd=World: Ending enemy level
|
||||
rampant-disableVanillaAI=AI: Disable Vanilla AI
|
||||
rampant-enableMigration=AI: Enable Migration
|
||||
rampant-liteMode=Optimization: Lite mode
|
||||
|
||||
@ -18806,7 +18805,6 @@ rampant-newEnemyVariations=This number corresponds to the number of variations p
|
||||
rampant-disallowFriendlyFire=Prevents enemy spitters and worms from damaging units or buildings from the same force through splash damage
|
||||
rampant-tierStart=This is the starting level of the enemy that will be used when generating the set of enemies for the specified number of tiers and increases linearly to the end tier for as many tiers selected. Roughly healthwise each tier is a follows (1-15,2-75,3-150,4-250,5-1000,6-2000,7-3500,8-7500,9-15000,10-30000). min 1, max 10
|
||||
rampant-tierEnd=This is the ending tier level that is reached after increasing linearly from the start tier for as many tiers selected. Roughly healthwise each tier is a follows (1-15,2-75,3-150,4-250,5-1000,6-2000,7-3500,8-7500,9-15000,10-30000). min 1, max 10
|
||||
rampant-disableVanillaAI=This will turn off the vanilla attack waves and the vanilla biter expansion.
|
||||
rampant-enableMigration=This will allow the ai to expand its worms and nests. Respects the map settings for biter expansion.
|
||||
|
||||
rampant-enableShrinkNestsAndWorms=Reduce the collision box size of nests and worms by 50%. May cause overlapping entities due to the collision box being smaller than the entity graphic.
|
||||
|
@ -1,5 +1,6 @@
|
||||
local biterFunctions = require("prototypes/utils/BiterUtils")
|
||||
local constants = require("libs/Constants")
|
||||
local smokeUtils = require("prototypes/utils/SmokeUtils")
|
||||
|
||||
data:extend({
|
||||
biterFunctions.makeBiter({
|
||||
@ -83,3 +84,39 @@ for t=1,11 do
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
smokeUtils.makeNewCloud(
|
||||
{
|
||||
name = "build-clear",
|
||||
wind = false,
|
||||
scale = 9,
|
||||
duration = 540,
|
||||
cooldown = 10,
|
||||
tint = { r=0.7, g=0.2, b=0.7 }
|
||||
},
|
||||
{
|
||||
type = "area",
|
||||
radius = 17,
|
||||
force = "not-same",
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 8, type = "poison"}
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 8, type = "acid"}
|
||||
},
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 8, type = "fire"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -2,6 +2,145 @@ local smokeUtils = {}
|
||||
|
||||
-- module code
|
||||
|
||||
function smokeUtils.makeNewCloud(attributes, attack)
|
||||
local name = attributes.name .. "-cloud-rampant"
|
||||
|
||||
data:extend({
|
||||
{
|
||||
type = "smoke-with-trigger",
|
||||
name = "dummy-" .. name,
|
||||
flags = {"not-on-map"},
|
||||
show_when_smoke_off = true,
|
||||
particle_count = 24,
|
||||
particle_spread = { 3.6 * 1.05, 3.6 * 0.6 * 1.05 },
|
||||
particle_distance_scale_factor = 0.5,
|
||||
particle_scale_factor = { 1, 0.707 },
|
||||
particle_duration_variation = 60 * 3,
|
||||
wave_speed = { 0.5 / 80, 0.5 / 60 },
|
||||
wave_distance = { 1, 0.5 },
|
||||
spread_duration_variation = 300 - 20,
|
||||
|
||||
render_layer = "object",
|
||||
|
||||
affected_by_wind = attributes.wind,
|
||||
cyclic = true,
|
||||
duration = attributes.duration or 60 * 20 + 4 * 60,
|
||||
fade_away_duration = 3 * 60,
|
||||
spread_duration = (300 - 20) / 2 ,
|
||||
color = attributes.tint or { r = 0.7, g = 0.9, b = 0.2 }, -- #035b6452
|
||||
|
||||
animation =
|
||||
{
|
||||
width = 152,
|
||||
height = 120,
|
||||
line_length = 5,
|
||||
frame_count = 60,
|
||||
shift = {-0.53125, -0.4375},
|
||||
priority = "high",
|
||||
animation_speed = 0.25,
|
||||
scale = (attributes.scale and attributes.scale * 0.75) or 2.25,
|
||||
filename = "__base__/graphics/entity/smoke/smoke.png",
|
||||
flags = { "smoke" }
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "smoke-with-trigger",
|
||||
name = name,
|
||||
flags = {"not-on-map"},
|
||||
show_when_smoke_off = true,
|
||||
animation =
|
||||
{
|
||||
width = 152,
|
||||
height = 120,
|
||||
line_length = 5,
|
||||
frame_count = 60,
|
||||
shift = {-0.53125, -0.4375},
|
||||
priority = "high",
|
||||
animation_speed = 0.25,
|
||||
filename = "__base__/graphics/entity/smoke/smoke.png",
|
||||
flags = { "smoke" },
|
||||
scale = attributes.scale or 3,
|
||||
tint = attributes.tint or { r = 0.7, g = 0.9, b = 0.2 }
|
||||
},
|
||||
created_effect =
|
||||
{
|
||||
{
|
||||
type = "cluster",
|
||||
cluster_count = (attributes.scale and attributes.scale * 0.5) and 10,
|
||||
distance = (attributes.scale and attributes.scale * 0.8) and 4,
|
||||
distance_deviation = 5,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
type = "create-smoke",
|
||||
show_in_tooltip = false,
|
||||
entity_name = "dummy-" .. name,
|
||||
initial_height = 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type = "cluster",
|
||||
cluster_count = (attributes.scale and attributes.scale * 0.65) and 11,
|
||||
distance = (attributes.scale and attributes.scale * 1.8) and 8 * 1.1,
|
||||
distance_deviation = 2,
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
type = "create-smoke",
|
||||
show_in_tooltip = false,
|
||||
entity_name = "dummy-" .. name,
|
||||
initial_height = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
slow_down_factor = attributes.slowdown or 0,
|
||||
affected_by_wind = attributes.wind,
|
||||
cyclic = true,
|
||||
render_layer = "higher-object-above",
|
||||
duration = attributes.duration or 60 * 20,
|
||||
fade_away_duration = attributes.outDuration or (attributes.duration and attributes.duration * 0.25) or 2 * 60,
|
||||
spread_duration = attributes.inDuration or (attributes.duration and attributes.duration * 0.25) or 10,
|
||||
action = attack or
|
||||
{
|
||||
type = "direct",
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
type = "nested-result",
|
||||
action =
|
||||
{
|
||||
type = "area",
|
||||
radius = 11,
|
||||
entity_flags = {"breaths-air"},
|
||||
action_delivery =
|
||||
{
|
||||
type = "instant",
|
||||
target_effects =
|
||||
{
|
||||
type = "damage",
|
||||
damage = { amount = 8, type = "poison"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
action_cooldown = attributes.cooldown or 30
|
||||
}
|
||||
})
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
|
||||
function smokeUtils.makeCloud(attributes, attack)
|
||||
local name = attributes.name .. "-cloud-rampant"
|
||||
|
||||
|
18
settings.lua
18
settings.lua
@ -393,15 +393,15 @@ data:extend({
|
||||
per_user = false
|
||||
},
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
name = "rampant-disableVanillaAI",
|
||||
description = "rampant-disableVanillaAI",
|
||||
setting_type = 'runtime-global',
|
||||
default_value = true,
|
||||
order = "m[total]-a[ai]",
|
||||
per_user = false
|
||||
},
|
||||
-- {
|
||||
-- type = "bool-setting",
|
||||
-- name = "rampant-disableVanillaAI",
|
||||
-- description = "rampant-disableVanillaAI",
|
||||
-- setting_type = 'runtime-global',
|
||||
-- default_value = true,
|
||||
-- order = "m[total]-a[ai]",
|
||||
-- per_user = false
|
||||
-- },
|
||||
|
||||
{
|
||||
type = "bool-setting",
|
||||
|
@ -219,9 +219,9 @@ function tests.attackOrigin()
|
||||
max_distance = 1000})
|
||||
if (enemy ~= nil) and enemy.valid then
|
||||
print(enemy, enemy.unit_number)
|
||||
enemy.set_command({type=defines.command.attack_area,
|
||||
enemy.set_command({type=defines.command.go_to_location,
|
||||
destination={0,0},
|
||||
radius=32})
|
||||
radius=15})
|
||||
end
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user