mirror of
https://github.com/veden/Rampant.git
synced 2026-06-19 22:15:20 +02:00
cleanup + optimizations + indestructible
This commit is contained in:
+22
-6
@@ -56,9 +56,6 @@ function upgrade.attempt(natives, regionMap)
|
||||
if (global.version < constants.VERSION_11) then
|
||||
natives.state = constants.AI_STATE_AGGRESSIVE
|
||||
natives.temperament = 0
|
||||
-- needs to be on inner logic tick loop interval
|
||||
natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
|
||||
global.version = constants.VERSION_11
|
||||
end
|
||||
@@ -74,9 +71,6 @@ function upgrade.attempt(natives, regionMap)
|
||||
global.version = constants.VERSION_12
|
||||
end
|
||||
if (global.version < constants.VERSION_13) then
|
||||
-- switched over to tick event
|
||||
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
|
||||
|
||||
-- used to rate limit the number of rally cries during a period of time
|
||||
natives.rallyCries = MAX_RALLY_CRIES
|
||||
@@ -124,6 +118,28 @@ function upgrade.attempt(natives, regionMap)
|
||||
game.surfaces[1].print("Rampant - Version 0.15.9")
|
||||
global.version = constants.VERSION_21
|
||||
end
|
||||
if (global.version < constants.VERSION_22) then
|
||||
|
||||
-- been made redundant
|
||||
natives.rallyCries = nil
|
||||
|
||||
-- switched over to tick event
|
||||
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
|
||||
-- needs to be on inner logic tick loop interval
|
||||
natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
|
||||
game.map_settings.path_finder.short_request_ratio = 0.8
|
||||
game.map_settings.path_finder.short_cache_size = 25
|
||||
game.map_settings.path_finder.long_cache_size = 5
|
||||
game.map_settings.path_finder.min_steps_to_check_path_find_termination = 300
|
||||
|
||||
game.map_settings.max_failed_behavior_count = 6
|
||||
|
||||
game.surfaces[1].print("Rampant - Version 0.15.10")
|
||||
global.version = constants.VERSION_22
|
||||
end
|
||||
return starting ~= global.version
|
||||
end
|
||||
|
||||
|
||||
+22
-23
@@ -12,7 +12,6 @@ local aiDefense = require("libs/AIDefense")
|
||||
local aiAttack = require("libs/AIAttack")
|
||||
local aiBuilding = require("libs/AIBuilding")
|
||||
local aiPlanning = require("libs/AIPlanning")
|
||||
local mathUtils = require("libs/MathUtils")
|
||||
local interop = require("libs/Interop")
|
||||
local tests = require("tests")
|
||||
|
||||
@@ -21,8 +20,6 @@ local tests = require("tests")
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
||||
|
||||
local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
|
||||
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
|
||||
@@ -47,6 +44,7 @@ local rallyUnits = aiBuilding.rallyUnits
|
||||
local deathScent = pheromoneUtils.deathScent
|
||||
local victoryScent = pheromoneUtils.victoryScent
|
||||
|
||||
local cleanSquads = unitGroupUtils.cleanSquads
|
||||
local regroupSquads = unitGroupUtils.regroupSquads
|
||||
local convertUnitGroupToSquad = unitGroupUtils.convertUnitGroupToSquad
|
||||
|
||||
@@ -55,11 +53,9 @@ local squadBeginAttack = aiAttack.squadBeginAttack
|
||||
|
||||
local retreatUnits = aiDefense.retreatUnits
|
||||
|
||||
local regenerateEntity = entityUtils.regenerateEntity
|
||||
-- local regenerateEntity = entityUtils.regenerateEntity
|
||||
local addRemoveEntity = entityUtils.addRemoveEntity
|
||||
--local makeImmortalEntity = entityUtils.makeImmortalEntity
|
||||
|
||||
local roundToNearest = mathUtils.roundToNearest
|
||||
local makeImmortalEntity = entityUtils.makeImmortalEntity
|
||||
|
||||
-- local references to global
|
||||
|
||||
@@ -102,7 +98,7 @@ local function onModSettingsChange(event)
|
||||
natives.safeEntityName["big-electric-pole-2"] = poles
|
||||
natives.safeEntityName["big-electric-pole-3"] = poles
|
||||
natives.safeEntityName["big-electric-pole-4"] = poles
|
||||
|
||||
|
||||
natives.attackUsePlayer = settings.global["rampant-attackWaveGenerationUsePlayerProximity"].value
|
||||
natives.attackUsePollution = settings.global["rampant-attackWaveGenerationUsePollution"].value
|
||||
|
||||
@@ -147,17 +143,16 @@ local function onTick(event)
|
||||
local evolutionFactor = game.forces.enemy.evolution_factor
|
||||
local players = game.players
|
||||
|
||||
processPendingChunks(regionMap, surface, pendingChunks)
|
||||
processPendingChunks(natives, regionMap, surface, pendingChunks)
|
||||
scanMap(regionMap, surface, natives, evolutionFactor)
|
||||
|
||||
if (tick == regionMap.logicTick) then
|
||||
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC
|
||||
|
||||
natives.rallyCries = MAX_RALLY_CRIES
|
||||
|
||||
planning(natives, evolutionFactor, tick, surface)
|
||||
|
||||
regroupSquads(natives, evolutionFactor)
|
||||
|
||||
cleanSquads(natives, evolutionFactor)
|
||||
-- regroupSquads(natives, evolutionFactor)
|
||||
|
||||
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
|
||||
|
||||
@@ -170,7 +165,13 @@ local function onTick(event)
|
||||
end
|
||||
|
||||
local function onBuild(event)
|
||||
addRemoveEntity(regionMap, event.created_entity, natives, true, false)
|
||||
local entity = event.created_entity
|
||||
addRemoveEntity(regionMap, entity, natives, true, false)
|
||||
if natives.safeBuildings then
|
||||
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
|
||||
entity.destructible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onPickUp(event)
|
||||
@@ -185,13 +186,14 @@ local function onDeath(event)
|
||||
if (entity.type == "unit") then
|
||||
local entityPosition = entity.position
|
||||
local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
|
||||
|
||||
|
||||
if (deathChunk ~= nil) then
|
||||
-- drop death pheromone where unit died
|
||||
deathScent(deathChunk)
|
||||
|
||||
if ((event.force ~= nil) and (event.force.name == "player")) then
|
||||
local evolutionFactor = game.forces.enemy.evolution_factor
|
||||
local tick = event.tick
|
||||
|
||||
if (deathChunk[MOVEMENT_PHEROMONE] < -(evolutionFactor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
|
||||
retreatUnits(deathChunk,
|
||||
@@ -200,15 +202,15 @@ local function onDeath(event)
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
event.tick)
|
||||
tick)
|
||||
local rallyThreshold = BASE_RALLY_CHANCE + (evolutionFactor * BONUS_RALLY_CHANCE)
|
||||
if (natives.rallyCries >= 0) and (math.random() < rallyThreshold) then
|
||||
natives.rallyCries = natives.rallyCries - 1
|
||||
if (math.random() < rallyThreshold) then
|
||||
rallyUnits(deathChunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
evolutionFactor)
|
||||
evolutionFactor,
|
||||
tick)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -227,10 +229,7 @@ local function onDeath(event)
|
||||
victoryScent(victoryChunk, entity.type)
|
||||
end
|
||||
if creditNatives and natives.safeBuildings and (natives.safeEntities[entity.type] or natives.safeEntityName[entity.name]) then
|
||||
-- makeImmortalEntity(surface, entity)
|
||||
|
||||
-- hack version
|
||||
regenerateEntity(entity, entityPosition, surface)
|
||||
makeImmortalEntity(surface, entity)
|
||||
else
|
||||
addRemoveEntity(regionMap, entity, natives, false, creditNatives)
|
||||
end
|
||||
|
||||
+6
-5
@@ -62,8 +62,9 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
for i=1,#squads do
|
||||
local squad = squads[i]
|
||||
local group = squad.group
|
||||
if group.valid and (squad.status == SQUAD_RAIDING) then
|
||||
if (group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering) or ((group.state == defines.group_state.moving) and (squad.cycles == 0)) then
|
||||
if group.valid and (squad.status == SQUAD_RAIDING) then
|
||||
local groupState = group.state
|
||||
if (groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering) or ((groupState == defines.group_state.moving) and (squad.cycles == 0)) then
|
||||
local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y)
|
||||
if (chunk ~= nil) then
|
||||
local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk,
|
||||
@@ -75,9 +76,9 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
attackPosition,
|
||||
true)
|
||||
addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
|
||||
if (attackChunk ~= nil) then
|
||||
if attackChunk then
|
||||
if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
|
||||
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
|
||||
((groupState == defines.group_state.finished) or (groupState == defines.group_state.gathering)) then
|
||||
|
||||
positionFromDirectionAndChunk(attackDirection, squad.group.position, attackPosition)
|
||||
|
||||
@@ -100,7 +101,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
elseif not squad.frenzy and not squad.rabid and
|
||||
((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_target) or
|
||||
((groupState == defines.group_state.attacking_distraction) or (groupState == defines.group_state.attacking_target) or
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squad.group.position.x
|
||||
|
||||
+13
-9
@@ -23,7 +23,8 @@ local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
|
||||
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
||||
|
||||
local AI_STATE_NOCTURNAL = constants.AI_STATE_NOCTURNAL
|
||||
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
|
||||
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
@@ -123,14 +124,17 @@ end
|
||||
-- --]]
|
||||
-- end
|
||||
|
||||
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor)
|
||||
local cX = chunk.cX
|
||||
local cY = chunk.cY
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
|
||||
local rallyChunk = getChunkByIndex(regionMap, x, y)
|
||||
if (rallyChunk ~= nil) and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then
|
||||
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
|
||||
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor, tick)
|
||||
if (tick - chunk[RALLY_TRIGGERED] > INTERVAL_LOGIC) then
|
||||
chunk[RALLY_TRIGGERED] = tick
|
||||
local cX = chunk.cX
|
||||
local cY = chunk.cY
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
|
||||
local rallyChunk = getChunkByIndex(regionMap, x, y)
|
||||
if (rallyChunk ~= nil) and (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then
|
||||
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+5
-9
@@ -53,19 +53,15 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
|
||||
if (tick - chunk[RETREAT_TRIGGERED] > INTERVAL_LOGIC) and (chunk[ENEMY_BASE_GENERATOR] == 0) then
|
||||
local performRetreat = false
|
||||
local enemiesToSquad
|
||||
|
||||
|
||||
if (squad == nil) then
|
||||
enemiesToSquad = surface.find_enemy_units({x=chunk.pX,
|
||||
y=chunk.pY}, RETREAT_GRAB_RADIUS)
|
||||
if (#enemiesToSquad > 0) then
|
||||
performRetreat = true
|
||||
end
|
||||
performRetreat = #enemiesToSquad > 0
|
||||
elseif squad.group.valid and (squad.status ~= SQUAD_RETREATING) and not squad.kamikaze then
|
||||
if (#squad.group.members > 1) then
|
||||
performRetreat = true
|
||||
end
|
||||
performRetreat = #squad.group.members > 1
|
||||
end
|
||||
|
||||
|
||||
if performRetreat then
|
||||
chunk[RETREAT_TRIGGERED] = tick
|
||||
local retreatPosition = {x=0, y=0}
|
||||
@@ -77,7 +73,7 @@ function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives, tick)
|
||||
surface,
|
||||
retreatPosition,
|
||||
false)
|
||||
if (exitPath ~= nil) then
|
||||
if exitPath then
|
||||
retreatPosition.x = exitPath.pX + HALF_CHUNK_SIZE
|
||||
retreatPosition.y = exitPath.pY + HALF_CHUNK_SIZE
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ local scoreChunk = chunkUtils.scoreChunk
|
||||
|
||||
-- module code
|
||||
|
||||
function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
|
||||
function chunkProcessor.processPendingChunks(natives, regionMap, surface, pendingStack)
|
||||
local processQueue = regionMap.processQueue
|
||||
|
||||
for _=#pendingStack, 1, -1 do
|
||||
@@ -29,7 +29,7 @@ function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
|
||||
regionMap[chunkX][chunk.cY] = chunk
|
||||
|
||||
checkChunkPassability(chunk, surface)
|
||||
scoreChunk(chunk, surface)
|
||||
scoreChunk(natives, chunk, surface)
|
||||
processQueue[#processQueue+1] = chunk
|
||||
end
|
||||
end
|
||||
|
||||
+14
-4
@@ -25,6 +25,7 @@ local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GEN
|
||||
local CHUNK_TICK = constants.CHUNK_TICK
|
||||
|
||||
local RETREAT_TRIGGERED = constants.RETREAT_TRIGGERED
|
||||
local RALLY_TRIGGERED = constants.RALLY_TRIGGERED
|
||||
|
||||
-- module code
|
||||
|
||||
@@ -68,7 +69,7 @@ function chunkUtils.checkChunkPassability(chunk, surface)
|
||||
chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
|
||||
end
|
||||
|
||||
function chunkUtils.scoreChunk(chunk, surface)
|
||||
function chunkUtils.scoreChunk(natives, chunk, surface)
|
||||
local x = chunk.pX
|
||||
local y = chunk.pY
|
||||
|
||||
@@ -92,10 +93,18 @@ function chunkUtils.scoreChunk(chunk, surface)
|
||||
chunk[ENEMY_BASE_GENERATOR] = (entities * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT) + worms
|
||||
|
||||
entities = surface.find_entities_filtered(playerChunkQuery)
|
||||
|
||||
|
||||
local safeBuildings = natives.safeBuildings
|
||||
for i=1, #entities do
|
||||
local entityType = entities[i].type
|
||||
|
||||
local entity = entities[i]
|
||||
local entityType = entity.type
|
||||
|
||||
if safeBuildings then
|
||||
if natives.safeEntities[entityType] or natives.safeEntityName[entity.name] then
|
||||
entity.destructible = false
|
||||
end
|
||||
end
|
||||
|
||||
local entityScore = BUILDING_PHEROMONES[entityType]
|
||||
if (entityScore ~= nil) then
|
||||
playerObjects = playerObjects + entityScore
|
||||
@@ -121,6 +130,7 @@ function chunkUtils.createChunk(topX, topY)
|
||||
chunk[EAST_WEST_PASSABLE] = false
|
||||
chunk[CHUNK_TICK] = 0
|
||||
chunk[RETREAT_TRIGGERED] = 0
|
||||
chunk[RALLY_TRIGGERED] = 0
|
||||
return chunk
|
||||
end
|
||||
|
||||
|
||||
+4
-2
@@ -16,6 +16,7 @@ constants.VERSION_18 = 18
|
||||
constants.VERSION_19 = 19
|
||||
constants.VERSION_20 = 20
|
||||
constants.VERSION_21 = 21
|
||||
constants.VERSION_22 = 22
|
||||
|
||||
-- misc
|
||||
|
||||
@@ -29,8 +30,8 @@ constants.PROCESS_PLAYER_BOUND = 4
|
||||
constants.TICKS_A_SECOND = 60
|
||||
constants.TICKS_A_MINUTE = constants.TICKS_A_SECOND * 60
|
||||
|
||||
constants.INTERVAL_PROCESS = 20
|
||||
constants.INTERVAL_LOGIC = 40
|
||||
constants.INTERVAL_PROCESS = 19
|
||||
constants.INTERVAL_LOGIC = 38
|
||||
|
||||
-- ai
|
||||
|
||||
@@ -100,6 +101,7 @@ constants.EAST_WEST_PASSABLE = 7
|
||||
|
||||
constants.CHUNK_TICK = 8
|
||||
constants.RETREAT_TRIGGERED = 9
|
||||
constants.RALLY_TRIGGERED = 10
|
||||
|
||||
-- Squad status
|
||||
|
||||
|
||||
+3
-21
@@ -117,9 +117,8 @@ function entityUtils.addRemoveEntity(regionMap, entity, natives, addObject, cred
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function entityUtils.regenerateEntity(entity, entityPosition, surface)
|
||||
local repairPosition = entityPosition
|
||||
function entityUtils.makeImmortalEntity(surface, entity)
|
||||
local repairPosition = entity.position
|
||||
local repairName = entity.name
|
||||
local repairForce = entity.force
|
||||
local repairDirection = entity.direction
|
||||
@@ -150,25 +149,8 @@ function entityUtils.regenerateEntity(entity, entityPosition, surface)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- forces enemy to disperse
|
||||
local enemies = surface.find_enemy_units({repairPosition.x, repairPosition.y}, CHUNK_SIZE)
|
||||
for i=1, #enemies do
|
||||
enemies[i].set_command({type=defines.command.wander,
|
||||
distraction=defines.distraction.by_enemy})
|
||||
end
|
||||
end
|
||||
|
||||
function entityUtils.makeImmortalEntity(surface, entity)
|
||||
local repairPosition = entity.position
|
||||
local repairName = entity.name
|
||||
local repairForce = entity.force
|
||||
local repairDirection = entity.direction
|
||||
entity.destroy()
|
||||
local entityRepaired = surface.create_entity({position=repairPosition,
|
||||
name=repairName,
|
||||
direction=repairDirection,
|
||||
force=repairForce})
|
||||
entityRepaired.destructible = false
|
||||
newEntity.destructible = false
|
||||
end
|
||||
|
||||
return entityUtils
|
||||
|
||||
+47
-19
@@ -46,6 +46,8 @@ local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
|
||||
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
|
||||
|
||||
local canAttackNocturnal = nocturnalUtils.canAttack
|
||||
|
||||
local mMin = math.min
|
||||
@@ -182,34 +184,54 @@ end
|
||||
function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
|
||||
local index = regionMap.scanPointer
|
||||
|
||||
local chunkPosition = {x=0,y=0}
|
||||
local chunkBox = {chunkPosition,
|
||||
{x=chunkPosition.x + CHUNK_SIZE, y=chunkPosition.y + CHUNK_SIZE}}
|
||||
local playerQuery = {area = chunkBox,
|
||||
force = "player"}
|
||||
local spawnerQuery = {area = chunkBox,
|
||||
type = "unit-spawner",
|
||||
force = "enemy"}
|
||||
local wormsQuery = {area = chunkBox,
|
||||
type = "turret",
|
||||
force = "enemy"}
|
||||
local unitCountQuery = {area = chunkBox,
|
||||
type = "unit",
|
||||
force = "enemy"}
|
||||
|
||||
local processQueue = regionMap.processQueue
|
||||
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
|
||||
|
||||
for x=index,endIndex do
|
||||
local chunk = processQueue[x]
|
||||
|
||||
local entities = surface.find_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
force = "player"})
|
||||
|
||||
local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
type = "unit-spawner",
|
||||
force = "enemy"})
|
||||
chunkPosition.x = chunk.pX
|
||||
chunkPosition.y = chunk.pY
|
||||
|
||||
local worms = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
type = "turret",
|
||||
force = "enemy"})
|
||||
chunkBox[2].x = chunkPosition.x + CHUNK_SIZE
|
||||
chunkBox[2].y = chunkPosition.y + CHUNK_SIZE
|
||||
|
||||
local unitCount = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
type = "unit",
|
||||
force = "enemy"})
|
||||
local entities = surface.find_entities_filtered(playerQuery)
|
||||
|
||||
local spawners = surface.count_entities_filtered(spawnerQuery)
|
||||
|
||||
if (unitCount > 550) then
|
||||
local worms = surface.count_entities_filtered(wormsQuery)
|
||||
|
||||
local unitCount = surface.count_entities_filtered(unitCountQuery)
|
||||
|
||||
local closeBy = false
|
||||
if (unitCount > 300) then
|
||||
for i=1,#natives.squads do
|
||||
local squadGroup = natives.squads[i].group
|
||||
if (euclideanDistanceNamed(squadGroup.position, chunkPosition) < CHUNK_SIZE * 2) then
|
||||
closeBy = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (unitCount > 300) and not closeBy then
|
||||
local weight = AI_UNIT_REFUND * evolution_factor
|
||||
local units = surface.find_enemy_units({chunk.pX, chunk.pY},
|
||||
CHUNK_SIZE * 3)
|
||||
local units = surface.find_enemy_units(chunkPosition, CHUNK_SIZE * 3)
|
||||
|
||||
for i=1,#units do
|
||||
units[i].destroy()
|
||||
@@ -222,9 +244,15 @@ function mapProcessor.scanMap(regionMap, surface, natives, evolution_factor)
|
||||
end
|
||||
|
||||
local playerBaseGenerator = 0
|
||||
local safeBuildings = natives.safeBuildings
|
||||
for i=1,#entities do
|
||||
local entity = entities[i]
|
||||
local value = BUILDING_PHEROMONES[entity.type]
|
||||
if safeBuildings then
|
||||
if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then
|
||||
entity.destructible = false
|
||||
end
|
||||
end
|
||||
if (value ~= nil) then
|
||||
playerBaseGenerator = playerBaseGenerator + value
|
||||
end
|
||||
|
||||
+27
-40
@@ -45,36 +45,27 @@ end
|
||||
6 7 8
|
||||
]]--
|
||||
function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY)
|
||||
local neighbors = {1,2,3,4,5,6,7,8}
|
||||
local neighbors = {false,false,false,false,false,false,false,false}
|
||||
local chunkYRow1 = chunkY - 1
|
||||
local chunkYRow3 = chunkY + 1
|
||||
local xChunks = regionMap[chunkX-1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[1] = xChunks[chunkY-1]
|
||||
neighbors[1] = xChunks[chunkYRow1]
|
||||
neighbors[4] = xChunks[chunkY]
|
||||
neighbors[6] = xChunks[chunkY+1]
|
||||
else
|
||||
neighbors[1] = nil
|
||||
neighbors[4] = nil
|
||||
neighbors[6] = nil
|
||||
neighbors[6] = xChunks[chunkYRow3]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[3] = xChunks[chunkY-1]
|
||||
neighbors[3] = xChunks[chunkYRow1]
|
||||
neighbors[5] = xChunks[chunkY]
|
||||
neighbors[8] = xChunks[chunkY+1]
|
||||
else
|
||||
neighbors[3] = nil
|
||||
neighbors[5] = nil
|
||||
neighbors[8] = nil
|
||||
neighbors[8] = xChunks[chunkYRow3]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[2] = xChunks[chunkY-1]
|
||||
neighbors[7] = xChunks[chunkY+1]
|
||||
else
|
||||
neighbors[2] = nil
|
||||
neighbors[7] = nil
|
||||
neighbors[2] = xChunks[chunkYRow1]
|
||||
neighbors[7] = xChunks[chunkYRow3]
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
@@ -93,25 +84,28 @@ function mapUtils.canMoveChunkDirection(direction, startChunk, endChunk)
|
||||
end
|
||||
|
||||
function mapUtils.getNeighborChunksWithDirection(regionMap, chunkX, chunkY)
|
||||
local neighbors = {{d=1},{d=2},{d=3},{d=4},{d=5},{d=6},{d=7},{d=8}}
|
||||
local neighbors = {false,false,false,false,false,false,false,false}
|
||||
local chunkYRow1 = chunkY - 1
|
||||
local chunkYRow3 = chunkY + 1
|
||||
|
||||
local xChunks = regionMap[chunkX-1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[1].c = xChunks[chunkY-1]
|
||||
neighbors[4].c = xChunks[chunkY]
|
||||
neighbors[6].c = xChunks[chunkY+1]
|
||||
neighbors[1] = xChunks[chunkYRow1]
|
||||
neighbors[4] = xChunks[chunkY]
|
||||
neighbors[6] = xChunks[chunkYRow3]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[3].c = xChunks[chunkY-1]
|
||||
neighbors[5].c = xChunks[chunkY]
|
||||
neighbors[8].c = xChunks[chunkY+1]
|
||||
neighbors[3] = xChunks[chunkYRow1]
|
||||
neighbors[5] = xChunks[chunkY]
|
||||
neighbors[8] = xChunks[chunkYRow3]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[2].c = xChunks[chunkY-1]
|
||||
neighbors[7].c = xChunks[chunkY+1]
|
||||
neighbors[2] = xChunks[chunkYRow1]
|
||||
neighbors[7] = xChunks[chunkYRow3]
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
@@ -124,48 +118,41 @@ end
|
||||
4
|
||||
]]--
|
||||
function mapUtils.getCardinalChunksWithDirection(regionMap, chunkX, chunkY)
|
||||
local neighbors = {{d=1},{d=2},{d=3},{d=4}}
|
||||
local neighbors = {false, false, false, false}
|
||||
local xChunks = regionMap[chunkX]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[1].c = xChunks[chunkY-1]
|
||||
neighbors[4].c = xChunks[chunkY+1]
|
||||
neighbors[1] = xChunks[chunkY-1]
|
||||
neighbors[4] = xChunks[chunkY+1]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX-1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[2].c = xChunks[chunkY]
|
||||
neighbors[2] = xChunks[chunkY]
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[3].c = xChunks[chunkY]
|
||||
neighbors[3] = xChunks[chunkY]
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
|
||||
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY)
|
||||
local neighbors = {1,2,3,4}
|
||||
local neighbors = {false,false,false,false}
|
||||
local xChunks = regionMap[chunkX]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[1] = xChunks[chunkY-1]
|
||||
neighbors[4] = xChunks[chunkY+1]
|
||||
else
|
||||
neighbors[1] = nil
|
||||
neighbors[4] = nil
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX-1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[2] = xChunks[chunkY]
|
||||
else
|
||||
neighbors[2] = nil
|
||||
end
|
||||
|
||||
xChunks = regionMap[chunkX+1]
|
||||
if (xChunks ~= nil) then
|
||||
neighbors[3] = xChunks[chunkY]
|
||||
else
|
||||
neighbors[3] = nil
|
||||
end
|
||||
return neighbors
|
||||
end
|
||||
|
||||
+15
-7
@@ -10,21 +10,25 @@ local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
|
||||
|
||||
-- module code
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
local highestDirection
|
||||
for x=1,#neighborDirectionChunks do
|
||||
local neighborDirectionChunk = neighborDirectionChunks[x]
|
||||
local neighborChunk = neighborDirectionChunk.c
|
||||
if (neighborChunk ~= nil) and validFunction(x, chunk, neighborChunk) then
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborDirectionChunks[x]
|
||||
|
||||
if neighborChunk and validFunction(x, chunk, neighborChunk) then
|
||||
position.x = neighborChunk.pX
|
||||
position.y = neighborChunk.pY
|
||||
local score = scoreFunction(position, squad, neighborChunk, surface)
|
||||
if (score > highestScore) then
|
||||
highestScore = score
|
||||
highestChunk = neighborChunk
|
||||
highestDirection = neighborDirectionChunk.d
|
||||
highestDirection = x
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -36,12 +40,16 @@ function neighborUtils.scoreNeighborsWithDirection(chunk, neighborDirectionChunk
|
||||
return highestChunk, highestDirection
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Expects all neighbors adjacent to a chunk
|
||||
--]]
|
||||
function neighborUtils.scoreNeighbors(chunk, neighborChunks, validFunction, scoreFunction, squad, surface, position, scoreSelf)
|
||||
local highestChunk
|
||||
local highestScore = -MAGIC_MAXIMUM_NUMBER
|
||||
for x=1,#neighborChunks do
|
||||
for x=1,8 do
|
||||
local neighborChunk = neighborChunks[x]
|
||||
if (neighborChunk ~= nil) and validFunction(x, chunk, neighborChunk) then
|
||||
if neighborChunk and validFunction(x, chunk, neighborChunk) then
|
||||
position.x = neighborChunk.pX
|
||||
position.y = neighborChunk.pY
|
||||
local score = scoreFunction(position, squad, neighborChunk, surface)
|
||||
|
||||
+14
-9
@@ -64,21 +64,26 @@ function pheromoneUtils.processPheromone(regionMap, chunk)
|
||||
return
|
||||
end
|
||||
|
||||
local neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
|
||||
local chunkMovement = chunk[MOVEMENT_PHEROMONE]
|
||||
local chunkBase = chunk[BASE_PHEROMONE]
|
||||
local chunkPlayer = chunk[PLAYER_PHEROMONE]
|
||||
|
||||
local totalMovement = 0
|
||||
local totalBase = 0
|
||||
local totalPlayer = 0
|
||||
local neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
|
||||
for i=1,#neighbors do
|
||||
|
||||
for i=1,4 do
|
||||
local neighborChunk = neighbors[i]
|
||||
if (neighborChunk ~= nil) then
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunk[MOVEMENT_PHEROMONE])
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunk[BASE_PHEROMONE])
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunk[PLAYER_PHEROMONE])
|
||||
if neighborChunk then
|
||||
totalMovement = totalMovement + (neighborChunk[MOVEMENT_PHEROMONE] - chunkMovement)
|
||||
totalBase = totalBase + (neighborChunk[BASE_PHEROMONE] - chunkBase)
|
||||
totalPlayer = totalPlayer + (neighborChunk[PLAYER_PHEROMONE] - chunkPlayer)
|
||||
end
|
||||
end
|
||||
chunk[MOVEMENT_PHEROMONE] = (chunk[MOVEMENT_PHEROMONE] + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE
|
||||
chunk[BASE_PHEROMONE] = (chunk[BASE_PHEROMONE] + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE
|
||||
chunk[PLAYER_PHEROMONE] = (chunk[PLAYER_PHEROMONE] + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE
|
||||
chunk[MOVEMENT_PHEROMONE] = (chunkMovement + (0.125 * totalMovement)) * MOVEMENT_PHEROMONE_PERSISTANCE
|
||||
chunk[BASE_PHEROMONE] = (chunkBase + (0.25 * totalBase)) * BASE_PHEROMONE_PERSISTANCE
|
||||
chunk[PLAYER_PHEROMONE] = (chunkPlayer + (0.25 * totalPlayer)) * PLAYER_PHEROMONE_PERSISTANCE
|
||||
end
|
||||
|
||||
return pheromoneUtils
|
||||
|
||||
+75
-57
@@ -4,7 +4,6 @@ local unitGroupUtils = {}
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local constants = require("Constants")
|
||||
local nocturnalUtils = require("NocturnalUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@@ -22,12 +21,16 @@ local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT
|
||||
local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX
|
||||
local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX
|
||||
|
||||
local AI_MAX_POINTS = constants.AI_MAX_POINTS
|
||||
local AI_UNIT_REFUND = constants.AI_UNIT_REFUND
|
||||
|
||||
local AI_MAX_BITER_GROUP_SIZE = constants.AI_MAX_BITER_GROUP_SIZE
|
||||
|
||||
-- imported functions
|
||||
|
||||
local mLog = math.log10
|
||||
|
||||
|
||||
local tableRemove = table.remove
|
||||
local tableInsert = table.insert
|
||||
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
|
||||
@@ -142,40 +145,78 @@ local function isAttacking(group)
|
||||
return (state == GROUP_STATE_ATTACKING_TARGET) or (state == GROUP_STATE_ATTACKING_DISTRACTION)
|
||||
end
|
||||
|
||||
function unitGroupUtils.regroupSquads(natives, evolution_factor)
|
||||
function unitGroupUtils.cleanSquads(natives, evolution_factor)
|
||||
local squads = natives.squads
|
||||
local squadCount = #squads
|
||||
|
||||
for i=1,squadCount do
|
||||
local squad = squads[i]
|
||||
local group = squad.group
|
||||
if group.valid then
|
||||
local memberCount = #group.members
|
||||
if (memberCount == 0) or (memberCount > AI_MAX_BITER_GROUP_SIZE) then
|
||||
group.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
local weight = AI_UNIT_REFUND * evolution_factor
|
||||
|
||||
local groupThreshold = AI_MAX_BITER_GROUP_SIZE * 0.75
|
||||
local cleanSquads = {}
|
||||
|
||||
for i=1,squadCount do
|
||||
local squad = squads[i]
|
||||
local group = squad.group
|
||||
if group.valid then
|
||||
local status = squad.status
|
||||
local memberCount = #group.members
|
||||
local squadPosition = group.position
|
||||
|
||||
if not isAttacking(group) and (memberCount < groupThreshold) then
|
||||
if (memberCount == 0) then
|
||||
group.destroy()
|
||||
elseif (memberCount > AI_MAX_BITER_GROUP_SIZE) then
|
||||
local members = group.members
|
||||
for x=1,memberCount do
|
||||
members[x].destroy()
|
||||
natives.points = natives.points + weight
|
||||
end
|
||||
|
||||
if (natives.points > (AI_MAX_POINTS * 3)) then
|
||||
natives.points = (AI_MAX_POINTS * 3)
|
||||
end
|
||||
group.destroy()
|
||||
else
|
||||
local status = squad.status
|
||||
local squadPosition = group.position
|
||||
local cycles = squad.cycles
|
||||
if (status == SQUAD_RETREATING) and (cycles == 0) then
|
||||
squad.status = SQUAD_GUARDING
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squadPosition.x
|
||||
squad.frenzyPosition.y = squadPosition.y
|
||||
elseif (group.state == GROUP_STATE_FINISHED) then
|
||||
squad.status = SQUAD_GUARDING
|
||||
elseif (cycles > 0) then
|
||||
squad.cycles = cycles - 1
|
||||
end
|
||||
|
||||
cleanSquads[#cleanSquads+1] = squad
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
natives.squads = cleanSquads
|
||||
end
|
||||
|
||||
|
||||
function unitGroupUtils.regroupSquads(natives, evolution_factor)
|
||||
local groupThreshold = AI_MAX_BITER_GROUP_SIZE * 0.75
|
||||
|
||||
local squads = natives.squads
|
||||
local squadCount = #squads
|
||||
|
||||
for i=1,squadCount 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
|
||||
local squadPosition = group.position
|
||||
local mergedSquads = false
|
||||
for x=i+1,squadCount do
|
||||
local mergeSquad = squads[x]
|
||||
local mergeGroup = mergeSquad.group
|
||||
if mergeGroup.valid then
|
||||
local mergeMembers = mergeGroup.members
|
||||
local mergeCount = #mergeMembers
|
||||
if ((mergeCount + memberCount) < AI_MAX_BITER_GROUP_SIZE) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) and (mergeSquad.status == status) and not isAttacking(mergeGroup) then
|
||||
local mergeSquad = squads[x]
|
||||
local mergeGroup = mergeSquad.group
|
||||
if mergeGroup.valid and (mergeSquad.status == status) and not isAttacking(mergeGroup) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) 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
|
||||
@@ -184,45 +225,22 @@ function unitGroupUtils.regroupSquads(natives, evolution_factor)
|
||||
end
|
||||
mergedSquads = true
|
||||
mergeGroup.destroy()
|
||||
end
|
||||
memberCount = memberCount + mergeCount
|
||||
if (memberCount > groupThreshold) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
memberCount = memberCount + mergeCount
|
||||
if (memberCount > groupThreshold) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if mergedSquads and not squad.kamikaze then
|
||||
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor)
|
||||
if (math.random() < kamikazeThreshold) then
|
||||
squad.kamikaze = true
|
||||
end
|
||||
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, natives, evolution_factor)
|
||||
if (math.random() < kamikazeThreshold) then
|
||||
squad.kamikaze = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cycles = squad.cycles
|
||||
if (status == SQUAD_RETREATING) and (cycles == 0) then
|
||||
squad.status = SQUAD_GUARDING
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squadPosition.x
|
||||
squad.frenzyPosition.y = squadPosition.y
|
||||
elseif (group.state == GROUP_STATE_FINISHED) then
|
||||
squad.status = SQUAD_GUARDING
|
||||
elseif (cycles > 0) then
|
||||
squad.cycles = cycles - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cleanSquads = {}
|
||||
for i=1,squadCount do
|
||||
local squad = squads[i]
|
||||
if squad.group.valid then
|
||||
cleanSquads[#cleanSquads+1] = squad
|
||||
end
|
||||
end
|
||||
|
||||
natives.squads = cleanSquads
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return unitGroupUtils
|
||||
|
||||
@@ -47,7 +47,7 @@ rampant-attackWaveGenerationUsePlayerProximity=Include player pheromones amount
|
||||
rampant-attackWaveGenerationThresholdMax=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (starting threshold @ 0.0 evolution)
|
||||
rampant-attackWaveGenerationThresholdMin=The total score that a chunk must reach in order for an attack wave to spawn. DOES NOT affect vanilla biters waves. Scaling linearly with evolution factor (ending threshold @ 100.0 evolution)
|
||||
rampant-attackWaveMaxSize=If you wish to change how the attack wave scales with evolution you will need to modify the config.lua in the zip file.
|
||||
rampant-safeBuildings=This needs to be toggle for the safe building toggles to work. Understand this can cause weird behavior due to the fact that this is a stopgap until a bug is fixed in factorio.
|
||||
rampant-safeBuildings=This needs to be toggle for the safe building toggles to work. This will cause entities made safe to regenerate with the destructible flag set to false, which causes them to never be targeted or damaged again.
|
||||
rampant-safeBuildings-curvedRail=Make curved rails safe from biters
|
||||
rampant-safeBuildings-straightRail=Make straight rails safe from biters
|
||||
rampant-safeBuildings-bigElectricPole=Make big electric poles safe from biters
|
||||
|
||||
Reference in New Issue
Block a user