1
0
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:
Aaron Veden 2020-05-19 19:37:16 -07:00
parent ed66822afa
commit fcd52cf91d
No known key found for this signature in database
GPG Key ID: FF5990B1C6DD3F84
22 changed files with 985 additions and 681 deletions

View File

@ -35,6 +35,7 @@ function upgrade.attempt(natives, setNewSurface, gameSurfaces)
natives.state = constants.AI_STATE_AGGRESSIVE natives.state = constants.AI_STATE_AGGRESSIVE
natives.safeEntities = {} natives.safeEntities = {}
natives.vengenceQueue = {}
natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value
natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value
@ -150,15 +151,30 @@ function upgrade.attempt(natives, setNewSurface, gameSurfaces)
end end
end end
natives.remainingSquads = 0
natives.groupNumberToSquad = {} natives.groupNumberToSquad = {}
game.forces.enemy.kill_all_units() game.forces.enemy.kill_all_units()
natives.squads = nil natives.squads = nil
natives.pendingAttack = nil natives.pendingAttack = nil
natives.building = nil natives.building = nil
end end
if (global.version < 112) then if (global.version < 113) then
global.version = 112 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 if not setNewSurface then
game.get_surface(natives.activeSurface).print("Rampant - Version 0.18.12") game.get_surface(natives.activeSurface).print("Rampant - Version 0.18.12")

View File

@ -1,10 +1,22 @@
--------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------
Version: 0.18.12 Version: 0.18.12
Date: 16. 4 2020 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: Tweaks:
- Changed ai credits per rocket launched to 5000 - Changed ai credits per rocket launched to 5000
Bugfixes: Bugfixes:
- fixed add movement penalty not using squad chunk - 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 Version: 0.18.11

View File

@ -22,9 +22,9 @@ local upgrade = require("Upgrade")
local config = require("config") local config = require("config")
local aiPredicates = require("libs/AIPredicates") local aiPredicates = require("libs/AIPredicates")
-- constants -- constants
local DIVISOR_DEATH_TRAIL_TABLE = constants.DIVISOR_DEATH_TRAIL_TABLE
local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local INTERVAL_PLAYER_PROCESS = constants.INTERVAL_PLAYER_PROCESS 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_SCAN = constants.INTERVAL_SCAN
local INTERVAL_SQUAD = constants.INTERVAL_SQUAD local INTERVAL_SQUAD = constants.INTERVAL_SQUAD
local INTERVAL_RESQUAD = constants.INTERVAL_RESQUAD 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_TEMPERAMENT = constants.INTERVAL_TEMPERAMENT
local INTERVAL_SPAWNER = constants.INTERVAL_SPAWNER
local HIVE_BUILDINGS = constants.HIVE_BUILDINGS 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 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_GROUP = defines.command.group
local DEFINES_COMMAND_WANDER = defines.command.wander local DEFINES_COMMAND_WANDER = defines.command.wander
local DEFINES_COMMAND_BUILD_BASE = defines.command.build_base local DEFINES_COMMAND_BUILD_BASE = defines.command.build_base
@ -91,6 +93,9 @@ local positionToChunkXY = mapUtils.positionToChunkXY
local temperamentPlanner = aiPlanning.temperamentPlanner local temperamentPlanner = aiPlanning.temperamentPlanner
local processVengence = mapProcessor.processVengence
local processSpawners = mapProcessor.processSpawners
local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator
local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByPosition = mapUtils.getChunkByPosition
@ -122,6 +127,10 @@ local findNearbyBase = baseUtils.findNearbyBase
local processActiveNests = mapProcessor.processActiveNests local processActiveNests = mapProcessor.processActiveNests
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
local retreatUnits = squadDefense.retreatUnits local retreatUnits = squadDefense.retreatUnits
local accountPlayerEntity = chunkUtils.accountPlayerEntity local accountPlayerEntity = chunkUtils.accountPlayerEntity
@ -137,16 +146,18 @@ local cleanSquads = unitGroupUtils.cleanSquads
local upgradeEntity = baseUtils.upgradeEntity local upgradeEntity = baseUtils.upgradeEntity
local rebuildNativeTables = baseUtils.rebuildNativeTables local rebuildNativeTables = baseUtils.rebuildNativeTables
local mMin = math.min
local mRandom = math.random local mRandom = math.random
local tRemove = table.remove local tRemove = table.remove
local sFind = string.find
-- local references to global -- local references to global
local gameSurfaces -- used for manage which surfaces have been visited local gameSurfaces -- used for manage which surfaces have been visited
local map -- manages the chunks that make up the game world local map -- manages the chunks that make up the game world
local natives -- manages the enemy units, structures, and ai local natives -- manages the enemy units, structures, and ai
local pendingChunks -- chunks that have yet to be processed by the mod
-- hook functions -- hook functions
@ -175,17 +186,17 @@ end
local function onLoad() local function onLoad()
map = global.map map = global.map
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks
gameSurfaces = global.gameSurfaces gameSurfaces = global.gameSurfaces
hookEvents() hookEvents()
end end
local function onChunkGenerated(event) 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 -- 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. -- are generated, which messes up the scoring.
if (event.surface.name == natives.activeSurface) then if (event.surface.name == natives.activeSurface) then
pendingChunks[#pendingChunks+1] = event map.pendingChunks[event] = true
end end
end end
@ -201,6 +212,7 @@ local function rebuildMap()
map.processIndex = 1 map.processIndex = 1
map.scanIndex = 1 map.scanIndex = 1
map.pendingChunks = {}
map.chunkToBase = {} map.chunkToBase = {}
map.chunkToNests = {} map.chunkToNests = {}
map.chunkToTurrets = {} map.chunkToTurrets = {}
@ -215,7 +227,6 @@ local function rebuildMap()
map.chunkToRetreats = {} map.chunkToRetreats = {}
map.chunkToRallys = {} map.chunkToRallys = {}
map.chunkToSettler = {}
map.chunkToPassable = {} map.chunkToPassable = {}
map.chunkToPathRating = {} map.chunkToPathRating = {}
@ -229,6 +240,11 @@ local function rebuildMap()
map.squadIterator = nil map.squadIterator = nil
map.regroupIterator = 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. -- preallocating memory to be used in code, making it fast by reducing garbage generated.
map.neighbors = { map.neighbors = {
@ -306,6 +322,10 @@ local function rebuildMap()
"turret" "turret"
} }
} }
map.createBuildCloudQuery = {
name = "build-clear-cloud-rampant",
position = map.position
}
map.activePlayerForces = {"player"} map.activePlayerForces = {"player"}
@ -434,6 +454,13 @@ local function rebuildMap()
use_group_distraction = false use_group_distraction = false
} }
map.mergeGroupCommand = {
type = DEFINES_COMMAND_GROUP,
group = nil,
distraction = DEFINES_DISTRACTION_NONE,
use_group_distraction = false
}
map.fleeCommand = { map.fleeCommand = {
type = DEFINES_COMMAND_FLEE, type = DEFINES_COMMAND_FLEE,
from = nil, from = nil,
@ -507,14 +534,10 @@ local function onModSettingsChange(event)
upgrade.compareTable(natives, "newEnemies", settings.startup["rampant-newEnemies"].value) upgrade.compareTable(natives, "newEnemies", settings.startup["rampant-newEnemies"].value)
upgrade.compareTable(natives, "enemySeed", settings.startup["rampant-enemySeed"].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 natives.enabledMigration = natives.expansion and settings.global["rampant-enableMigration"].value
upgrade.compareTable(natives, "ENEMY_VARIATIONS", settings.startup["rampant-newEnemyVariations"].value) upgrade.compareTable(natives, "ENEMY_VARIATIONS", settings.startup["rampant-newEnemyVariations"].value)
game.forces.enemy.ai_controllable = not natives.disableVanillaAI
return true return true
end end
@ -548,10 +571,6 @@ local function prepWorld(rebuild, surfaceName)
map.natives = natives map.natives = natives
natives.map = map 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 -- queue all current chunks that wont be generated during play
local surface = game.get_surface(natives.activeSurface) local surface = game.get_surface(natives.activeSurface)
local tick = game.tick local tick = game.tick
@ -569,7 +588,7 @@ local function prepWorld(rebuild, surfaceName)
end end
end end
processPendingChunks(map, surface, pendingChunks, tick, rebuild) processPendingChunks(map, surface, tick, rebuild, true)
end end
end end
@ -578,6 +597,7 @@ local function onConfigChanged()
end end
local function onBuild(event) local function onBuild(event)
print("2", game.tick)
local entity = event.created_entity or event.entity local entity = event.created_entity or event.entity
if (entity.surface.name == natives.activeSurface) then if (entity.surface.name == natives.activeSurface) then
if (entity.type == "resource") and (entity.force.name == "neutral") then if (entity.type == "resource") and (entity.force.name == "neutral") then
@ -594,6 +614,7 @@ local function onBuild(event)
end end
local function onMine(event) local function onMine(event)
print("3", game.tick)
local entity = event.entity local entity = event.entity
local surface = entity.surface local surface = entity.surface
if (surface.name == natives.activeSurface) then if (surface.name == natives.activeSurface) then
@ -608,6 +629,7 @@ local function onMine(event)
end end
local function onDeath(event) local function onDeath(event)
print("4", game.tick)
local entity = event.entity local entity = event.entity
if entity.valid then if entity.valid then
local surface = entity.surface local surface = entity.surface
@ -634,14 +656,15 @@ local function onDeath(event)
natives.lostEnemyUnits = natives.lostEnemyUnits + 1 natives.lostEnemyUnits = natives.lostEnemyUnits + 1
retreatUnits(chunk, -- retreatUnits(chunk,
entityPosition, -- entityPosition,
entity.unit_group, -- entity.unit_group,
map, -- map,
surface, -- surface,
tick, -- tick,
(artilleryBlast and RETREAT_SPAWNER_GRAB_RADIUS) or RETREAT_GRAB_RADIUS, -- (artilleryBlast and RETREAT_SPAWNER_GRAB_RADIUS) or RETREAT_GRAB_RADIUS-- ,
artilleryBlast) -- -- artilleryBlast
-- )
if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then
rallyUnits(chunk, map, surface, tick) 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) 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) rallyUnits(chunk, map, surface, tick)
retreatUnits(chunk, -- retreatUnits(chunk,
entityPosition, -- entityPosition,
nil, -- nil,
map, -- map,
surface, -- surface,
tick, -- tick,
RETREAT_SPAWNER_GRAB_RADIUS, -- RETREAT_SPAWNER_GRAB_RADIUS-- ,
(cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret")))) -- -- (cause and ((cause.type == "artillery-wagon") or (cause.type == "artillery-turret")))
-- )
end end
end end
@ -751,6 +775,7 @@ local function onDeath(event)
end end
local function onEnemyBaseBuild(event) local function onEnemyBaseBuild(event)
print("5", game.tick)
local entity = event.entity local entity = event.entity
if entity.valid then if entity.valid then
local surface = entity.surface local surface = entity.surface
@ -782,36 +807,35 @@ local function onEnemyBaseBuild(event)
end end
local function onSurfaceTileChange(event) 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 surfaceIndex = event.surface_index or (event.robot and event.robot.surface and event.robot.surface.index)
local surfaceName = game.surfaces[surfaceIndex].name local surface = game.get_surface(natives.activeSurface)
if (surfaceName == natives.activeSurface) and if (surface.index == surfaceIndex) then
((event.item.name == "landfill") or (event.item.name == "waterfill")) and
event.item
then
local surface = game.get_surface(natives.activeSurface)
local chunks = {} local chunks = {}
local tiles = event.tiles local tiles = event.tiles
for i=1,#tiles do if (event.tile.name == "landfill") or sFind(event.tile.name, "water") then
local position = tiles[i].position for i=1,#tiles do
local chunk = getChunkByPosition(map, position) local position = tiles[i].position
local chunk = getChunkByPosition(map, position)
if (chunk ~= -1) then if (chunk ~= -1) then
map.chunkToPassScan[chunk] = true map.chunkToPassScan[chunk] = true
else else
local x,y = positionToChunkXY(position) local x,y = positionToChunkXY(position)
local addMe = true local addMe = true
for ci=1,#chunks do for ci=1,#chunks do
local c = chunks[ci] local c = chunks[ci]
if (c.x == x) and (c.y == y) then if (c.x == x) and (c.y == y) then
addMe = false addMe = false
break 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
end
if addMe then
local chunkXY = {x=x,y=y}
chunks[#chunks+1] = chunkXY
onChunkGenerated({area = { left_top = chunkXY },
surface = surface})
end end
end end
end end
@ -819,6 +843,7 @@ local function onSurfaceTileChange(event)
end end
local function onResourceDepleted(event) local function onResourceDepleted(event)
print("7", game.tick)
local entity = event.entity local entity = event.entity
if (entity.surface.name == natives.activeSurface) then if (entity.surface.name == natives.activeSurface) then
unregisterResource(entity, map) unregisterResource(entity, map)
@ -826,7 +851,7 @@ local function onResourceDepleted(event)
end end
local function onRobotCliff(event) local function onRobotCliff(event)
print("8", game.tick)
local surface = event.robot.surface local surface = event.robot.surface
if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then
entityForPassScan(map, event.cliff) entityForPassScan(map, event.cliff)
@ -834,6 +859,7 @@ local function onRobotCliff(event)
end end
local function onUsedCapsule(event) local function onUsedCapsule(event)
print("9", game.tick)
local surface = game.players[event.player_index].surface local surface = game.players[event.player_index].surface
if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then if (surface.name == natives.activeSurface) and (event.item.name == "cliff-explosives") then
map.position2Top.x = event.position.x-0.75 map.position2Top.x = event.position.x-0.75
@ -848,6 +874,7 @@ local function onUsedCapsule(event)
end end
local function onRocketLaunch(event) local function onRocketLaunch(event)
print("10", game.tick)
local entity = event.rocket_silo or event.rocket local entity = event.rocket_silo or event.rocket
if entity and entity.valid and (entity.surface.name == natives.activeSurface) then if entity and entity.valid and (entity.surface.name == natives.activeSurface) then
natives.rocketLaunched = natives.rocketLaunched + 1 natives.rocketLaunched = natives.rocketLaunched + 1
@ -856,6 +883,7 @@ local function onRocketLaunch(event)
end end
local function onTriggerEntityCreated(event) local function onTriggerEntityCreated(event)
print("11", game.tick)
local entity = event.entity local entity = event.entity
if entity.valid and (entity.surface.name == natives.activeSurface) and (entity.name == "drain-trigger-rampant") then if entity.valid and (entity.surface.name == natives.activeSurface) and (entity.name == "drain-trigger-rampant") then
local chunk = getChunkByPosition(map, entity.position) local chunk = getChunkByPosition(map, entity.position)
@ -868,13 +896,11 @@ end
local function onInit() local function onInit()
global.map = {} global.map = {}
global.pendingChunks = {}
global.natives = {} global.natives = {}
global.gameSurfaces = {} global.gameSurfaces = {}
map = global.map map = global.map
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks
gameSurfaces = global.gameSurfaces gameSurfaces = global.gameSurfaces
prepWorld(false, "nauvis") prepWorld(false, "nauvis")
@ -882,6 +908,7 @@ local function onInit()
end end
local function onEntitySpawned(event) local function onEntitySpawned(event)
print("12", game.tick)
local entity = event.entity local entity = event.entity
if natives.newEnemies and entity.valid then if natives.newEnemies and entity.valid then
local surface = entity.surface local surface = entity.surface
@ -921,41 +948,76 @@ local function onEntitySpawned(event)
end end
local function onUnitGroupCreated(event) local function onUnitGroupCreated(event)
print("13", game.tick)
local group = event.group 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 if not group.is_script_driven then
squad = createSquad(nil, if not natives.aiNocturnalMode then
nil, squad = createSquad(nil,
group, nil,
mRandom() < 0.75 and canMigrate(natives, game.get_surface(natives.activeSurface))) group,
natives.groupNumberToSquad[group.group_number] = squad 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 end
end end
local function onCommandComplete(event) local function onCommandComplete(event)
-- local msg print("14", game.tick)
-- 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
local unitNumber = event.unit_number local unitNumber = event.unit_number
local squad = natives.groupNumberToSquad[unitNumber] local squad = natives.groupNumberToSquad[unitNumber]
if squad then 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 local group = squad.group
if group and group.valid and (group.surface.name == natives.activeSurface) then 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 end
end end
local function onGroupFinishedGathering(event) local function onGroupFinishedGathering(event)
print("15", game.tick)
local group = event.group local group = event.group
if group.valid then if group.valid then
local unitNumber = group.group_number local unitNumber = group.group_number
@ -967,10 +1029,12 @@ local function onGroupFinishedGathering(event)
end end
local function onForceCreated(event) local function onForceCreated(event)
print("16", game.tick)
map.activePlayerForces[#map.activePlayerForces+1] = event.force.name map.activePlayerForces[#map.activePlayerForces+1] = event.force.name
end end
local function onForceMerged(event) local function onForceMerged(event)
print("17", game.tick)
for i=#map.activePlayerForces,1,-1 do for i=#map.activePlayerForces,1,-1 do
if (map.activePlayerForces[i] == event.source_name) then if (map.activePlayerForces[i] == event.source_name) then
tRemove(map.activePlayerForces, i) tRemove(map.activePlayerForces, i)
@ -980,6 +1044,7 @@ local function onForceMerged(event)
end end
local function onSurfaceRenamed(event) local function onSurfaceRenamed(event)
print("18", game.tick)
if event.old_name == natives.activeSurface then if event.old_name == natives.activeSurface then
natives.activeSurface = event.new_name natives.activeSurface = event.new_name
end end
@ -990,6 +1055,7 @@ local function onSurfaceRenamed(event)
end end
local function onSurfaceCleared(event) local function onSurfaceCleared(event)
print("19", game.tick)
local surface = game.get_surface(event.surface_index) local surface = game.get_surface(event.surface_index)
if surface and surface.valid and (surface.name == natives.activeSurface) then if surface and surface.valid and (surface.name == natives.activeSurface) then
prepWorld(true, natives.activeSurface) prepWorld(true, natives.activeSurface)
@ -997,6 +1063,7 @@ local function onSurfaceCleared(event)
end end
local function onPlayerChangedSurface(event) local function onPlayerChangedSurface(event)
print("20", game.tick)
local player = game.players[event.player_index] local player = game.players[event.player_index]
local surface local surface
if player and player.valid and not settings.get_player_settings(player)["rampant-suppress-surface-change-warnings"].value 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 end
local function onSurfaceDeleted(event) local function onSurfaceDeleted(event)
print("21", game.tick)
local surface = game.get_surface(event.surface_index) local surface = game.get_surface(event.surface_index)
if surface and surface.valid then if surface and surface.valid then
if (surface.name == natives.activeSurface) then if (surface.name == natives.activeSurface) then
@ -1035,68 +1103,106 @@ end
script.on_nth_tick(INTERVAL_PLAYER_PROCESS, script.on_nth_tick(INTERVAL_PLAYER_PROCESS,
function (event) function (event)
print("22", game.tick)
local profiler = game.create_profiler()
local gameRef = game local gameRef = game
processPlayers(gameRef.connected_players, processPlayers(gameRef.connected_players,
map, map,
gameRef.get_surface(natives.activeSurface), gameRef.get_surface(natives.activeSurface),
event.tick) event.tick)
game.print({"", "player", profiler})
end) end)
script.on_nth_tick(INTERVAL_MAP_PROCESS, script.on_nth_tick(INTERVAL_MAP_PROCESS,
function (event) function (event)
print("23", game.tick)
local profiler = game.create_profiler()
local gameRef = game local gameRef = game
processMap(map, -- processMap(map,
gameRef.get_surface(natives.activeSurface), -- gameRef.get_surface(natives.activeSurface),
event.tick) -- event.tick)
game.print({"", "map", profiler})
end) end)
script.on_nth_tick(INTERVAL_SCAN, script.on_nth_tick(INTERVAL_SCAN,
function (event) function (event)
print("24", game.tick)
local profiler = game.create_profiler()
local tick = event.tick local tick = event.tick
local gameRef = game local gameRef = game
local surface = gameRef.get_surface(natives.activeSurface) local surface = gameRef.get_surface(natives.activeSurface)
processPendingChunks(map, surface, pendingChunks, tick) processPendingChunks(map, surface, tick)
scanMap(map, surface, tick) scanMap(map, surface, tick)
processScanChunks(map, surface) processScanChunks(map, surface)
game.print({"", "scan", profiler})
end) end)
script.on_nth_tick(INTERVAL_LOGIC, script.on_nth_tick(INTERVAL_LOGIC,
function (event) function (event)
print("25", game.tick)
local profiler = game.create_profiler()
local tick = event.tick local tick = event.tick
planning(natives, planning(natives,
game.forces.enemy.evolution_factor, game.forces.enemy.evolution_factor,
tick) tick)
map.squadIterator = cleanSquads(natives, map.squadIterator) cleanSquads(natives, map.squadIterator)
if natives.newEnemies then if natives.newEnemies then
recycleBases(natives, tick) recycleBases(natives, tick)
end 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) end)
script.on_nth_tick(INTERVAL_TEMPERAMENT, script.on_nth_tick(INTERVAL_TEMPERAMENT,
function (event) function (event)
print("28", game.tick)
local profiler = game.create_profiler()
temperamentPlanner(natives) temperamentPlanner(natives)
game.print({"", "temperament", profiler})
end) end)
script.on_nth_tick(INTERVAL_RESQUAD, script.on_nth_tick(INTERVAL_RESQUAD,
function () function ()
print("29", game.tick)
local profiler = game.create_profiler()
map.regroupIterator = regroupSquads(natives, map.regroupIterator) map.regroupIterator = regroupSquads(natives, map.regroupIterator)
game.print({"", "regroup", profiler})
end) end)
script.on_event(defines.events.on_tick, script.on_event(defines.events.on_tick,
function (event) function (event)
processActiveNests(map, print("30", game.tick)
game.get_surface(natives.activeSurface), local profiler = game.create_profiler()
event.tick) -- processActiveNests(map,
-- game.get_surface(natives.activeSurface),
-- event.tick)
game.print({"", "processActiveNests", profiler})
end) end)
script.on_event(defines.events.on_surface_cleared, onSurfaceCleared) script.on_event(defines.events.on_surface_cleared, onSurfaceCleared)

View File

@ -5,6 +5,6 @@
"title" : "Rampant", "title" : "Rampant",
"author" : "Veden", "author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", "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"] "dependencies" : ["base >= 0.18.22", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Orbital Ion Cannon", "? RampantArsenal", "? RampantResources", "? ArmouredBiters"]
} }

View File

@ -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_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE 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 local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
@ -52,16 +52,12 @@ local randomTickEvent = mathUtils.randomTickEvent
local mRandom = math.random local mRandom = math.random
local createSpawnerProxies = baseUtils.createSpawnerProxies
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
local getPassable = chunkPropertyUtils.getPassable local getPassable = chunkPropertyUtils.getPassable
local getNestCount = chunkPropertyUtils.getNestCount local getNestCount = chunkPropertyUtils.getNestCount
local getChunkSettlerTick = chunkPropertyUtils.getChunkSettlerTick
local getRaidNestActiveness = chunkPropertyUtils.getRaidNestActiveness local getRaidNestActiveness = chunkPropertyUtils.getRaidNestActiveness
local getNestActiveness = chunkPropertyUtils.getNestActiveness local getNestActiveness = chunkPropertyUtils.getNestActiveness
local setChunkSettlerTick = chunkPropertyUtils.setChunkSettlerTick
local getRallyTick = chunkPropertyUtils.getRallyTick local getRallyTick = chunkPropertyUtils.getRallyTick
local setRallyTick = chunkPropertyUtils.setRallyTick local setRallyTick = chunkPropertyUtils.setRallyTick
@ -121,68 +117,76 @@ local function validUnitGroupLocation(map, neighborChunk)
(getNestCount(map, neighborChunk) == 0) (getNestCount(map, neighborChunk) == 0)
end 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) 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) setRallyTick(map, chunk, tick)
local cX = chunk.x local cX = chunk.x
local cY = chunk.y local cY = chunk.y
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do local startX, endX, stepX, startY, endY, stepY = visitPattern(tick % 4, cX, cY, RALLY_CRY_DISTANCE)
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do local vengenceQueue = map.natives.vengenceQueue
for x=startX, endX, stepX do
for y=startY, endY, stepY do
if (x ~= cX) and (y ~= cY) then if (x ~= cX) and (y ~= cY) then
local rallyChunk = getChunkByXY(map, x, y) local rallyChunk = getChunkByXY(map, x, y)
if (rallyChunk ~= -1) and (getNestCount(map, rallyChunk) > 0) then if (rallyChunk ~= -1) and (getNestCount(map, rallyChunk) > 0) then
if not aiAttackWave.formVengenceSquad(map, surface, rallyChunk) then local count = vengenceQueue[rallyChunk]
return false if not count then
count = 0
vengenceQueue[rallyChunk] = count
end end
vengenceQueue[rallyChunk] = count + 1
end end
end end
end end
end end
return true return true
end end
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) 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 local squadPath, squadDirection
if (natives.state == AI_STATE_SIEGE) then if (natives.state == AI_STATE_SIEGE) then
squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y), squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
@ -197,7 +201,7 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
map) map)
end 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", local squadPosition = surface.find_non_colliding_position("chunk-scanner-squad-rampant",
positionFromDirectionAndChunk(squadDirection, positionFromDirectionAndChunk(squadDirection,
chunk, chunk,
@ -214,14 +218,12 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
10, 10,
natives.expansionMaxDistance) natives.expansionMaxDistance)
local scaledWaveSize = settlerWaveScaling(natives) local scaledWaveSize = settlerWaveScaling(natives)
map.formGroupCommand.group = squad.group map.formGroupCommand.group = squad.group
map.formCommand.unit_count = scaledWaveSize map.formCommand.unit_count = scaledWaveSize
local foundUnits = surface.set_multi_command(map.formCommand) local foundUnits = surface.set_multi_command(map.formCommand)
if (foundUnits > 0) then 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.points = natives.points - AI_SETTLER_COST
natives.groupNumberToSquad[squad.groupNumber] = squad natives.groupNumberToSquad[squad.groupNumber] = squad
else else
@ -232,13 +234,11 @@ function aiAttackWave.formSettlers(map, surface, chunk, tick)
end end
end end
end end
return ((natives.points - AI_SETTLER_COST) > 0) and (natives.remainingSquads > 0)
end end
function aiAttackWave.formVengenceSquad(map, surface, chunk) function aiAttackWave.formVengenceSquad(map, surface, chunk)
local natives = map.natives 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), local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
validUnitGroupLocation, validUnitGroupLocation,
scoreUnitGroupLocation, scoreUnitGroupLocation,
@ -262,7 +262,6 @@ function aiAttackWave.formVengenceSquad(map, surface, chunk)
map.formCommand.unit_count = scaledWaveSize map.formCommand.unit_count = scaledWaveSize
local foundUnits = surface.set_multi_command(map.formCommand) local foundUnits = surface.set_multi_command(map.formCommand)
if (foundUnits > 0) then if (foundUnits > 0) then
createSpawnerProxies(map, surface, chunk, foundUnits)
natives.groupNumberToSquad[squad.groupNumber] = squad natives.groupNumberToSquad[squad.groupNumber] = squad
natives.points = natives.points - AI_VENGENCE_SQUAD_COST natives.points = natives.points - AI_VENGENCE_SQUAD_COST
else else
@ -273,15 +272,13 @@ function aiAttackWave.formVengenceSquad(map, surface, chunk)
end end
end end
end end
return (natives.points - AI_VENGENCE_SQUAD_COST) > 0
end end
function aiAttackWave.formSquads(map, surface, chunk, tick) function aiAttackWave.formSquads(map, surface, chunk, tick)
local natives = map.natives local natives = map.natives
if attackWaveValidCandidate(chunk, natives, map) and if attackWaveValidCandidate(chunk, natives, map) and
(mRandom() < natives.formSquadThreshold) and (mRandom() < natives.formSquadThreshold) and
(natives.remainingSquads > 0) ((natives.points - AI_SQUAD_COST) > 0)
then then
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y), local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
validUnitGroupLocation, validUnitGroupLocation,
@ -308,13 +305,11 @@ function aiAttackWave.formSquads(map, surface, chunk, tick)
if (foundUnits > 0) then if (foundUnits > 0) then
createSpawnerProxies(map, surface, chunk, foundUnits) createSpawnerProxies(map, surface, chunk, foundUnits)
natives.points = natives.points - AI_SQUAD_COST natives.points = natives.points - AI_SQUAD_COST
natives.remainingSquads = natives.remainingSquads - 1
natives.groupNumberToSquad[squad.groupNumber] = squad natives.groupNumberToSquad[squad.groupNumber] = squad
if tick and (natives.state == AI_STATE_AGGRESSIVE) then if tick and (natives.state == AI_STATE_AGGRESSIVE) then
natives.canAttackTick = randomTickEvent(tick, natives.canAttackTick = randomTickEvent(tick,
AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION, AGGRESSIVE_CAN_ATTACK_WAIT_MIN_DURATION,
AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION) AGGRESSIVE_CAN_ATTACK_WAIT_MAX_DURATION)
return false
end end
else else
if (squad.group.valid) then if (squad.group.valid) then
@ -324,8 +319,6 @@ function aiAttackWave.formSquads(map, surface, chunk, tick)
end end
end end
end end
return ((natives.points - AI_SQUAD_COST) > 0) and (natives.remainingSquads > 0)
end end

View File

@ -71,7 +71,7 @@ function aiPlanning.planning(natives, evolution_factor, tick)
local attackWaveMaxSize = natives.attackWaveMaxSize local attackWaveMaxSize = natives.attackWaveMaxSize
natives.retreatThreshold = linearInterpolation(evolution_factor, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX) 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.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.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.15)
natives.attackWaveDeviation = (natives.attackWaveSize * 0.333) natives.attackWaveDeviation = (natives.attackWaveSize * 0.333)

View File

@ -19,8 +19,10 @@ local AI_STATE_ONSLAUGHT = constants.AI_STATE_ONSLAUGHT
-- module code -- module code
function aiPredicates.canAttack(natives, surface) function aiPredicates.canAttack(natives, surface, tick)
local goodAI = ((natives.state == AI_STATE_AGGRESSIVE) or (natives.state == AI_STATE_RAIDING) or (natives.state == AI_STATE_ONSLAUGHT)) 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 notPeaceful = not surface.peaceful_mode
local noctural = (not natives.aiNocturnalMode) or (natives.aiNocturnalMode and surface.darkness > 0.65) local noctural = (not natives.aiNocturnalMode) or (natives.aiNocturnalMode and surface.darkness > 0.65)
return goodAI and notPeaceful and noctural return goodAI and notPeaceful and noctural

View File

@ -76,6 +76,8 @@ local setChunkBase = chunkPropertyUtils.setChunkBase
local getResourceGenerator = chunkPropertyUtils.getResourceGenerator local getResourceGenerator = chunkPropertyUtils.getResourceGenerator
local next = next
local tRemove = table.remove local tRemove = table.remove
local mRandom = math.random local mRandom = math.random
@ -95,50 +97,6 @@ local function evoToTier(natives, evolutionFactor)
return v return v
end 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) function baseUtils.findNearbyBase(map, chunk)
local x = chunk.x local x = chunk.x
local y = chunk.y local y = chunk.y
@ -150,8 +108,7 @@ function baseUtils.findNearbyBase(map, chunk)
local bases = map.natives.bases local bases = map.natives.bases
local closet = MAGIC_MAXIMUM_NUMBER local closet = MAGIC_MAXIMUM_NUMBER
for i=1, #bases do for _, base in pairs(bases) do
local base = bases[i]
local distance = euclideanDistancePoints(base.x, base.y, x, y) local distance = euclideanDistancePoints(base.x, base.y, x, y)
if (distance <= base.distanceThreshold) and (distance < closet) then if (distance <= base.distanceThreshold) and (distance < closet) then
closet = distance closet = distance
@ -283,7 +240,8 @@ local function findEntityUpgrade(baseAlignment, currentEvo, evoIndex, originalEn
end end
local function findBaseInitialAlignment(natives, evoIndex) 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 local result
if mRandom() < 0.05 then if mRandom() < 0.05 then
@ -298,21 +256,23 @@ end
function baseUtils.recycleBases(natives, tick) function baseUtils.recycleBases(natives, tick)
local baseIndex = natives.baseIndex local baseIndex = natives.baseIndex
local bases = natives.bases local bases = natives.bases
local id, base = next(bases, natives.map.recycleBaseIterator)
local endIndex = mMin(baseIndex+BASE_QUEUE_SIZE, #bases) for i=1,2 do
for index = endIndex, baseIndex, -1 do if not id then
local base = bases[index] natives.map.recycleBaseIterator = nil
return
if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then else
tRemove(bases, index) 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
end end
natives.map.recycleBaseIterator = id
if (endIndex == #bases) then
natives.baseIndex = 1
else
natives.baseIndex = endIndex + 1
end
end end
@ -495,12 +455,14 @@ function baseUtils.createBase(natives, chunk, tick, rebuilding)
temperamentTick = 0, temperamentTick = 0,
createdTick = tick, createdTick = tick,
temperament = 0, temperament = 0,
points = 0 points = 0,
id = natives.baseId
} }
natives.baseId = natives.baseId + 1
setChunkBase(natives.map, chunk, base) setChunkBase(natives.map, chunk, base)
natives.bases[#natives.bases+1] = base natives.bases[base.id] = base
return base return base
end end
@ -653,8 +615,7 @@ function baseUtils.rebuildNativeTables(natives, surface, rg)
local evoIndex = evoToTier(natives, natives.evolutionLevel) local evoIndex = evoToTier(natives, natives.evolutionLevel)
for i=1,#natives.bases do for id,base in pairs(natives.bases) do
local base = natives.bases[i]
for x=1,#base.alignment do for x=1,#base.alignment do
local alignment = base.alignment[x] local alignment = base.alignment[x]
if not natives.buildingEvolveLookup[alignment] then if not natives.buildingEvolveLookup[alignment] then

View File

@ -27,6 +27,8 @@ local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
local tSort = table.sort local tSort = table.sort
local abs = math.abs local abs = math.abs
local next = next
local table_size = table_size
local tRemove = table.remove local tRemove = table.remove
@ -49,49 +51,67 @@ local function sorter(a, b)
return (aDistance < bDistance) return (aDistance < bDistance)
end 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 processQueue = map.processQueue
local pendingChunks = map.pendingChunks
local area = map.area local area = map.area
local topOffset = area[1] local topOffset = area[1]
local bottomOffset = area[2] local bottomOffset = area[2]
for i=#pendingStack, 1, -1 do local event = next(pendingChunks, map.chunkProcessorIterator)
local event = pendingStack[i] local endCount = 5
pendingStack[i] = nil if flush then
endCount = table_size(pendingChunks)
local topLeft = event.area.left_top end
local x = topLeft.x for i=1,endCount do
local y = topLeft.y if not event then
map.chunkProcessorIterator = nil
topOffset[1] = x if (table_size(pendingChunks) == 0) then
topOffset[2] = y -- this is needed as the next command remembers the max length a table has been
bottomOffset[1] = x + CHUNK_SIZE map.pendingChunks = {}
bottomOffset[2] = y + CHUNK_SIZE end
break
if map[x] and map[x][y] then
mapScanChunk(map[x][y], surface, map)
else else
if map[x] == nil then local topLeft = event.area.left_top
map[x] = {} local x = topLeft.x
end local y = topLeft.y
local chunk = createChunk(x, y) topOffset[1] = x
topOffset[2] = y
chunk = initialScan(chunk, surface, map, tick, rebuilding) bottomOffset[1] = x + CHUNK_SIZE
bottomOffset[2] = y + CHUNK_SIZE
if (chunk ~= -1) then
map[x][y] = chunk if map[x] and map[x][y] then
processQueue[#processQueue+1] = chunk 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 end
local newEvent,_ = next(pendingChunks, event)
pendingChunks[event] = nil
event = newEvent
end end
end end
map.chunkProcessorIterator = event
if (#processQueue > map.nextChunkSort) or 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 then
map.nextChunkSort = #processQueue + 75 map.nextChunkSort = #processQueue + 150
map.nextChunkSortTick = tick map.nextChunkSortTick = tick
tSort(processQueue, sorter) tSort(processQueue, sorter)
end end

View File

@ -79,23 +79,14 @@ end
function chunkPropertyUtils.setNestCount(map, chunk, count) function chunkPropertyUtils.setNestCount(map, chunk, count)
if (count <= 0) then if (count <= 0) then
map.chunkToNests[chunk] = nil map.chunkToNests[chunk] = nil
if (map.processMigrationIterator == chunk) then
map.processMigrationIterator = nil
end
else else
map.chunkToNests[chunk] = count map.chunkToNests[chunk] = count
end end
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) function chunkPropertyUtils.getNestCount(map, chunk)
return map.chunkToNests[chunk] or 0 return map.chunkToNests[chunk] or 0
end end
@ -163,6 +154,9 @@ function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value)
if (map.chunkToActiveRaidNest[chunk] ~= nil) then if (map.chunkToActiveRaidNest[chunk] ~= nil) then
map.natives.activeRaidNests = map.natives.activeRaidNests - 1 map.natives.activeRaidNests = map.natives.activeRaidNests - 1
end end
if (map.processActiveRaidSpawnerIterator == chunk) then
map.processActiveRaidSpawnerIterator = nil
end
map.chunkToActiveRaidNest[chunk] = nil map.chunkToActiveRaidNest[chunk] = nil
else else
if (map.chunkToActiveRaidNest[chunk] == nil) then if (map.chunkToActiveRaidNest[chunk] == nil) then
@ -193,6 +187,9 @@ function chunkPropertyUtils.setNestActiveness(map, chunk, value)
if (map.chunkToActiveNest[chunk] ~= nil) then if (map.chunkToActiveNest[chunk] ~= nil) then
map.natives.activeNests = map.natives.activeNests - 1 map.natives.activeNests = map.natives.activeNests - 1
end end
if (map.processActiveSpawnerIterator == chunk) then
map.processActiveSpawnerIterator = nil
end
map.chunkToActiveNest[chunk] = nil map.chunkToActiveNest[chunk] = nil
else else
if (map.chunkToActiveNest[chunk] == nil) then if (map.chunkToActiveNest[chunk] == nil) then

View File

@ -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_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_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_SCAN = (settings.startup["rampant-liteMode"].value and 42) or 21
constants.INTERVAL_CHUNK = 17
constants.INTERVAL_LOGIC = 60 constants.INTERVAL_LOGIC = 60
constants.INTERVAL_TEMPERAMENT = 121 constants.INTERVAL_TEMPERAMENT = 121
constants.INTERVAL_SQUAD = 41 constants.INTERVAL_SQUAD = 17
constants.INTERVAL_RESQUAD = 101 constants.INTERVAL_RESQUAD = 101
constants.INTERVAL_SPAWNER = 31
constants.INTERVAL_BUILDERS = 300 constants.INTERVAL_BUILDERS = 300
constants.INTERVAL_SPAWNER = constants.TICKS_A_SECOND * 10
constants.INTERVAL_RALLY = constants.TICKS_A_SECOND * 10 constants.COOLDOWN_RALLY = constants.TICKS_A_SECOND * 10
constants.INTERVAL_RETREAT = constants.TICKS_A_SECOND * 10 constants.COOLDOWN_RETREAT = constants.TICKS_A_SECOND * 10
constants.RESOURCE_NORMALIZER = 1 / 1024 constants.RESOURCE_NORMALIZER = 1 / 1024

View File

@ -36,15 +36,12 @@ local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
local AI_SETTLER_COST = constants.AI_SETTLER_COST local AI_SETTLER_COST = constants.AI_SETTLER_COST
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
local processNestActiveness = chunkPropertyUtils.processNestActiveness
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local BASE_PHEROMONE = constants.BASE_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE
local INTERVAL_RALLY = constants.INTERVAL_RALLY local COOLDOWN_RALLY = constants.COOLDOWN_RALLY
local INTERVAL_RETREAT = constants.INTERVAL_RETREAT local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
local INTERVAL_SPAWNER = constants.INTERVAL_SPAWNER
local BASE_PROCESS_INTERVAL = constants.BASE_PROCESS_INTERVAL 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 -- imported functions
-- local scents = pheromoneUtils.scents
local processPheromone = pheromoneUtils.processPheromone local processPheromone = pheromoneUtils.processPheromone
local commitPheromone = pheromoneUtils.commitPheromone local commitPheromone = pheromoneUtils.commitPheromone
local playerScent = pheromoneUtils.playerScent local playerScent = pheromoneUtils.playerScent
local processBase = baseUtils.processBase
local processNestActiveness = chunkPropertyUtils.processNestActiveness
local formSquads = aiAttackWave.formSquads local formSquads = aiAttackWave.formSquads
local formAttackWave = aiAttackWave.formAttackWave
local formSettlers = aiAttackWave.formSettlers
local formVengenceSquad = aiAttackWave.formVengenceSquad local formVengenceSquad = aiAttackWave.formVengenceSquad
local formSettlers = aiAttackWave.formSettlers
local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByPosition = mapUtils.getChunkByPosition
local getChunkByXY = mapUtils.getChunkByXY local getChunkByXY = mapUtils.getChunkByXY
@ -89,11 +88,9 @@ local canMigrate = aiPredicates.canMigrate
local findNearbySquad = unitGroupUtils.findNearbySquad local findNearbySquad = unitGroupUtils.findNearbySquad
local processBase = baseUtils.processBase
local mMin = math.min local mMin = math.min
-- local mMax = math.max
local next = next
local mRandom = math.random local mRandom = math.random
-- module code -- module code
@ -109,47 +106,21 @@ function mapProcessor.processMap(map, surface, tick)
local roll = map.processRoll local roll = map.processRoll
local index = map.processIndex local index = map.processIndex
local chunkToBase = map.chunkToBase
local natives = map.natives
if (index == 1) then if (index == 1) then
roll = mRandom() roll = mRandom()
map.processRoll = roll map.processRoll = roll
natives.remainingSquads = AI_MAX_SQUADS_PER_CYCLE
end end
local newEnemies = natives.newEnemies
local scentStaging = map.scentStaging 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 processQueue = map.processQueue
local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue) local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue)
local i = 1 local i = 1
for x=index,endIndex do for x=index,endIndex do
local chunk = processQueue[x] local chunk = processQueue[x]
if (chunk[CHUNK_TICK] ~= tick) then if (chunk[CHUNK_TICK] ~= tick) then
processPheromone(map, chunk, scentStaging[i]) 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 end
i = i + 1 i = i + 1
end end
@ -170,12 +141,11 @@ function mapProcessor.processMap(map, surface, tick)
end end
end end
local function queueNestSpawners(map, chunk, tick) local function queueNestSpawners(map, chunk, tick)
local limitPerActiveChunkTick = map.natives.activeNests * DURATION_ACTIVE_NEST_DIVIDER local limitPerActiveChunkTick = map.natives.activeNests * DURATION_ACTIVE_NEST_DIVIDER
local processActiveNest = map.processActiveNest local processActiveNest = map.processActiveNest
if ((getNestActiveness(map, chunk) > 0) and (getNestActiveTick(map, chunk) == 0)) then if ((getNestActiveness(map, chunk) > 0) and (getNestActiveTick(map, chunk) == 0)) then
local nextTick = tick + DURATION_ACTIVE_NEST local nextTick = tick + DURATION_ACTIVE_NEST
local slot = processActiveNest[nextTick] local slot = processActiveNest[nextTick]
@ -223,8 +193,6 @@ function mapProcessor.processPlayers(players, map, surface, tick)
local scentStaging = map.scentStaging 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 -- not looping everyone because the cost is high enough already in multiplayer
if (#players > 0) then if (#players > 0) then
local player = players[mRandom(#players)] local player = players[mRandom(#players)]
@ -233,9 +201,10 @@ function mapProcessor.processPlayers(players, map, surface, tick)
if (playerChunk ~= -1) then if (playerChunk ~= -1) then
local i = 1 local i = 1
local vengence = (allowingAttacks and local vengence = allowingAttacks and
(natives.points >= AI_VENGENCE_SQUAD_COST) and (natives.points >= AI_VENGENCE_SQUAD_COST) and
((getEnemyStructureCount(map, playerChunk) > 0) or (playerChunk[MOVEMENT_PHEROMONE] < -natives.retreatThreshold))) ((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 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 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) processNestActiveness(map, chunk, natives, surface)
queueNestSpawners(map, chunk, tick) queueNestSpawners(map, chunk, tick)
if vengence and (getNestCount(map, chunk) > 0) then 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
end end
i = i + 1 i = i + 1
@ -293,8 +267,6 @@ function mapProcessor.scanMap(map, surface, tick)
local retreats = map.chunkToRetreats local retreats = map.chunkToRetreats
local rallys = map.chunkToRallys local rallys = map.chunkToRallys
-- local spawners = map.chunkToSpawner
local settlers = map.chunkToSettler
local drained = map.chunkToDrained local drained = map.chunkToDrained
local processQueue = map.processQueue local processQueue = map.processQueue
@ -314,20 +286,15 @@ function mapProcessor.scanMap(map, surface, tick)
offset[2] = chunk.y + CHUNK_SIZE offset[2] = chunk.y + CHUNK_SIZE
local retreatTick = retreats[chunk] local retreatTick = retreats[chunk]
if retreatTick and ((tick - retreatTick) > INTERVAL_RETREAT) then if retreatTick and ((tick - retreatTick) > COOLDOWN_RETREAT) then
retreats[chunk] = nil retreats[chunk] = nil
end end
local rallyTick = rallys[chunk] local rallyTick = rallys[chunk]
if rallyTick and ((tick - rallyTick) > INTERVAL_RALLY) then if rallyTick and ((tick - rallyTick) > COOLDOWN_RALLY) then
rallys[chunk] = nil rallys[chunk] = nil
end end
local settlerTick = settlers[chunk]
if settlerTick and ((tick - settlerTick) > 0) then
settlers[chunk] = nil
end
local drainTick = drained[chunk] local drainTick = drained[chunk]
if drainTick and ((tick - drainTick) > 0) then if drainTick and ((tick - drainTick) > 0) then
drained[chunk] = nil drained[chunk] = nil
@ -362,11 +329,11 @@ function mapProcessor.processActiveNests(map, surface, tick)
local processActiveNest = map.processActiveNest local processActiveNest = map.processActiveNest
local slot = processActiveNest[tick] local slot = processActiveNest[tick]
if slot then if slot then
local natives = map.natives
for i=1,#slot do for i=1,#slot do
local chunk = slot[i] local chunk = slot[i]
if (getNestActiveness(map, chunk) > 0) then if (getNestActiveness(map, chunk) > 0) then
createSpawnerProxy(map, surface, chunk) processNestActiveness(map, chunk, natives, surface)
-- setNestActiveTick(map, chunk, tick)
local nextTick = tick + DURATION_ACTIVE_NEST local nextTick = tick + DURATION_ACTIVE_NEST
local nextSlot = processActiveNest[nextTick] local nextSlot = processActiveNest[nextTick]
if not nextSlot then if not nextSlot then
@ -382,7 +349,75 @@ function mapProcessor.processActiveNests(map, surface, tick)
end end
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 mapProcessorG = mapProcessor
return mapProcessor return mapProcessor

View File

@ -31,25 +31,25 @@ local distortPosition = mathUtils.distortPosition
function movementUtils.findMovementPosition(surface, position) function movementUtils.findMovementPosition(surface, position)
local pos = position local pos = position
if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then -- 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) pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 10, 2, false)
end -- end
return pos return pos
end end
function movementUtils.findMovementPositionEntity(entityName, surface, position) function movementUtils.findMovementPositionEntity(entityName, surface, position)
local pos = 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) pos = surface.find_non_colliding_position(entityName, pos, 5, 4, true)
end -- end
return pos return pos
end end
function movementUtils.findMovementPositionDistort(surface, position) function movementUtils.findMovementPositionDistort(surface, position)
local pos = position local pos = position
if not surface.can_place_entity({name="chunk-scanner-squad-movement-rampant", position=pos}) then -- 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) pos = surface.find_non_colliding_position("chunk-scanner-squad-movement-rampant", pos, 10, 2, false)
end -- end
return distortPosition(pos, 8) return distortPosition(pos, 8)
end end
@ -176,7 +176,6 @@ function movementUtils.scoreNeighborsForSettling(map, chunk, neighborDirectionCh
neighborDirectionChunks = getNeighborChunks(map, highestChunk.x, highestChunk.y) neighborDirectionChunks = getNeighborChunks(map, highestChunk.x, highestChunk.y)
for x=1,8 do for x=1,8 do
local neighborChunk = neighborDirectionChunks[x] local neighborChunk = neighborDirectionChunks[x]
if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and
canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then
local score = scoreFunction(squad, neighborChunk) local score = scoreFunction(squad, neighborChunk)

View File

@ -104,7 +104,7 @@ function pheromoneUtils.processPheromone(map, chunk, staging)
local baseTotal = 0 local baseTotal = 0
local playerTotal = 0 local playerTotal = 0
local resourceTotal = 0 local resourceTotal = 0
local neighborCount = 0 local neighborCount = 0
local neighbor local neighbor
@ -113,151 +113,175 @@ function pheromoneUtils.processPheromone(map, chunk, staging)
local chunkPass = getPassable(map, chunk) local chunkPass = getPassable(map, chunk)
if (chunkPass == CHUNK_ALL_DIRECTIONS) then if (chunkPass == CHUNK_ALL_DIRECTIONS) then
neighbor = tempNeighbors[2] neighbor = tempNeighbors[2]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) -- movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement)
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) -- baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase)
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) -- playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer)
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) -- 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 end
neighbor = tempNeighbors[7] neighbor = tempNeighbors[7]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[4] neighbor = tempNeighbors[4]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[5] neighbor = tempNeighbors[5]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[1] neighbor = tempNeighbors[1]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then neighborPass = getPassable(map, neighbor)
neighborCount = neighborCount + 1 if (neighborPass == CHUNK_ALL_DIRECTIONS) then
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) neighborCount = neighborCount + 1
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[3] neighbor = tempNeighbors[3]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then neighborPass = getPassable(map, neighbor)
neighborCount = neighborCount + 1 if (neighborPass == CHUNK_ALL_DIRECTIONS) then
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) neighborCount = neighborCount + 1
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[6] neighbor = tempNeighbors[6]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then neighborPass = getPassable(map, neighbor)
neighborCount = neighborCount + 1 if (neighborPass == CHUNK_ALL_DIRECTIONS) then
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) neighborCount = neighborCount + 1
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[8] neighbor = tempNeighbors[8]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if (neighbor ~= -1) and (neighborPass == CHUNK_ALL_DIRECTIONS) then neighborPass = getPassable(map, neighbor)
neighborCount = neighborCount + 1 if (neighborPass == CHUNK_ALL_DIRECTIONS) then
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) neighborCount = neighborCount + 1
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
elseif (chunkPass == CHUNK_EAST_WEST) then elseif (chunkPass == CHUNK_EAST_WEST) then
neighbor = tempNeighbors[4] neighbor = tempNeighbors[4]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[5] neighbor = tempNeighbors[5]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_EAST_WEST)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE] - chunkPlayer playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
elseif (chunkPass == CHUNK_NORTH_SOUTH) then elseif (chunkPass == CHUNK_NORTH_SOUTH) then
neighbor = tempNeighbors[2] neighbor = tempNeighbors[2]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
neighbor = tempNeighbors[7] neighbor = tempNeighbors[7]
neighborPass = getPassable(map, neighbor) if (neighbor ~= -1) then
if ((neighbor ~= -1) and neighborPass = getPassable(map, neighbor)
((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH))) then if ((neighborPass == CHUNK_ALL_DIRECTIONS) or (neighborPass == CHUNK_NORTH_SOUTH)) then
neighborCount = neighborCount + 1 neighborCount = neighborCount + 1
movementTotal = movementTotal + (neighbor[MOVEMENT_PHEROMONE] - chunkMovement) movementTotal = movementTotal + neighbor[MOVEMENT_PHEROMONE]
baseTotal = baseTotal + (neighbor[BASE_PHEROMONE] - chunkBase) baseTotal = baseTotal + neighbor[BASE_PHEROMONE]
playerTotal = playerTotal + (neighbor[PLAYER_PHEROMONE] - chunkPlayer) playerTotal = playerTotal + neighbor[PLAYER_PHEROMONE]
resourceTotal = resourceTotal + (neighbor[RESOURCE_PHEROMONE] - chunkResource) resourceTotal = resourceTotal + neighbor[RESOURCE_PHEROMONE]
end
end end
end end
local neighborDiv = 0 local neighborDiv = 0
if neighborCount ~= 0 then if neighborCount ~= 0 then
neighborDiv = NEIGHBOR_DIVIDER[neighborCount] 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 end
staging[MOVEMENT_PHEROMONE] = (chunkMovement + (neighborDiv * movementTotal)) * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating staging[MOVEMENT_PHEROMONE] = chunkMovement * MOVEMENT_PHEROMONE_PERSISTANCE * chunkPathRating
staging[BASE_PHEROMONE] = (chunkBase + (neighborDiv * baseTotal)) * BASE_PHEROMONE_PERSISTANCE * chunkPathRating staging[BASE_PHEROMONE] = chunkBase * BASE_PHEROMONE_PERSISTANCE * chunkPathRating
staging[PLAYER_PHEROMONE] = (chunkPlayer + (neighborDiv * playerTotal)) * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating staging[PLAYER_PHEROMONE] = chunkPlayer * PLAYER_PHEROMONE_PERSISTANCE * chunkPathRating
if clear then if clear then
staging[RESOURCE_PHEROMONE] = (chunkResource + (neighborDiv * resourceTotal)) * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating staging[RESOURCE_PHEROMONE] = chunkResource * RESOURCE_PHEROMONE_PERSISTANCE * chunkPathRating
else else
staging[RESOURCE_PHEROMONE] = (chunkResource + (neighborDiv * resourceTotal)) * 0.01 staging[RESOURCE_PHEROMONE] = chunkResource * 0.01
end end
end end

View File

@ -76,7 +76,6 @@ local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
local positionFromDirectionAndFlat = mapUtils.positionFromDirectionAndFlat local positionFromDirectionAndFlat = mapUtils.positionFromDirectionAndFlat
local createSquad = unitGroupUtils.createSquad local createSquad = unitGroupUtils.createSquad
local membersToSquad = unitGroupUtils.membersToSquad
local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
@ -108,14 +107,14 @@ local function scoreAttackLocation(natives, squad, neighborChunk)
if (movementPheromone >= 0) then if (movementPheromone >= 0) then
damage = movementPheromone + (neighborChunk[BASE_PHEROMONE]) + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER) damage = movementPheromone + (neighborChunk[BASE_PHEROMONE]) + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
else 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 end
return damage -- - lookupMovementPenalty(squad, neighborChunk) return damage -- - lookupMovementPenalty(squad, neighborChunk)
end end
local function scoreAttackKamikazeLocation(natives, squad, neighborChunk) 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) return damage -- - lookupMovementPenalty(squad, neighborChunk)
end end
@ -140,7 +139,6 @@ local function settleMove(map, squad, surface)
groupPosition.y, groupPosition.y,
squad.originPosition.x, squad.originPosition.x,
squad.originPosition.y) squad.originPosition.y)
local cmd local cmd
local position local position
local position2 local position2
@ -165,18 +163,7 @@ local function settleMove(map, squad, surface)
squad.status = SQUAD_BUILDING squad.status = SQUAD_BUILDING
map.buildPositionTop.x = position.x - BASE_CLEAN_DISTANCE surface.create_entity(map.createBuildCloudQuery)
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
group.set_command(cmd) group.set_command(cmd)
else else
@ -186,70 +173,52 @@ local function settleMove(map, squad, surface)
scoreFunction, scoreFunction,
squad) squad)
if (attackChunk == -1) then if (attackChunk == -1) then
cmd = map.wonderCommand cmd = map.wonderCommand
group.set_command(cmd) group.set_command(cmd)
return return
else elseif (attackDirection ~= 0) then
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
position = findMovementPosition(surface, targetPosition)
local attackPlayerThreshold = natives.attackPlayerThreshold 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 cmd = map.wonderCommand
group.set_command(cmd) group.set_command(cmd)
return 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 else
targetPosition.x = position.x cmd = map.moveCommand
targetPosition.y = position.y if squad.rabid or squad.kamikaze then
cmd.distraction = DEFINES_DISTRACTION_NONE
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 else
cmd = map.moveCommand cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
if squad.rabid or squad.kamikaze then
cmd.distraction = DEFINES_DISTRACTION_NONE
else
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
end
end end
end end
else
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
cmd = map.settleCommand cmd = map.settleCommand
if squad.kamikaze then if squad.kamikaze then
cmd.distraction = DEFINES_DISTRACTION_NONE cmd.distraction = DEFINES_DISTRACTION_NONE
@ -259,32 +228,21 @@ local function settleMove(map, squad, surface)
squad.status = SQUAD_BUILDING squad.status = SQUAD_BUILDING
map.buildPositionTop.x = targetPosition.x - BASE_CLEAN_DISTANCE surface.create_entity(map.createBuildCloudQuery)
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)
end end
group.set_command(cmd)
end end
end end
local function attackMove(map, squad, surface) local function attackMove(map, squad, surface)
local targetPosition = map.position local targetPosition = map.position
local targetPosition2 = map.position2 local targetPosition2 = map.position2
local group = squad.group local group = squad.group
local position
local groupPosition = group.position local groupPosition = group.position
local x, y = positionToChunkXY(groupPosition) local x, y = positionToChunkXY(groupPosition)
local chunk = getChunkByXY(map, x, y) local chunk = getChunkByXY(map, x, y)
@ -305,68 +263,45 @@ local function attackMove(map, squad, surface)
cmd = map.wonderCommand cmd = map.wonderCommand
group.set_command(cmd) group.set_command(cmd)
return return
elseif (nextAttackChunk ~= -1) then
attackChunk = nextAttackChunk
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
position = findMovementPosition(surface, targetPosition2)
else else
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition) positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
position = findMovementPosition(surface, 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)
end 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 end
local function buildMove(map, squad, surface) local function buildMove(map, squad, surface)
@ -385,53 +320,36 @@ local function buildMove(map, squad, surface)
end end
function squadAttack.squadDispatch(map, surface, squad) function squadAttack.squadDispatch(map, surface, squad)
-- local profiler = game.create_profiler()
local group = squad.group local group = squad.group
if group and group.valid then if group and group.valid then
local memberCount = #group.members local status = squad.status
if (memberCount == 0) then if (status == SQUAD_RAIDING) then
removeSquadFromChunk(map, squad) attackMove(map, squad, surface)
local deathGen = getDeathGenerator(map, squad.chunk) elseif (status == SQUAD_SETTLING) then
local penalties = squad.penalties settleMove(map, squad, surface)
for xc=1,mMin(#squad.penalties,5) do elseif (status == SQUAD_RETREATING) then
addDeathGenerator(map, if squad.settlers then
penalties[xc].c, squad.status = SQUAD_SETTLING
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
settleMove(map, squad, surface) settleMove(map, squad, surface)
elseif (status == SQUAD_RETREATING) then else
if squad.settlers then squad.status = SQUAD_RAIDING
squad.status = SQUAD_SETTLING attackMove(map, squad, surface)
settleMove(map, squad, surface) end
else elseif (status == SQUAD_BUILDING) then
squad.status = SQUAD_RAIDING removeSquadFromChunk(map, squad)
attackMove(map, squad, surface) buildMove(map, squad, surface)
end elseif (status == SQUAD_GUARDING) then
elseif (status == SQUAD_BUILDING) then if squad.settlers then
removeSquadFromChunk(map, squad) squad.status = SQUAD_SETTLING
buildMove(map, squad, surface) settleMove(map, squad, surface)
elseif (status == SQUAD_GUARDING) then else
if squad.settlers then squad.status = SQUAD_RAIDING
squad.status = SQUAD_SETTLING attackMove(map, squad, surface)
settleMove(map, squad, surface)
else
squad.status = SQUAD_RAIDING
attackMove(map, squad, surface)
end
end end
end end
end end
-- game.print({"", "--dispatch4 ", profiler})
end end
squadAttackG = squadAttack squadAttackG = squadAttack

View File

@ -21,7 +21,7 @@ local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER
local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_RETREATING = constants.SQUAD_RETREATING
local INTERVAL_RETREAT = constants.INTERVAL_RETREAT local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
-- imported functions -- imported functions
@ -54,23 +54,24 @@ local function scoreRetreatLocation(map, neighborChunk)
-(getPlayerBaseGenerator(map, neighborChunk) * 1000)) -(getPlayerBaseGenerator(map, neighborChunk) * 1000))
end end
function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radius, artilleryBlast) function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radius)
if (tick - getRetreatTick(map, chunk) > INTERVAL_RETREAT) and if (tick - getRetreatTick(map, chunk) > COOLDOWN_RETREAT) and (getEnemyStructureCount(map, chunk) == 0) then
((getEnemyStructureCount(map, chunk) == 0) or artilleryBlast)
then
local performRetreat = false local performRetreat = false
local enemiesToSquad = nil local enemiesToSquad = nil
local squad local squad
local groupMembers
if group and group.valid then if group and group.valid then
squad = map.natives.groupNumberToSquad[group.group_number] squad = map.natives.groupNumberToSquad[group.group_number]
if not squad then if not squad then
squad = createSquad(position, surface, group) squad = createSquad(position, surface, group)
squad.kamikaze = mRandom() < calculateKamikazeThreshold(group.members, natives) groupMembers = group.members
squad.kamikaze = mRandom() < calculateKamikazeThreshold(#groupMembers, natives)
end end
end end
if not squad then if not squad then
print("grabbing people", position.x, position.y)
enemiesToSquad = map.enemiesToSquad enemiesToSquad = map.enemiesToSquad
local unitCount = 0 local unitCount = 0
local units = surface.find_enemy_units(position, radius) local units = surface.find_enemy_units(position, radius)
@ -83,16 +84,16 @@ function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radi
end end
enemiesToSquad.len = unitCount enemiesToSquad.len = unitCount
if (mRandom() < calculateKamikazeThreshold(unitCount, map.natives)) then if (mRandom() < calculateKamikazeThreshold(unitCount, map.natives)) then
setRetreatTick(map, chunk, tick) performRetreat = false
return else
end performRetreat = unitCount > 6
performRetreat = unitCount > 6 end
elseif squad.group and squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then 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 end
setRetreatTick(map, chunk, tick)
if performRetreat then if performRetreat then
setRetreatTick(map, chunk, tick)
local exitPath,exitDirection,nextExitPath,nextExitDirection = scoreNeighborsForRetreat(chunk, local exitPath,exitDirection,nextExitPath,nextExitDirection = scoreNeighborsForRetreat(chunk,
getNeighborChunks(map, getNeighborChunks(map,
chunk.x, chunk.x,
@ -140,7 +141,7 @@ function aiDefense.retreatUnits(chunk, position, group, map, surface, tick, radi
if enemiesToSquad then if enemiesToSquad then
membersToSquad(cmd, enemiesToSquad.len, enemiesToSquad, artilleryBlast) membersToSquad(cmd, enemiesToSquad.len, enemiesToSquad, artilleryBlast)
else else
membersToSquad(cmd, #squad.group.members, squad.group.members, true) membersToSquad(cmd, #groupMembers, groupMembers, true)
if squad.rabid then if squad.rabid then
newSquad.rabid = true newSquad.rabid = true
end end

View File

@ -15,6 +15,7 @@ local movementUtils = require("MovementUtils")
local DEFINES_GROUP_FINISHED = defines.group_state.finished 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 SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE
local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
@ -36,6 +37,11 @@ local mRandom = math.random
local findMovementPosition = movementUtils.findMovementPosition local findMovementPosition = movementUtils.findMovementPosition
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
local next = next
local table_size = table_size
local mLog = math.log10 local mLog = math.log10
@ -139,15 +145,21 @@ function unitGroupUtils.createSquad(position, surface, group, settlers)
end end
function unitGroupUtils.cleanSquads(natives, iterator) function unitGroupUtils.cleanSquads(natives, iterator)
local profiler = game.create_profiler()
local squads = natives.groupNumberToSquad local squads = natives.groupNumberToSquad
local map = natives.map local map = natives.map
local k, squad = next(squads, iterator) local k, squad = next(squads, iterator)
local nextK local nextK
for i=1,2 do -- for i=1,2 do
if not k then if not k then
return nil if (table_size(squads) == 0) then
elseif not squad.group.valid 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) removeSquadFromChunk(map, squad)
if (map.regroupIterator == k) then if (map.regroupIterator == k) then
map.regroupIterator = nil map.regroupIterator = nil
@ -155,9 +167,39 @@ function unitGroupUtils.cleanSquads(natives, iterator)
nextK,squad = next(squads, k) nextK,squad = next(squads, k)
squads[k] = nil squads[k] = nil
k = nextK 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
end end
return k -- end
map.squadIterator = k
end end
function unitGroupUtils.membersToSquad(cmd, size, members, overwriteGroup) function unitGroupUtils.membersToSquad(cmd, size, members, overwriteGroup)
@ -185,6 +227,7 @@ end
function unitGroupUtils.regroupSquads(natives, iterator) function unitGroupUtils.regroupSquads(natives, iterator)
local map = natives.map local map = natives.map
local squads = natives.groupNumberToSquad local squads = natives.groupNumberToSquad
local cmd = map.mergeGroupCommand
local k, squad = iterator, nil local k, squad = iterator, nil
for i=1,SQUAD_QUEUE_SIZE do for i=1,SQUAD_QUEUE_SIZE do
@ -194,42 +237,45 @@ function unitGroupUtils.regroupSquads(natives, iterator)
else else
local group = squad.group local group = squad.group
if group and group.valid then if group and group.valid then
cmd.group = group
local groupState = group.state local groupState = group.state
if (groupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and if (groupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
(groupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION) (groupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
then then
local memberCount = #group.members -- local memberCount = #group.members
if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then -- if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
local status = squad.status local status = squad.status
local chunk = squad.chunk local chunk = squad.chunk
if (chunk ~= -1) then if (chunk ~= -1) then
for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do
if (mergeSquad ~= squad) then if (mergeSquad ~= squad) then
local mergeGroup = mergeSquad.group local mergeGroup = mergeSquad.group
if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then
local mergeGroupState = mergeGroup.state local mergeGroupState = mergeGroup.state
if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
(mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION) (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
then then
local mergeMembers = mergeGroup.members print("merging group")
local mergeCount = #mergeMembers mergeGroup.set_command(cmd)
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then -- local mergeMembers = mergeGroup.members
for memberIndex=1, mergeCount do -- local mergeCount = #mergeMembers
group.add_member(mergeMembers[memberIndex]) -- if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then
end -- for memberIndex=1, mergeCount do
mergeGroup.destroy() -- group.add_member(mergeMembers[memberIndex])
end -- end
squad.status = SQUAD_GUARDING -- mergeGroup.destroy()
memberCount = memberCount + mergeCount -- end
if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then squad.status = SQUAD_GUARDING
break -- memberCount = memberCount + mergeCount
end -- if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
end -- break
-- end
end end
end end
end end
end end
-- end
end end
end end
end end

View File

@ -18710,7 +18710,6 @@ rampant-enableNEUnits=World: Enable NE as a faction
rampant-disallowFriendlyFire=Safety: Disallow Friendly Fire Splash Damage rampant-disallowFriendlyFire=Safety: Disallow Friendly Fire Splash Damage
rampant-tierStart=World: Beginning enemy level rampant-tierStart=World: Beginning enemy level
rampant-tierEnd=World: Ending enemy level rampant-tierEnd=World: Ending enemy level
rampant-disableVanillaAI=AI: Disable Vanilla AI
rampant-enableMigration=AI: Enable Migration rampant-enableMigration=AI: Enable Migration
rampant-liteMode=Optimization: Lite mode 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-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-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-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-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. 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.

View File

@ -1,5 +1,6 @@
local biterFunctions = require("prototypes/utils/BiterUtils") local biterFunctions = require("prototypes/utils/BiterUtils")
local constants = require("libs/Constants") local constants = require("libs/Constants")
local smokeUtils = require("prototypes/utils/SmokeUtils")
data:extend({ data:extend({
biterFunctions.makeBiter({ biterFunctions.makeBiter({
@ -83,3 +84,39 @@ for t=1,11 do
) )
end end
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"}
}
}
}
}
)

View File

@ -2,6 +2,145 @@ local smokeUtils = {}
-- module code -- 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) function smokeUtils.makeCloud(attributes, attack)
local name = attributes.name .. "-cloud-rampant" local name = attributes.name .. "-cloud-rampant"

View File

@ -393,15 +393,15 @@ data:extend({
per_user = false per_user = false
}, },
{ -- {
type = "bool-setting", -- type = "bool-setting",
name = "rampant-disableVanillaAI", -- name = "rampant-disableVanillaAI",
description = "rampant-disableVanillaAI", -- description = "rampant-disableVanillaAI",
setting_type = 'runtime-global', -- setting_type = 'runtime-global',
default_value = true, -- default_value = true,
order = "m[total]-a[ai]", -- order = "m[total]-a[ai]",
per_user = false -- per_user = false
}, -- },
{ {
type = "bool-setting", type = "bool-setting",

View File

@ -219,9 +219,9 @@ function tests.attackOrigin()
max_distance = 1000}) max_distance = 1000})
if (enemy ~= nil) and enemy.valid then if (enemy ~= nil) and enemy.valid then
print(enemy, enemy.unit_number) 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}, destination={0,0},
radius=32}) radius=15})
end end
end end