1
0
mirror of https://github.com/veden/Rampant.git synced 2025-02-09 13:36:53 +02:00

Merge branch 'fixTileError'

This commit is contained in:
Aaron Veden 2018-01-23 19:38:10 -08:00
commit 2d5930047f
30 changed files with 1338 additions and 503 deletions

298
BuildSwarm.lua Executable file
View File

@ -0,0 +1,298 @@
local swarmUtils = {}
-- imports
local biterUtils = require("prototypes/enemies/BiterUtils")
local mathUtils = require("libs/MathUtils")
-- imported functions
local gaussianRandomRangeRG = mathUtils.gaussianRandomRangeRG
local mMax = math.max
local mMin = math.min
local mFloor = math.floor
local deepcopy = util.table.deepcopy
local xorRandom = mathUtils.xorRandom(settings.startup["rampant-enemySeed"].value)
local makeBiter = biterUtils.makeBiter
local makeSpitter = biterUtils.makeSpitter
local makeWorm = biterUtils.makeWorm
local makeUnitSpawner = biterUtils.makeUnitSpawner
-- module code
local function unitSetToProbabilityTable(points, upgradeTable, unitSet)
local dividers = {}
for i=1,#unitSet do
dividers[i] = 1
end
if upgradeTable then
while (points > 0) do
local upgrade = upgradeTable[mFloor(xorRandom() * #upgradeTable)+1]
local cost = upgrade.cost
local index = upgrade.index
dividers[index] = dividers[index] + upgrade.adjustment
points = points - cost
end
end
local total = 0
for i=1,#dividers do
total = total + dividers[i]
end
local runningTotal = 0
for i=1,#dividers do
runningTotal = runningTotal + (dividers[i] / total)
dividers[i] = runningTotal
end
local stepUnit = 1 / (#unitSet[1] + 1)
local probabilityTable = {}
for i=1,#unitSet do
local result
if (i == 1) then
result = {
{
0,
stepUnit
},
{
dividers[i],
0
}
}
elseif (i == #unitSet) then
result = {
{
dividers[i-2],
0
},
{
1,
stepUnit
}
}
else
result = {
{
((i - 2) > 0 and dividers[i-2]) or 0,
0
},
{
dividers[i-1],
stepUnit
},
{
dividers[i],
0
}
}
end
probabilityTable[i] = result
end
local result = {}
for i=1, #probabilityTable do
local probability = probabilityTable[i]
for x=1, #unitSet[i] do
result[#result+1] = {unitSet[i][x], probability}
end
end
return result
end
local function upgradeEntity(points, entity, upgradeTable)
local remainingPoints = points
if upgradeTable then
while (remainingPoints > 0) do
local upgrade = upgradeTable[mFloor(xorRandom() * #upgradeTable)+1]
local cost = upgrade.cost
for i=1, #upgrade.bonus do
local bonus = upgrade.bonus[i]
if (bonus.type == "attribute") then
if bonus.mapping then
entity.attributes[bonus.name] = bonus.mapping[entity.attributes[bonus.name] or "default"]
else
entity.attributes[bonus.name] = (entity.attributes[bonus.name] or 0) + bonus.adjustment
end
end
if (bonus.type == "resistance") then
local field = bonus.resistance.name
if not entity.resistances[field] then
entity.resistances[field] = {}
end
if bonus.resistance.decrease then
entity.resistances[field].decrease = (entity.resistances[field].decrease or 0) + bonus.resistance.decrease
end
if bonus.resistance.percentage then
entity.resistances[field].percentage = (entity.resistances[field].percentage or 0) + bonus.resistance.percentage
end
end
if (bonus.type == "attack") then
local attack = bonus.attack
entity.attack[attack.name] = (entity.attack[attack.name] or 0) + attack.adjustment
if attack.mapping then
entity.attributes[attack.name] = attack.mapping[entity.attributes[attack.name] or "default"]
else
entity.attributes[attack.name] = (entity.attributes[attack.name] or 0) + attack.adjustment
end
end
end
remainingPoints = remainingPoints - cost
end
end
end
local function generateApperance(unit, tier)
local scale = gaussianRandomRangeRG(unit.scale, unit.scale * 0.12, unit.scale * 0.60, unit.scale * 1.40, xorRandom) + (0.05 * tier)
local r,g,b,a
if unit.tint then
r = gaussianRandomRangeRG(unit.tint.r, unit.tint.r * 0.10 + (0.005 * tier), mMax(unit.tint.r * 0.85 - (0.005 * tier), 0), mMin(unit.tint.r * 1.15, 1), xorRandom)
g = gaussianRandomRangeRG(unit.tint.g, unit.tint.g * 0.10 + (0.005 * tier), mMax(unit.tint.g * 0.85 - (0.005 * tier), 0), mMin(unit.tint.g * 1.15, 1), xorRandom)
b = gaussianRandomRangeRG(unit.tint.b, unit.tint.b * 0.10 + (0.005 * tier), mMax(unit.tint.b * 0.85 - (0.005 * tier), 0), mMin(unit.tint.b * 1.15, 1), xorRandom)
a = gaussianRandomRangeRG(unit.tint.a, unit.tint.a * 0.10 + (0.005 * tier), mMax(unit.tint.a * 0.85 - (0.005 * tier), 0), mMin(unit.tint.a * 1.15, 1), xorRandom)
local tint = { r=r, g=g, b=b, a=a }
unit.attributes.scale = scale
unit.attributes.tint = tint
else
r = gaussianRandomRangeRG(unit.tint1.r, unit.tint1.r * 0.10 + (0.005 * tier), mMax(unit.tint1.r * 0.85 - (0.005 * tier), 0), mMin(unit.tint1.r * 1.15, 1), xorRandom)
g = gaussianRandomRangeRG(unit.tint1.g, unit.tint1.g * 0.10 + (0.005 * tier), mMax(unit.tint1.g * 0.85 - (0.005 * tier), 0), mMin(unit.tint1.g * 1.15, 1), xorRandom)
b = gaussianRandomRangeRG(unit.tint1.b, unit.tint1.b * 0.10 + (0.005 * tier), mMax(unit.tint1.b * 0.85 - (0.005 * tier), 0), mMin(unit.tint1.b * 1.15, 1), xorRandom)
a = gaussianRandomRangeRG(unit.tint1.a, unit.tint1.a * 0.10 + (0.005 * tier), mMax(unit.tint1.a * 0.85 - (0.005 * tier), 0), mMin(unit.tint1.a * 1.15, 1), xorRandom)
local tint1 = { r=r, g=g, b=b, a=a }
r = gaussianRandomRangeRG(unit.tint2.r, unit.tint2.r * 0.10 + (0.005 * tier), mMax(unit.tint2.r * 0.85 - (0.005 * tier), 0), mMin(unit.tint2.r * 1.15, 1), xorRandom)
g = gaussianRandomRangeRG(unit.tint2.g, unit.tint2.g * 0.10 + (0.005 * tier), mMax(unit.tint2.g * 0.85 - (0.005 * tier), 0), mMin(unit.tint2.g * 1.15, 1), xorRandom)
b = gaussianRandomRangeRG(unit.tint2.b, unit.tint2.b * 0.10 + (0.005 * tier), mMax(unit.tint2.b * 0.85 - (0.005 * tier), 0), mMin(unit.tint2.b * 1.15, 1), xorRandom)
a = gaussianRandomRangeRG(unit.tint2.a, unit.tint2.a * 0.10 + (0.005 * tier), mMax(unit.tint2.a * 0.85 - (0.005 * tier), 0), mMin(unit.tint2.a * 1.15, 1), xorRandom)
local tint2 = { r=r, g=g, b=b, a=a }
unit.attributes.scale = scale
unit.attributes.tint1 = tint1
unit.attributes.tint2 = tint2
unit.attack.scale = scale
unit.attack.tint1 = tint1
unit.attack.tint2 = tint2
end
end
local function buildUnits(startingPoints, template, attackGenerator, upgradeTable, variations, tiers)
local unitSet = {}
for t=1, tiers do
local result = {}
local allottedPoints = startingPoints * t
for i=1,variations do
local unit = deepcopy(template)
unit.name = unit.name .. "-v" .. i .. "-t" .. t
generateApperance(unit, t)
upgradeEntity(allottedPoints, unit, upgradeTable)
local entity
if (unit.type == "spitter") then
entity = makeSpitter(unit.name,
unit.attributes,
attackGenerator(unit.attack),
unit.resistances)
elseif (unit.type == "biter") then
entity = makeBiter(unit.name,
unit.attributes,
attackGenerator(unit.attack),
unit.resistances)
end
result[i] = entity.name
data:extend({entity})
end
unitSet[t] = result
end
return unitSet
end
local function buildUnitSpawner(startingPoints, template, upgradeTable, unitTable, variations, tiers)
for t=1, tiers do
local allottedPoints = startingPoints * t
for i=1,variations do
local unitSpawner = deepcopy(template)
unitSpawner.name = unitSpawner.name .. "-v" .. i .. "-t" .. t
generateApperance(unitSpawner, t)
upgradeEntity(allottedPoints, unitSpawner, upgradeTable)
data:extend({
makeUnitSpawner(unitSpawner.name,
unitSpawner.attributes,
unitSpawner.resistances,
unitTable)
})
end
end
end
function swarmUtils.buildWorm(startingPoints, template, attackGenerator, upgradeTable, variations, tiers)
for t=1, tiers do
local allottedPoints = startingPoints * t
for i=1,variations do
local worm = deepcopy(template)
worm.name = worm.name .. "-v" .. i .. "-t" .. t
generateApperance(worm, t)
upgradeEntity(allottedPoints, worm, upgradeTable)
data:extend({
makeWorm(worm.name,
worm.attributes,
attackGenerator(worm.attack),
worm.resistances)
})
end
end
end
function swarmUtils.createUnitClass(points, templates, upgradeTable, attackGenerator, variations, tiers)
buildUnitSpawner(points.unitSpawner,
templates.unitSpawner,
upgradeTable.unitSpawner,
unitSetToProbabilityTable(points.probabilityTable,
upgradeTable.probabilityTable,
buildUnits(points.unit,
templates.unit,
attackGenerator,
upgradeTable.unit,
variations.unit,
tiers.unit)),
variations.unitSpawner,
tiers.unitSpawner)
end
return swarmUtils

188
UnitClasses.lua Executable file
View File

@ -0,0 +1,188 @@
-- imports
local biterUtils = require("prototypes/enemies/BiterUtils")
local swarmUtils = require("Swarmutils")
-- imported functions
local createUnitClass = swarmUtils.createUnitClass
local createSuicideAttack = biterUtils.createSuicideAttack
-- module code
createUnitClass(
{
unit = 10,
unitSpawner = 5,
probabilityTable = 5
},
{
unit = {
name = "rampant-suicide-biter",
attributes = {
health = 30,
movement = 0.21,
distancePerFrame = 0.1,
healing = 0.01,
explosion = "blood-explosion-small",
},
attack = {
area = 3.5,
damage = 20,
explosion = "explosion",
scorchmark = "small-scorchmark",
explosionCount = 2,
explosionDistance = 2,
},
resistances = {
explosion = {
decrease = 0,
percentage = -50
},
laser = {
decrease = 1,
percentage = 0
},
fire = {
decrease = 0,
percentage = -60
}
},
type = "biter",
scale = 0.55,
tint1 = {r=0.6, g=0.0, b=0.70, a=0.8},
tint2 = {r=0.7, g=0.0, b=0.72, a=0.4}
},
unitSpawner = {
name = "rampant-suicide-nest",
attributes = {
health = 30,
healing = 0.01,
unitsOwned = 7,
unitsToSpawn = 5,
spawingCooldownStart = 360,
spawingCooldownStop = 150,
},
resistances = {
explosion = {
decrease = 0,
percentage = -50
},
laser = {
decrease = 1,
percentage = 0
},
fire = {
decrease = 0,
percentage = -60
}
},
scale = 0.95,
tint = {r=0.7, g=0.0, b=0.72, a=0.4}
}
},
{
unit = {
{
cost = 1,
bonus = {
{
type = "attribute",
name = "health",
adjustment = 50
}
}
}
},
unitSpawner = {
{
cost = 1,
bonus = {
{
type = "attribute",
name = "health",
adjustment = 50
}
}
}
},
probabilityTable = {
{
cost = 1,
index = 1,
adjustment = 1
},
{
cost = 1,
index = 2,
adjustment = 1
},
{
cost = 1,
index = 3,
adjustment = 1
},
{
cost = 1,
index = 4,
adjustment = 1
},
{
cost = 1,
index = 5,
adjustment = 1
},
{
cost = 1,
index = 6,
adjustment = 1.5
},
{
cost = 1,
index = 7,
adjustment = 2
},
{
cost = 1,
index = 8,
adjustment = 2
},
{
cost = 1,
index = 9,
adjustment = 1.5
},
{
cost = 1,
index = 10,
adjustment = 1
}
}
},
createSuicideAttack,
{
unit = 5,
unitSpawner = 5
},
{
unit = 10,
unitSpawner = 7
}
)

View File

@ -105,7 +105,7 @@ function upgrade.attempt(natives)
-- used to precompute some values per logic cycle -- used to precompute some values per logic cycle
natives.retreatThreshold = 0 natives.retreatThreshold = 0
natives.maxSquads = 0 -- natives.maxSquads = 0
natives.rallyThreshold = 0 natives.rallyThreshold = 0
natives.formSquadThreshold = 0 natives.formSquadThreshold = 0
natives.attackWaveSize = 0 natives.attackWaveSize = 0
@ -163,10 +163,16 @@ function upgrade.attempt(natives)
game.surfaces[1].print("Rampant - Version 0.15.23") game.surfaces[1].print("Rampant - Version 0.15.23")
global.version = constants.VERSION_33 global.version = constants.VERSION_33
end end
if (global.version < constants.VERSION_37) then if (global.version < constants.VERSION_38) then
game.surfaces[1].print("Rampant - Version 0.16.2") for _,squad in pairs(natives.squads) do
global.version = constants.VERSION_37 squad.chunk = nil
end
global.regionMap = nil
game.surfaces[1].print("Rampant - Version 0.16.3")
global.version = constants.VERSION_38
end end
return starting ~= global.version, natives return starting ~= global.version, natives
end end

View File

@ -1,3 +1,15 @@
---------------------------------------------------------------------------------------------------
Version: 0.16.3
Date: 1. 13. 2018
Bugfixes:
- Fixed creative mode tile wand robot error (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=220&hilit=rampant#p335574)
Improvements:
- Removed squad limit
Optimizations:
- Reworked squad regrouping to be surrounding chunks instead comparing against master list
Framework:
- Add squads to chunk map for faster location sensitive lookups
--------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------
Version: 0.16.2 Version: 0.16.2
Date: 1. 2. 2018 Date: 1. 2. 2018

View File

@ -36,6 +36,14 @@ 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_COMMAND_GROUP = defines.command.group
local DEFINES_COMMAND_ATTACK_AREA = defines.command.attack_area
local CHUNK_SIZE = constants.CHUNK_SIZE
local DEFINES_DISTRACTION_NONE = defines.distraction.none
local DEFINES_DISTRACTION_BY_ENEMY = defines.distraction.by_enemy
-- imported functions -- imported functions
local roundToNearest = mathUtils.roundToNearest local roundToNearest = mathUtils.roundToNearest
@ -80,7 +88,7 @@ local mRandom = math.random
-- local references to global -- local references to global
local regionMap -- 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 local pendingChunks -- chunks that have yet to be processed by the mod
@ -96,9 +104,9 @@ local function onIonCannonFired(event)
if (natives.points > AI_MAX_OVERFLOW_POINTS) then if (natives.points > AI_MAX_OVERFLOW_POINTS) then
natives.points = AI_MAX_OVERFLOW_POINTS natives.points = AI_MAX_OVERFLOW_POINTS
end end
local chunk = getChunkByPosition(regionMap, event.position) local chunk = getChunkByPosition(map, event.position)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
rallyUnits(chunk, regionMap, surface, natives, event.tick) rallyUnits(chunk, map, surface, natives, event.tick)
end end
end end
end end
@ -113,7 +121,7 @@ local function hookEvents()
end end
local function onLoad() local function onLoad()
regionMap = global.regionMap map = global.map
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks pendingChunks = global.pendingChunks
@ -130,27 +138,28 @@ end
local function rebuildRegionMap() local function rebuildRegionMap()
game.surfaces[1].print("Rampant - Reindexing chunks, please wait.") game.surfaces[1].print("Rampant - Reindexing chunks, please wait.")
-- clear old regionMap processing Queue -- clear old map processing Queue
-- prevents queue adding duplicate chunks -- prevents queue adding duplicate chunks
-- chunks are by key, so should overwrite old -- chunks are by key, so should overwrite old
global.regionMap = {} global.map = {}
regionMap = global.regionMap map = global.map
regionMap.processQueue = {} map.processQueue = {}
regionMap.processIndex = 1 map.processIndex = 1
regionMap.scanIndex = 1 map.scanIndex = 1
regionMap.chunkToHives = {} map.chunkToHives = {}
regionMap.chunkToNests = {} map.chunkToNests = {}
regionMap.chunkToWorms = {} map.chunkToWorms = {}
regionMap.chunkToRetreats = {} map.chunkToRetreats = {}
regionMap.chunkToRallys = {} map.chunkToRallys = {}
regionMap.chunkToPlayerBase = {} map.chunkToPlayerBase = {}
regionMap.chunkToResource = {} map.chunkToResource = {}
regionMap.chunkToPassScan = {} map.chunkToPassScan = {}
map.chunkToSquad = {}
-- 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.
regionMap.neighbors = { SENTINEL_IMPASSABLE_CHUNK, map.neighbors = { SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
@ -158,29 +167,40 @@ local function rebuildRegionMap()
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK } SENTINEL_IMPASSABLE_CHUNK }
regionMap.cardinalNeighbors = { SENTINEL_IMPASSABLE_CHUNK, map.cardinalNeighbors = { SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK, SENTINEL_IMPASSABLE_CHUNK,
SENTINEL_IMPASSABLE_CHUNK } SENTINEL_IMPASSABLE_CHUNK }
regionMap.position = {x=0, map.position = {x=0,
y=0} y=0}
--this is shared between two different queries --this is shared between two different queries
regionMap.area = {{0, 0}, {0, 0}} map.area = {{0, 0}, {0, 0}}
regionMap.countResourcesQuery = { area=regionMap.area, type="resource" } map.countResourcesQuery = { area=map.area, type="resource" }
regionMap.filteredEntitiesEnemyQuery = { area=regionMap.area, force="enemy" } map.filteredEntitiesEnemyQuery = { area=map.area, force="enemy" }
regionMap.filteredEntitiesEnemyUnitQuery = { area=regionMap.area, force="enemy", type="unit", limit=301 } map.filteredEntitiesEnemyUnitQuery = { area=map.area, force="enemy", type="unit", limit=301 }
regionMap.filteredEntitiesEnemyTypeQuery = { area=regionMap.area, force="enemy", type="unit-spawner" } map.filteredEntitiesEnemyTypeQuery = { area=map.area, force="enemy", type="unit-spawner" }
regionMap.filteredEntitiesPlayerQuery = { area=regionMap.area, force="player" } map.filteredEntitiesPlayerQuery = { area=map.area, force="player" }
regionMap.canPlaceQuery = { name="", position={0,0} } map.canPlaceQuery = { name="", position={0,0} }
regionMap.filteredTilesQuery = { name="", area=regionMap.area } map.filteredTilesQuery = { name="", area=map.area }
map.attackAreaCommand = {
type = DEFINES_COMMAND_ATTACK_AREA,
destination = map.position,
radius = CHUNK_SIZE,
distraction = DEFINES_DISTRACTION_BY_ENEMY
}
map.retreatCommand = { type = DEFINES_COMMAND_GROUP,
group = nil,
distraction = DEFINES_DISTRACTION_NONE }
-- switched over to tick event -- switched over to tick event
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) map.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
regionMap.scanTick = roundToNearest(game.tick + INTERVAL_SCAN, INTERVAL_SCAN) map.scanTick = roundToNearest(game.tick + INTERVAL_SCAN, INTERVAL_SCAN)
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS) map.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
regionMap.chunkTick = roundToNearest(game.tick + INTERVAL_CHUNK, INTERVAL_CHUNK) map.chunkTick = roundToNearest(game.tick + INTERVAL_CHUNK, INTERVAL_CHUNK)
regionMap.squadTick = roundToNearest(game.tick + INTERVAL_SQUAD, INTERVAL_SQUAD) map.squadTick = roundToNearest(game.tick + INTERVAL_SQUAD, INTERVAL_SQUAD)
-- clear pending chunks, will be added when loop runs below -- clear pending chunks, will be added when loop runs below
global.pendingChunks = {} global.pendingChunks = {}
@ -196,7 +216,7 @@ local function rebuildRegionMap()
y = chunk.y * 32 }}}) y = chunk.y * 32 }}})
end end
processPendingChunks(natives, regionMap, surface, pendingChunks, tick) processPendingChunks(natives, map, surface, pendingChunks, tick)
end end
local function onModSettingsChange(event) local function onModSettingsChange(event)
@ -260,28 +280,28 @@ end
local function onTick(event) local function onTick(event)
local tick = event.tick local tick = event.tick
if (tick == regionMap.processTick) then if (tick == map.processTick) then
regionMap.processTick = regionMap.processTick + INTERVAL_PROCESS map.processTick = map.processTick + INTERVAL_PROCESS
local gameRef = game local gameRef = game
local surface = gameRef.surfaces[1] local surface = gameRef.surfaces[1]
processPlayers(gameRef.players, regionMap, surface, natives, tick) processPlayers(gameRef.players, map, surface, natives, tick)
processMap(regionMap, surface, natives, tick) processMap(map, surface, natives, tick)
end end
if (tick == regionMap.scanTick) then if (tick == map.scanTick) then
regionMap.scanTick = regionMap.scanTick + INTERVAL_SCAN map.scanTick = map.scanTick + INTERVAL_SCAN
local surface = game.surfaces[1] local surface = game.surfaces[1]
processPendingChunks(natives, regionMap, surface, pendingChunks, tick) processPendingChunks(natives, map, surface, pendingChunks, tick)
scanMap(regionMap, surface, natives) scanMap(map, surface, natives)
regionMap.chunkToPassScan = processScanChunks(regionMap, surface) map.chunkToPassScan = processScanChunks(map, surface)
end end
if (tick == regionMap.logicTick) then if (tick == map.logicTick) then
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC map.logicTick = map.logicTick + INTERVAL_LOGIC
local gameRef = game local gameRef = game
local surface = gameRef.surfaces[1] local surface = gameRef.surfaces[1]
@ -292,26 +312,26 @@ local function onTick(event)
surface) surface)
if natives.useCustomAI then if natives.useCustomAI then
processBases(regionMap, surface, natives, tick) processBases(map, surface, natives, tick)
end end
end end
if (tick == regionMap.squadTick) then if (tick == map.squadTick) then
regionMap.squadTick = regionMap.squadTick + INTERVAL_SQUAD map.squadTick = map.squadTick + INTERVAL_SQUAD
local gameRef = game local gameRef = game
cleanSquads(natives) cleanSquads(natives, map)
regroupSquads(natives) regroupSquads(natives, map)
squadsBeginAttack(natives, gameRef.players) squadsBeginAttack(natives, gameRef.players)
squadsAttack(regionMap, gameRef.surfaces[1], natives) squadsAttack(map, gameRef.surfaces[1], natives)
end end
end end
local function onBuild(event) local function onBuild(event)
local entity = event.created_entity local entity = event.created_entity
if (entity.surface.index == 1) then if (entity.surface.index == 1) then
addRemovePlayerEntity(regionMap, entity, natives, true, false) addRemovePlayerEntity(map, entity, natives, true, false)
if natives.safeBuildings then if natives.safeBuildings then
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
entity.destructible = false entity.destructible = false
@ -324,7 +344,7 @@ local function onMine(event)
local entity = event.entity local entity = event.entity
local surface = entity.surface local surface = entity.surface
if (surface.index == 1) then if (surface.index == 1) then
addRemovePlayerEntity(regionMap, entity, natives, false, false) addRemovePlayerEntity(map, entity, natives, false, false)
end end
end end
@ -333,7 +353,7 @@ local function onDeath(event)
local surface = entity.surface local surface = entity.surface
if (surface.index == 1) then if (surface.index == 1) then
local entityPosition = entity.position local entityPosition = entity.position
local chunk = getChunkByPosition(regionMap, entityPosition) local chunk = getChunkByPosition(map, entityPosition)
local cause = event.cause local cause = event.cause
if (entity.force.name == "enemy") then if (entity.force.name == "enemy") then
if (entity.type == "unit") then if (entity.type == "unit") then
@ -350,7 +370,7 @@ local function onDeath(event)
retreatUnits(chunk, retreatUnits(chunk,
entityPosition, entityPosition,
convertUnitGroupToSquad(natives, entity.unit_group), convertUnitGroupToSquad(natives, entity.unit_group),
regionMap, map,
surface, surface,
natives, natives,
tick, tick,
@ -358,7 +378,7 @@ local function onDeath(event)
artilleryBlast) artilleryBlast)
if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then if (mRandom() < natives.rallyThreshold) and not surface.peaceful_mode then
rallyUnits(chunk, regionMap, surface, natives, tick) rallyUnits(chunk, map, surface, natives, tick)
end end
end end
end end
@ -367,14 +387,14 @@ local function onDeath(event)
local tick = event.tick local tick = event.tick
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
unregisterEnemyBaseStructure(regionMap, entity) unregisterEnemyBaseStructure(map, entity)
rallyUnits(chunk, regionMap, surface, natives, tick) rallyUnits(chunk, map, surface, natives, tick)
retreatUnits(chunk, retreatUnits(chunk,
entityPosition, entityPosition,
nil, nil,
regionMap, map,
surface, surface,
natives, natives,
tick, tick,
@ -393,7 +413,7 @@ local function onDeath(event)
if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then
makeImmortalEntity(surface, entity) makeImmortalEntity(surface, entity)
else else
addRemovePlayerEntity(regionMap, entity, natives, false, creditNatives) addRemovePlayerEntity(map, entity, natives, false, creditNatives)
end end
end end
end end
@ -403,12 +423,12 @@ local function onEnemyBaseBuild(event)
local entity = event.entity local entity = event.entity
local surface = entity.surface local surface = entity.surface
if (surface.index == 1) then if (surface.index == 1) then
registerEnemyBaseStructure(regionMap, entity, nil) registerEnemyBaseStructure(map, entity, nil)
end end
end end
local function onSurfaceTileChange(event) local function onSurfaceTileChange(event)
local surfaceIndex = event.surface_index or event.robot.surface.index local surfaceIndex = event.surface_index or (event.robot and event.robot.surface.index)
if (event.item.name == "landfill") and (surfaceIndex == 1) then if (event.item.name == "landfill") and (surfaceIndex == 1) then
local chunks = {} local chunks = {}
local positions = event.tiles local positions = event.tiles
@ -418,7 +438,7 @@ local function onSurfaceTileChange(event)
-- weird bug with table pointer equality using name instead pointer comparison -- weird bug with table pointer equality using name instead pointer comparison
if not chunk.name then if not chunk.name then
regionMap.chunkToPassScan[chunk] = true map.chunkToPassScan[chunk] = true
else else
local x,y = mapUtils.positionToChunkXY(position) local x,y = mapUtils.positionToChunkXY(position)
local addMe = true local addMe = true
@ -444,7 +464,7 @@ end
local function onResourceDepleted(event) local function onResourceDepleted(event)
local entity = event.entity local entity = event.entity
if (entity.surface.index == 1) then if (entity.surface.index == 1) then
chunkUtils.unregisterResource(entity, regionMap) chunkUtils.unregisterResource(entity, map)
end end
end end
@ -455,17 +475,17 @@ local function onUsedCapsule(event)
{event.position.x+0.75,event.position.y+0.75}}, {event.position.x+0.75,event.position.y+0.75}},
type="cliff"}) type="cliff"})
for i=1,#cliffs do for i=1,#cliffs do
entityForPassScan(regionMap, cliffs[i]) entityForPassScan(map, cliffs[i])
end end
end end
end end
local function onInit() local function onInit()
global.regionMap = {} global.map = {}
global.pendingChunks = {} global.pendingChunks = {}
global.natives = {} global.natives = {}
regionMap = global.regionMap map = global.map
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks pendingChunks = global.pendingChunks

View File

@ -6,8 +6,12 @@ require("prototypes/buildings/UnitSpawners")
require("prototypes/tile/fillableDirt") require("prototypes/tile/fillableDirt")
require("prototypes/enemies/UnitSuicideBiters")
require("prototypes/enemies/UnitFireSpitters")
require("prototypes/enemies/UnitTendril")
if settings.startup["rampant-newEnemies"].value then
require("BuildSwarm")
end
-- require("prototypes/enemies/UnitSuicideBiters")
-- require("prototypes/enemies/UnitFireSpitters")
-- require("prototypes/enemies/UnitTendril")

View File

@ -1,7 +1,7 @@
{ {
"name" : "Rampant", "name" : "Rampant",
"factorio_version" : "0.16", "factorio_version" : "0.16",
"version" : "0.16.2", "version" : "0.16.3",
"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",

View File

@ -81,23 +81,25 @@ local function scoreUnitGroupLocation(neighborChunk)
return neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] return neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
end end
local function validUnitGroupLocation(regionMap, neighborChunk) local function validUnitGroupLocation(map, neighborChunk)
return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(regionMap, neighborChunk) == 0) return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(map, neighborChunk) == 0)
end end
function aiAttackWave.rallyUnits(chunk, regionMap, surface, natives, tick) function aiAttackWave.rallyUnits(chunk, map, surface, natives, tick)
if ((tick - getRallyTick(regionMap, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) and if ((tick - getRallyTick(map, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) -- and
(#natives.squads < natives.maxSquads)) then -- (#natives.squads < natives.maxSquads)
setRallyTick(regionMap, chunk, tick) ) then
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 for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do
if (x ~= cX) and (y ~= cY) then if (x ~= cX) and (y ~= cY) then
local rallyChunk = getChunkByXY(regionMap, x, y) local rallyChunk = getChunkByXY(map, x, y)
if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(regionMap, rallyChunk) > 0) then if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(map, rallyChunk) > 0) then
aiAttackWave.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST) aiAttackWave.formSquads(map, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
if (natives.points < AI_VENGENCE_SQUAD_COST) and (#natives.squads < natives.maxSquads) then if (natives.points < AI_VENGENCE_SQUAD_COST) -- and (#natives.squads < natives.maxSquads)
then
return return
end end
end end
@ -107,20 +109,20 @@ function aiAttackWave.rallyUnits(chunk, regionMap, surface, natives, tick)
end end
end end
function aiAttackWave.formSquads(regionMap, surface, natives, chunk, cost) function aiAttackWave.formSquads(map, surface, natives, chunk, cost)
local valid = (cost == AI_VENGENCE_SQUAD_COST) or ((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface)) local valid = (cost == AI_VENGENCE_SQUAD_COST) or ((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface))
if valid and (mRandom() < natives.formSquadThreshold) then if valid and (mRandom() < natives.formSquadThreshold) then
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(regionMap, chunk.x, chunk.y), local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
validUnitGroupLocation, validUnitGroupLocation,
scoreUnitGroupLocation, scoreUnitGroupLocation,
regionMap) map)
if (squadPath ~= SENTINEL_IMPASSABLE_CHUNK) then if (squadPath ~= SENTINEL_IMPASSABLE_CHUNK) then
local squadPosition = surface.find_non_colliding_position("biter-spawner-hive-rampant", local squadPosition = surface.find_non_colliding_position("biter-spawner-hive-rampant",
positionFromDirectionAndChunk(squadDirection, positionFromDirectionAndChunk(squadDirection,
chunk, chunk,
regionMap.position, map.position,
0.98), 0.98),
CHUNK_SIZE, CHUNK_SIZE,
4) 4)

View File

@ -65,7 +65,7 @@ function aiPlanning.planning(natives, evolution_factor, tick, surface)
local attackWaveMaxSize = natives.attackWaveMaxSize local attackWaveMaxSize = natives.attackWaveMaxSize
natives.retreatThreshold = -(evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL) natives.retreatThreshold = -(evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)
natives.maxSquads = AI_MAX_SQUAD_COUNT * evolution_factor -- natives.maxSquads = AI_MAX_SQUAD_COUNT * evolution_factor
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.25 * evolution_factor), 0.10)
natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.66667) natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.66667)

View File

@ -15,7 +15,8 @@ local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL
function aiPredicates.canAttack(natives, surface) function aiPredicates.canAttack(natives, surface)
return (((natives.state == AI_STATE_AGGRESSIVE) or aiPredicates.canAttackDark(natives, surface)) return (((natives.state == AI_STATE_AGGRESSIVE) or aiPredicates.canAttackDark(natives, surface))
and not surface.peaceful_mode and (#natives.squads < natives.maxSquads)) and not surface.peaceful_mode -- and (#natives.squads < natives.maxSquads)
)
end end
function aiPredicates.isDark(surface) function aiPredicates.isDark(surface)

View File

@ -19,7 +19,7 @@ local advanceTendrils = tendrilUtils.advanceTendrils
-- module code -- module code
function baseProcessor.processBases(regionMap, surface, natives, tick) function baseProcessor.processBases(map, surface, natives, tick)
local baseIndex = natives.baseIndex local baseIndex = natives.baseIndex
local bases = natives.bases local bases = natives.bases
@ -27,8 +27,8 @@ function baseProcessor.processBases(regionMap, surface, natives, tick)
for index = baseIndex, endIndex do for index = baseIndex, endIndex do
local base = bases[index] local base = bases[index]
buildOrder(regionMap, natives, base, surface, tick) buildOrder(map, natives, base, surface, tick)
advanceTendrils(regionMap, base, surface, tick, natives) advanceTendrils(map, base, surface, tick, natives)
end end
if (endIndex == #bases) then if (endIndex == #bases) then

View File

@ -47,7 +47,7 @@ function baseUtils.findNearbyBase(natives, position)
return foundBase return foundBase
end end
function baseUtils.createBase(regionMap, natives, position, surface, tick) function baseUtils.createBase(map, natives, position, surface, tick)
local bases = natives.bases local bases = natives.bases
local distance = euclideanDistancePoints(position.x, position.y, 0, 0) local distance = euclideanDistancePoints(position.x, position.y, 0, 0)
local base = { local base = {
@ -65,10 +65,10 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick)
pattern = mRandom(MAGIC_MAXIMUM_BASE_NUMBER), pattern = mRandom(MAGIC_MAXIMUM_BASE_NUMBER),
level = mFloor(distance / 200) level = mFloor(distance / 200)
} }
if not buildHive(regionMap, base, surface) then if not buildHive(map, base, surface) then
return nil return nil
end end
-- buildTendril(regionMap, natives, base, surface, tick) -- buildTendril(map, natives, base, surface, tick)
bases[#bases+1] = base bases[#bases+1] = base
return base return base
end end

View File

@ -19,10 +19,10 @@ local chunkPassScan = chunkUtils.chunkPassScan
-- module code -- module code
function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendingStack) function chunkProcessor.processPendingChunks(natives, map, surface, pendingStack)
local processQueue = regionMap.processQueue local processQueue = map.processQueue
local area = regionMap.area local area = map.area
local topOffset = area[1] local topOffset = area[1]
local bottomOffset = area[2] local bottomOffset = area[2]
@ -41,30 +41,30 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin
bottomOffset[1] = x + CHUNK_SIZE bottomOffset[1] = x + CHUNK_SIZE
bottomOffset[2] = y + CHUNK_SIZE bottomOffset[2] = y + CHUNK_SIZE
chunk = initialScan(chunk, natives, surface, regionMap) chunk = initialScan(chunk, natives, surface, map)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local chunkX = chunk.x local chunkX = chunk.x
if regionMap[chunkX] == nil then if map[chunkX] == nil then
regionMap[chunkX] = {} map[chunkX] = {}
end end
regionMap[chunkX][chunk.y] = chunk map[chunkX][chunk.y] = chunk
processQueue[#processQueue+1] = chunk processQueue[#processQueue+1] = chunk
end end
end end
end end
function chunkProcessor.processScanChunks(regionMap, surface) function chunkProcessor.processScanChunks(map, surface)
local area = regionMap.area local area = map.area
local topOffset = area[1] local topOffset = area[1]
local bottomOffset = area[2] local bottomOffset = area[2]
local removals = {} local removals = {}
for chunk,_ in pairs(regionMap.chunkToPassScan) do for chunk,_ in pairs(map.chunkToPassScan) do
local x = chunk.x local x = chunk.x
local y = chunk.y local y = chunk.y
@ -73,17 +73,17 @@ function chunkProcessor.processScanChunks(regionMap, surface)
bottomOffset[1] = x + CHUNK_SIZE bottomOffset[1] = x + CHUNK_SIZE
bottomOffset[2] = y + CHUNK_SIZE bottomOffset[2] = y + CHUNK_SIZE
chunk = chunkPassScan(chunk, surface, regionMap) chunk = chunkPassScan(chunk, surface, map)
if (chunk == SENTINEL_IMPASSABLE_CHUNK) then if (chunk == SENTINEL_IMPASSABLE_CHUNK) then
regionMap[x][y] = nil map[x][y] = nil
removals[#removals+1] = chunk removals[#removals+1] = chunk
end end
end end
for i=#removals,1,-1 do for i=#removals,1,-1 do
table.remove(regionMap.processQueue, i) table.remove(map.processQueue, i)
end end
return {} return {}

View File

@ -39,6 +39,8 @@ local RESOURCE_GENERATOR_INCREMENT = constants.RESOURCE_GENERATOR_INCREMENT
local getChunkByUnalignedXY = mapUtils.getChunkByUnalignedXY local getChunkByUnalignedXY = mapUtils.getChunkByUnalignedXY
local tRemove = table.remove
local mFloor = math.floor local mFloor = math.floor
-- module code -- module code
@ -76,12 +78,12 @@ local function fullScan(chunk, can_place_entity, canPlaceQuery)
return passableNorthSouth, passableEastWest return passableNorthSouth, passableEastWest
end end
local function addEnemyStructureToChunk(regionMap, chunk, entity, base) local function addEnemyStructureToChunk(map, chunk, entity, base)
local lookup local lookup
if (entity.type == "unit-spawner") then if (entity.type == "unit-spawner") then
lookup = regionMap.chunkToNests lookup = map.chunkToNests
elseif (entity.type == "turret") then elseif (entity.type == "turret") then
lookup = regionMap.chunkToWorms lookup = map.chunkToWorms
else else
return return
end end
@ -93,22 +95,22 @@ local function addEnemyStructureToChunk(regionMap, chunk, entity, base)
lookup[chunk] = lookup[chunk] + 1 lookup[chunk] = lookup[chunk] + 1
-- if base then -- if base then
-- local baseCollection = regionMap.chunkToBases[chunk] -- local baseCollection = map.chunkToBases[chunk]
-- if not baseCollection then -- if not baseCollection then
-- baseCollection = {} -- baseCollection = {}
-- regionMap.chunkToBases[chunk] = baseCollection -- map.chunkToBases[chunk] = baseCollection
-- end -- end
-- baseCollection[base.id] = chunk -- baseCollection[base.id] = chunk
-- end -- end
end end
local function removeEnemyStructureFromChunk(regionMap, chunk, entity) local function removeEnemyStructureFromChunk(map, chunk, entity)
local lookup local lookup
if (entity.type == "unit-spawner") then if (entity.type == "unit-spawner") then
lookup = regionMap.chunkToNests lookup = map.chunkToNests
elseif (entity.type == "turret") then elseif (entity.type == "turret") then
lookup = regionMap.chunkToWorms lookup = map.chunkToWorms
else else
return return
end end
@ -137,7 +139,7 @@ local function removeEnemyStructureFromChunk(regionMap, chunk, entity)
end end
end end
local function getEntityOverlapChunks(regionMap, entity) local function getEntityOverlapChunks(map, entity)
local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box; local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box;
local leftTopChunk = SENTINEL_IMPASSABLE_CHUNK local leftTopChunk = SENTINEL_IMPASSABLE_CHUNK
@ -179,15 +181,15 @@ local function getEntityOverlapChunks(regionMap, entity)
local rightBottomChunkX = rightTopChunkX local rightBottomChunkX = rightTopChunkX
local rightBottomChunkY = leftBottomChunkY local rightBottomChunkY = leftBottomChunkY
leftTopChunk = getChunkByUnalignedXY(regionMap, leftTopChunkX, leftTopChunkY) leftTopChunk = getChunkByUnalignedXY(map, leftTopChunkX, leftTopChunkY)
if (leftTopChunkX ~= rightTopChunkX) then if (leftTopChunkX ~= rightTopChunkX) then
rightTopChunk = getChunkByUnalignedXY(regionMap, rightTopChunkX, rightTopChunkY) rightTopChunk = getChunkByUnalignedXY(map, rightTopChunkX, rightTopChunkY)
end end
if (leftTopChunkY ~= leftBottomChunkY) then if (leftTopChunkY ~= leftBottomChunkY) then
leftBottomChunk = getChunkByUnalignedXY(regionMap, leftBottomChunkX, leftBottomChunkY) leftBottomChunk = getChunkByUnalignedXY(map, leftBottomChunkX, leftBottomChunkY)
end end
if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then
rightBottomChunk = getChunkByUnalignedXY(regionMap, rightBottomChunkX, rightBottomChunkY) rightBottomChunk = getChunkByUnalignedXY(map, rightBottomChunkX, rightBottomChunkY)
end end
end end
return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk
@ -195,9 +197,9 @@ end
-- external functions -- external functions
function chunkUtils.calculatePassScore(surface, regionMap) function chunkUtils.calculatePassScore(surface, map)
local count_tiles_filtered = surface.count_tiles_filtered local count_tiles_filtered = surface.count_tiles_filtered
local filteredTilesQuery = regionMap.filteredTilesQuery local filteredTilesQuery = map.filteredTilesQuery
local passScore = 0 local passScore = 0
for i=1,#WATER_TILE_NAMES do for i=1,#WATER_TILE_NAMES do
@ -208,11 +210,11 @@ function chunkUtils.calculatePassScore(surface, regionMap)
return 1 - (passScore * 0.0009765625) return 1 - (passScore * 0.0009765625)
end end
function chunkUtils.scanChunkPaths(chunk, surface, regionMap) function chunkUtils.scanChunkPaths(chunk, surface, map)
local pass = CHUNK_IMPASSABLE local pass = CHUNK_IMPASSABLE
local passableNorthSouth, passableEastWest = fullScan(chunk, local passableNorthSouth, passableEastWest = fullScan(chunk,
surface.can_place_entity, surface.can_place_entity,
regionMap.canPlaceQuery) map.canPlaceQuery)
if passableEastWest and passableNorthSouth then if passableEastWest and passableNorthSouth then
pass = CHUNK_ALL_DIRECTIONS pass = CHUNK_ALL_DIRECTIONS
@ -224,8 +226,8 @@ function chunkUtils.scanChunkPaths(chunk, surface, regionMap)
return pass return pass
end end
function chunkUtils.scorePlayerBuildings(surface, regionMap, natives) function chunkUtils.scorePlayerBuildings(surface, map, natives)
local entities = surface.find_entities_filtered(regionMap.filteredEntitiesPlayerQuery) local entities = surface.find_entities_filtered(map.filteredEntitiesPlayerQuery)
local playerObjects = 0 local playerObjects = 0
local safeBuildings = natives.safeBuildings local safeBuildings = natives.safeBuildings
@ -251,38 +253,38 @@ function chunkUtils.scorePlayerBuildings(surface, regionMap, natives)
return playerObjects return playerObjects
end end
function chunkUtils.scoreEnemyBuildings(surface, regionMap) function chunkUtils.scoreEnemyBuildings(surface, map)
local query = regionMap.filteredEntitiesEnemyTypeQuery local query = map.filteredEntitiesEnemyTypeQuery
query.type = "unit-spawner" query.type = "unit-spawner"
local nests = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery) local nests = surface.count_entities_filtered(map.filteredEntitiesEnemyTypeQuery)
query.type = "turret" query.type = "turret"
local worms = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery) local worms = surface.count_entities_filtered(map.filteredEntitiesEnemyTypeQuery)
return nests, worms return nests, worms
end end
function chunkUtils.initialScan(chunk, natives, surface, regionMap) function chunkUtils.initialScan(chunk, natives, surface, map)
local passScore = chunkUtils.calculatePassScore(surface, regionMap) local passScore = chunkUtils.calculatePassScore(surface, map)
if (passScore >= 0.40) then if (passScore >= 0.40) then
local pass = chunkUtils.scanChunkPaths(chunk, surface, regionMap) local pass = chunkUtils.scanChunkPaths(chunk, surface, map)
local playerObjects = chunkUtils.scorePlayerBuildings(surface, regionMap, natives) local playerObjects = chunkUtils.scorePlayerBuildings(surface, map, natives)
local nests, worms = chunkUtils.scoreEnemyBuildings(surface, regionMap) local nests, worms = chunkUtils.scoreEnemyBuildings(surface, map)
local resources = surface.count_entities_filtered(regionMap.countResourcesQuery) * 0.001 local resources = surface.count_entities_filtered(map.countResourcesQuery) * 0.001
if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS pass = CHUNK_ALL_DIRECTIONS
end end
chunkUtils.setNestCount(regionMap, chunk, nests) chunkUtils.setNestCount(map, chunk, nests)
chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects) chunkUtils.setPlayerBaseGenerator(map, chunk, playerObjects)
chunkUtils.setResourceGenerator(regionMap, chunk, resources) chunkUtils.setResourceGenerator(map, chunk, resources)
chunkUtils.setWormCount(regionMap, chunk, worms) chunkUtils.setWormCount(map, chunk, worms)
chunk[PASSABLE] = pass chunk[PASSABLE] = pass
chunk[PATH_RATING] = passScore chunk[PATH_RATING] = passScore
@ -293,15 +295,15 @@ function chunkUtils.initialScan(chunk, natives, surface, regionMap)
return SENTINEL_IMPASSABLE_CHUNK return SENTINEL_IMPASSABLE_CHUNK
end end
function chunkUtils.chunkPassScan(chunk, surface, regionMap) function chunkUtils.chunkPassScan(chunk, surface, map)
local passScore = chunkUtils.calculatePassScore(surface, regionMap) local passScore = chunkUtils.calculatePassScore(surface, map)
if (passScore >= 0.40) then if (passScore >= 0.40) then
local pass = chunkUtils.scanChunkPaths(chunk, surface, regionMap) local pass = chunkUtils.scanChunkPaths(chunk, surface, map)
local playerObjects = chunkUtils.getPlayerBaseGenerator(regionMap, chunk) local playerObjects = chunkUtils.getPlayerBaseGenerator(map, chunk)
local nests = chunkUtils.getNestCount(regionMap, chunk) local nests = chunkUtils.getNestCount(map, chunk)
if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then if ((playerObjects > 0) or (nests > 0)) and (pass == CHUNK_IMPASSABLE) then
pass = CHUNK_ALL_DIRECTIONS pass = CHUNK_ALL_DIRECTIONS
@ -316,12 +318,12 @@ function chunkUtils.chunkPassScan(chunk, surface, regionMap)
return SENTINEL_IMPASSABLE_CHUNK return SENTINEL_IMPASSABLE_CHUNK
end end
function chunkUtils.analyzeChunk(chunk, natives, surface, regionMap) function chunkUtils.analyzeChunk(chunk, natives, surface, map)
local playerObjects = chunkUtils.scorePlayerBuildings(surface, regionMap, natives) local playerObjects = chunkUtils.scorePlayerBuildings(surface, map, natives)
chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects) chunkUtils.setPlayerBaseGenerator(map, chunk, playerObjects)
end end
-- function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQuery) -- function chunkUtils.remakeChunk(map, chunk, surface, natives, tick, tempQuery)
-- tempQuery.force = "enemy" -- tempQuery.force = "enemy"
-- local enemies = surface.find_entities_filtered(tempQuery) -- local enemies = surface.find_entities_filtered(tempQuery)
@ -340,94 +342,129 @@ end
-- enemy.destroy() -- enemy.destroy()
-- end -- end
-- end -- end
-- -- local foundBase = findNearbyBase(natives, chunk) or createBase(regionMap, natives, chunk, surface, tick) -- -- local foundBase = findNearbyBase(natives, chunk) or createBase(map, natives, chunk, surface, tick)
-- -- if foundBase then -- -- if foundBase then
-- -- foundBase.upgradePoints = foundBase.upgradePoints + points -- -- foundBase.upgradePoints = foundBase.upgradePoints + points
-- -- end -- -- end
-- end -- end
function chunkUtils.getNestCount(regionMap, chunk) function chunkUtils.getNestCount(map, chunk)
return regionMap.chunkToNests[chunk] or 0 return map.chunkToNests[chunk] or 0
end end
function chunkUtils.getWormCount(regionMap, chunk) function chunkUtils.getWormCount(map, chunk)
return regionMap.chunkToWorms[chunk] or 0 return map.chunkToWorms[chunk] or 0
end end
function chunkUtils.setWormCount(regionMap, chunk, count) function chunkUtils.setWormCount(map, chunk, count)
if (count == 0) then if (count == 0) then
regionMap.chunkToWorms[chunk] = nil map.chunkToWorms[chunk] = nil
else else
regionMap.chunkToWorms[chunk] = count map.chunkToWorms[chunk] = count
end end
end end
function chunkUtils.setNestCount(regionMap, chunk, count) function chunkUtils.setNestCount(map, chunk, count)
if (count == 0) then if (count == 0) then
regionMap.chunkToNests[chunk] = nil map.chunkToNests[chunk] = nil
else else
regionMap.chunkToNests[chunk] = count map.chunkToNests[chunk] = count
end end
end end
function chunkUtils.getNestCount(regionMap, chunk) function chunkUtils.getNestCount(map, chunk)
return regionMap.chunkToNests[chunk] or 0 return map.chunkToNests[chunk] or 0
end end
function chunkUtils.getWormCount(regionMap, chunk) function chunkUtils.getWormCount(map, chunk)
return regionMap.chunkToWorms[chunk] or 0 return map.chunkToWorms[chunk] or 0
end end
function chunkUtils.getEnemyStructureCount(regionMap, chunk) function chunkUtils.getEnemyStructureCount(map, chunk)
return (regionMap.chunkToNests[chunk] or 0) + (regionMap.chunkToWorms[chunk] or 0) return (map.chunkToNests[chunk] or 0) + (map.chunkToWorms[chunk] or 0)
end end
function chunkUtils.getRetreatTick(regionMap, chunk) function chunkUtils.getRetreatTick(map, chunk)
return regionMap.chunkToRetreats[chunk] or 0 return map.chunkToRetreats[chunk] or 0
end end
function chunkUtils.getRallyTick(regionMap, chunk) function chunkUtils.getRallyTick(map, chunk)
return regionMap.chunkToRallys[chunk] or 0 return map.chunkToRallys[chunk] or 0
end end
function chunkUtils.setRallyTick(regionMap, chunk, tick) function chunkUtils.setRallyTick(map, chunk, tick)
regionMap.chunkToRallys[chunk] = tick map.chunkToRallys[chunk] = tick
end end
function chunkUtils.setRetreatTick(regionMap, chunk, tick) function chunkUtils.setRetreatTick(map, chunk, tick)
regionMap.chunkToRetreats[chunk] = tick map.chunkToRetreats[chunk] = tick
end end
function chunkUtils.setResourceGenerator(regionMap, chunk, resourceGenerator) function chunkUtils.setResourceGenerator(map, chunk, resourceGenerator)
if (resourceGenerator == 0) then if (resourceGenerator == 0) then
regionMap.chunkToResource[chunk] = nil map.chunkToResource[chunk] = nil
else else
regionMap.chunkToResource[chunk] = resourceGenerator map.chunkToResource[chunk] = resourceGenerator
end end
end end
function chunkUtils.getResourceGenerator(regionMap, chunk) function chunkUtils.getResourceGenerator(map, chunk)
return regionMap.chunkToResource[chunk] or 0 return map.chunkToResource[chunk] or 0
end end
function chunkUtils.addResourceGenerator(regionMap, chunk, delta) function chunkUtils.addResourceGenerator(map, chunk, delta)
regionMap.chunkToResource[chunk] = (regionMap.chunkToResource[chunk] or 0) + delta map.chunkToResource[chunk] = (map.chunkToResource[chunk] or 0) + delta
end end
function chunkUtils.getPlayerBaseGenerator(regionMap, chunk) function chunkUtils.getPlayerBaseGenerator(map, chunk)
return regionMap.chunkToPlayerBase[chunk] or 0 return map.chunkToPlayerBase[chunk] or 0
end end
function chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerGenerator) function chunkUtils.addSquadToChunk(map, chunk, squad)
if (chunk ~= squad.chunk) then
local chunkToSquad = map.chunkToSquad
chunkUtils.removeSquadFromChunk(map, squad)
if not chunkToSquad[chunk] then
chunkToSquad[chunk] = {}
end
chunkToSquad[chunk][#chunkToSquad[chunk]+1] = squad
squad.chunk = chunk
end
end
function chunkUtils.removeSquadFromChunk(map, squad)
local chunkToSquad = map.chunkToSquad
if squad.chunk then
local squads = chunkToSquad[squad.chunk]
if squads then
for i=#squads, 1, -1 do
if (squads[i] == squad) then
tRemove(squads, i)
break
end
end
if (#squads == 0) then
chunkToSquad[squad.chunk] = nil
end
end
end
end
function chunkUtils.getSquadsOnChunk(map, chunk)
return map.chunkToSquad[chunk] or {}
end
function chunkUtils.setPlayerBaseGenerator(map, chunk, playerGenerator)
if (playerGenerator == 0) then if (playerGenerator == 0) then
regionMap.chunkToPlayerBase[chunk] = nil map.chunkToPlayerBase[chunk] = nil
else else
regionMap.chunkToPlayerBase[chunk] = playerGenerator map.chunkToPlayerBase[chunk] = playerGenerator
end end
end end
function chunkUtils.addPlayerBaseGenerator(regionMap, chunk, playerGenerator) function chunkUtils.addPlayerBaseGenerator(map, chunk, playerGenerator)
regionMap.chunkToPlayerBase[chunk] = (regionMap.chunkToPlayerBase[chunk] or 0) + playerGenerator map.chunkToPlayerBase[chunk] = (map.chunkToPlayerBase[chunk] or 0) + playerGenerator
end end
function chunkUtils.createChunk(topX, topY) function chunkUtils.createChunk(topX, topY)
@ -456,70 +493,70 @@ function chunkUtils.colorChunk(x, y, tileType, surface)
surface.set_tiles(tiles, false) surface.set_tiles(tiles, false)
end end
function chunkUtils.entityForPassScan(regionMap, entity) function chunkUtils.entityForPassScan(map, entity)
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[leftTop] = true map.chunkToPassScan[leftTop] = true
end end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[rightTop] = true map.chunkToPassScan[rightTop] = true
end end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[leftBottom] = true map.chunkToPassScan[leftBottom] = true
end end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
regionMap.chunkToPassScan[rightBottom] = true map.chunkToPassScan[rightBottom] = true
end end
end end
function chunkUtils.registerEnemyBaseStructure(regionMap, entity, base) function chunkUtils.registerEnemyBaseStructure(map, entity, base)
local entityType = entity.type local entityType = entity.type
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
addEnemyStructureToChunk(regionMap, leftTop, entity, base) addEnemyStructureToChunk(map, leftTop, entity, base)
end end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
addEnemyStructureToChunk(regionMap, rightTop, entity, base) addEnemyStructureToChunk(map, rightTop, entity, base)
end end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
addEnemyStructureToChunk(regionMap, leftBottom, entity, base) addEnemyStructureToChunk(map, leftBottom, entity, base)
end end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
addEnemyStructureToChunk(regionMap, rightBottom, entity, base) addEnemyStructureToChunk(map, rightBottom, entity, base)
end end
end end
end end
function chunkUtils.unregisterEnemyBaseStructure(regionMap, entity) function chunkUtils.unregisterEnemyBaseStructure(map, entity)
local entityType = entity.type local entityType = entity.type
if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then if ((entityType == "unit-spawner") or (entityType == "turret")) and (entity.force.name == "enemy") then
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
removeEnemyStructureFromChunk(regionMap, leftTop, entity) removeEnemyStructureFromChunk(map, leftTop, entity)
end end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
removeEnemyStructureFromChunk(regionMap, rightTop, entity) removeEnemyStructureFromChunk(map, rightTop, entity)
end end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
removeEnemyStructureFromChunk(regionMap, leftBottom, entity) removeEnemyStructureFromChunk(map, leftBottom, entity)
end end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
removeEnemyStructureFromChunk(regionMap, rightBottom, entity) removeEnemyStructureFromChunk(map, rightBottom, entity)
end end
end end
end end
function chunkUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject, creditNatives) function chunkUtils.addRemovePlayerEntity(map, entity, natives, addObject, creditNatives)
local leftTop, rightTop, leftBottom, rightBottom local leftTop, rightTop, leftBottom, rightBottom
local entityValue local entityValue
if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then
entityValue = BUILDING_PHEROMONES[entity.type] entityValue = BUILDING_PHEROMONES[entity.type]
leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity)
if not addObject then if not addObject then
if creditNatives then if creditNatives then
natives.points = natives.points + entityValue natives.points = natives.points + entityValue
@ -527,38 +564,38 @@ function chunkUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject,
entityValue = -entityValue entityValue = -entityValue
end end
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addPlayerBaseGenerator(regionMap, leftTop, entityValue) chunkUtils.addPlayerBaseGenerator(map, leftTop, entityValue)
end end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addPlayerBaseGenerator(regionMap, rightTop, entityValue) chunkUtils.addPlayerBaseGenerator(map, rightTop, entityValue)
end end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addPlayerBaseGenerator(regionMap, leftBottom, entityValue) chunkUtils.addPlayerBaseGenerator(map, leftBottom, entityValue)
end end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addPlayerBaseGenerator(regionMap, rightBottom, entityValue) chunkUtils.addPlayerBaseGenerator(map, rightBottom, entityValue)
end end
end end
return entity return entity
end end
function chunkUtils.unregisterResource(entity, regionMap) function chunkUtils.unregisterResource(entity, map)
if entity.prototype.infinite_resource then if entity.prototype.infinite_resource then
return return
end end
local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity)
if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, leftTop, -RESOURCE_GENERATOR_INCREMENT) chunkUtils.addResourceGenerator(map, leftTop, -RESOURCE_GENERATOR_INCREMENT)
end end
if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, rightTop, -RESOURCE_GENERATOR_INCREMENT) chunkUtils.addResourceGenerator(map, rightTop, -RESOURCE_GENERATOR_INCREMENT)
end end
if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, leftBottom, -RESOURCE_GENERATOR_INCREMENT) chunkUtils.addResourceGenerator(map, leftBottom, -RESOURCE_GENERATOR_INCREMENT)
end end
if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then
chunkUtils.addResourceGenerator(regionMap, rightBottom, -RESOURCE_GENERATOR_INCREMENT) chunkUtils.addResourceGenerator(map, rightBottom, -RESOURCE_GENERATOR_INCREMENT)
end end
end end

View File

@ -16,7 +16,7 @@ constants.VERSION_26 = 26
constants.VERSION_27 = 27 constants.VERSION_27 = 27
constants.VERSION_28 = 28 constants.VERSION_28 = 28
constants.VERSION_33 = 33 constants.VERSION_33 = 33
constants.VERSION_37 = 37 constants.VERSION_38 = 38
-- misc -- misc
@ -79,7 +79,7 @@ constants.AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_POINTS * 3
constants.AI_UNIT_REFUND = 3 constants.AI_UNIT_REFUND = 3
constants.AI_MAX_SQUAD_COUNT = 30 -- constants.AI_MAX_SQUAD_COUNT = 30
constants.AI_MAX_BITER_GROUP_SIZE = 450 constants.AI_MAX_BITER_GROUP_SIZE = 450
constants.AI_SQUAD_MERGE_THRESHOLD = constants.AI_MAX_BITER_GROUP_SIZE * 0.75 constants.AI_SQUAD_MERGE_THRESHOLD = constants.AI_MAX_BITER_GROUP_SIZE * 0.75
@ -189,8 +189,8 @@ constants.BUILDING_PHEROMONES["fluid-turret"] = 28
constants.BUILDING_PHEROMONES["turret"] = 10 constants.BUILDING_PHEROMONES["turret"] = 10
constants.BUILDING_PHEROMONES["artillery-turret"] = 100 constants.BUILDING_PHEROMONES["artillery-turret"] = 100
constants.retreatFilter = {} constants.RETREAT_FILTER = {}
constants.retreatFilter[constants.SQUAD_RETREATING] = true constants.RETREAT_FILTER[constants.SQUAD_RETREATING] = true
-- map settings tweaks -- map settings tweaks
@ -221,8 +221,8 @@ constants.SENTINEL_IMPASSABLE_CHUNK[constants.RESOURCE_PHEROMONE] = constants.IM
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PASSABLE] = constants.CHUNK_IMPASSABLE constants.SENTINEL_IMPASSABLE_CHUNK[constants.PASSABLE] = constants.CHUNK_IMPASSABLE
constants.SENTINEL_IMPASSABLE_CHUNK[constants.CHUNK_TICK] = 0 constants.SENTINEL_IMPASSABLE_CHUNK[constants.CHUNK_TICK] = 0
constants.SENTINEL_IMPASSABLE_CHUNK[constants.PATH_RATING] = 0 constants.SENTINEL_IMPASSABLE_CHUNK[constants.PATH_RATING] = 0
constants.SENTINEL_IMPASSABLE_CHUNK.x = 0 constants.SENTINEL_IMPASSABLE_CHUNK.x = -1
constants.SENTINEL_IMPASSABLE_CHUNK.y = 0 constants.SENTINEL_IMPASSABLE_CHUNK.y = -1
return constants return constants

View File

@ -83,18 +83,18 @@ end
In theory, this might be fine as smaller bases have less surface to attack and need to have In theory, this might be fine as smaller bases have less surface to attack and need to have
pheromone dissipate at a faster rate. pheromone dissipate at a faster rate.
--]] --]]
function mapProcessor.processMap(regionMap, surface, natives, tick) function mapProcessor.processMap(map, surface, natives, tick)
local roll = regionMap.processRoll local roll = map.processRoll
local index = regionMap.processIndex local index = map.processIndex
if (index == 1) then if (index == 1) then
roll = mRandom() roll = mRandom()
regionMap.processRoll = roll map.processRoll = roll
end end
local squads = canAttack(natives, surface) and (0.11 <= roll) and (roll <= 0.35) and (natives.points >= AI_SQUAD_COST) local squads = canAttack(natives, surface) and (0.11 <= roll) and (roll <= 0.35) and (natives.points >= AI_SQUAD_COST)
local processQueue = regionMap.processQueue local processQueue = map.processQueue
local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue) local endIndex = mMin(index + PROCESS_QUEUE_SIZE, #processQueue)
for x=index,endIndex do for x=index,endIndex do
local chunk = processQueue[x] local chunk = processQueue[x]
@ -102,21 +102,21 @@ function mapProcessor.processMap(regionMap, surface, natives, tick)
if (chunk[CHUNK_TICK] ~= tick) then if (chunk[CHUNK_TICK] ~= tick) then
chunk[CHUNK_TICK] = tick chunk[CHUNK_TICK] = tick
processPheromone(regionMap, chunk) processPheromone(map, chunk)
if squads and (getNestCount(regionMap, chunk) > 0) then if squads and (getNestCount(map, chunk) > 0) then
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST) formSquads(map, surface, natives, chunk, AI_SQUAD_COST)
squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads) squads = (natives.points >= AI_SQUAD_COST) -- and (#natives.squads < natives.maxSquads)
end end
scents(regionMap, chunk) scents(map, chunk)
end end
end end
if (endIndex == #processQueue) then if (endIndex == #processQueue) then
regionMap.processIndex = 1 map.processIndex = 1
else else
regionMap.processIndex = endIndex + 1 map.processIndex = endIndex + 1
end end
end end
@ -126,7 +126,7 @@ end
vs vs
the slower passive version processing the entire map in multiple passes. the slower passive version processing the entire map in multiple passes.
--]] --]]
function mapProcessor.processPlayers(players, regionMap, surface, natives, tick) function mapProcessor.processPlayers(players, map, surface, natives, tick)
-- put down player pheromone for player hunters -- put down player pheromone for player hunters
-- randomize player order to ensure a single player isn't singled out -- randomize player order to ensure a single player isn't singled out
local playerOrdering = nonRepeatingRandom(players) local playerOrdering = nonRepeatingRandom(players)
@ -140,7 +140,7 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
for i=1,#playerOrdering do for i=1,#playerOrdering do
local player = players[playerOrdering[i]] local player = players[playerOrdering[i]]
if validPlayer(player) then if validPlayer(player) then
local playerChunk = getChunkByPosition(regionMap, player.character.position) local playerChunk = getChunkByPosition(map, player.character.position)
if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
playerScent(playerChunk) playerScent(playerChunk)
@ -150,34 +150,34 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick)
for i=1,#playerOrdering do for i=1,#playerOrdering do
local player = players[playerOrdering[i]] local player = players[playerOrdering[i]]
if validPlayer(player) then if validPlayer(player) then
local playerChunk = getChunkByPosition(regionMap, player.character.position) local playerChunk = getChunkByPosition(map, player.character.position)
if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local vengence = (allowingAttacks and local vengence = (allowingAttacks and
(natives.points >= AI_VENGENCE_SQUAD_COST) and (natives.points >= AI_VENGENCE_SQUAD_COST) and
((getEnemyStructureCount(regionMap, 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
local chunk = getChunkByXY(regionMap, x, y) local chunk = getChunkByXY(map, x, y)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[CHUNK_TICK] ~= tick) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[CHUNK_TICK] ~= tick) then
chunk[CHUNK_TICK] = tick chunk[CHUNK_TICK] = tick
processPheromone(regionMap, chunk) processPheromone(map, chunk)
if (getNestCount(regionMap, chunk) > 0) then if (getNestCount(map, chunk) > 0) then
if squads then if squads then
formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST) formSquads(map, surface, natives, chunk, AI_SQUAD_COST)
squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads) squads = (natives.points >= AI_SQUAD_COST) -- and (#natives.squads < natives.maxSquads)
end end
if vengence then if vengence then
formSquads(regionMap, surface, natives, chunk, AI_VENGENCE_SQUAD_COST) formSquads(map, surface, natives, chunk, AI_VENGENCE_SQUAD_COST)
vengence = (natives.points >= AI_VENGENCE_SQUAD_COST) and (#natives.squads < natives.maxSquads) vengence = (natives.points >= AI_VENGENCE_SQUAD_COST) -- and (#natives.squads < natives.maxSquads)
end end
end end
scents(regionMap, chunk) scents(map, chunk)
end end
end end
end end
@ -189,14 +189,14 @@ end
--[[ --[[
Passive scan to find entities that have been generated outside the factorio event system Passive scan to find entities that have been generated outside the factorio event system
--]] --]]
function mapProcessor.scanMap(regionMap, surface, natives) function mapProcessor.scanMap(map, surface, natives)
local index = regionMap.scanIndex local index = map.scanIndex
local unitCountQuery = regionMap.filteredEntitiesEnemyUnitQuery local unitCountQuery = map.filteredEntitiesEnemyUnitQuery
local offset = unitCountQuery.area[2] local offset = unitCountQuery.area[2]
local chunkBox = unitCountQuery.area[1] local chunkBox = unitCountQuery.area[1]
local processQueue = regionMap.processQueue local processQueue = map.processQueue
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue) local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
for x=index,endIndex do for x=index,endIndex do
@ -226,13 +226,13 @@ function mapProcessor.scanMap(regionMap, surface, natives)
end end
end end
analyzeChunk(chunk, natives, surface, regionMap) analyzeChunk(chunk, natives, surface, map)
end end
if (endIndex == #processQueue) then if (endIndex == #processQueue) then
regionMap.scanIndex = 1 map.scanIndex = 1
else else
regionMap.scanIndex = endIndex + 1 map.scanIndex = endIndex + 1
end end
end end

View File

@ -25,16 +25,16 @@ local mFloor = math.floor
-- module code -- module code
function mapUtils.getChunkByXY(regionMap, x, y) function mapUtils.getChunkByXY(map, x, y)
local chunkX = regionMap[x] local chunkX = map[x]
if chunkX then if chunkX then
return chunkX[y] or SENTINEL_IMPASSABLE_CHUNK return chunkX[y] or SENTINEL_IMPASSABLE_CHUNK
end end
return SENTINEL_IMPASSABLE_CHUNK return SENTINEL_IMPASSABLE_CHUNK
end end
function mapUtils.getChunkByPosition(regionMap, position) function mapUtils.getChunkByPosition(map, position)
local chunkX = regionMap[mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] local chunkX = map[mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE]
if chunkX then if chunkX then
local chunkY = mFloor(position.y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE local chunkY = mFloor(position.y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK
@ -42,8 +42,8 @@ function mapUtils.getChunkByPosition(regionMap, position)
return SENTINEL_IMPASSABLE_CHUNK return SENTINEL_IMPASSABLE_CHUNK
end end
function mapUtils.getChunkByUnalignedXY(regionMap, x, y) function mapUtils.getChunkByUnalignedXY(map, x, y)
local chunkX = regionMap[mFloor(x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] local chunkX = map[mFloor(x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE]
if chunkX then if chunkX then
local chunkY = mFloor(y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE local chunkY = mFloor(y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE
return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK
@ -64,11 +64,11 @@ end
/|\ /|\
6 7 8 6 7 8
]]-- ]]--
function mapUtils.getNeighborChunks(regionMap, x, y) function mapUtils.getNeighborChunks(map, x, y)
local neighbors = regionMap.neighbors local neighbors = map.neighbors
local chunkYRow1 = y - CHUNK_SIZE local chunkYRow1 = y - CHUNK_SIZE
local chunkYRow3 = y + CHUNK_SIZE local chunkYRow3 = y + CHUNK_SIZE
local xChunks = regionMap[x-CHUNK_SIZE] local xChunks = map[x-CHUNK_SIZE]
if xChunks then if xChunks then
neighbors[1] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK neighbors[1] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
neighbors[4] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK neighbors[4] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
@ -79,7 +79,7 @@ function mapUtils.getNeighborChunks(regionMap, x, y)
neighbors[6] = SENTINEL_IMPASSABLE_CHUNK neighbors[6] = SENTINEL_IMPASSABLE_CHUNK
end end
xChunks = regionMap[x+CHUNK_SIZE] xChunks = map[x+CHUNK_SIZE]
if xChunks then if xChunks then
neighbors[3] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK neighbors[3] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
neighbors[5] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK neighbors[5] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
@ -90,7 +90,7 @@ function mapUtils.getNeighborChunks(regionMap, x, y)
neighbors[8] = SENTINEL_IMPASSABLE_CHUNK neighbors[8] = SENTINEL_IMPASSABLE_CHUNK
end end
xChunks = regionMap[x] xChunks = map[x]
if xChunks then if xChunks then
neighbors[2] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK neighbors[2] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK
neighbors[7] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK neighbors[7] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK
@ -117,9 +117,9 @@ function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk)
return canMove return canMove
end end
function mapUtils.getCardinalChunks(regionMap, x, y) function mapUtils.getCardinalChunks(map, x, y)
local neighbors = regionMap.cardinalNeighbors local neighbors = map.cardinalNeighbors
local xChunks = regionMap[x] local xChunks = map[x]
if xChunks then if xChunks then
neighbors[1] = xChunks[y-CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK neighbors[1] = xChunks[y-CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK
neighbors[4] = xChunks[y+CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK neighbors[4] = xChunks[y+CHUNK_SIZE] or SENTINEL_IMPASSABLE_CHUNK
@ -128,14 +128,14 @@ function mapUtils.getCardinalChunks(regionMap, x, y)
neighbors[4] = SENTINEL_IMPASSABLE_CHUNK neighbors[4] = SENTINEL_IMPASSABLE_CHUNK
end end
xChunks = regionMap[x-CHUNK_SIZE] xChunks = map[x-CHUNK_SIZE]
if xChunks then if xChunks then
neighbors[2] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK neighbors[2] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
else else
neighbors[2] = SENTINEL_IMPASSABLE_CHUNK neighbors[2] = SENTINEL_IMPASSABLE_CHUNK
end end
xChunks = regionMap[x+CHUNK_SIZE] xChunks = map[x+CHUNK_SIZE]
if xChunks then if xChunks then
neighbors[3] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK neighbors[3] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK
else else

View File

@ -16,9 +16,8 @@ local mMax = math.max
local mSqrt = math.sqrt local mSqrt = math.sqrt
local mLog10 = math.log10 local mLog10 = math.log10
local mFloor = math.floor
local mRandom = math.random local mRandom = math.random
local mFloor = math.floor
-- module code -- module code
@ -33,41 +32,98 @@ function mathUtils.randomTickEvent(tick, low, high)
return tick + nextTick return tick + nextTick
end end
function mathUtils.xorRandom(state)
local xor = bit32.bxor
local lshift = bit32.lshift
local rshift = bit32.rshift
state = state + 21594771
return function()
state = xor(state, lshift(state, 13))
state = xor(state, rshift(state, 17))
state = xor(state, lshift(state, 5))
state = state % 2147483647
return state * 4.65661287525e-10
end
end
--[[ --[[
Used for gaussian random numbers Used for gaussian random numbers
--]] --]]
local function marsagliaPolarMethod(rg) function mathUtils.gaussianRandom(mean, std_dev)
-- marsagliaPolarMethod
local iid1 local iid1
local iid2 local iid2
local q local q
repeat repeat
if rg then iid1 = 2 * mRandom() + -1
iid1 = 2 * rg() + -1 iid2 = 2 * mRandom() + -1
iid2 = 2 * rg() + -1
else
iid1 = 2 * mRandom() + -1
iid2 = 2 * mRandom() + -1
end
q = (iid1 * iid1) + (iid2 * iid2) q = (iid1 * iid1) + (iid2 * iid2)
until (q ~= 0) and (q < 1) until (q ~= 0) and (q < 1)
local s = mSqrt((-2 * mLog10(q)) / q) local s = mSqrt((-2 * mLog10(q)) / q)
return iid1 * s local v = iid1 * s
return mean + (v * std_dev)
end end
function mathUtils.gaussianRandom(mean, std_dev, rg) function mathUtils.gaussianRandomRange(mean, std_dev, min, max)
return mean + (marsagliaPolarMethod(rg) * std_dev) if (min == max) then
return min
end
local r
repeat
local iid1
local iid2
local q
repeat
iid1 = 2 * mRandom() + -1
iid2 = 2 * mRandom() + -1
q = (iid1 * iid1) + (iid2 * iid2)
until (q ~= 0) and (q < 1)
local s = mSqrt((-2 * mLog10(q)) / q)
local v = iid1 * s
r = mean + (v * std_dev)
until (r >= min) and (r <= max)
return r
end end
function mathUtils.gaussianRandomRange(mean, std_dev, min, max, rg) function mathUtils.gaussianRandomRG(mean, std_dev, rg)
-- marsagliaPolarMethod
local iid1
local iid2
local q local q
repeat repeat
q = mathUtils.gaussianRandom(mean, std_dev, rg) iid1 = 2 * rg() + -1
until (q >= min) and (q <= max) iid2 = 2 * rg() + -1
return q q = (iid1 * iid1) + (iid2 * iid2)
until (q ~= 0) and (q < 1)
local s = mSqrt((-2 * mLog10(q)) / q)
local v = iid1 * s
return mean + (v * std_dev)
end end
function mathUtils.positionToChunkOffset(position) function mathUtils.gaussianRandomRangeRG(mean, std_dev, min, max, rg)
return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125) local r
if (min == max) then
return min
end
repeat
local iid1
local iid2
local q
repeat
iid1 = 2 * rg() + -1
iid2 = 2 * rg() + -1
q = (iid1 * iid1) + (iid2 * iid2)
until (q ~= 0) and (q < 1)
local s = mSqrt((-2 * mLog10(q)) / q)
local v = iid1 * s
r = mean + (v * std_dev)
until (r >= min) and (r <= max)
return r
end end
function mathUtils.euclideanDistanceNamed(p1, p2) function mathUtils.euclideanDistanceNamed(p1, p2)

View File

@ -97,7 +97,7 @@ function movementUtils.scoreNeighborsForAttack(chunk, neighborDirectionChunks, s
end end
end end
if scoreFunction(squad, chunk) > highestScore then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (scoreFunction(squad, chunk) > highestScore) then
return SENTINEL_IMPASSABLE_CHUNK, -1 return SENTINEL_IMPASSABLE_CHUNK, -1
end end
@ -133,14 +133,14 @@ end
--[[ --[[
Expects all neighbors adjacent to a chunk Expects all neighbors adjacent to a chunk
--]] --]]
function movementUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, scoreFunction, regionMap) function movementUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, scoreFunction, map)
local highestChunk = SENTINEL_IMPASSABLE_CHUNK local highestChunk = SENTINEL_IMPASSABLE_CHUNK
local highestScore = -MAGIC_MAXIMUM_NUMBER local highestScore = -MAGIC_MAXIMUM_NUMBER
local highestDirection local highestDirection
for x=1,8 do for x=1,8 do
local neighborChunk = neighborDirectionChunks[x] local neighborChunk = neighborDirectionChunks[x]
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and canMoveChunkDirection(x, chunk, neighborChunk) then if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and canMoveChunkDirection(x, chunk, neighborChunk) then
local score = scoreFunction(regionMap, neighborChunk) local score = scoreFunction(map, neighborChunk)
if (score > highestScore) then if (score > highestScore) then
highestScore = score highestScore = score
highestChunk = neighborChunk highestChunk = neighborChunk
@ -156,13 +156,13 @@ end
--[[ --[[
Expects all neighbors adjacent to a chunk Expects all neighbors adjacent to a chunk
--]] --]]
function movementUtils.scoreNeighborsForFormation(neighborChunks, validFunction, scoreFunction, regionMap) function movementUtils.scoreNeighborsForFormation(neighborChunks, validFunction, scoreFunction, map)
local highestChunk = SENTINEL_IMPASSABLE_CHUNK local highestChunk = SENTINEL_IMPASSABLE_CHUNK
local highestScore = -MAGIC_MAXIMUM_NUMBER local highestScore = -MAGIC_MAXIMUM_NUMBER
local highestDirection local highestDirection
for x=1,8 do for x=1,8 do
local neighborChunk = neighborChunks[x] local neighborChunk = neighborChunks[x]
if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and validFunction(regionMap, neighborChunk) then if (neighborChunk ~= SENTINEL_IMPASSABLE_CHUNK) and validFunction(map, neighborChunk) then
local score = scoreFunction(neighborChunk) local score = scoreFunction(neighborChunk)
if (score > highestScore) then if (score > highestScore) then
highestScore = score highestScore = score

View File

@ -31,21 +31,21 @@ local getChunkByPosition = mapUtils.getChunkByPosition
-- module code -- module code
function nestUtils.buildNest(regionMap, base, surface, targetPosition, name) function nestUtils.buildNest(map, base, surface, targetPosition, name)
local position = surface.find_non_colliding_position(name, targetPosition, DOUBLE_CHUNK_SIZE, 2) local position = surface.find_non_colliding_position(name, targetPosition, DOUBLE_CHUNK_SIZE, 2)
local chunk = getChunkByPosition(regionMap, position) local chunk = getChunkByPosition(map, position)
local nest = nil local nest = nil
if position and (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[NEST_COUNT] < 3) then if position and (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[NEST_COUNT] < 3) then
local biterSpawner = {name=name, position=position} local biterSpawner = {name=name, position=position}
nest = surface.create_entity(biterSpawner) nest = surface.create_entity(biterSpawner)
registerEnemyBaseStructure(regionMap, nest, base) registerEnemyBaseStructure(map, nest, base)
end end
return nest return nest
end end
function nestUtils.buildHive(regionMap, base, surface) function nestUtils.buildHive(map, base, surface)
local valid = false local valid = false
local hive = nestUtils.buildNest(regionMap, base, surface, base, "biter-spawner-hive-rampant") local hive = nestUtils.buildNest(map, base, surface, base, "biter-spawner-hive-rampant")
if hive then if hive then
if (#base.hives == 0) then if (#base.hives == 0) then
base.x = hive.position.x base.x = hive.position.x
@ -57,7 +57,7 @@ function nestUtils.buildHive(regionMap, base, surface)
return valid return valid
end end
function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril) function nestUtils.buildOutpost(map, natives, base, surface, tendril)
local foundHive = false local foundHive = false
for _,_ in pairs(base.hives) do for _,_ in pairs(base.hives) do
foundHive = true foundHive = true
@ -101,7 +101,7 @@ function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril)
y = position.y + (distortion * math.sin(pos))} y = position.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition} local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then if surface.can_place_entity(biterSpawner) then
registerEnemyBaseStructure(natives, regionMap, surface.create_entity(biterSpawner), base) registerEnemyBaseStructure(natives, map, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost base.upgradePoints = base.upgradePoints - cost
end end
pos = pos + slice pos = pos + slice
@ -109,7 +109,7 @@ function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril)
end end
end end
function nestUtils.buildOrder(regionMap, natives, base, surface) function nestUtils.buildOrder(map, natives, base, surface)
local foundHive = false local foundHive = false
for _,_ in pairs(base.hives) do for _,_ in pairs(base.hives) do
foundHive = true foundHive = true
@ -149,7 +149,7 @@ function nestUtils.buildOrder(regionMap, natives, base, surface)
y = base.y + (distortion * math.sin(pos))} y = base.y + (distortion * math.sin(pos))}
local biterSpawner = {name=thing, position=nestPosition} local biterSpawner = {name=thing, position=nestPosition}
if surface.can_place_entity(biterSpawner) then if surface.can_place_entity(biterSpawner) then
registerEnemyBaseStructure(natives, regionMap, surface.create_entity(biterSpawner), base) registerEnemyBaseStructure(natives, map, surface.create_entity(biterSpawner), base)
base.upgradePoints = base.upgradePoints - cost base.upgradePoints = base.upgradePoints - cost
end end
pos = pos + slice pos = pos + slice

View File

@ -36,10 +36,10 @@ local getResourceGenerator = chunkUtils.getResourceGenerator
-- module code -- module code
function pheromoneUtils.scents(regionMap, chunk) function pheromoneUtils.scents(map, chunk)
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + getPlayerBaseGenerator(regionMap, chunk) chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + getPlayerBaseGenerator(map, chunk)
local resourceGenerator = getResourceGenerator(regionMap, chunk) local resourceGenerator = getResourceGenerator(map, chunk)
if (resourceGenerator > 0) and (getEnemyStructureCount(regionMap, chunk) == 0) then if (resourceGenerator > 0) and (getEnemyStructureCount(map, chunk) == 0) then
chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + mMax(resourceGenerator * 100, 90) chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + mMax(resourceGenerator * 100, 90)
end end
end end
@ -59,7 +59,7 @@ function pheromoneUtils.playerScent(playerChunk)
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
end end
function pheromoneUtils.processPheromone(regionMap, chunk) function pheromoneUtils.processPheromone(map, chunk)
local chunkMovement = chunk[MOVEMENT_PHEROMONE] local chunkMovement = chunk[MOVEMENT_PHEROMONE]
local chunkBase = chunk[BASE_PHEROMONE] local chunkBase = chunk[BASE_PHEROMONE]
@ -67,7 +67,7 @@ function pheromoneUtils.processPheromone(regionMap, chunk)
local chunkResource = chunk[RESOURCE_PHEROMONE] local chunkResource = chunk[RESOURCE_PHEROMONE]
local chunkPathRating = chunk[PATH_RATING] local chunkPathRating = chunk[PATH_RATING]
local tempNeighbors = getCardinalChunks(regionMap, chunk.x, chunk.y) local tempNeighbors = getCardinalChunks(map, chunk.x, chunk.y)
local totalMovement = ((tempNeighbors[1][MOVEMENT_PHEROMONE] - chunkMovement) + local totalMovement = ((tempNeighbors[1][MOVEMENT_PHEROMONE] - chunkMovement) +
(tempNeighbors[2][MOVEMENT_PHEROMONE] - chunkMovement) + (tempNeighbors[2][MOVEMENT_PHEROMONE] - chunkMovement) +

View File

@ -19,11 +19,8 @@ local BASE_PHEROMONE = constants.BASE_PHEROMONE
local SQUAD_RAIDING = constants.SQUAD_RAIDING local SQUAD_RAIDING = constants.SQUAD_RAIDING
local SQUAD_GUARDING = constants.SQUAD_GUARDING local SQUAD_GUARDING = constants.SQUAD_GUARDING
local CHUNK_SIZE = constants.CHUNK_SIZE
local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER
local DEFINES_COMMAND_ATTACK_AREA = defines.command.attack_area
local DEFINES_GROUP_FINISHED = defines.group_state.finished local DEFINES_GROUP_FINISHED = defines.group_state.finished
local DEFINES_GROUP_GATHERING = defines.group_state.gathering local DEFINES_GROUP_GATHERING = defines.group_state.gathering
local DEFINES_GROUP_MOVING = defines.group_state.moving local DEFINES_GROUP_MOVING = defines.group_state.moving
@ -41,7 +38,9 @@ local mRandom = math.random
local findMovementPosition = movementUtils.findMovementPosition local findMovementPosition = movementUtils.findMovementPosition
local getNeighborChunks = mapUtils.getNeighborChunks local getNeighborChunks = mapUtils.getNeighborChunks
local getChunkByPosition = mapUtils.getChunkByPosition local addSquadToChunk = chunkUtils.addSquadToChunk
local getChunkByXY = mapUtils.getChunkByXY
local positionToChunkXY = mapUtils.positionToChunkXY
local addMovementPenalty = movementUtils.addMovementPenalty local addMovementPenalty = movementUtils.addMovementPenalty
local lookupMovementPenalty = movementUtils.lookupMovementPenalty local lookupMovementPenalty = movementUtils.lookupMovementPenalty
local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold
@ -52,8 +51,6 @@ local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPosition local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPosition
local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator
local positionToChunkXY = mapUtils.positionToChunkXY
local scoreNeighborsForAttack = movementUtils.scoreNeighborsForAttack local scoreNeighborsForAttack = movementUtils.scoreNeighborsForAttack
-- module code -- module code
@ -63,18 +60,10 @@ local function scoreAttackLocation(squad, neighborChunk)
return damage - lookupMovementPenalty(squad, neighborChunk) return damage - lookupMovementPenalty(squad, neighborChunk)
end end
function squadAttack.squadsAttack(regionMap, surface, natives) function squadAttack.squadsAttack(map, surface, natives)
local squads = natives.squads local squads = natives.squads
local attackPosition local attackPosition = map.position
local attackCmd local attackCmd = map.attackAreaCommand
if (#squads > 0) then
attackPosition = regionMap.position
attackCmd = { type = DEFINES_COMMAND_ATTACK_AREA,
destination = attackPosition,
radius = CHUNK_SIZE,
distraction = DEFINES_DISTRACTION_BY_ENEMY }
end
for i=1,#squads do for i=1,#squads do
local squad = squads[i] local squad = squads[i]
@ -83,45 +72,50 @@ function squadAttack.squadsAttack(regionMap, surface, natives)
local groupState = group.state local groupState = group.state
if (groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING) or ((groupState == DEFINES_GROUP_MOVING) and (squad.cycles == 0)) then if (groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING) or ((groupState == DEFINES_GROUP_MOVING) and (squad.cycles == 0)) then
local groupPosition = group.position local groupPosition = group.position
local chunk = getChunkByPosition(regionMap, groupPosition) local x, y = positionToChunkXY(groupPosition)
local chunk = getChunkByXY(map, x, y)
local attackChunk, attackDirection = scoreNeighborsForAttack(chunk,
getNeighborChunks(map, x, y),
scoreAttackLocation,
squad)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local attackChunk, attackDirection = scoreNeighborsForAttack(chunk, addSquadToChunk(map, chunk, squad)
getNeighborChunks(regionMap, chunk.x, chunk.y),
scoreAttackLocation,
squad)
addMovementPenalty(natives, squad, chunk) addMovementPenalty(natives, squad, chunk)
if group.valid and (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then elseif (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local playerBaseGenerator = getPlayerBaseGenerator(regionMap, attackChunk) addSquadToChunk(map, attackChunk, squad)
if (playerBaseGenerator == 0) or ((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then addMovementPenalty(natives, squad, attackChunk)
end
if group.valid and (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local playerBaseGenerator = getPlayerBaseGenerator(map, attackChunk)
if (playerBaseGenerator == 0) or ((groupState == DEFINES_GROUP_FINISHED) or (groupState == DEFINES_GROUP_GATHERING)) then
squad.cycles = ((#squad.group.members > 80) and 6) or 4 squad.cycles = ((#squad.group.members > 80) and 6) or 4
local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100) local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100)
squad.frenzy = moreFrenzy squad.frenzy = moreFrenzy
if squad.rabid or squad.frenzy then if squad.rabid or squad.frenzy then
attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING
else else
attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY attackCmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
end
local position = findMovementPosition(surface, positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition, 1.35))
if position then
attackPosition.x = position.x
attackPosition.y = position.y
group.set_command(attackCmd)
group.start_moving()
else
addMovementPenalty(natives, squad, attackChunk)
end
elseif not squad.frenzy and not squad.rabid and
((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or
(playerBaseGenerator ~= 0)) then
squad.frenzy = true
squad.frenzyPosition.x = groupPosition.x
squad.frenzyPosition.y = groupPosition.y
end end
local position = findMovementPosition(surface, positionFromDirectionAndChunk(attackDirection, groupPosition, attackPosition, 1.35))
if position then
attackPosition.x = position.x
attackPosition.y = position.y
group.set_command(attackCmd)
group.start_moving()
else
addMovementPenalty(natives, squad, attackChunk)
end
elseif not squad.frenzy and not squad.rabid and
((groupState == DEFINES_GROUP_ATTACKING_DISTRACTION) or (groupState == DEFINES_GROUP_ATTACKING_TARGET) or
(playerBaseGenerator ~= 0)) then
squad.frenzy = true
squad.frenzyPosition.x = groupPosition.x
squad.frenzyPosition.y = groupPosition.y
end end
end end
end end

View File

@ -10,26 +10,24 @@ local chunkUtils = require("ChunkUtils")
-- constants -- constants
local RETREAT_SPAWNER_GRAB_RADIUS = constants.RETREAT_SPAWNER_GRAB_RADIUS -- local RETREAT_SPAWNER_GRAB_RADIUS = constants.RETREAT_SPAWNER_GRAB_RADIUS
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 HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_RETREATING = constants.SQUAD_RETREATING
local RETREAT_FILTER = constants.RETREAT_FILTER
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
-- imported functions -- imported functions
local addSquadToChunk = chunkUtils.addSquadToChunk
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
local getNeighborChunks = mapUtils.getNeighborChunks local getNeighborChunks = mapUtils.getNeighborChunks
local findNearBySquad = unitGroupUtils.findNearBySquad local findNearbySquadFiltered = unitGroupUtils.findNearbySquadFiltered
local addMovementPenalty = movementUtils.addMovementPenalty local addMovementPenalty = movementUtils.addMovementPenalty
local createSquad = unitGroupUtils.createSquad local createSquad = unitGroupUtils.createSquad
local membersToSquad = unitGroupUtils.membersToSquad local membersToSquad = unitGroupUtils.membersToSquad
@ -43,12 +41,12 @@ local getEnemyStructureCount = chunkUtils.getEnemyStructureCount
-- module code -- module code
local function scoreRetreatLocation(regionMap, neighborChunk) local function scoreRetreatLocation(map, neighborChunk)
return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (getPlayerBaseGenerator(regionMap, neighborChunk) * 20)) return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (getPlayerBaseGenerator(map, neighborChunk) * 20))
end end
function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, natives, tick, radius, force) function aiDefense.retreatUnits(chunk, position, squad, map, surface, natives, tick, radius, force)
if (tick - getRetreatTick(regionMap, chunk) > INTERVAL_LOGIC) and ((getEnemyStructureCount(regionMap, chunk) == 0) or force) then if (tick - getRetreatTick(map, chunk) > INTERVAL_LOGIC) and ((getEnemyStructureCount(map, chunk) == 0) or force) then
local performRetreat = false local performRetreat = false
local enemiesToSquad = nil local enemiesToSquad = nil
@ -60,14 +58,14 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
end end
if performRetreat then if performRetreat then
setRetreatTick(regionMap, chunk, tick) setRetreatTick(map, chunk, tick)
local exitPath,exitDirection = scoreNeighborsForRetreat(chunk, local exitPath,exitDirection = scoreNeighborsForRetreat(chunk,
getNeighborChunks(regionMap, chunk.x, chunk.y), getNeighborChunks(map, chunk.x, chunk.y),
scoreRetreatLocation, scoreRetreatLocation,
regionMap) map)
if (exitPath ~= SENTINEL_IMPASSABLE_CHUNK) then if (exitPath ~= SENTINEL_IMPASSABLE_CHUNK) then
local retreatPosition = findMovementPosition(surface, local retreatPosition = findMovementPosition(surface,
positionFromDirectionAndChunk(exitDirection, position, regionMap.position, 0.98), positionFromDirectionAndChunk(exitDirection, position, map.position, 0.98),
false) false)
if not retreatPosition then if not retreatPosition then
@ -77,7 +75,7 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
-- in order for units in a group attacking to retreat, we have to create a new group and give the command to join -- in order for units in a group attacking to retreat, we have to create a new group and give the command to join
-- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4 -- to each unit, this is the only way I have found to have snappy mid battle retreats even after 0.14.4
local newSquad = findNearBySquad(natives, retreatPosition, HALF_CHUNK_SIZE, RETREAT_FILTER) local newSquad = findNearbySquadFiltered(map, exitPath, retreatPosition)
if not newSquad then if not newSquad then
newSquad = createSquad(retreatPosition, surface, natives) newSquad = createSquad(retreatPosition, surface, natives)
@ -86,15 +84,18 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati
end end
if newSquad then if newSquad then
local cmd = map.retreatCommand
cmd.group = newSquad.group
if enemiesToSquad then if enemiesToSquad then
membersToSquad(newSquad, enemiesToSquad, force) membersToSquad(cmd, enemiesToSquad, force)
else else
membersToSquad(newSquad, squad.group.members, true) membersToSquad(cmd, squad.group.members, true)
newSquad.penalties = squad.penalties newSquad.penalties = squad.penalties
if squad.rabid then if squad.rabid then
newSquad.rabid = true newSquad.rabid = true
end end
end end
addSquadToChunk(map, chunk, newSquad)
addMovementPenalty(natives, newSquad, chunk) addMovementPenalty(natives, newSquad, chunk)
end end
end end

View File

@ -55,11 +55,11 @@ local function removeTendril(base, tendril)
end end
end end
local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives) local function buildTendrilPath(map, tendril, surface, base, tick, natives)
local tendrilUnit = tendril.unit local tendrilUnit = tendril.unit
if not tendrilUnit.valid then if not tendrilUnit.valid then
removeTendril(base, tendril) removeTendril(base, tendril)
tendrilUtils.buildTendril(regionMap, natives, base, surface, tick) tendrilUtils.buildTendril(map, natives, base, surface, tick)
return return
end end
if (tendril.cycles > 0) then if (tendril.cycles > 0) then
@ -67,17 +67,17 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives
return return
end end
local tendrilPosition = tendrilUnit.position local tendrilPosition = tendrilUnit.position
local chunk = getChunkByPosition(regionMap, tendrilPosition) local chunk = getChunkByPosition(map, tendrilPosition)
if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then
local tendrilPath,tendrilDirection = scoreNeighborsForResource(chunk, local tendrilPath,tendrilDirection = scoreNeighborsForResource(chunk,
getNeighborChunks(regionMap, chunk.x, chunk.y), getNeighborChunks(map, chunk.x, chunk.y),
scoreTendrilChunk, scoreTendrilChunk,
nil) nil)
if (tendrilDirection == -1) then if (tendrilDirection == -1) then
if (chunk[RESOURCE_GENERATOR] ~= 0) then if (chunk[RESOURCE_GENERATOR] ~= 0) then
buildOutpost(regionMap, natives, base, surface, tendril) buildOutpost(map, natives, base, surface, tendril)
removeTendril(base, tendril) removeTendril(base, tendril)
tendrilUtils.buildTendril(regionMap, natives, base, surface, tick) tendrilUtils.buildTendril(map, natives, base, surface, tick)
colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface) colorChunk(chunk.x, chunk.y, "hazard-concrete-left", surface)
end end
return return
@ -90,7 +90,7 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives
32, 32,
2) 2)
if position then if position then
buildNest(regionMap, base, surface, tendril.unit.position, "spitter-spawner") buildNest(map, base, surface, tendril.unit.position, "spitter-spawner")
-- tendril.cycles = 3 -- tendril.cycles = 3
tendrilUnit.set_command({ type = defines.command.go_to_location, tendrilUnit.set_command({ type = defines.command.go_to_location,
destination = position, destination = position,
@ -101,9 +101,9 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives
end end
end end
function tendrilUtils.advanceTendrils(regionMap, base, surface, tick, natives) function tendrilUtils.advanceTendrils(map, base, surface, tick, natives)
for i=1, #base.tendrils do for i=1, #base.tendrils do
buildTendrilPath(regionMap, base.tendrils[i], surface, base, tick, natives) buildTendrilPath(map, base.tendrils[i], surface, base, tick, natives)
end end
end end
@ -128,11 +128,11 @@ function tendrilUtils.createTendril(base, surface)
return tendril return tendril
end end
function tendrilUtils.buildTendril(regionMap, natives, base, surface, tick) function tendrilUtils.buildTendril(map, natives, base, surface, tick)
-- local chunk = getChunkByPosition(regionMap, base.x, base.y) -- local chunk = getChunkByPosition(map, base.x, base.y)
-- if chunk then -- if chunk then
-- local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil} -- local tempNeighbors = {nil, nil, nil, nil, nil, nil, nil, nil}
-- buildTendrilPath(regionMap, chunk, surface, base, tempNeighbors) -- buildTendrilPath(map, chunk, surface, base, tempNeighbors)
local tendril = tendrilUtils.createTendril(base, surface) local tendril = tendrilUtils.createTendril(base, surface)
if tendril then if tendril then
base.tendrils[#base.tendrils+1] = tendril base.tendrils[#base.tendrils+1] = tendril

View File

@ -1,10 +1,10 @@
local tunnelUtils = {} local tunnelUtils = {}
function tunnelUtils.digTunnel(regionMap, surface, natives, startChunk, endChunk) function tunnelUtils.digTunnel(map, surface, natives, startChunk, endChunk)
end end
function tunnelUtils.fillTunnel(regionMap, surface, natives, tilePositions) function tunnelUtils.fillTunnel(map, surface, natives, tilePositions)
local tunnels = natives.tunnels local tunnels = natives.tunnels
for i=1, #tunnels do for i=1, #tunnels do

View File

@ -2,23 +2,27 @@ local unitGroupUtils = {}
-- imports -- imports
local mapUtils = require("MapUtils")
local mathUtils = require("MathUtils") local mathUtils = require("MathUtils")
local constants = require("Constants") local constants = require("Constants")
local chunkUtils = require("ChunkUtils")
-- constants -- constants
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE
local DEFINES_GROUP_STATE_FINISHED = defines.group_state.finished local DEFINES_GROUP_STATE_FINISHED = defines.group_state.finished
local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target local DEFINES_GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
local DEFINES_GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction local DEFINES_GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction
local DEFINES_COMMAND_GROUP = defines.command.group
local DEFINES_DISTRACTION_NONE = defines.distraction.none
local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_RETREATING = constants.SQUAD_RETREATING
local SQUAD_GUARDING = constants.SQUAD_GUARDING local SQUAD_GUARDING = constants.SQUAD_GUARDING
local GROUP_MERGE_DISTANCE = constants.GROUP_MERGE_DISTANCE local GROUP_MERGE_DISTANCE = constants.GROUP_MERGE_DISTANCE
local RETREAT_FILTER = constants.RETREAT_FILTER
local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX
local AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_OVERFLOW_POINTS local AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_OVERFLOW_POINTS
@ -34,29 +38,37 @@ local mLog = math.log10
local mMin = math.min local mMin = math.min
local getSquadsOnChunk = chunkUtils.getSquadsOnChunk
local removeSquadFromChunk = chunkUtils.removeSquadFromChunk
local getNeighborChunks = mapUtils.getNeighborChunks
local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
-- module code -- module code
function unitGroupUtils.findNearBySquad(natives, position, distance, filter) function unitGroupUtils.findNearbySquadFiltered(map, chunk, position)
local squads = natives.squads
if filter then local squads = getSquadsOnChunk(map, chunk)
for i=1,#squads do for s=1,#squads do
local squad = squads[i] local squad = squads[s]
local unitGroup = squad.group local unitGroup = squad.group
if unitGroup.valid and filter[squad.status] then if unitGroup.valid and RETREAT_FILTER[squad.status] then
if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then if (euclideanDistanceNamed(unitGroup.position, position) <= HALF_CHUNK_SIZE) then
return squad return squad
end
end end
end end
else end
for i=1,#squads do
local squad = squads[i] local neighbors = getNeighborChunks(map, chunk.x, chunk.y)
for i=1,#neighbors do
squads = getSquadsOnChunk(map, neighbors[i])
for s=1,#squads do
local squad = squads[s]
local unitGroup = squad.group local unitGroup = squad.group
if unitGroup.valid then if unitGroup.valid and RETREAT_FILTER[squad.status] then
if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then if (euclideanDistanceNamed(unitGroup.position, position) <= HALF_CHUNK_SIZE) then
return squad return squad
end end
end end
@ -64,27 +76,41 @@ function unitGroupUtils.findNearBySquad(natives, position, distance, filter)
end end
end end
-- function unitGroupUtils.findNearbySquad(natives, position, distance)
-- local squads = natives.squads
-- for i=1,#squads do
-- local squad = squads[i]
-- local unitGroup = squad.group
-- if unitGroup.valid then
-- if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then
-- return squad
-- end
-- end
-- end
-- end
function unitGroupUtils.createSquad(position, surface, natives) function unitGroupUtils.createSquad(position, surface, natives)
local unitGroup = surface.create_unit_group({position=position}) local unitGroup = surface.create_unit_group({position=position})
local squad = { group = unitGroup, local squad = {
status = SQUAD_GUARDING, group = unitGroup,
penalties = {}, status = SQUAD_GUARDING,
rabid = false, penalties = {},
frenzy = false, rabid = false,
kamikaze = false, frenzy = false,
frenzyPosition = {x = 0, kamikaze = false,
y = 0}, frenzyPosition = {x = 0,
cycles = 0 } y = 0},
cycles = 0,
chunk = nil
}
natives.squads[#natives.squads+1] = squad natives.squads[#natives.squads+1] = squad
return squad return squad
end end
function unitGroupUtils.membersToSquad(squad, members, overwriteGroup) function unitGroupUtils.membersToSquad(cmd, members, overwriteGroup)
if (members ~= nil) then if (members ~= nil) then
local cmd = { type = DEFINES_COMMAND_GROUP,
group = squad.group,
distraction = DEFINES_DISTRACTION_NONE }
for i=1,#members do for i=1,#members do
local member = members[i] local member = members[i]
if member.valid and (overwriteGroup or (not overwriteGroup and not member.unit_group)) then if member.valid and (overwriteGroup or (not overwriteGroup and not member.unit_group)) then
@ -118,7 +144,7 @@ local function isAttacking(group)
return (state == DEFINES_GROUP_STATE_ATTACKING_TARGET) or (state == DEFINES_GROUP_STATE_ATTACKING_DISTRACTION) return (state == DEFINES_GROUP_STATE_ATTACKING_TARGET) or (state == DEFINES_GROUP_STATE_ATTACKING_DISTRACTION)
end end
function unitGroupUtils.cleanSquads(natives) function unitGroupUtils.cleanSquads(natives, map)
local squads = natives.squads local squads = natives.squads
local squadCount = #squads local squadCount = #squads
@ -130,10 +156,12 @@ function unitGroupUtils.cleanSquads(natives)
if group.valid then if group.valid then
local memberCount = #group.members local memberCount = #group.members
if (memberCount == 0) then if (memberCount == 0) then
removeSquadFromChunk(map, squad)
group.destroy() group.destroy()
elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
local members = group.members local members = group.members
unitGroupUtils.recycleBiters(natives, members) unitGroupUtils.recycleBiters(natives, members)
removeSquadFromChunk(map, squad)
group.destroy() group.destroy()
else else
local status = squad.status local status = squad.status
@ -170,9 +198,39 @@ function unitGroupUtils.recycleBiters(natives, biters)
end end
end end
function unitGroupUtils.regroupSquads(natives) local function mergeGroups(squads, squad, group, status, position, memberCount)
local groupThreshold = AI_SQUAD_MERGE_THRESHOLD local merge = false
local maxed = false
for x=1, #squads do
local mergeSquad = squads[x]
if mergeSquad ~= squad then
local mergeGroup = mergeSquad.group
if mergeGroup.valid and (euclideanDistanceNamed(position, mergeGroup.position) < GROUP_MERGE_DISTANCE) and (mergeSquad.status == status) and not isAttacking(mergeGroup) 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
if mergeSquad.kamikaze then
squad.kamikaze = true
end
merge = true
mergeGroup.destroy()
end
memberCount = memberCount + mergeCount
if (memberCount > AI_SQUAD_MERGE_THRESHOLD) then
maxed = true
break
end
end
end
end
return merge, memberCount, maxed
end
function unitGroupUtils.regroupSquads(natives, map)
local squads = natives.squads local squads = natives.squads
local squadCount = #squads local squadCount = #squads
@ -183,33 +241,39 @@ function unitGroupUtils.regroupSquads(natives)
local squad = squads[i] local squad = squads[i]
local group = squad.group local group = squad.group
if group.valid and not isAttacking(group) then if group.valid and not isAttacking(group) then
local status = squad.status
local memberCount = #group.members local memberCount = #group.members
if (memberCount < groupThreshold) then if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then
local status = squad.status
local squadPosition = group.position local squadPosition = group.position
local mergedSquads = false local mergedSquads
for x=i+1,squadCount do local maxed
local mergeSquad = squads[x] local chunk = squad.chunk
local mergeGroup = mergeSquad.group
if mergeGroup.valid and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) and (mergeSquad.status == status) and not isAttacking(mergeGroup) then if chunk then
local mergeMembers = mergeGroup.members mergedSquads, memberCount, maxed = mergeGroups(getSquadsOnChunk(map, chunk),
local mergeCount = #mergeMembers squad,
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) then group,
for memberIndex=1, mergeCount do status,
group.add_member(mergeMembers[memberIndex]) squadPosition,
end memberCount)
if mergeSquad.kamikaze then
squad.kamikaze = true if not maxed then
end local neighbors = getNeighborChunks(map, chunk.x, chunk.y)
mergedSquads = true
mergeGroup.destroy() for x=1,#neighbors do
end mergedSquads, memberCount, maxed = mergeGroups(getSquadsOnChunk(map, neighbors[x]),
memberCount = memberCount + mergeCount squad,
if (memberCount > groupThreshold) then group,
break status,
end squadPosition,
end memberCount)
end if maxed then
break
end
end
end
end
if mergedSquads and not squad.kamikaze then if mergedSquads and not squad.kamikaze then
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives) local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives)
if (mRandom() < kamikazeThreshold) then if (mRandom() < kamikazeThreshold) then

View File

@ -34,6 +34,7 @@
(string->path "changelog.txt") (string->path "changelog.txt")
(string->path "Upgrade.lua") (string->path "Upgrade.lua")
(string->path "settings.lua") (string->path "settings.lua")
(string->path "BuildSwarm.lua")
(string->path "README.md") (string->path "README.md")
(string->path "NOTICE") (string->path "NOTICE")
(string->path "libs") (string->path "libs")
@ -73,6 +74,7 @@
(copyFile "changelog.txt" modFolder) (copyFile "changelog.txt" modFolder)
(copyFile "Upgrade.lua" modFolder) (copyFile "Upgrade.lua" modFolder)
(copyFile "tests.lua" modFolder) (copyFile "tests.lua" modFolder)
(copyFile "BuildSwarm.lua" modFolder)
(copyDirectory "libs" modFolder) (copyDirectory "libs" modFolder)
(copyDirectory "locale" modFolder) (copyDirectory "locale" modFolder)
(copyDirectory "sounds" modFolder) (copyDirectory "sounds" modFolder)
@ -80,6 +82,6 @@
(copyDirectory "prototypes" modFolder))) (copyDirectory "prototypes" modFolder)))
(define (run) (define (run)
;;(copyFiles modFolder) (copyFiles modFolder)
(makeZip modFolder) ;;(makeZip modFolder)
(system*/exit-code "/data/games/factorio/bin/x64/factorio"))) (system*/exit-code "/data/games/factorio/bin/x64/factorio")))

View File

@ -1,20 +1,23 @@
local biterFunctions = {} local biterFunctions = {}
function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances) function biterFunctions.makeBiter(name, biterAttributes, biterAttack, biterResistances)
biterAttack.scale = biterAttributes.scale; local resistances = {}
biterAttack.tint1 = biterAttributes.tint1; for k,v in pairs(biterResistances) do
biterAttack.tint2 = biterAttributes.tint2; v.type = k
resistances[#resistances+1] = v
end
return { return {
type = "unit", type = "unit",
name = biterAttributes.name, name = name,
icon = "__base__/graphics/icons/small-biter.png", icon = "__base__/graphics/icons/small-biter.png",
icon_size = 32, icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"}, flags = biterAttributes.flags or {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"},
max_health = biterAttributes.health, max_health = biterAttributes.health,
order = "b-b-a", order = "b-b-a",
subgroup="enemies", subgroup="enemies",
healing_per_tick = biterAttributes.healing, healing_per_tick = biterAttributes.healing,
resistances = biterResistances, resistances = resistances,
collision_box = {{-0.4 * biterAttributes.scale, -0.4 * biterAttributes.scale}, collision_box = {{-0.4 * biterAttributes.scale, -0.4 * biterAttributes.scale},
{0.4 * biterAttributes.scale, 0.4 * biterAttributes.scale}}, {0.4 * biterAttributes.scale, 0.4 * biterAttributes.scale}},
selection_box = {{-0.7 * biterAttributes.scale, -1.5 * biterAttributes.scale}, selection_box = {{-0.7 * biterAttributes.scale, -1.5 * biterAttributes.scale},
@ -22,11 +25,11 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances
sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale},
{0.6 * biterAttributes.scale, 0}}, {0.6 * biterAttributes.scale, 0}},
attack_parameters = biterAttack, attack_parameters = biterAttack,
vision_distance = 30, vision_distance = biterAttributes.vision or 30,
movement_speed = biterAttributes.movement, movement_speed = biterAttributes.movement,
distance_per_frame = 0.1, distance_per_frame = biterAttributes.distancePerFrame or 0.1,
pollution_to_join_attack = 200, pollution_to_join_attack = biterAttributes.pollutionToAttack or 200,
distraction_cooldown = 300, distraction_cooldown = biterAttributes.distractionCooldown or 300,
corpse = biterAttributes.corpse, corpse = biterAttributes.corpse,
dying_explosion = biterAttributes.explosion, dying_explosion = biterAttributes.explosion,
dying_sound = make_biter_dying_sounds(1.0), dying_sound = make_biter_dying_sounds(1.0),
@ -35,21 +38,24 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances
} }
end end
function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistances) function biterFunctions.makeSpitter(name, biterAttributes, biterAttack, biterResistances)
-- biterAttack.scale = biterAttributes.scale; local resistances = {}
-- biterAttack.tint1 = biterAttributes.tint1; for k,v in pairs(biterResistances) do
-- biterAttack.tint2 = biterAttributes.tint2; v.type = k
resistances[#resistances+1] = v
end
return { return {
type = "unit", type = "unit",
name = biterAttributes.name, name = name,
icon = "__base__/graphics/icons/small-spitter.png", icon = "__base__/graphics/icons/small-spitter.png",
icon_size = 32, icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"}, flags = biterAttributes.flags or {"placeable-player", "placeable-enemy", "placeable-off-grid", "breaths-air"},
max_health = biterAttributes.health, max_health = biterAttributes.health,
order = "b-b-a", order = "b-b-a",
subgroup="enemies", subgroup="enemies",
healing_per_tick = biterAttributes.healing, healing_per_tick = biterAttributes.healing,
resistances = biterResistances, resistances = resistances,
collision_box = {{-0.4 * biterAttributes.scale, -0.4 * biterAttributes.scale}, collision_box = {{-0.4 * biterAttributes.scale, -0.4 * biterAttributes.scale},
{0.4 * biterAttributes.scale, 0.4 * biterAttributes.scale}}, {0.4 * biterAttributes.scale, 0.4 * biterAttributes.scale}},
selection_box = {{-0.7 * biterAttributes.scale, -1.5 * biterAttributes.scale}, selection_box = {{-0.7 * biterAttributes.scale, -1.5 * biterAttributes.scale},
@ -57,11 +63,11 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc
sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale},
{0.6 * biterAttributes.scale, 0}}, {0.6 * biterAttributes.scale, 0}},
attack_parameters = biterAttack, attack_parameters = biterAttack,
vision_distance = 30, vision_distance = biterAttributes.vision or 30,
movement_speed = biterAttributes.movement, movement_speed = biterAttributes.movement,
distance_per_frame = biterAttributes.distancePerFrame, distance_per_frame = biterAttributes.distancePerFrame or 0.1,
pollution_to_join_attack = 200, pollution_to_join_attack = biterAttributes.pollutionToAttack or 200,
distraction_cooldown = 300, distraction_cooldown = biterAttributes.distractionCooldown or 300,
corpse = biterAttributes.corpse, corpse = biterAttributes.corpse,
dying_explosion = biterAttributes.explosion, dying_explosion = biterAttributes.explosion,
dying_sound = make_biter_dying_sounds(1.0), dying_sound = make_biter_dying_sounds(1.0),
@ -70,6 +76,128 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc
} }
end end
function biterFunctions.makeUnitSpawner(name, biterAttributes, biterResistances, unitSet)
local resistances = {}
for k,v in pairs(biterResistances) do
v.type = k
resistances[#resistances+1] = v
end
local o = {
type = "unit-spawner",
name = name,
icon = "__base__/graphics/icons/biter-spawner.png",
icon_size = 32,
flags = {"placeable-player", "placeable-enemy", "not-repairable"},
max_health = biterAttributes.health,
order="b-b-g",
subgroup="enemies",
resistances = resistances,
working_sound = {
sound =
{
{
filename = "__base__/sound/creatures/spawner.ogg",
volume = 1.0
}
},
apparent_volume = 2
},
dying_sound =
{
{
filename = "__base__/sound/creatures/spawner-death-1.ogg",
volume = 1.0
},
{
filename = "__base__/sound/creatures/spawner-death-2.ogg",
volume = 1.0
}
},
healing_per_tick = biterAttributes.healing or 0.02,
collision_box = {{-3.2 * biterAttributes.scale, -2.2 * biterAttributes.scale}, {2.2 * biterAttributes.scale, 2.2 * biterAttributes.scale}},
selection_box = {{-3.5 * biterAttributes.scale, -2.5 * biterAttributes.scale}, {2.5 * biterAttributes.scale, 2.5 * biterAttributes.scale}},
-- in ticks per 1 pu
pollution_absorbtion_absolute = biterAttributes.pollutionAbsorbtionAbs or 20,
pollution_absorbtion_proportional = biterAttributes.pollutionAbsorbtionPro or 0.01,
corpse = "biter-spawner-corpse",
dying_explosion = "blood-explosion-huge",
max_count_of_owned_units = biterAttributes.unitsOwned or 7,
max_friends_around_to_spawn = biterAttributes.unitsToSpawn or 5,
animations =
{
spawner_idle_animation(0, biterAttributes.tint),
spawner_idle_animation(1, biterAttributes.tint),
spawner_idle_animation(2, biterAttributes.tint),
spawner_idle_animation(3, biterAttributes.tint)
},
result_units = unitSet,
-- With zero evolution the spawn rate is 6 seconds, with max evolution it is 2.5 seconds
spawning_cooldown = biterAttributes.spawningCooldown or {360, 150},
spawning_radius = biterAttributes.spawningRadius or 10,
spawning_spacing = biterAttributes.spawningSpacing or 3,
max_spawn_shift = 0,
max_richness_for_spawn_shift = 100,
build_base_evolution_requirement = biterAttributes.evolutionRequirement or 0.0,
call_for_help_radius = 50
}
if biterAttributes.autoplace then
o["autoplace"] = enemy_spawner_autoplace(biterAttributes.autoplace)
end
return o
end
function biterFunctions.makeWorm(name, attributes, attack, wormResistances)
local resistances = {}
for k,v in pairs(wormResistances) do
v.type = k
resistances[#resistances+1] = v
end
local o = {
type = "turret",
name = name,
icon = "__base__/graphics/icons/medium-worm.png",
icon_size = 32,
flags = attributes.flags or {"placeable-player", "placeable-enemy", "not-repairable", "breaths-air"},
order="b-b-e",
subgroup="enemies",
max_health = attributes.health,
resistances = resistances,
healing_per_tick = attributes.healing or 0.01,
collision_box = {{-1.1 * attributes.scale, -1.0 * attributes.scale}, {1.1 * attributes.scale, 1.0 * attributes.scale}},
selection_box = {{-1.1 * attributes.scale, -1.0 * attributes.scale}, {1.1 * attributes.scale, 1.0 * attributes.scale}},
shooting_cursor_size = attributes.cursorSize or 3,
rotation_speed = attributes.rotationSpeed or 1,
corpse = "medium-worm-corpse",
dying_explosion = "blood-explosion-big",
dying_sound = make_worm_dying_sounds(0.9),
folded_speed = attributes.foldedSpeed or 0.01,
folded_animation = worm_folded_animation(attributes.scale, attributes.tint),
preparing_speed = attributes.preparingSpeed or 0.025,
preparing_animation = worm_preparing_animation(attributes.scale, attributes.tint, "forward"),
prepared_speed = attributes.preparedSpeed or 0.015,
prepared_animation = worm_prepared_animation(attributes.scale, attributes.tint),
starting_attack_speed = attributes.attackSpeed or 0.03,
starting_attack_animation = worm_attack_animation(attributes.scale, attributes.tint, "forward"),
starting_attack_sound = make_worm_roars(0.8),
ending_attack_speed = attributes.endingAttackSpeed or 0.03,
ending_attack_animation = worm_attack_animation(attributes.scale, attributes.tint, "backward"),
folding_speed = attributes.foldingSpeed or 0.015,
folding_animation = worm_preparing_animation(attributes.scale, attributes.tint, "backward"),
prepare_range = attributes.prepareRange or 30,
attack_parameters = attack,
build_base_evolution_requirement = attributes.evolutionRequirement or 0.0,
call_for_help_radius = 40
}
if attributes.autoplace then
o["autoplace"] = enemy_worm_autoplace(attributes.autoplace)
end
return o
end
function biterFunctions.createSuicideAttack(attributes) function biterFunctions.createSuicideAttack(attributes)
return { type = "projectile", return { type = "projectile",
range = 0.5, range = 0.5,

View File

@ -212,8 +212,30 @@ data:extend({
default_value = true, default_value = true,
order = "k[modifier]-a[unit]", order = "k[modifier]-a[unit]",
per_user = false per_user = false
},
{
type = "int-setting",
name = "rampant-enemySeed",
description = "rampant-enemySeed",
setting_type = "startup",
minimum_value = 0,
default_value = 0,
order = "l[modifer]-a[seed]",
per_user = false
},
{
type = "bool-setting",
name = "rampant-newEnemies",
description = "rampant-newEnemies",
setting_type = "startup",
default_value = true,
order = "l[modifier]-b[unit]",
per_user = false
} }
-- { -- {
-- type = "bool-setting", -- type = "bool-setting",
-- name = "rampant-reduceAnimations", -- name = "rampant-reduceAnimations",

View File

@ -17,19 +17,19 @@ function tests.pheromoneLevels(size)
size = size * constants.CHUNK_SIZE size = size * constants.CHUNK_SIZE
end end
print("------") print("------")
print(#global.regionMap.processQueue) print(#global.map.processQueue)
print(playerChunkX .. ", " .. playerChunkY) print(playerChunkX .. ", " .. playerChunkY)
print("--") print("--")
for y=playerChunkY-size, playerChunkY+size,32 do for y=playerChunkY-size, playerChunkY+size,32 do
for x=playerChunkX-size, playerChunkX+size,32 do for x=playerChunkX-size, playerChunkX+size,32 do
if (global.regionMap[x] ~= nil) then if (global.map[x] ~= nil) then
local chunk = global.regionMap[x][y] local chunk = global.map[x][y]
if (chunk ~= nil) then if (chunk ~= nil) then
local str = "" local str = ""
for i=1,#chunk do for i=1,#chunk do
str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i]) str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i])
end end
str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk) .. " " .. "n/" .. chunkUtils.getNestCount(global.regionMap, chunk) .. " " .. "w/" .. chunkUtils.getWormCount(global.regionMap, chunk) str = str .. " " .. "p/" .. game.surfaces[1].get_pollution(chunk) .. " " .. "n/" .. chunkUtils.getNestCount(global.map, chunk) .. " " .. "w/" .. chunkUtils.getWormCount(global.map, chunk)
if (chunk.x == playerChunkX) and (chunk.y == playerChunkY) then if (chunk.x == playerChunkX) and (chunk.y == playerChunkY) then
print("=============") print("=============")
print(chunk.x, chunk.y, str) print(chunk.x, chunk.y, str)
@ -124,7 +124,7 @@ function tests.getOffsetChunk(x, y)
local playerPosition = game.players[1].position local playerPosition = game.players[1].position
local chunkX = math.floor(playerPosition.x * 0.03125) local chunkX = math.floor(playerPosition.x * 0.03125)
local chunkY = math.floor(playerPosition.y * 0.03125) local chunkY = math.floor(playerPosition.y * 0.03125)
local chunk = mapUtils.getChunkByIndex(global.regionMap, chunkX + x, chunkY + y) local chunk = mapUtils.getChunkByIndex(global.map, chunkX + x, chunkY + y)
print(serpent.dump(chunk)) print(serpent.dump(chunk))
end end
@ -163,7 +163,7 @@ end
function tests.registeredNest(x) function tests.registeredNest(x)
local entity = tests.createEnemy(x) local entity = tests.createEnemy(x)
chunk.registerEnemyBaseStructure(global.regionMap, chunk.registerEnemyBaseStructure(global.map,
entity, entity,
nil) nil)
end end
@ -272,7 +272,7 @@ end
function tests.showMovementGrid() function tests.showMovementGrid()
local chunks = global.regionMap.processQueue local chunks = global.map.processQueue
for i=1,#chunks do for i=1,#chunks do
local chunk = chunks[i] local chunk = chunks[i]
local color = "concrete" local color = "concrete"
@ -288,7 +288,7 @@ function tests.showMovementGrid()
end end
function tests.colorResourcePoints() function tests.colorResourcePoints()
local chunks = global.regionMap.processQueue local chunks = global.map.processQueue
for i=1,#chunks do for i=1,#chunks do
local chunk = chunks[i] local chunk = chunks[i]
local color = "concrete" local color = "concrete"
@ -307,7 +307,7 @@ end
function tests.exportAiState(onTick) function tests.exportAiState(onTick)
local printState = function () local printState = function ()
local chunks = global.regionMap.processQueue local chunks = global.map.processQueue
local s = "" local s = ""
for i=1,#chunks do for i=1,#chunks do
local chunk = chunks[i] local chunk = chunks[i]
@ -321,12 +321,12 @@ function tests.exportAiState(onTick)
chunk[constants.PATH_RATING], chunk[constants.PATH_RATING],
chunk.x, chunk.x,
chunk.y, chunk.y,
chunkUtils.getNestCount(global.regionMap, chunk), chunkUtils.getNestCount(global.map, chunk),
chunkUtils.getWormCount(global.regionMap, chunk), chunkUtils.getWormCount(global.map, chunk),
chunkUtils.getRallyTick(global.regionMap, chunk), chunkUtils.getRallyTick(global.map, chunk),
chunkUtils.getRetreatTick(global.regionMap, chunk), chunkUtils.getRetreatTick(global.map, chunk),
chunkUtils.getResourceGenerator(global.regionMap, chunk), chunkUtils.getResourceGenerator(global.map, chunk),
chunkUtils.getPlayerBaseGenerator(global.regionMap, chunk)}, ",") .. "\n" chunkUtils.getPlayerBaseGenerator(global.map, chunk)}, ",") .. "\n"
end end
game.write_file("rampantState.txt", s, false) game.write_file("rampantState.txt", s, false)
end end
@ -357,7 +357,7 @@ end
function tests.stepAdvanceTendrils() function tests.stepAdvanceTendrils()
-- for _, base in pairs(global.natives.bases) do -- for _, base in pairs(global.natives.bases) do
-- tendrilUtils.advanceTendrils(global.regionMap, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil}) -- tendrilUtils.advanceTendrils(global.map, base, game.surfaces[1], {nil,nil,nil,nil,nil,nil,nil,nil})
-- end -- end
end end