diff --git a/BuildSwarm.lua b/BuildSwarm.lua new file mode 100755 index 0000000..74da448 --- /dev/null +++ b/BuildSwarm.lua @@ -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 diff --git a/UnitClasses.lua b/UnitClasses.lua new file mode 100755 index 0000000..39a6bce --- /dev/null +++ b/UnitClasses.lua @@ -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 + } +) + diff --git a/Upgrade.lua b/Upgrade.lua index 24ed657..3d04637 100755 --- a/Upgrade.lua +++ b/Upgrade.lua @@ -105,7 +105,7 @@ function upgrade.attempt(natives) -- used to precompute some values per logic cycle natives.retreatThreshold = 0 - natives.maxSquads = 0 + -- natives.maxSquads = 0 natives.rallyThreshold = 0 natives.formSquadThreshold = 0 natives.attackWaveSize = 0 @@ -163,10 +163,16 @@ function upgrade.attempt(natives) game.surfaces[1].print("Rampant - Version 0.15.23") global.version = constants.VERSION_33 end - if (global.version < constants.VERSION_37) then + if (global.version < constants.VERSION_38) then - game.surfaces[1].print("Rampant - Version 0.16.2") - global.version = constants.VERSION_37 + for _,squad in pairs(natives.squads) do + squad.chunk = nil + end + + global.regionMap = nil + + game.surfaces[1].print("Rampant - Version 0.16.3") + global.version = constants.VERSION_38 end return starting ~= global.version, natives end diff --git a/changelog.txt b/changelog.txt index 6bae04e..d009d1a 100755 --- a/changelog.txt +++ b/changelog.txt @@ -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 Date: 1. 2. 2018 diff --git a/control.lua b/control.lua index 2beccde..a482af8 100755 --- a/control.lua +++ b/control.lua @@ -36,6 +36,14 @@ local RETREAT_GRAB_RADIUS = constants.RETREAT_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 local roundToNearest = mathUtils.roundToNearest @@ -80,7 +88,7 @@ local mRandom = math.random -- 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 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 natives.points = AI_MAX_OVERFLOW_POINTS end - local chunk = getChunkByPosition(regionMap, event.position) + local chunk = getChunkByPosition(map, event.position) if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then - rallyUnits(chunk, regionMap, surface, natives, event.tick) + rallyUnits(chunk, map, surface, natives, event.tick) end end end @@ -113,7 +121,7 @@ local function hookEvents() end local function onLoad() - regionMap = global.regionMap + map = global.map natives = global.natives pendingChunks = global.pendingChunks @@ -130,27 +138,28 @@ end local function rebuildRegionMap() game.surfaces[1].print("Rampant - Reindexing chunks, please wait.") - -- clear old regionMap processing Queue + -- clear old map processing Queue -- prevents queue adding duplicate chunks -- chunks are by key, so should overwrite old - global.regionMap = {} - regionMap = global.regionMap - regionMap.processQueue = {} - regionMap.processIndex = 1 - regionMap.scanIndex = 1 - - regionMap.chunkToHives = {} - regionMap.chunkToNests = {} - regionMap.chunkToWorms = {} - regionMap.chunkToRetreats = {} - regionMap.chunkToRallys = {} - regionMap.chunkToPlayerBase = {} - regionMap.chunkToResource = {} - regionMap.chunkToPassScan = {} + global.map = {} + map = global.map + map.processQueue = {} + map.processIndex = 1 + map.scanIndex = 1 + map.chunkToHives = {} + map.chunkToNests = {} + map.chunkToWorms = {} + map.chunkToRetreats = {} + map.chunkToRallys = {} + map.chunkToPlayerBase = {} + map.chunkToResource = {} + map.chunkToPassScan = {} + map.chunkToSquad = {} + -- 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, @@ -158,29 +167,40 @@ local function rebuildRegionMap() 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 } - regionMap.position = {x=0, + map.position = {x=0, y=0} --this is shared between two different queries - regionMap.area = {{0, 0}, {0, 0}} - regionMap.countResourcesQuery = { area=regionMap.area, type="resource" } - regionMap.filteredEntitiesEnemyQuery = { area=regionMap.area, force="enemy" } - regionMap.filteredEntitiesEnemyUnitQuery = { area=regionMap.area, force="enemy", type="unit", limit=301 } - regionMap.filteredEntitiesEnemyTypeQuery = { area=regionMap.area, force="enemy", type="unit-spawner" } - regionMap.filteredEntitiesPlayerQuery = { area=regionMap.area, force="player" } - regionMap.canPlaceQuery = { name="", position={0,0} } - regionMap.filteredTilesQuery = { name="", area=regionMap.area } + map.area = {{0, 0}, {0, 0}} + map.countResourcesQuery = { area=map.area, type="resource" } + map.filteredEntitiesEnemyQuery = { area=map.area, force="enemy" } + map.filteredEntitiesEnemyUnitQuery = { area=map.area, force="enemy", type="unit", limit=301 } + map.filteredEntitiesEnemyTypeQuery = { area=map.area, force="enemy", type="unit-spawner" } + map.filteredEntitiesPlayerQuery = { area=map.area, force="player" } + map.canPlaceQuery = { name="", position={0,0} } + 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 - regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) - regionMap.scanTick = roundToNearest(game.tick + INTERVAL_SCAN, INTERVAL_SCAN) - regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS) - regionMap.chunkTick = roundToNearest(game.tick + INTERVAL_CHUNK, INTERVAL_CHUNK) - regionMap.squadTick = roundToNearest(game.tick + INTERVAL_SQUAD, INTERVAL_SQUAD) + map.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC) + map.scanTick = roundToNearest(game.tick + INTERVAL_SCAN, INTERVAL_SCAN) + map.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS) + map.chunkTick = roundToNearest(game.tick + INTERVAL_CHUNK, INTERVAL_CHUNK) + map.squadTick = roundToNearest(game.tick + INTERVAL_SQUAD, INTERVAL_SQUAD) -- clear pending chunks, will be added when loop runs below global.pendingChunks = {} @@ -196,7 +216,7 @@ local function rebuildRegionMap() y = chunk.y * 32 }}}) end - processPendingChunks(natives, regionMap, surface, pendingChunks, tick) + processPendingChunks(natives, map, surface, pendingChunks, tick) end local function onModSettingsChange(event) @@ -260,28 +280,28 @@ end local function onTick(event) local tick = event.tick - if (tick == regionMap.processTick) then - regionMap.processTick = regionMap.processTick + INTERVAL_PROCESS + if (tick == map.processTick) then + map.processTick = map.processTick + INTERVAL_PROCESS local gameRef = game 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 - if (tick == regionMap.scanTick) then - regionMap.scanTick = regionMap.scanTick + INTERVAL_SCAN + if (tick == map.scanTick) then + map.scanTick = map.scanTick + INTERVAL_SCAN 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 - if (tick == regionMap.logicTick) then - regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC + if (tick == map.logicTick) then + map.logicTick = map.logicTick + INTERVAL_LOGIC local gameRef = game local surface = gameRef.surfaces[1] @@ -292,26 +312,26 @@ local function onTick(event) surface) if natives.useCustomAI then - processBases(regionMap, surface, natives, tick) + processBases(map, surface, natives, tick) end end - if (tick == regionMap.squadTick) then - regionMap.squadTick = regionMap.squadTick + INTERVAL_SQUAD + if (tick == map.squadTick) then + map.squadTick = map.squadTick + INTERVAL_SQUAD local gameRef = game - cleanSquads(natives) - regroupSquads(natives) + cleanSquads(natives, map) + regroupSquads(natives, map) squadsBeginAttack(natives, gameRef.players) - squadsAttack(regionMap, gameRef.surfaces[1], natives) + squadsAttack(map, gameRef.surfaces[1], natives) end end local function onBuild(event) local entity = event.created_entity if (entity.surface.index == 1) then - addRemovePlayerEntity(regionMap, entity, natives, true, false) + addRemovePlayerEntity(map, entity, natives, true, false) if natives.safeBuildings then if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then entity.destructible = false @@ -324,7 +344,7 @@ local function onMine(event) local entity = event.entity local surface = entity.surface if (surface.index == 1) then - addRemovePlayerEntity(regionMap, entity, natives, false, false) + addRemovePlayerEntity(map, entity, natives, false, false) end end @@ -333,7 +353,7 @@ local function onDeath(event) local surface = entity.surface if (surface.index == 1) then local entityPosition = entity.position - local chunk = getChunkByPosition(regionMap, entityPosition) + local chunk = getChunkByPosition(map, entityPosition) local cause = event.cause if (entity.force.name == "enemy") then if (entity.type == "unit") then @@ -350,7 +370,7 @@ local function onDeath(event) retreatUnits(chunk, entityPosition, convertUnitGroupToSquad(natives, entity.unit_group), - regionMap, + map, surface, natives, tick, @@ -358,7 +378,7 @@ local function onDeath(event) artilleryBlast) 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 @@ -367,14 +387,14 @@ local function onDeath(event) local tick = event.tick 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, entityPosition, nil, - regionMap, + map, surface, natives, 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 makeImmortalEntity(surface, entity) else - addRemovePlayerEntity(regionMap, entity, natives, false, creditNatives) + addRemovePlayerEntity(map, entity, natives, false, creditNatives) end end end @@ -403,12 +423,12 @@ local function onEnemyBaseBuild(event) local entity = event.entity local surface = entity.surface if (surface.index == 1) then - registerEnemyBaseStructure(regionMap, entity, nil) + registerEnemyBaseStructure(map, entity, nil) end end 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 local chunks = {} local positions = event.tiles @@ -418,7 +438,7 @@ local function onSurfaceTileChange(event) -- weird bug with table pointer equality using name instead pointer comparison if not chunk.name then - regionMap.chunkToPassScan[chunk] = true + map.chunkToPassScan[chunk] = true else local x,y = mapUtils.positionToChunkXY(position) local addMe = true @@ -444,7 +464,7 @@ end local function onResourceDepleted(event) local entity = event.entity if (entity.surface.index == 1) then - chunkUtils.unregisterResource(entity, regionMap) + chunkUtils.unregisterResource(entity, map) end end @@ -455,17 +475,17 @@ local function onUsedCapsule(event) {event.position.x+0.75,event.position.y+0.75}}, type="cliff"}) for i=1,#cliffs do - entityForPassScan(regionMap, cliffs[i]) + entityForPassScan(map, cliffs[i]) end end end local function onInit() - global.regionMap = {} + global.map = {} global.pendingChunks = {} global.natives = {} - regionMap = global.regionMap + map = global.map natives = global.natives pendingChunks = global.pendingChunks diff --git a/data.lua b/data.lua index cb2ce0f..083d592 100755 --- a/data.lua +++ b/data.lua @@ -6,8 +6,12 @@ require("prototypes/buildings/UnitSpawners") 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") diff --git a/info.json b/info.json index c914897..13f57f6 100755 --- a/info.json +++ b/info.json @@ -1,7 +1,7 @@ { "name" : "Rampant", "factorio_version" : "0.16", - "version" : "0.16.2", + "version" : "0.16.3", "title" : "Rampant", "author" : "Veden", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", diff --git a/libs/AIAttackWave.lua b/libs/AIAttackWave.lua index a8bc2f1..322c682 100755 --- a/libs/AIAttackWave.lua +++ b/libs/AIAttackWave.lua @@ -81,23 +81,25 @@ local function scoreUnitGroupLocation(neighborChunk) return neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] end -local function validUnitGroupLocation(regionMap, neighborChunk) - return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(regionMap, neighborChunk) == 0) +local function validUnitGroupLocation(map, neighborChunk) + return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(map, neighborChunk) == 0) end -function aiAttackWave.rallyUnits(chunk, regionMap, surface, natives, tick) - if ((tick - getRallyTick(regionMap, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) and - (#natives.squads < natives.maxSquads)) then - setRallyTick(regionMap, chunk, tick) +function aiAttackWave.rallyUnits(chunk, map, surface, natives, tick) + if ((tick - getRallyTick(map, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST) -- and + -- (#natives.squads < natives.maxSquads) + ) then + setRallyTick(map, chunk, tick) local cX = chunk.x local cY = chunk.y for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do if (x ~= cX) and (y ~= cY) then - local rallyChunk = getChunkByXY(regionMap, x, y) - if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(regionMap, rallyChunk) > 0) then - aiAttackWave.formSquads(regionMap, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST) - if (natives.points < AI_VENGENCE_SQUAD_COST) and (#natives.squads < natives.maxSquads) then + local rallyChunk = getChunkByXY(map, x, y) + if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(map, rallyChunk) > 0) then + aiAttackWave.formSquads(map, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST) + if (natives.points < AI_VENGENCE_SQUAD_COST) -- and (#natives.squads < natives.maxSquads) + then return end end @@ -107,20 +109,20 @@ function aiAttackWave.rallyUnits(chunk, regionMap, surface, natives, tick) 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)) 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, scoreUnitGroupLocation, - regionMap) + map) if (squadPath ~= SENTINEL_IMPASSABLE_CHUNK) then local squadPosition = surface.find_non_colliding_position("biter-spawner-hive-rampant", positionFromDirectionAndChunk(squadDirection, chunk, - regionMap.position, + map.position, 0.98), CHUNK_SIZE, 4) diff --git a/libs/AIPlanning.lua b/libs/AIPlanning.lua index 6f1e80f..5856072 100755 --- a/libs/AIPlanning.lua +++ b/libs/AIPlanning.lua @@ -65,7 +65,7 @@ function aiPlanning.planning(natives, evolution_factor, tick, surface) local attackWaveMaxSize = natives.attackWaveMaxSize 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.formSquadThreshold = mMax((0.25 * evolution_factor), 0.10) natives.attackWaveSize = attackWaveMaxSize * (evolution_factor ^ 1.66667) diff --git a/libs/AIPredicates.lua b/libs/AIPredicates.lua index 6fde0b2..3897e47 100755 --- a/libs/AIPredicates.lua +++ b/libs/AIPredicates.lua @@ -15,7 +15,8 @@ local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL function aiPredicates.canAttack(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 function aiPredicates.isDark(surface) diff --git a/libs/BaseProcessor.lua b/libs/BaseProcessor.lua index 12b4bc1..4288a0b 100755 --- a/libs/BaseProcessor.lua +++ b/libs/BaseProcessor.lua @@ -19,7 +19,7 @@ local advanceTendrils = tendrilUtils.advanceTendrils -- module code -function baseProcessor.processBases(regionMap, surface, natives, tick) +function baseProcessor.processBases(map, surface, natives, tick) local baseIndex = natives.baseIndex local bases = natives.bases @@ -27,8 +27,8 @@ function baseProcessor.processBases(regionMap, surface, natives, tick) for index = baseIndex, endIndex do local base = bases[index] - buildOrder(regionMap, natives, base, surface, tick) - advanceTendrils(regionMap, base, surface, tick, natives) + buildOrder(map, natives, base, surface, tick) + advanceTendrils(map, base, surface, tick, natives) end if (endIndex == #bases) then diff --git a/libs/BaseUtils.lua b/libs/BaseUtils.lua index 512c5ac..4a2aaff 100755 --- a/libs/BaseUtils.lua +++ b/libs/BaseUtils.lua @@ -47,7 +47,7 @@ function baseUtils.findNearbyBase(natives, position) return foundBase end -function baseUtils.createBase(regionMap, natives, position, surface, tick) +function baseUtils.createBase(map, natives, position, surface, tick) local bases = natives.bases local distance = euclideanDistancePoints(position.x, position.y, 0, 0) local base = { @@ -65,10 +65,10 @@ function baseUtils.createBase(regionMap, natives, position, surface, tick) pattern = mRandom(MAGIC_MAXIMUM_BASE_NUMBER), level = mFloor(distance / 200) } - if not buildHive(regionMap, base, surface) then + if not buildHive(map, base, surface) then return nil end - -- buildTendril(regionMap, natives, base, surface, tick) + -- buildTendril(map, natives, base, surface, tick) bases[#bases+1] = base return base end diff --git a/libs/ChunkProcessor.lua b/libs/ChunkProcessor.lua index 33c2324..70c04bb 100755 --- a/libs/ChunkProcessor.lua +++ b/libs/ChunkProcessor.lua @@ -19,10 +19,10 @@ local chunkPassScan = chunkUtils.chunkPassScan -- module code -function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendingStack) - local processQueue = regionMap.processQueue +function chunkProcessor.processPendingChunks(natives, map, surface, pendingStack) + local processQueue = map.processQueue - local area = regionMap.area + local area = map.area local topOffset = area[1] local bottomOffset = area[2] @@ -41,30 +41,30 @@ function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendin bottomOffset[1] = x + 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 local chunkX = chunk.x - if regionMap[chunkX] == nil then - regionMap[chunkX] = {} + if map[chunkX] == nil then + map[chunkX] = {} end - regionMap[chunkX][chunk.y] = chunk + map[chunkX][chunk.y] = chunk processQueue[#processQueue+1] = chunk end end end -function chunkProcessor.processScanChunks(regionMap, surface) - local area = regionMap.area +function chunkProcessor.processScanChunks(map, surface) + local area = map.area local topOffset = area[1] local bottomOffset = area[2] local removals = {} - for chunk,_ in pairs(regionMap.chunkToPassScan) do + for chunk,_ in pairs(map.chunkToPassScan) do local x = chunk.x local y = chunk.y @@ -73,17 +73,17 @@ function chunkProcessor.processScanChunks(regionMap, surface) bottomOffset[1] = x + CHUNK_SIZE bottomOffset[2] = y + CHUNK_SIZE - chunk = chunkPassScan(chunk, surface, regionMap) + chunk = chunkPassScan(chunk, surface, map) if (chunk == SENTINEL_IMPASSABLE_CHUNK) then - regionMap[x][y] = nil + map[x][y] = nil removals[#removals+1] = chunk end end for i=#removals,1,-1 do - table.remove(regionMap.processQueue, i) + table.remove(map.processQueue, i) end return {} diff --git a/libs/ChunkUtils.lua b/libs/ChunkUtils.lua index 07070a0..fe38868 100755 --- a/libs/ChunkUtils.lua +++ b/libs/ChunkUtils.lua @@ -39,6 +39,8 @@ local RESOURCE_GENERATOR_INCREMENT = constants.RESOURCE_GENERATOR_INCREMENT local getChunkByUnalignedXY = mapUtils.getChunkByUnalignedXY +local tRemove = table.remove + local mFloor = math.floor -- module code @@ -76,12 +78,12 @@ local function fullScan(chunk, can_place_entity, canPlaceQuery) return passableNorthSouth, passableEastWest end -local function addEnemyStructureToChunk(regionMap, chunk, entity, base) +local function addEnemyStructureToChunk(map, chunk, entity, base) local lookup if (entity.type == "unit-spawner") then - lookup = regionMap.chunkToNests + lookup = map.chunkToNests elseif (entity.type == "turret") then - lookup = regionMap.chunkToWorms + lookup = map.chunkToWorms else return end @@ -93,22 +95,22 @@ local function addEnemyStructureToChunk(regionMap, chunk, entity, base) lookup[chunk] = lookup[chunk] + 1 -- if base then - -- local baseCollection = regionMap.chunkToBases[chunk] + -- local baseCollection = map.chunkToBases[chunk] -- if not baseCollection then -- baseCollection = {} - -- regionMap.chunkToBases[chunk] = baseCollection + -- map.chunkToBases[chunk] = baseCollection -- end -- baseCollection[base.id] = chunk -- end end -local function removeEnemyStructureFromChunk(regionMap, chunk, entity) +local function removeEnemyStructureFromChunk(map, chunk, entity) local lookup if (entity.type == "unit-spawner") then - lookup = regionMap.chunkToNests + lookup = map.chunkToNests elseif (entity.type == "turret") then - lookup = regionMap.chunkToWorms + lookup = map.chunkToWorms else return end @@ -137,7 +139,7 @@ local function removeEnemyStructureFromChunk(regionMap, chunk, entity) end end -local function getEntityOverlapChunks(regionMap, entity) +local function getEntityOverlapChunks(map, entity) local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box; local leftTopChunk = SENTINEL_IMPASSABLE_CHUNK @@ -179,15 +181,15 @@ local function getEntityOverlapChunks(regionMap, entity) local rightBottomChunkX = rightTopChunkX local rightBottomChunkY = leftBottomChunkY - leftTopChunk = getChunkByUnalignedXY(regionMap, leftTopChunkX, leftTopChunkY) + leftTopChunk = getChunkByUnalignedXY(map, leftTopChunkX, leftTopChunkY) if (leftTopChunkX ~= rightTopChunkX) then - rightTopChunk = getChunkByUnalignedXY(regionMap, rightTopChunkX, rightTopChunkY) + rightTopChunk = getChunkByUnalignedXY(map, rightTopChunkX, rightTopChunkY) end if (leftTopChunkY ~= leftBottomChunkY) then - leftBottomChunk = getChunkByUnalignedXY(regionMap, leftBottomChunkX, leftBottomChunkY) + leftBottomChunk = getChunkByUnalignedXY(map, leftBottomChunkX, leftBottomChunkY) end if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then - rightBottomChunk = getChunkByUnalignedXY(regionMap, rightBottomChunkX, rightBottomChunkY) + rightBottomChunk = getChunkByUnalignedXY(map, rightBottomChunkX, rightBottomChunkY) end end return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk @@ -195,9 +197,9 @@ end -- external functions -function chunkUtils.calculatePassScore(surface, regionMap) +function chunkUtils.calculatePassScore(surface, map) local count_tiles_filtered = surface.count_tiles_filtered - local filteredTilesQuery = regionMap.filteredTilesQuery + local filteredTilesQuery = map.filteredTilesQuery local passScore = 0 for i=1,#WATER_TILE_NAMES do @@ -208,11 +210,11 @@ function chunkUtils.calculatePassScore(surface, regionMap) return 1 - (passScore * 0.0009765625) end -function chunkUtils.scanChunkPaths(chunk, surface, regionMap) +function chunkUtils.scanChunkPaths(chunk, surface, map) local pass = CHUNK_IMPASSABLE local passableNorthSouth, passableEastWest = fullScan(chunk, surface.can_place_entity, - regionMap.canPlaceQuery) + map.canPlaceQuery) if passableEastWest and passableNorthSouth then pass = CHUNK_ALL_DIRECTIONS @@ -224,8 +226,8 @@ function chunkUtils.scanChunkPaths(chunk, surface, regionMap) return pass end -function chunkUtils.scorePlayerBuildings(surface, regionMap, natives) - local entities = surface.find_entities_filtered(regionMap.filteredEntitiesPlayerQuery) +function chunkUtils.scorePlayerBuildings(surface, map, natives) + local entities = surface.find_entities_filtered(map.filteredEntitiesPlayerQuery) local playerObjects = 0 local safeBuildings = natives.safeBuildings @@ -251,38 +253,38 @@ function chunkUtils.scorePlayerBuildings(surface, regionMap, natives) return playerObjects end -function chunkUtils.scoreEnemyBuildings(surface, regionMap) - local query = regionMap.filteredEntitiesEnemyTypeQuery +function chunkUtils.scoreEnemyBuildings(surface, map) + local query = map.filteredEntitiesEnemyTypeQuery query.type = "unit-spawner" - local nests = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery) + local nests = surface.count_entities_filtered(map.filteredEntitiesEnemyTypeQuery) query.type = "turret" - local worms = surface.count_entities_filtered(regionMap.filteredEntitiesEnemyTypeQuery) + local worms = surface.count_entities_filtered(map.filteredEntitiesEnemyTypeQuery) return nests, worms end -function chunkUtils.initialScan(chunk, natives, surface, regionMap) - local passScore = chunkUtils.calculatePassScore(surface, regionMap) +function chunkUtils.initialScan(chunk, natives, surface, map) + local passScore = chunkUtils.calculatePassScore(surface, map) 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 pass = CHUNK_ALL_DIRECTIONS end - chunkUtils.setNestCount(regionMap, chunk, nests) - chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects) - chunkUtils.setResourceGenerator(regionMap, chunk, resources) - chunkUtils.setWormCount(regionMap, chunk, worms) + chunkUtils.setNestCount(map, chunk, nests) + chunkUtils.setPlayerBaseGenerator(map, chunk, playerObjects) + chunkUtils.setResourceGenerator(map, chunk, resources) + chunkUtils.setWormCount(map, chunk, worms) chunk[PASSABLE] = pass chunk[PATH_RATING] = passScore @@ -293,15 +295,15 @@ function chunkUtils.initialScan(chunk, natives, surface, regionMap) return SENTINEL_IMPASSABLE_CHUNK end -function chunkUtils.chunkPassScan(chunk, surface, regionMap) - local passScore = chunkUtils.calculatePassScore(surface, regionMap) +function chunkUtils.chunkPassScan(chunk, surface, map) + local passScore = chunkUtils.calculatePassScore(surface, map) 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 pass = CHUNK_ALL_DIRECTIONS @@ -316,12 +318,12 @@ function chunkUtils.chunkPassScan(chunk, surface, regionMap) return SENTINEL_IMPASSABLE_CHUNK end -function chunkUtils.analyzeChunk(chunk, natives, surface, regionMap) - local playerObjects = chunkUtils.scorePlayerBuildings(surface, regionMap, natives) - chunkUtils.setPlayerBaseGenerator(regionMap, chunk, playerObjects) +function chunkUtils.analyzeChunk(chunk, natives, surface, map) + local playerObjects = chunkUtils.scorePlayerBuildings(surface, map, natives) + chunkUtils.setPlayerBaseGenerator(map, chunk, playerObjects) end --- function chunkUtils.remakeChunk(regionMap, chunk, surface, natives, tick, tempQuery) +-- function chunkUtils.remakeChunk(map, chunk, surface, natives, tick, tempQuery) -- tempQuery.force = "enemy" -- local enemies = surface.find_entities_filtered(tempQuery) @@ -340,94 +342,129 @@ end -- enemy.destroy() -- 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 -- -- foundBase.upgradePoints = foundBase.upgradePoints + points -- -- end -- end -function chunkUtils.getNestCount(regionMap, chunk) - return regionMap.chunkToNests[chunk] or 0 +function chunkUtils.getNestCount(map, chunk) + return map.chunkToNests[chunk] or 0 end -function chunkUtils.getWormCount(regionMap, chunk) - return regionMap.chunkToWorms[chunk] or 0 +function chunkUtils.getWormCount(map, chunk) + return map.chunkToWorms[chunk] or 0 end -function chunkUtils.setWormCount(regionMap, chunk, count) +function chunkUtils.setWormCount(map, chunk, count) if (count == 0) then - regionMap.chunkToWorms[chunk] = nil + map.chunkToWorms[chunk] = nil else - regionMap.chunkToWorms[chunk] = count + map.chunkToWorms[chunk] = count end end -function chunkUtils.setNestCount(regionMap, chunk, count) +function chunkUtils.setNestCount(map, chunk, count) if (count == 0) then - regionMap.chunkToNests[chunk] = nil + map.chunkToNests[chunk] = nil else - regionMap.chunkToNests[chunk] = count + map.chunkToNests[chunk] = count end end -function chunkUtils.getNestCount(regionMap, chunk) - return regionMap.chunkToNests[chunk] or 0 +function chunkUtils.getNestCount(map, chunk) + return map.chunkToNests[chunk] or 0 end -function chunkUtils.getWormCount(regionMap, chunk) - return regionMap.chunkToWorms[chunk] or 0 +function chunkUtils.getWormCount(map, chunk) + return map.chunkToWorms[chunk] or 0 end -function chunkUtils.getEnemyStructureCount(regionMap, chunk) - return (regionMap.chunkToNests[chunk] or 0) + (regionMap.chunkToWorms[chunk] or 0) +function chunkUtils.getEnemyStructureCount(map, chunk) + return (map.chunkToNests[chunk] or 0) + (map.chunkToWorms[chunk] or 0) end -function chunkUtils.getRetreatTick(regionMap, chunk) - return regionMap.chunkToRetreats[chunk] or 0 +function chunkUtils.getRetreatTick(map, chunk) + return map.chunkToRetreats[chunk] or 0 end -function chunkUtils.getRallyTick(regionMap, chunk) - return regionMap.chunkToRallys[chunk] or 0 +function chunkUtils.getRallyTick(map, chunk) + return map.chunkToRallys[chunk] or 0 end -function chunkUtils.setRallyTick(regionMap, chunk, tick) - regionMap.chunkToRallys[chunk] = tick +function chunkUtils.setRallyTick(map, chunk, tick) + map.chunkToRallys[chunk] = tick end -function chunkUtils.setRetreatTick(regionMap, chunk, tick) - regionMap.chunkToRetreats[chunk] = tick +function chunkUtils.setRetreatTick(map, chunk, tick) + map.chunkToRetreats[chunk] = tick end -function chunkUtils.setResourceGenerator(regionMap, chunk, resourceGenerator) +function chunkUtils.setResourceGenerator(map, chunk, resourceGenerator) if (resourceGenerator == 0) then - regionMap.chunkToResource[chunk] = nil + map.chunkToResource[chunk] = nil else - regionMap.chunkToResource[chunk] = resourceGenerator + map.chunkToResource[chunk] = resourceGenerator end end -function chunkUtils.getResourceGenerator(regionMap, chunk) - return regionMap.chunkToResource[chunk] or 0 +function chunkUtils.getResourceGenerator(map, chunk) + return map.chunkToResource[chunk] or 0 end -function chunkUtils.addResourceGenerator(regionMap, chunk, delta) - regionMap.chunkToResource[chunk] = (regionMap.chunkToResource[chunk] or 0) + delta +function chunkUtils.addResourceGenerator(map, chunk, delta) + map.chunkToResource[chunk] = (map.chunkToResource[chunk] or 0) + delta end -function chunkUtils.getPlayerBaseGenerator(regionMap, chunk) - return regionMap.chunkToPlayerBase[chunk] or 0 +function chunkUtils.getPlayerBaseGenerator(map, chunk) + return map.chunkToPlayerBase[chunk] or 0 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 - regionMap.chunkToPlayerBase[chunk] = nil + map.chunkToPlayerBase[chunk] = nil else - regionMap.chunkToPlayerBase[chunk] = playerGenerator + map.chunkToPlayerBase[chunk] = playerGenerator end end -function chunkUtils.addPlayerBaseGenerator(regionMap, chunk, playerGenerator) - regionMap.chunkToPlayerBase[chunk] = (regionMap.chunkToPlayerBase[chunk] or 0) + playerGenerator +function chunkUtils.addPlayerBaseGenerator(map, chunk, playerGenerator) + map.chunkToPlayerBase[chunk] = (map.chunkToPlayerBase[chunk] or 0) + playerGenerator end function chunkUtils.createChunk(topX, topY) @@ -456,70 +493,70 @@ function chunkUtils.colorChunk(x, y, tileType, surface) surface.set_tiles(tiles, false) end -function chunkUtils.entityForPassScan(regionMap, entity) - local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) +function chunkUtils.entityForPassScan(map, entity) + local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity) if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then - regionMap.chunkToPassScan[leftTop] = true + map.chunkToPassScan[leftTop] = true end if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then - regionMap.chunkToPassScan[rightTop] = true + map.chunkToPassScan[rightTop] = true end if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - regionMap.chunkToPassScan[leftBottom] = true + map.chunkToPassScan[leftBottom] = true end if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - regionMap.chunkToPassScan[rightBottom] = true + map.chunkToPassScan[rightBottom] = true end end -function chunkUtils.registerEnemyBaseStructure(regionMap, entity, base) +function chunkUtils.registerEnemyBaseStructure(map, entity, base) local entityType = entity.type 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 - addEnemyStructureToChunk(regionMap, leftTop, entity, base) + addEnemyStructureToChunk(map, leftTop, entity, base) end if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then - addEnemyStructureToChunk(regionMap, rightTop, entity, base) + addEnemyStructureToChunk(map, rightTop, entity, base) end if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - addEnemyStructureToChunk(regionMap, leftBottom, entity, base) + addEnemyStructureToChunk(map, leftBottom, entity, base) end if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - addEnemyStructureToChunk(regionMap, rightBottom, entity, base) + addEnemyStructureToChunk(map, rightBottom, entity, base) end end end -function chunkUtils.unregisterEnemyBaseStructure(regionMap, entity) +function chunkUtils.unregisterEnemyBaseStructure(map, entity) local entityType = entity.type 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 - removeEnemyStructureFromChunk(regionMap, leftTop, entity) + removeEnemyStructureFromChunk(map, leftTop, entity) end if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then - removeEnemyStructureFromChunk(regionMap, rightTop, entity) + removeEnemyStructureFromChunk(map, rightTop, entity) end if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - removeEnemyStructureFromChunk(regionMap, leftBottom, entity) + removeEnemyStructureFromChunk(map, leftBottom, entity) end if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - removeEnemyStructureFromChunk(regionMap, rightBottom, entity) + removeEnemyStructureFromChunk(map, rightBottom, entity) 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 entityValue if (BUILDING_PHEROMONES[entity.type] ~= nil) and (entity.force.name == "player") then entityValue = BUILDING_PHEROMONES[entity.type] - leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) + leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity) if not addObject then if creditNatives then natives.points = natives.points + entityValue @@ -527,38 +564,38 @@ function chunkUtils.addRemovePlayerEntity(regionMap, entity, natives, addObject, entityValue = -entityValue end if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addPlayerBaseGenerator(regionMap, leftTop, entityValue) + chunkUtils.addPlayerBaseGenerator(map, leftTop, entityValue) end if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addPlayerBaseGenerator(regionMap, rightTop, entityValue) + chunkUtils.addPlayerBaseGenerator(map, rightTop, entityValue) end if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addPlayerBaseGenerator(regionMap, leftBottom, entityValue) + chunkUtils.addPlayerBaseGenerator(map, leftBottom, entityValue) end if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addPlayerBaseGenerator(regionMap, rightBottom, entityValue) + chunkUtils.addPlayerBaseGenerator(map, rightBottom, entityValue) end end return entity end -function chunkUtils.unregisterResource(entity, regionMap) +function chunkUtils.unregisterResource(entity, map) if entity.prototype.infinite_resource then return end - local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(regionMap, entity) - + local leftTop, rightTop, leftBottom, rightBottom = getEntityOverlapChunks(map, entity) + if (leftTop ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addResourceGenerator(regionMap, leftTop, -RESOURCE_GENERATOR_INCREMENT) + chunkUtils.addResourceGenerator(map, leftTop, -RESOURCE_GENERATOR_INCREMENT) end if (rightTop ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addResourceGenerator(regionMap, rightTop, -RESOURCE_GENERATOR_INCREMENT) + chunkUtils.addResourceGenerator(map, rightTop, -RESOURCE_GENERATOR_INCREMENT) end if (leftBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addResourceGenerator(regionMap, leftBottom, -RESOURCE_GENERATOR_INCREMENT) + chunkUtils.addResourceGenerator(map, leftBottom, -RESOURCE_GENERATOR_INCREMENT) end if (rightBottom ~= SENTINEL_IMPASSABLE_CHUNK) then - chunkUtils.addResourceGenerator(regionMap, rightBottom, -RESOURCE_GENERATOR_INCREMENT) + chunkUtils.addResourceGenerator(map, rightBottom, -RESOURCE_GENERATOR_INCREMENT) end end diff --git a/libs/Constants.lua b/libs/Constants.lua index f0f0ade..beab368 100755 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -16,7 +16,7 @@ constants.VERSION_26 = 26 constants.VERSION_27 = 27 constants.VERSION_28 = 28 constants.VERSION_33 = 33 -constants.VERSION_37 = 37 +constants.VERSION_38 = 38 -- misc @@ -79,7 +79,7 @@ constants.AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_POINTS * 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_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["artillery-turret"] = 100 -constants.retreatFilter = {} -constants.retreatFilter[constants.SQUAD_RETREATING] = true +constants.RETREAT_FILTER = {} +constants.RETREAT_FILTER[constants.SQUAD_RETREATING] = true -- 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.CHUNK_TICK] = 0 constants.SENTINEL_IMPASSABLE_CHUNK[constants.PATH_RATING] = 0 -constants.SENTINEL_IMPASSABLE_CHUNK.x = 0 -constants.SENTINEL_IMPASSABLE_CHUNK.y = 0 +constants.SENTINEL_IMPASSABLE_CHUNK.x = -1 +constants.SENTINEL_IMPASSABLE_CHUNK.y = -1 return constants diff --git a/libs/MapProcessor.lua b/libs/MapProcessor.lua index 91554bd..fb04ea5 100755 --- a/libs/MapProcessor.lua +++ b/libs/MapProcessor.lua @@ -83,18 +83,18 @@ end In theory, this might be fine as smaller bases have less surface to attack and need to have pheromone dissipate at a faster rate. --]] -function mapProcessor.processMap(regionMap, surface, natives, tick) - local roll = regionMap.processRoll - local index = regionMap.processIndex +function mapProcessor.processMap(map, surface, natives, tick) + local roll = map.processRoll + local index = map.processIndex if (index == 1) then roll = mRandom() - regionMap.processRoll = roll + map.processRoll = roll end 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) for x=index,endIndex do local chunk = processQueue[x] @@ -102,21 +102,21 @@ function mapProcessor.processMap(regionMap, surface, natives, tick) if (chunk[CHUNK_TICK] ~= tick) then chunk[CHUNK_TICK] = tick - processPheromone(regionMap, chunk) + processPheromone(map, chunk) - if squads and (getNestCount(regionMap, chunk) > 0) then - formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST) - squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads) + if squads and (getNestCount(map, chunk) > 0) then + formSquads(map, surface, natives, chunk, AI_SQUAD_COST) + squads = (natives.points >= AI_SQUAD_COST) -- and (#natives.squads < natives.maxSquads) end - scents(regionMap, chunk) + scents(map, chunk) end end if (endIndex == #processQueue) then - regionMap.processIndex = 1 + map.processIndex = 1 else - regionMap.processIndex = endIndex + 1 + map.processIndex = endIndex + 1 end end @@ -126,7 +126,7 @@ end vs 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 -- randomize player order to ensure a single player isn't singled out local playerOrdering = nonRepeatingRandom(players) @@ -140,7 +140,7 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick) for i=1,#playerOrdering do local player = players[playerOrdering[i]] if validPlayer(player) then - local playerChunk = getChunkByPosition(regionMap, player.character.position) + local playerChunk = getChunkByPosition(map, player.character.position) if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then playerScent(playerChunk) @@ -150,34 +150,34 @@ function mapProcessor.processPlayers(players, regionMap, surface, natives, tick) for i=1,#playerOrdering do local player = players[playerOrdering[i]] if validPlayer(player) then - local playerChunk = getChunkByPosition(regionMap, player.character.position) + local playerChunk = getChunkByPosition(map, player.character.position) if (playerChunk ~= SENTINEL_IMPASSABLE_CHUNK) then local vengence = (allowingAttacks 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 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 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 - formSquads(regionMap, surface, natives, chunk, AI_SQUAD_COST) - squads = (natives.points >= AI_SQUAD_COST) and (#natives.squads < natives.maxSquads) + formSquads(map, surface, natives, chunk, AI_SQUAD_COST) + squads = (natives.points >= AI_SQUAD_COST) -- and (#natives.squads < natives.maxSquads) end if vengence then - formSquads(regionMap, surface, natives, chunk, AI_VENGENCE_SQUAD_COST) - vengence = (natives.points >= AI_VENGENCE_SQUAD_COST) and (#natives.squads < natives.maxSquads) + formSquads(map, surface, natives, chunk, AI_VENGENCE_SQUAD_COST) + vengence = (natives.points >= AI_VENGENCE_SQUAD_COST) -- and (#natives.squads < natives.maxSquads) end end - scents(regionMap, chunk) + scents(map, chunk) end end end @@ -189,14 +189,14 @@ end --[[ Passive scan to find entities that have been generated outside the factorio event system --]] -function mapProcessor.scanMap(regionMap, surface, natives) - local index = regionMap.scanIndex +function mapProcessor.scanMap(map, surface, natives) + local index = map.scanIndex - local unitCountQuery = regionMap.filteredEntitiesEnemyUnitQuery + local unitCountQuery = map.filteredEntitiesEnemyUnitQuery local offset = unitCountQuery.area[2] local chunkBox = unitCountQuery.area[1] - local processQueue = regionMap.processQueue + local processQueue = map.processQueue local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue) for x=index,endIndex do @@ -226,13 +226,13 @@ function mapProcessor.scanMap(regionMap, surface, natives) end end - analyzeChunk(chunk, natives, surface, regionMap) + analyzeChunk(chunk, natives, surface, map) end if (endIndex == #processQueue) then - regionMap.scanIndex = 1 + map.scanIndex = 1 else - regionMap.scanIndex = endIndex + 1 + map.scanIndex = endIndex + 1 end end diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index 62f85b2..28cd49f 100755 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -25,16 +25,16 @@ local mFloor = math.floor -- module code -function mapUtils.getChunkByXY(regionMap, x, y) - local chunkX = regionMap[x] +function mapUtils.getChunkByXY(map, x, y) + local chunkX = map[x] if chunkX then return chunkX[y] or SENTINEL_IMPASSABLE_CHUNK end return SENTINEL_IMPASSABLE_CHUNK end -function mapUtils.getChunkByPosition(regionMap, position) - local chunkX = regionMap[mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] +function mapUtils.getChunkByPosition(map, position) + local chunkX = map[mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] if chunkX then local chunkY = mFloor(position.y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK @@ -42,8 +42,8 @@ function mapUtils.getChunkByPosition(regionMap, position) return SENTINEL_IMPASSABLE_CHUNK end -function mapUtils.getChunkByUnalignedXY(regionMap, x, y) - local chunkX = regionMap[mFloor(x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] +function mapUtils.getChunkByUnalignedXY(map, x, y) + local chunkX = map[mFloor(x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE] if chunkX then local chunkY = mFloor(y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE return chunkX[chunkY] or SENTINEL_IMPASSABLE_CHUNK @@ -64,11 +64,11 @@ end /|\ 6 7 8 ]]-- -function mapUtils.getNeighborChunks(regionMap, x, y) - local neighbors = regionMap.neighbors +function mapUtils.getNeighborChunks(map, x, y) + local neighbors = map.neighbors local chunkYRow1 = y - CHUNK_SIZE local chunkYRow3 = y + CHUNK_SIZE - local xChunks = regionMap[x-CHUNK_SIZE] + local xChunks = map[x-CHUNK_SIZE] if xChunks then neighbors[1] = xChunks[chunkYRow1] 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 end - xChunks = regionMap[x+CHUNK_SIZE] + xChunks = map[x+CHUNK_SIZE] if xChunks then neighbors[3] = xChunks[chunkYRow1] 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 end - xChunks = regionMap[x] + xChunks = map[x] if xChunks then neighbors[2] = xChunks[chunkYRow1] or SENTINEL_IMPASSABLE_CHUNK neighbors[7] = xChunks[chunkYRow3] or SENTINEL_IMPASSABLE_CHUNK @@ -117,9 +117,9 @@ function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk) return canMove end -function mapUtils.getCardinalChunks(regionMap, x, y) - local neighbors = regionMap.cardinalNeighbors - local xChunks = regionMap[x] +function mapUtils.getCardinalChunks(map, x, y) + local neighbors = map.cardinalNeighbors + local xChunks = map[x] if xChunks then neighbors[1] = 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 end - xChunks = regionMap[x-CHUNK_SIZE] + xChunks = map[x-CHUNK_SIZE] if xChunks then neighbors[2] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK else neighbors[2] = SENTINEL_IMPASSABLE_CHUNK end - xChunks = regionMap[x+CHUNK_SIZE] + xChunks = map[x+CHUNK_SIZE] if xChunks then neighbors[3] = xChunks[y] or SENTINEL_IMPASSABLE_CHUNK else diff --git a/libs/MathUtils.lua b/libs/MathUtils.lua index 6f18bf4..4877be4 100755 --- a/libs/MathUtils.lua +++ b/libs/MathUtils.lua @@ -16,9 +16,8 @@ local mMax = math.max local mSqrt = math.sqrt local mLog10 = math.log10 -local mFloor = math.floor - local mRandom = math.random +local mFloor = math.floor -- module code @@ -33,41 +32,98 @@ function mathUtils.randomTickEvent(tick, low, high) return tick + nextTick 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 --]] -local function marsagliaPolarMethod(rg) +function mathUtils.gaussianRandom(mean, std_dev) + -- marsagliaPolarMethod local iid1 local iid2 local q repeat - if rg then - iid1 = 2 * rg() + -1 - iid2 = 2 * rg() + -1 - else - iid1 = 2 * mRandom() + -1 - iid2 = 2 * mRandom() + -1 - end + 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) - return iid1 * s + local v = iid1 * s + + return mean + (v * std_dev) end -function mathUtils.gaussianRandom(mean, std_dev, rg) - return mean + (marsagliaPolarMethod(rg) * std_dev) -end - -function mathUtils.gaussianRandomRange(mean, std_dev, min, max, rg) - local q +function mathUtils.gaussianRandomRange(mean, std_dev, min, max) + if (min == max) then + return min + end + local r repeat - q = mathUtils.gaussianRandom(mean, std_dev, rg) - until (q >= min) and (q <= max) - return q + 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 -function mathUtils.positionToChunkOffset(position) - return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125) +function mathUtils.gaussianRandomRG(mean, std_dev, rg) + -- marsagliaPolarMethod + 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 + + return mean + (v * std_dev) +end + +function mathUtils.gaussianRandomRangeRG(mean, std_dev, min, max, rg) + 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 function mathUtils.euclideanDistanceNamed(p1, p2) diff --git a/libs/MovementUtils.lua b/libs/MovementUtils.lua index a984528..427761b 100755 --- a/libs/MovementUtils.lua +++ b/libs/MovementUtils.lua @@ -97,7 +97,7 @@ function movementUtils.scoreNeighborsForAttack(chunk, neighborDirectionChunks, s end end - if scoreFunction(squad, chunk) > highestScore then + if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (scoreFunction(squad, chunk) > highestScore) then return SENTINEL_IMPASSABLE_CHUNK, -1 end @@ -133,14 +133,14 @@ end --[[ 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 highestScore = -MAGIC_MAXIMUM_NUMBER local highestDirection for x=1,8 do local neighborChunk = neighborDirectionChunks[x] 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 highestScore = score highestChunk = neighborChunk @@ -156,13 +156,13 @@ end --[[ 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 highestScore = -MAGIC_MAXIMUM_NUMBER local highestDirection for x=1,8 do 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) if (score > highestScore) then highestScore = score diff --git a/libs/NestUtils.lua b/libs/NestUtils.lua index 6dc58f6..71b7e83 100755 --- a/libs/NestUtils.lua +++ b/libs/NestUtils.lua @@ -31,21 +31,21 @@ local getChunkByPosition = mapUtils.getChunkByPosition -- 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 chunk = getChunkByPosition(regionMap, position) + local chunk = getChunkByPosition(map, position) local nest = nil if position and (chunk ~= SENTINEL_IMPASSABLE_CHUNK) and (chunk[NEST_COUNT] < 3) then local biterSpawner = {name=name, position=position} nest = surface.create_entity(biterSpawner) - registerEnemyBaseStructure(regionMap, nest, base) + registerEnemyBaseStructure(map, nest, base) end return nest end -function nestUtils.buildHive(regionMap, base, surface) +function nestUtils.buildHive(map, base, surface) 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 (#base.hives == 0) then base.x = hive.position.x @@ -57,7 +57,7 @@ function nestUtils.buildHive(regionMap, base, surface) return valid end -function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril) +function nestUtils.buildOutpost(map, natives, base, surface, tendril) local foundHive = false for _,_ in pairs(base.hives) do foundHive = true @@ -101,7 +101,7 @@ function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril) y = position.y + (distortion * math.sin(pos))} local biterSpawner = {name=thing, position=nestPosition} 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 end pos = pos + slice @@ -109,7 +109,7 @@ function nestUtils.buildOutpost(regionMap, natives, base, surface, tendril) end end -function nestUtils.buildOrder(regionMap, natives, base, surface) +function nestUtils.buildOrder(map, natives, base, surface) local foundHive = false for _,_ in pairs(base.hives) do foundHive = true @@ -149,7 +149,7 @@ function nestUtils.buildOrder(regionMap, natives, base, surface) y = base.y + (distortion * math.sin(pos))} local biterSpawner = {name=thing, position=nestPosition} 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 end pos = pos + slice diff --git a/libs/PheromoneUtils.lua b/libs/PheromoneUtils.lua index c25fb92..c05ecd3 100755 --- a/libs/PheromoneUtils.lua +++ b/libs/PheromoneUtils.lua @@ -36,10 +36,10 @@ local getResourceGenerator = chunkUtils.getResourceGenerator -- module code -function pheromoneUtils.scents(regionMap, chunk) - chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + getPlayerBaseGenerator(regionMap, chunk) - local resourceGenerator = getResourceGenerator(regionMap, chunk) - if (resourceGenerator > 0) and (getEnemyStructureCount(regionMap, chunk) == 0) then +function pheromoneUtils.scents(map, chunk) + chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + getPlayerBaseGenerator(map, chunk) + local resourceGenerator = getResourceGenerator(map, chunk) + if (resourceGenerator > 0) and (getEnemyStructureCount(map, chunk) == 0) then chunk[RESOURCE_PHEROMONE] = chunk[RESOURCE_PHEROMONE] + mMax(resourceGenerator * 100, 90) end end @@ -59,7 +59,7 @@ function pheromoneUtils.playerScent(playerChunk) playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT end -function pheromoneUtils.processPheromone(regionMap, chunk) +function pheromoneUtils.processPheromone(map, chunk) local chunkMovement = chunk[MOVEMENT_PHEROMONE] local chunkBase = chunk[BASE_PHEROMONE] @@ -67,7 +67,7 @@ function pheromoneUtils.processPheromone(regionMap, chunk) local chunkResource = chunk[RESOURCE_PHEROMONE] 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) + (tempNeighbors[2][MOVEMENT_PHEROMONE] - chunkMovement) + diff --git a/libs/SquadAttack.lua b/libs/SquadAttack.lua index 840c27a..6985229 100755 --- a/libs/SquadAttack.lua +++ b/libs/SquadAttack.lua @@ -19,11 +19,8 @@ local BASE_PHEROMONE = constants.BASE_PHEROMONE local SQUAD_RAIDING = constants.SQUAD_RAIDING local SQUAD_GUARDING = constants.SQUAD_GUARDING -local CHUNK_SIZE = constants.CHUNK_SIZE - 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_GATHERING = defines.group_state.gathering local DEFINES_GROUP_MOVING = defines.group_state.moving @@ -41,7 +38,9 @@ local mRandom = math.random local findMovementPosition = movementUtils.findMovementPosition 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 lookupMovementPenalty = movementUtils.lookupMovementPenalty local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold @@ -52,8 +51,6 @@ local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPosition local getPlayerBaseGenerator = chunkUtils.getPlayerBaseGenerator -local positionToChunkXY = mapUtils.positionToChunkXY - local scoreNeighborsForAttack = movementUtils.scoreNeighborsForAttack -- module code @@ -63,19 +60,11 @@ local function scoreAttackLocation(squad, neighborChunk) return damage - lookupMovementPenalty(squad, neighborChunk) end -function squadAttack.squadsAttack(regionMap, surface, natives) +function squadAttack.squadsAttack(map, surface, natives) local squads = natives.squads - local attackPosition - local attackCmd - - if (#squads > 0) then - attackPosition = regionMap.position - attackCmd = { type = DEFINES_COMMAND_ATTACK_AREA, - destination = attackPosition, - radius = CHUNK_SIZE, - distraction = DEFINES_DISTRACTION_BY_ENEMY } - end - + local attackPosition = map.position + local attackCmd = map.attackAreaCommand + for i=1,#squads do local squad = squads[i] local group = squad.group @@ -83,45 +72,50 @@ function squadAttack.squadsAttack(regionMap, surface, natives) local groupState = group.state 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 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 - local attackChunk, attackDirection = scoreNeighborsForAttack(chunk, - getNeighborChunks(regionMap, chunk.x, chunk.y), - scoreAttackLocation, - squad) + addSquadToChunk(map, chunk, squad) addMovementPenalty(natives, squad, chunk) - if group.valid and (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then - local playerBaseGenerator = getPlayerBaseGenerator(regionMap, 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 + elseif (attackChunk ~= SENTINEL_IMPASSABLE_CHUNK) then + addSquadToChunk(map, attackChunk, squad) + 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 - local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100) - squad.frenzy = moreFrenzy - - if squad.rabid or squad.frenzy then - attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING - else - 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 + local moreFrenzy = not squad.rabid and squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100) + squad.frenzy = moreFrenzy + + if squad.rabid or squad.frenzy then + attackCmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING + else + 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 end diff --git a/libs/SquadDefense.lua b/libs/SquadDefense.lua index c18596c..c9e05d6 100755 --- a/libs/SquadDefense.lua +++ b/libs/SquadDefense.lua @@ -10,26 +10,24 @@ local chunkUtils = require("ChunkUtils") -- 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 PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE -local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE - local SQUAD_RETREATING = constants.SQUAD_RETREATING -local RETREAT_FILTER = constants.RETREAT_FILTER - local INTERVAL_LOGIC = constants.INTERVAL_LOGIC local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK -- imported functions +local addSquadToChunk = chunkUtils.addSquadToChunk + local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk local getNeighborChunks = mapUtils.getNeighborChunks -local findNearBySquad = unitGroupUtils.findNearBySquad +local findNearbySquadFiltered = unitGroupUtils.findNearbySquadFiltered local addMovementPenalty = movementUtils.addMovementPenalty local createSquad = unitGroupUtils.createSquad local membersToSquad = unitGroupUtils.membersToSquad @@ -43,12 +41,12 @@ local getEnemyStructureCount = chunkUtils.getEnemyStructureCount -- module code -local function scoreRetreatLocation(regionMap, neighborChunk) - return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (getPlayerBaseGenerator(regionMap, neighborChunk) * 20)) +local function scoreRetreatLocation(map, neighborChunk) + return -(neighborChunk[BASE_PHEROMONE] + -neighborChunk[MOVEMENT_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * 100) + (getPlayerBaseGenerator(map, neighborChunk) * 20)) end -function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, natives, tick, radius, force) - if (tick - getRetreatTick(regionMap, chunk) > INTERVAL_LOGIC) and ((getEnemyStructureCount(regionMap, chunk) == 0) or force) then +function aiDefense.retreatUnits(chunk, position, squad, map, surface, natives, tick, radius, force) + if (tick - getRetreatTick(map, chunk) > INTERVAL_LOGIC) and ((getEnemyStructureCount(map, chunk) == 0) or force) then local performRetreat = false local enemiesToSquad = nil @@ -60,14 +58,14 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati end if performRetreat then - setRetreatTick(regionMap, chunk, tick) + setRetreatTick(map, chunk, tick) local exitPath,exitDirection = scoreNeighborsForRetreat(chunk, - getNeighborChunks(regionMap, chunk.x, chunk.y), + getNeighborChunks(map, chunk.x, chunk.y), scoreRetreatLocation, - regionMap) + map) if (exitPath ~= SENTINEL_IMPASSABLE_CHUNK) then local retreatPosition = findMovementPosition(surface, - positionFromDirectionAndChunk(exitDirection, position, regionMap.position, 0.98), + positionFromDirectionAndChunk(exitDirection, position, map.position, 0.98), false) 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 -- 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 newSquad = createSquad(retreatPosition, surface, natives) @@ -86,15 +84,18 @@ function aiDefense.retreatUnits(chunk, position, squad, regionMap, surface, nati end if newSquad then + local cmd = map.retreatCommand + cmd.group = newSquad.group if enemiesToSquad then - membersToSquad(newSquad, enemiesToSquad, force) + membersToSquad(cmd, enemiesToSquad, force) else - membersToSquad(newSquad, squad.group.members, true) + membersToSquad(cmd, squad.group.members, true) newSquad.penalties = squad.penalties if squad.rabid then newSquad.rabid = true end end + addSquadToChunk(map, chunk, newSquad) addMovementPenalty(natives, newSquad, chunk) end end diff --git a/libs/TendrilUtils.lua b/libs/TendrilUtils.lua index 6942a1b..265ba01 100755 --- a/libs/TendrilUtils.lua +++ b/libs/TendrilUtils.lua @@ -55,11 +55,11 @@ local function removeTendril(base, tendril) end end -local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives) +local function buildTendrilPath(map, tendril, surface, base, tick, natives) local tendrilUnit = tendril.unit if not tendrilUnit.valid then removeTendril(base, tendril) - tendrilUtils.buildTendril(regionMap, natives, base, surface, tick) + tendrilUtils.buildTendril(map, natives, base, surface, tick) return end if (tendril.cycles > 0) then @@ -67,17 +67,17 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives return end local tendrilPosition = tendrilUnit.position - local chunk = getChunkByPosition(regionMap, tendrilPosition) + local chunk = getChunkByPosition(map, tendrilPosition) if (chunk ~= SENTINEL_IMPASSABLE_CHUNK) then local tendrilPath,tendrilDirection = scoreNeighborsForResource(chunk, - getNeighborChunks(regionMap, chunk.x, chunk.y), + getNeighborChunks(map, chunk.x, chunk.y), scoreTendrilChunk, nil) if (tendrilDirection == -1) then if (chunk[RESOURCE_GENERATOR] ~= 0) then - buildOutpost(regionMap, natives, base, surface, tendril) + buildOutpost(map, natives, base, surface, 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) end return @@ -90,7 +90,7 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives 32, 2) if position then - buildNest(regionMap, base, surface, tendril.unit.position, "spitter-spawner") + buildNest(map, base, surface, tendril.unit.position, "spitter-spawner") -- tendril.cycles = 3 tendrilUnit.set_command({ type = defines.command.go_to_location, destination = position, @@ -101,9 +101,9 @@ local function buildTendrilPath(regionMap, tendril, surface, base, tick, natives end end -function tendrilUtils.advanceTendrils(regionMap, base, surface, tick, natives) +function tendrilUtils.advanceTendrils(map, base, surface, tick, natives) 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 @@ -128,11 +128,11 @@ function tendrilUtils.createTendril(base, surface) return tendril end -function tendrilUtils.buildTendril(regionMap, natives, base, surface, tick) - -- local chunk = getChunkByPosition(regionMap, base.x, base.y) +function tendrilUtils.buildTendril(map, natives, base, surface, tick) + -- local chunk = getChunkByPosition(map, base.x, base.y) -- if chunk then -- 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) if tendril then base.tendrils[#base.tendrils+1] = tendril diff --git a/libs/TunnelUtils.lua b/libs/TunnelUtils.lua index 7be089c..db80df0 100755 --- a/libs/TunnelUtils.lua +++ b/libs/TunnelUtils.lua @@ -1,14 +1,14 @@ local tunnelUtils = {} -function tunnelUtils.digTunnel(regionMap, surface, natives, startChunk, endChunk) +function tunnelUtils.digTunnel(map, surface, natives, startChunk, endChunk) end -function tunnelUtils.fillTunnel(regionMap, surface, natives, tilePositions) +function tunnelUtils.fillTunnel(map, surface, natives, tilePositions) local tunnels = natives.tunnels for i=1, #tunnels do end end -return tunnelUtils \ No newline at end of file +return tunnelUtils diff --git a/libs/UnitGroupUtils.lua b/libs/UnitGroupUtils.lua index 9c4fca2..186f9cb 100755 --- a/libs/UnitGroupUtils.lua +++ b/libs/UnitGroupUtils.lua @@ -2,23 +2,27 @@ local unitGroupUtils = {} -- imports +local mapUtils = require("MapUtils") local mathUtils = require("MathUtils") local constants = require("Constants") +local chunkUtils = require("ChunkUtils") -- constants +local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE + local SQUAD_QUEUE_SIZE = constants.SQUAD_QUEUE_SIZE 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_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_GUARDING = constants.SQUAD_GUARDING 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 AI_MAX_OVERFLOW_POINTS = constants.AI_MAX_OVERFLOW_POINTS @@ -34,29 +38,37 @@ local mLog = math.log10 local mMin = math.min +local getSquadsOnChunk = chunkUtils.getSquadsOnChunk +local removeSquadFromChunk = chunkUtils.removeSquadFromChunk + +local getNeighborChunks = mapUtils.getNeighborChunks + local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed -- module code -function unitGroupUtils.findNearBySquad(natives, position, distance, filter) - local squads = natives.squads +function unitGroupUtils.findNearbySquadFiltered(map, chunk, position) - if filter then - for i=1,#squads do - local squad = squads[i] - local unitGroup = squad.group - if unitGroup.valid and filter[squad.status] then - if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then - return squad - end + local squads = getSquadsOnChunk(map, chunk) + for s=1,#squads do + local squad = squads[s] + local unitGroup = squad.group + if unitGroup.valid and RETREAT_FILTER[squad.status] then + if (euclideanDistanceNamed(unitGroup.position, position) <= HALF_CHUNK_SIZE) then + return squad end end - else - for i=1,#squads do - local squad = squads[i] + end + + 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 - if unitGroup.valid then - if (euclideanDistanceNamed(unitGroup.position, position) <= distance) then + if unitGroup.valid and RETREAT_FILTER[squad.status] then + if (euclideanDistanceNamed(unitGroup.position, position) <= HALF_CHUNK_SIZE) then return squad end end @@ -64,27 +76,41 @@ function unitGroupUtils.findNearBySquad(natives, position, distance, filter) 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) local unitGroup = surface.create_unit_group({position=position}) - local squad = { group = unitGroup, - status = SQUAD_GUARDING, - penalties = {}, - rabid = false, - frenzy = false, - kamikaze = false, - frenzyPosition = {x = 0, - y = 0}, - cycles = 0 } + local squad = { + group = unitGroup, + status = SQUAD_GUARDING, + penalties = {}, + rabid = false, + frenzy = false, + kamikaze = false, + frenzyPosition = {x = 0, + y = 0}, + cycles = 0, + chunk = nil + } natives.squads[#natives.squads+1] = squad return squad end -function unitGroupUtils.membersToSquad(squad, members, overwriteGroup) +function unitGroupUtils.membersToSquad(cmd, members, overwriteGroup) if (members ~= nil) then - local cmd = { type = DEFINES_COMMAND_GROUP, - group = squad.group, - distraction = DEFINES_DISTRACTION_NONE } for i=1,#members do local member = members[i] 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) end -function unitGroupUtils.cleanSquads(natives) +function unitGroupUtils.cleanSquads(natives, map) local squads = natives.squads local squadCount = #squads @@ -130,10 +156,12 @@ function unitGroupUtils.cleanSquads(natives) if group.valid then local memberCount = #group.members if (memberCount == 0) then + removeSquadFromChunk(map, squad) group.destroy() elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then local members = group.members unitGroupUtils.recycleBiters(natives, members) + removeSquadFromChunk(map, squad) group.destroy() else local status = squad.status @@ -170,46 +198,82 @@ function unitGroupUtils.recycleBiters(natives, biters) end end -function unitGroupUtils.regroupSquads(natives) - local groupThreshold = AI_SQUAD_MERGE_THRESHOLD +local function mergeGroups(squads, squad, group, status, position, memberCount) + 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 squadCount = #squads local startIndex = natives.regroupIndex - + local maxSquadIndex = mMin(startIndex + SQUAD_QUEUE_SIZE, squadCount) for i=startIndex,maxSquadIndex do local squad = squads[i] local group = squad.group if group.valid and not isAttacking(group) then - local status = squad.status local memberCount = #group.members - if (memberCount < groupThreshold) then + if (memberCount < AI_SQUAD_MERGE_THRESHOLD) then + local status = squad.status local squadPosition = group.position - local mergedSquads = false - for x=i+1,squadCount do - local mergeSquad = squads[x] - local mergeGroup = mergeSquad.group - if mergeGroup.valid and (euclideanDistanceNamed(squadPosition, 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 - mergedSquads = true - mergeGroup.destroy() - end - memberCount = memberCount + mergeCount - if (memberCount > groupThreshold) then - break - end - end - end + local mergedSquads + local maxed + local chunk = squad.chunk + + if chunk then + mergedSquads, memberCount, maxed = mergeGroups(getSquadsOnChunk(map, chunk), + squad, + group, + status, + squadPosition, + memberCount) + + if not maxed then + local neighbors = getNeighborChunks(map, chunk.x, chunk.y) + + for x=1,#neighbors do + mergedSquads, memberCount, maxed = mergeGroups(getSquadsOnChunk(map, neighbors[x]), + squad, + group, + status, + squadPosition, + memberCount) + if maxed then + break + end + end + end + end + if mergedSquads and not squad.kamikaze then local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives) if (mRandom() < kamikazeThreshold) then diff --git a/make.rkt b/make.rkt index d41955e..6d16fed 100755 --- a/make.rkt +++ b/make.rkt @@ -34,6 +34,7 @@ (string->path "changelog.txt") (string->path "Upgrade.lua") (string->path "settings.lua") + (string->path "BuildSwarm.lua") (string->path "README.md") (string->path "NOTICE") (string->path "libs") @@ -73,6 +74,7 @@ (copyFile "changelog.txt" modFolder) (copyFile "Upgrade.lua" modFolder) (copyFile "tests.lua" modFolder) + (copyFile "BuildSwarm.lua" modFolder) (copyDirectory "libs" modFolder) (copyDirectory "locale" modFolder) (copyDirectory "sounds" modFolder) @@ -80,6 +82,6 @@ (copyDirectory "prototypes" modFolder))) (define (run) - ;;(copyFiles modFolder) - (makeZip modFolder) + (copyFiles modFolder) + ;;(makeZip modFolder) (system*/exit-code "/data/games/factorio/bin/x64/factorio"))) diff --git a/prototypes/enemies/BiterUtils.lua b/prototypes/enemies/BiterUtils.lua index b34cf86..28ed9c5 100755 --- a/prototypes/enemies/BiterUtils.lua +++ b/prototypes/enemies/BiterUtils.lua @@ -1,20 +1,23 @@ local biterFunctions = {} -function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances) - biterAttack.scale = biterAttributes.scale; - biterAttack.tint1 = biterAttributes.tint1; - biterAttack.tint2 = biterAttributes.tint2; +function biterFunctions.makeBiter(name, biterAttributes, biterAttack, biterResistances) + local resistances = {} + for k,v in pairs(biterResistances) do + v.type = k + resistances[#resistances+1] = v + end + return { type = "unit", - name = biterAttributes.name, + name = name, icon = "__base__/graphics/icons/small-biter.png", 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, order = "b-b-a", subgroup="enemies", healing_per_tick = biterAttributes.healing, - resistances = biterResistances, + resistances = resistances, collision_box = {{-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}, @@ -22,11 +25,11 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, {0.6 * biterAttributes.scale, 0}}, attack_parameters = biterAttack, - vision_distance = 30, + vision_distance = biterAttributes.vision or 30, movement_speed = biterAttributes.movement, - distance_per_frame = 0.1, - pollution_to_join_attack = 200, - distraction_cooldown = 300, + distance_per_frame = biterAttributes.distancePerFrame or 0.1, + pollution_to_join_attack = biterAttributes.pollutionToAttack or 200, + distraction_cooldown = biterAttributes.distractionCooldown or 300, corpse = biterAttributes.corpse, dying_explosion = biterAttributes.explosion, dying_sound = make_biter_dying_sounds(1.0), @@ -35,21 +38,24 @@ function biterFunctions.makeBiter(biterAttributes, biterAttack, biterResistances } end -function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistances) - -- biterAttack.scale = biterAttributes.scale; - -- biterAttack.tint1 = biterAttributes.tint1; - -- biterAttack.tint2 = biterAttributes.tint2; +function biterFunctions.makeSpitter(name, biterAttributes, biterAttack, biterResistances) + local resistances = {} + for k,v in pairs(biterResistances) do + v.type = k + resistances[#resistances+1] = v + end + return { type = "unit", - name = biterAttributes.name, + name = name, icon = "__base__/graphics/icons/small-spitter.png", 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, order = "b-b-a", subgroup="enemies", healing_per_tick = biterAttributes.healing, - resistances = biterResistances, + resistances = resistances, collision_box = {{-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}, @@ -57,11 +63,11 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc sticker_box = {{-0.6 * biterAttributes.scale, -0.8 * biterAttributes.scale}, {0.6 * biterAttributes.scale, 0}}, attack_parameters = biterAttack, - vision_distance = 30, + vision_distance = biterAttributes.vision or 30, movement_speed = biterAttributes.movement, - distance_per_frame = biterAttributes.distancePerFrame, - pollution_to_join_attack = 200, - distraction_cooldown = 300, + distance_per_frame = biterAttributes.distancePerFrame or 0.1, + pollution_to_join_attack = biterAttributes.pollutionToAttack or 200, + distraction_cooldown = biterAttributes.distractionCooldown or 300, corpse = biterAttributes.corpse, dying_explosion = biterAttributes.explosion, dying_sound = make_biter_dying_sounds(1.0), @@ -70,6 +76,128 @@ function biterFunctions.makeSpitter(biterAttributes, biterAttack, biterResistanc } 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) return { type = "projectile", range = 0.5, diff --git a/settings.lua b/settings.lua index 0760433..34a9c15 100755 --- a/settings.lua +++ b/settings.lua @@ -212,7 +212,29 @@ data:extend({ default_value = true, order = "k[modifier]-a[unit]", 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", diff --git a/tests.lua b/tests.lua index eca19be..72c2842 100755 --- a/tests.lua +++ b/tests.lua @@ -17,19 +17,19 @@ function tests.pheromoneLevels(size) size = size * constants.CHUNK_SIZE end print("------") - print(#global.regionMap.processQueue) + print(#global.map.processQueue) print(playerChunkX .. ", " .. playerChunkY) print("--") for y=playerChunkY-size, playerChunkY+size,32 do for x=playerChunkX-size, playerChunkX+size,32 do - if (global.regionMap[x] ~= nil) then - local chunk = global.regionMap[x][y] + if (global.map[x] ~= nil) then + local chunk = global.map[x][y] if (chunk ~= nil) then local str = "" for i=1,#chunk do str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i]) 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 print("=============") print(chunk.x, chunk.y, str) @@ -124,7 +124,7 @@ function tests.getOffsetChunk(x, y) local playerPosition = game.players[1].position local chunkX = math.floor(playerPosition.x * 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)) end @@ -163,7 +163,7 @@ end function tests.registeredNest(x) local entity = tests.createEnemy(x) - chunk.registerEnemyBaseStructure(global.regionMap, + chunk.registerEnemyBaseStructure(global.map, entity, nil) end @@ -272,7 +272,7 @@ end function tests.showMovementGrid() - local chunks = global.regionMap.processQueue + local chunks = global.map.processQueue for i=1,#chunks do local chunk = chunks[i] local color = "concrete" @@ -288,7 +288,7 @@ function tests.showMovementGrid() end function tests.colorResourcePoints() - local chunks = global.regionMap.processQueue + local chunks = global.map.processQueue for i=1,#chunks do local chunk = chunks[i] local color = "concrete" @@ -307,7 +307,7 @@ end function tests.exportAiState(onTick) local printState = function () - local chunks = global.regionMap.processQueue + local chunks = global.map.processQueue local s = "" for i=1,#chunks do local chunk = chunks[i] @@ -321,12 +321,12 @@ function tests.exportAiState(onTick) chunk[constants.PATH_RATING], chunk.x, chunk.y, - chunkUtils.getNestCount(global.regionMap, chunk), - chunkUtils.getWormCount(global.regionMap, chunk), - chunkUtils.getRallyTick(global.regionMap, chunk), - chunkUtils.getRetreatTick(global.regionMap, chunk), - chunkUtils.getResourceGenerator(global.regionMap, chunk), - chunkUtils.getPlayerBaseGenerator(global.regionMap, chunk)}, ",") .. "\n" + chunkUtils.getNestCount(global.map, chunk), + chunkUtils.getWormCount(global.map, chunk), + chunkUtils.getRallyTick(global.map, chunk), + chunkUtils.getRetreatTick(global.map, chunk), + chunkUtils.getResourceGenerator(global.map, chunk), + chunkUtils.getPlayerBaseGenerator(global.map, chunk)}, ",") .. "\n" end game.write_file("rampantState.txt", s, false) end @@ -357,7 +357,7 @@ end function tests.stepAdvanceTendrils() -- 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