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.safeEntities = {}
natives.vengenceQueue = {}
natives.aiPointsScaler = settings.global["rampant-aiPointsScaler"].value
natives.aiNocturnalMode = settings.global["rampant-permanentNocturnal"].value
@ -150,15 +151,30 @@ function upgrade.attempt(natives, setNewSurface, gameSurfaces)
end
end
natives.remainingSquads = 0
natives.groupNumberToSquad = {}
game.forces.enemy.kill_all_units()
natives.squads = nil
natives.pendingAttack = nil
natives.building = nil
end
if (global.version < 112) then
global.version = 112
if (global.version < 113) then
global.version = 113
natives.baseId = 0
local newBases = {}
for i=1,#natives.bases do
local base = natives.bases
base.id = natives.baseId
newBases[base.id] = base
natives.baseId = natives.baseId + 1
end
natives.bases = newBases
global.pendingChunks = nil
natives.vengenceQueue = {}
game.forces.enemy.ai_controllable = true
if not setNewSurface then
game.get_surface(natives.activeSurface).print("Rampant - Version 0.18.12")

View File

@ -1,10 +1,22 @@
---------------------------------------------------------------------------------------------------
Version: 0.18.12
Date: 16. 4 2020
Improvements:
- Swapped to ai command completed for unit movements
- When squads reach a movement threshold for being in the same spots to much they switch to kamikaze mode
- Added effect when spawners build to destroy build site
- Integrated vanilla AI into Rampant for pollution management
Tweaks:
- Changed ai credits per rocket launched to 5000
Bugfixes:
- fixed add movement penalty not using squad chunk
- fixed landfill and waterfill getting registered properly
Optimizations:
- Cleaned up regroup squads
- Cleaned up invalid group detection
- Minimized use of group.members
- Changed how settlers remove entities around build sites
- Split map processing and unit group creation
---------------------------------------------------------------------------------------------------
Version: 0.18.11

View File

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

View File

@ -5,6 +5,6 @@
"title" : "Rampant",
"author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
"description" : "Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies (disabled by default). Can completely replace the vanilla AI. Difficulty setting in mod options menu.",
"description" : "Improves the enemies tactics by using potential fields/pheromones allowing probing of defenses, retreats, reinforcements, counterattacking, breaching, raids, rallying death cry, and player hunting. Uses blockable biter projectiles. Adds new Enemies (disabled by default). Difficulty setting in mod options menu.",
"dependencies" : ["base >= 0.18.22", "? bobenemies", "? Natural_Evolution_Enemies >= 0.17.0", "? Clockwork", "? Orbital Ion Cannon", "? RampantArsenal", "? RampantResources", "? ArmouredBiters"]
}

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

View File

@ -71,7 +71,7 @@ function aiPlanning.planning(natives, evolution_factor, tick)
local attackWaveMaxSize = natives.attackWaveMaxSize
natives.retreatThreshold = linearInterpolation(evolution_factor, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MIN, RETREAT_MOVEMENT_PHEROMONE_LEVEL_MAX)
natives.rallyThreshold = BASE_RALLY_CHANCE + (evolution_factor * BONUS_RALLY_CHANCE)
natives.formSquadThreshold = mMax((0.25 * evolution_factor), 0.10)
natives.formSquadThreshold = mMax((0.20 * evolution_factor), 0.05)
natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.15)
natives.attackWaveDeviation = (natives.attackWaveSize * 0.333)

View File

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

View File

@ -76,6 +76,8 @@ local setChunkBase = chunkPropertyUtils.setChunkBase
local getResourceGenerator = chunkPropertyUtils.getResourceGenerator
local next = next
local tRemove = table.remove
local mRandom = math.random
@ -95,50 +97,6 @@ local function evoToTier(natives, evolutionFactor)
return v
end
function baseUtils.createSpawnerProxies(map, surface, chunk, foundUnits)
local query = map.placeSpawnerProxyQuery
if (foundUnits >= 60) then
query.name = "spawner-proxy-2-rampant"
elseif (foundUnits >= 120) then
query.name = "spawner-proxy-3-rampant"
else
query.name = "spawner-proxy-1-rampant"
end
local position3 = map.position3
local chunkX = chunk.x + 5
local chunkY = chunk.y + 5
position3.x = chunkX
position3.y = chunkY
local entity = surface.create_entity(query)
entity.destructible = false
position3.x = chunkX+CHUNK_SIZE
position3.y = chunkY
entity = surface.create_entity(query)
entity.destructible = false
position3.x = chunkX-CHUNK_SIZE
position3.y = chunkY
entity = surface.create_entity(query)
entity.destructible = false
position3.x = chunkX
position3.y = chunkY-CHUNK_SIZE
entity = surface.create_entity(query)
entity.destructible = false
position3.x = chunkX
position3.y = chunkY+CHUNK_SIZE
entity = surface.create_entity(query)
entity.destructible = false
end
function baseUtils.createSpawnerProxy(map, surface, chunk)
local query = map.placeSpawnerProxyQuery
query.name = "spawner-proxy-1-rampant"
local position3 = map.position3
position3.x = chunk.x + 5
position3.y = chunk.y + 5
local entity = surface.create_entity(query)
entity.destructible = false
end
function baseUtils.findNearbyBase(map, chunk)
local x = chunk.x
local y = chunk.y
@ -150,8 +108,7 @@ function baseUtils.findNearbyBase(map, chunk)
local bases = map.natives.bases
local closet = MAGIC_MAXIMUM_NUMBER
for i=1, #bases do
local base = bases[i]
for _, base in pairs(bases) do
local distance = euclideanDistancePoints(base.x, base.y, x, y)
if (distance <= base.distanceThreshold) and (distance < closet) then
closet = distance
@ -283,7 +240,8 @@ local function findEntityUpgrade(baseAlignment, currentEvo, evoIndex, originalEn
end
local function findBaseInitialAlignment(natives, evoIndex)
local evoTop = gaussianRandomRange(evoIndex, evoIndex * 0.3, 0, evoIndex)
local dev = evoIndex * 0.3
local evoTop = gaussianRandomRange(evoIndex - dev, dev, 0, evoIndex)
local result
if mRandom() < 0.05 then
@ -298,21 +256,23 @@ end
function baseUtils.recycleBases(natives, tick)
local baseIndex = natives.baseIndex
local bases = natives.bases
local endIndex = mMin(baseIndex+BASE_QUEUE_SIZE, #bases)
for index = endIndex, baseIndex, -1 do
local base = bases[index]
if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then
tRemove(bases, index)
local id, base = next(bases, natives.map.recycleBaseIterator)
for i=1,2 do
if not id then
natives.map.recycleBaseIterator = nil
return
else
if ((tick - base.tick) > BASE_COLLECTION_THRESHOLD) then
local nextId
nextId, base = next(bases, id)
bases[id] = nil
id = nextId
else
id, base = next(bases, id)
end
end
end
if (endIndex == #bases) then
natives.baseIndex = 1
else
natives.baseIndex = endIndex + 1
end
natives.map.recycleBaseIterator = id
end
@ -495,12 +455,14 @@ function baseUtils.createBase(natives, chunk, tick, rebuilding)
temperamentTick = 0,
createdTick = tick,
temperament = 0,
points = 0
points = 0,
id = natives.baseId
}
natives.baseId = natives.baseId + 1
setChunkBase(natives.map, chunk, base)
natives.bases[#natives.bases+1] = base
natives.bases[base.id] = base
return base
end
@ -653,8 +615,7 @@ function baseUtils.rebuildNativeTables(natives, surface, rg)
local evoIndex = evoToTier(natives, natives.evolutionLevel)
for i=1,#natives.bases do
local base = natives.bases[i]
for id,base in pairs(natives.bases) do
for x=1,#base.alignment do
local alignment = base.alignment[x]
if not natives.buildingEvolveLookup[alignment] then

View File

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

View File

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

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

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_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
local processNestActiveness = chunkPropertyUtils.processNestActiveness
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local BASE_PHEROMONE = constants.BASE_PHEROMONE
local INTERVAL_RALLY = constants.INTERVAL_RALLY
local INTERVAL_RETREAT = constants.INTERVAL_RETREAT
local INTERVAL_SPAWNER = constants.INTERVAL_SPAWNER
local COOLDOWN_RALLY = constants.COOLDOWN_RALLY
local COOLDOWN_RETREAT = constants.COOLDOWN_RETREAT
local BASE_PROCESS_INTERVAL = constants.BASE_PROCESS_INTERVAL
@ -52,15 +49,17 @@ local AI_MAX_SQUADS_PER_CYCLE = constants.AI_MAX_SQUADS_PER_CYCLE
-- imported functions
-- local scents = pheromoneUtils.scents
local processPheromone = pheromoneUtils.processPheromone
local commitPheromone = pheromoneUtils.commitPheromone
local playerScent = pheromoneUtils.playerScent
local processBase = baseUtils.processBase
local processNestActiveness = chunkPropertyUtils.processNestActiveness
local formSquads = aiAttackWave.formSquads
local formAttackWave = aiAttackWave.formAttackWave
local formSettlers = aiAttackWave.formSettlers
local formVengenceSquad = aiAttackWave.formVengenceSquad
local formSettlers = aiAttackWave.formSettlers
local getChunkByPosition = mapUtils.getChunkByPosition
local getChunkByXY = mapUtils.getChunkByXY
@ -89,11 +88,9 @@ local canMigrate = aiPredicates.canMigrate
local findNearbySquad = unitGroupUtils.findNearbySquad
local processBase = baseUtils.processBase
local mMin = math.min
-- local mMax = math.max
local next = next
local mRandom = math.random
-- module code
@ -109,47 +106,21 @@ function mapProcessor.processMap(map, surface, tick)
local roll = map.processRoll
local index = map.processIndex
local chunkToBase = map.chunkToBase
local natives = map.natives
if (index == 1) then
roll = mRandom()
map.processRoll = roll
natives.remainingSquads = AI_MAX_SQUADS_PER_CYCLE
end
local newEnemies = natives.newEnemies
local scentStaging = map.scentStaging
local squads = canAttack(natives, surface) and (roll <= 0.45) and (natives.points >= AI_SQUAD_COST)
if squads and (natives.state == AI_STATE_AGGRESSIVE) and (tick < natives.canAttackTick) then
squads = false
end
local settlers = canMigrate(natives, surface) and (roll <= 0.45) and (natives.points >= AI_SETTLER_COST)
local processQueue = map.processQueue
local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue)
local i = 1
for x=index,endIndex do
local chunk = processQueue[x]
if (chunk[CHUNK_TICK] ~= tick) then
processPheromone(map, chunk, scentStaging[i])
if settlers and (getNestCount(map, chunk) > 0) then
settlers = formSettlers(map, surface, chunk, tick)
end
if squads then
squads = formAttackWave(chunk, map, surface, tick)
end
if newEnemies then
local base = chunkToBase[chunk]
if base and ((tick - base.tick) > BASE_PROCESS_INTERVAL) then
processBase(chunk, surface, natives, tick, base)
end
end
end
i = i + 1
end
@ -170,12 +141,11 @@ function mapProcessor.processMap(map, surface, tick)
end
end
local function queueNestSpawners(map, chunk, tick)
local limitPerActiveChunkTick = map.natives.activeNests * DURATION_ACTIVE_NEST_DIVIDER
local processActiveNest = map.processActiveNest
if ((getNestActiveness(map, chunk) > 0) and (getNestActiveTick(map, chunk) == 0)) then
local nextTick = tick + DURATION_ACTIVE_NEST
local slot = processActiveNest[nextTick]
@ -223,8 +193,6 @@ function mapProcessor.processPlayers(players, map, surface, tick)
local scentStaging = map.scentStaging
local squads = allowingAttacks and (0.11 <= roll) and (roll <= 0.20) and (natives.points >= AI_SQUAD_COST)
-- not looping everyone because the cost is high enough already in multiplayer
if (#players > 0) then
local player = players[mRandom(#players)]
@ -233,9 +201,10 @@ function mapProcessor.processPlayers(players, map, surface, tick)
if (playerChunk ~= -1) then
local i = 1
local vengence = (allowingAttacks and
(natives.points >= AI_VENGENCE_SQUAD_COST) and
((getEnemyStructureCount(map, playerChunk) > 0) or (playerChunk[MOVEMENT_PHEROMONE] < -natives.retreatThreshold)))
local vengence = allowingAttacks and
(natives.points >= AI_VENGENCE_SQUAD_COST) and
((getEnemyStructureCount(map, playerChunk) > 0) or
(playerChunk[MOVEMENT_PHEROMONE] < -natives.retreatThreshold))
for x=playerChunk.x - PROCESS_PLAYER_BOUND, playerChunk.x + PROCESS_PLAYER_BOUND, 32 do
for y=playerChunk.y - PROCESS_PLAYER_BOUND, playerChunk.y + PROCESS_PLAYER_BOUND, 32 do
@ -246,9 +215,14 @@ function mapProcessor.processPlayers(players, map, surface, tick)
processNestActiveness(map, chunk, natives, surface)
queueNestSpawners(map, chunk, tick)
if vengence and (getNestCount(map, chunk) > 0) then
vengence = formVengenceSquad(map, surface, chunk)
local count = natives.vengenceQueue[chunk]
if not count then
count = 0
natives.vengenceQueue[chunk] = count
end
natives.vengenceQueue[chunk] = count + 1
end
end
i = i + 1
@ -293,8 +267,6 @@ function mapProcessor.scanMap(map, surface, tick)
local retreats = map.chunkToRetreats
local rallys = map.chunkToRallys
-- local spawners = map.chunkToSpawner
local settlers = map.chunkToSettler
local drained = map.chunkToDrained
local processQueue = map.processQueue
@ -314,20 +286,15 @@ function mapProcessor.scanMap(map, surface, tick)
offset[2] = chunk.y + CHUNK_SIZE
local retreatTick = retreats[chunk]
if retreatTick and ((tick - retreatTick) > INTERVAL_RETREAT) then
if retreatTick and ((tick - retreatTick) > COOLDOWN_RETREAT) then
retreats[chunk] = nil
end
local rallyTick = rallys[chunk]
if rallyTick and ((tick - rallyTick) > INTERVAL_RALLY) then
if rallyTick and ((tick - rallyTick) > COOLDOWN_RALLY) then
rallys[chunk] = nil
end
local settlerTick = settlers[chunk]
if settlerTick and ((tick - settlerTick) > 0) then
settlers[chunk] = nil
end
local drainTick = drained[chunk]
if drainTick and ((tick - drainTick) > 0) then
drained[chunk] = nil
@ -362,11 +329,11 @@ function mapProcessor.processActiveNests(map, surface, tick)
local processActiveNest = map.processActiveNest
local slot = processActiveNest[tick]
if slot then
local natives = map.natives
for i=1,#slot do
local chunk = slot[i]
if (getNestActiveness(map, chunk) > 0) then
createSpawnerProxy(map, surface, chunk)
-- setNestActiveTick(map, chunk, tick)
processNestActiveness(map, chunk, natives, surface)
local nextTick = tick + DURATION_ACTIVE_NEST
local nextSlot = processActiveNest[nextTick]
if not nextSlot then
@ -382,7 +349,75 @@ function mapProcessor.processActiveNests(map, surface, tick)
end
end
function mapProcessor.processVengence(map, surface, tick)
local natives = map.natives
local ss = natives.vengenceQueue
-- local generated = 0
local chunk, count = next(ss, map.deployVengenceIterator)
-- for i=1,3 do
if not chunk then
map.deployVengenceIterator = nil
-- break
else
-- generated = generated + 1
formVengenceSquad(map, surface, chunk)
local nextChunk
nextChunk, count = next(ss, chunk)
ss[chunk] = nil
chunk = nextChunk
end
-- end
map.deployVengenceIterator = chunk
end
local function processSpawners(map, surface, tick, natives, iteration, iterator, chunks)
local bases = map.chunkToBase
local chunk, count = next(chunks, map[iterator])
for i=1,iteration do
if not chunk then
map[iterator] = nil
return
else
if canMigrate(natives, surface) then
formSettlers(map, surface, chunk, tick)
elseif (canAttack(natives, surface, tick)) then
formSquads(map, surface, chunk, tick)
end
if (natives.newEnemies) then
local base = bases[chunk]
if base and ((tick - base.tick) > BASE_PROCESS_INTERVAL) then
processBase(chunk, surface, natives, tick, base)
end
end
chunk, count = next(chunks, chunk)
end
end
map[iterator] = chunk
end
function mapProcessor.processSpawners(map, surface, tick)
local chunks
local natives = map.natives
if (natives.state ~= AI_STATE_PEACEFUL) then
if (natives.state == AI_STATE_MIGRATING) or
((natives.state == AI_STATE_SIEGE) and natives.temperament <= 0.5)
then
processSpawners(map, surface, tick, natives, 2, "processMigrationIterator", map.chunkToNests)
else
if (natives.state ~= AI_STATE_AGGRESSIVE) then
processSpawners(map, surface, tick, natives, 1, "processActiveSpawnerIterator", map.chunkToActiveNest)
processSpawners(map, surface, tick, natives, 1, "processActiveRaidSpawnerIterator", map.chunkToActiveRaidNest)
else
processSpawners(map, surface, tick, natives, 2, "processActiveSpawnerIterator", map.chunkToActiveNest)
end
end
end
end
mapProcessorG = mapProcessor
return mapProcessor

View File

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

View File

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

View File

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

View File

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

View File

@ -15,6 +15,7 @@ local movementUtils = require("MovementUtils")
local DEFINES_GROUP_FINISHED = defines.group_state.finished
local DIVISOR_DEATH_TRAIL_TABLE = constants.DIVISOR_DEATH_TRAIL_TABLE
local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE
local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
@ -36,6 +37,11 @@ local mRandom = math.random
local findMovementPosition = movementUtils.findMovementPosition
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
local next = next
local table_size = table_size
local mLog = math.log10
@ -139,15 +145,21 @@ function unitGroupUtils.createSquad(position, surface, group, settlers)
end
function unitGroupUtils.cleanSquads(natives, iterator)
local profiler = game.create_profiler()
local squads = natives.groupNumberToSquad
local map = natives.map
local k, squad = next(squads, iterator)
local nextK
for i=1,2 do
if not k then
return nil
elseif not squad.group.valid then
-- for i=1,2 do
if not k then
if (table_size(squads) == 0) then
-- this is needed as the next command remembers the max length a table has been
natives.groupNumberToSquad = {}
end
else
local group = squad.group
if not group.valid then
removeSquadFromChunk(map, squad)
if (map.regroupIterator == k) then
map.regroupIterator = nil
@ -155,9 +167,39 @@ function unitGroupUtils.cleanSquads(natives, iterator)
nextK,squad = next(squads, k)
squads[k] = nil
k = nextK
-- else
-- game.print({"", "3b", profiler})
-- profiler.restart()
-- local members = group.members
-- local memberCount = #members
-- if (memberCount == 0) then
-- game.print({"", "4a", profiler})
-- profiler.restart()
-- local deathGen = getDeathGenerator(map, squad.chunk)
-- local penalties = squad.penalties
-- for xc=1,mMin(#squad.penalties,5) do
-- addDeathGenerator(map,
-- penalties[xc].c,
-- deathGen * DIVISOR_DEATH_TRAIL_TABLE[xc])
-- end
-- removeSquadFromChunk(map, squad)
-- group.destroy()
-- game.print({"", "4ea", profiler})
-- profiler.restart()
-- elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
-- game.print({"", "4b", profiler})
-- profiler.restart()
-- unitGroupUtils.recycleBiters(natives, members)
-- removeSquadFromChunk(map, squad)
-- group.destroy()
-- game.print({"", "4eb", profiler})
-- profiler.restart()
-- end
-- game.print({"", "3be", profiler})
end
end
return k
-- end
map.squadIterator = k
end
function unitGroupUtils.membersToSquad(cmd, size, members, overwriteGroup)
@ -185,6 +227,7 @@ end
function unitGroupUtils.regroupSquads(natives, iterator)
local map = natives.map
local squads = natives.groupNumberToSquad
local cmd = map.mergeGroupCommand
local k, squad = iterator, nil
for i=1,SQUAD_QUEUE_SIZE do
@ -194,42 +237,45 @@ function unitGroupUtils.regroupSquads(natives, iterator)
else
local group = squad.group
if group and group.valid then
cmd.group = group
local groupState = group.state
if (groupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
(groupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
then
local memberCount = #group.members
if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
local status = squad.status
local chunk = squad.chunk
-- local memberCount = #group.members
-- if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
local status = squad.status
local chunk = squad.chunk
if (chunk ~= -1) then
for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do
if (mergeSquad ~= squad) then
local mergeGroup = mergeSquad.group
if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then
local mergeGroupState = mergeGroup.state
if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
(mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
then
local mergeMembers = mergeGroup.members
local mergeCount = #mergeMembers
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then
for memberIndex=1, mergeCount do
group.add_member(mergeMembers[memberIndex])
end
mergeGroup.destroy()
end
squad.status = SQUAD_GUARDING
memberCount = memberCount + mergeCount
if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
break
end
end
if (chunk ~= -1) then
for _,mergeSquad in pairs(getSquadsOnChunk(map, chunk)) do
if (mergeSquad ~= squad) then
local mergeGroup = mergeSquad.group
if mergeGroup and mergeGroup.valid and (mergeSquad.status == status) then
local mergeGroupState = mergeGroup.state
if (mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_TARGET) and
(mergeGroupState ~= DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
then
print("merging group")
mergeGroup.set_command(cmd)
-- local mergeMembers = mergeGroup.members
-- local mergeCount = #mergeMembers
-- if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then
-- for memberIndex=1, mergeCount do
-- group.add_member(mergeMembers[memberIndex])
-- end
-- mergeGroup.destroy()
-- end
squad.status = SQUAD_GUARDING
-- memberCount = memberCount + mergeCount
-- if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
-- break
-- end
end
end
end
end
-- end
end
end
end

View File

@ -18710,7 +18710,6 @@ rampant-enableNEUnits=World: Enable NE as a faction
rampant-disallowFriendlyFire=Safety: Disallow Friendly Fire Splash Damage
rampant-tierStart=World: Beginning enemy level
rampant-tierEnd=World: Ending enemy level
rampant-disableVanillaAI=AI: Disable Vanilla AI
rampant-enableMigration=AI: Enable Migration
rampant-liteMode=Optimization: Lite mode
@ -18806,7 +18805,6 @@ rampant-newEnemyVariations=This number corresponds to the number of variations p
rampant-disallowFriendlyFire=Prevents enemy spitters and worms from damaging units or buildings from the same force through splash damage
rampant-tierStart=This is the starting level of the enemy that will be used when generating the set of enemies for the specified number of tiers and increases linearly to the end tier for as many tiers selected. Roughly healthwise each tier is a follows (1-15,2-75,3-150,4-250,5-1000,6-2000,7-3500,8-7500,9-15000,10-30000). min 1, max 10
rampant-tierEnd=This is the ending tier level that is reached after increasing linearly from the start tier for as many tiers selected. Roughly healthwise each tier is a follows (1-15,2-75,3-150,4-250,5-1000,6-2000,7-3500,8-7500,9-15000,10-30000). min 1, max 10
rampant-disableVanillaAI=This will turn off the vanilla attack waves and the vanilla biter expansion.
rampant-enableMigration=This will allow the ai to expand its worms and nests. Respects the map settings for biter expansion.
rampant-enableShrinkNestsAndWorms=Reduce the collision box size of nests and worms by 50%. May cause overlapping entities due to the collision box being smaller than the entity graphic.

View File

@ -1,5 +1,6 @@
local biterFunctions = require("prototypes/utils/BiterUtils")
local constants = require("libs/Constants")
local smokeUtils = require("prototypes/utils/SmokeUtils")
data:extend({
biterFunctions.makeBiter({
@ -83,3 +84,39 @@ for t=1,11 do
)
end
end
smokeUtils.makeNewCloud(
{
name = "build-clear",
wind = false,
scale = 9,
duration = 540,
cooldown = 10,
tint = { r=0.7, g=0.2, b=0.7 }
},
{
type = "area",
radius = 17,
force = "not-same",
action_delivery =
{
type = "instant",
target_effects =
{
{
type = "damage",
damage = { amount = 8, type = "poison"}
},
{
type = "damage",
damage = { amount = 8, type = "acid"}
},
{
type = "damage",
damage = { amount = 8, type = "fire"}
}
}
}
}
)

View File

@ -2,6 +2,145 @@ local smokeUtils = {}
-- module code
function smokeUtils.makeNewCloud(attributes, attack)
local name = attributes.name .. "-cloud-rampant"
data:extend({
{
type = "smoke-with-trigger",
name = "dummy-" .. name,
flags = {"not-on-map"},
show_when_smoke_off = true,
particle_count = 24,
particle_spread = { 3.6 * 1.05, 3.6 * 0.6 * 1.05 },
particle_distance_scale_factor = 0.5,
particle_scale_factor = { 1, 0.707 },
particle_duration_variation = 60 * 3,
wave_speed = { 0.5 / 80, 0.5 / 60 },
wave_distance = { 1, 0.5 },
spread_duration_variation = 300 - 20,
render_layer = "object",
affected_by_wind = attributes.wind,
cyclic = true,
duration = attributes.duration or 60 * 20 + 4 * 60,
fade_away_duration = 3 * 60,
spread_duration = (300 - 20) / 2 ,
color = attributes.tint or { r = 0.7, g = 0.9, b = 0.2 }, -- #035b6452
animation =
{
width = 152,
height = 120,
line_length = 5,
frame_count = 60,
shift = {-0.53125, -0.4375},
priority = "high",
animation_speed = 0.25,
scale = (attributes.scale and attributes.scale * 0.75) or 2.25,
filename = "__base__/graphics/entity/smoke/smoke.png",
flags = { "smoke" }
}
},
{
type = "smoke-with-trigger",
name = name,
flags = {"not-on-map"},
show_when_smoke_off = true,
animation =
{
width = 152,
height = 120,
line_length = 5,
frame_count = 60,
shift = {-0.53125, -0.4375},
priority = "high",
animation_speed = 0.25,
filename = "__base__/graphics/entity/smoke/smoke.png",
flags = { "smoke" },
scale = attributes.scale or 3,
tint = attributes.tint or { r = 0.7, g = 0.9, b = 0.2 }
},
created_effect =
{
{
type = "cluster",
cluster_count = (attributes.scale and attributes.scale * 0.5) and 10,
distance = (attributes.scale and attributes.scale * 0.8) and 4,
distance_deviation = 5,
action_delivery =
{
type = "instant",
target_effects =
{
type = "create-smoke",
show_in_tooltip = false,
entity_name = "dummy-" .. name,
initial_height = 0
}
}
},
{
type = "cluster",
cluster_count = (attributes.scale and attributes.scale * 0.65) and 11,
distance = (attributes.scale and attributes.scale * 1.8) and 8 * 1.1,
distance_deviation = 2,
action_delivery =
{
type = "instant",
target_effects =
{
type = "create-smoke",
show_in_tooltip = false,
entity_name = "dummy-" .. name,
initial_height = 0
}
}
}
},
slow_down_factor = attributes.slowdown or 0,
affected_by_wind = attributes.wind,
cyclic = true,
render_layer = "higher-object-above",
duration = attributes.duration or 60 * 20,
fade_away_duration = attributes.outDuration or (attributes.duration and attributes.duration * 0.25) or 2 * 60,
spread_duration = attributes.inDuration or (attributes.duration and attributes.duration * 0.25) or 10,
action = attack or
{
type = "direct",
action_delivery =
{
type = "instant",
target_effects =
{
type = "nested-result",
action =
{
type = "area",
radius = 11,
entity_flags = {"breaths-air"},
action_delivery =
{
type = "instant",
target_effects =
{
type = "damage",
damage = { amount = 8, type = "poison"}
}
}
}
}
}
},
action_cooldown = attributes.cooldown or 30
}
})
return name
end
function smokeUtils.makeCloud(attributes, attack)
local name = attributes.name .. "-cloud-rampant"

View File

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

View File

@ -219,9 +219,9 @@ function tests.attackOrigin()
max_distance = 1000})
if (enemy ~= nil) and enemy.valid then
print(enemy, enemy.unit_number)
enemy.set_command({type=defines.command.attack_area,
enemy.set_command({type=defines.command.go_to_location,
destination={0,0},
radius=32})
radius=15})
end
end