1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-26 03:20:07 +02:00

fixes for nil attack chunk, surface checks, and some work to help with desyncs

This commit is contained in:
veden 2016-08-24 16:30:45 -07:00
parent 75f041984c
commit 52a88abd92
12 changed files with 160 additions and 222 deletions

View File

@ -1,12 +1,16 @@
# THIS IS STILL AN ALPHA
# Rampant
Factorio Mod - Uses potential fields/pheromones to improve the enemy AI
# Forum Post
https://forums.factorio.com/viewtopic.php?f=94&t=31445
# Notes
There will be a slight pause the first time this is started up due to indexing all the chunks that have been generated.
Still working on MP
# Features
Tactical Retreats - these will take place when a unit group is in a chunk that has reached a death threshold
@ -18,5 +22,12 @@ Pathfinding - unit groups will use potential fields to perform only single step
# Planned Features
Tunneling biters
Tunneling Biters
Fire Biters
Suicide Biters
Base Expansion
# Version History
0.0.5 - fix for nil chunk in ai attack, checks for main surface
0.0.4 - initial release

View File

@ -12,12 +12,6 @@ local aiAttack = require("libs/AIAttack")
local aiBuilding = require("libs/AIBuilding")
local tests = require("tests")
-- global state references
local regionMap -- chunk based map
local pendingChunks -- pending chunks to be processed
local natives -- units that are being commanded
-- imported functions
local processPendingChunks = chunkProcessor.processPendingChunks
@ -50,17 +44,14 @@ function onInit()
global.pendingChunks = {}
global.natives = {}
regionMap = global.regionMap
pendingChunks = global.pendingChunks
regionMap.pQ = {{}} -- processing queue
regionMap.pI = 1 -- insertion location for chunk processing
regionMap.pP = 1 -- index for the chunk set to process
regionMap.pR = -1 -- current processing roll
natives = global.natives
natives.squads = {}
natives.scouts = {}
natives.tunnels = {}
natives.points = 0
global.regionMap.pQ = {{}} -- processing queue
global.regionMap.pI = 1 -- insertion location for chunk processing
global.regionMap.pP = 1 -- index for the chunk set to process
global.regionMap.pR = -1 -- current processing roll
global.natives.squads = {}
global.natives.scouts = {}
global.natives.tunnels = {}
global.natives.points = 0
-- game.forces.player.research_all_technologies()
@ -75,16 +66,16 @@ end
function onLoad()
-- print("load")
regionMap = global.regionMap
pendingChunks = global.pendingChunks
natives = global.natives
-- regionMap = global.regionMap
-- pendingChunks = global.pendingChunks
-- natives = global.natives
end
function onChunkGenerated(event)
-- queue generated chunk for delayed processing, queuing is required because some mods (RSO) mess with chunk as they
-- are generated, which messes up the scoring.
if (event.surface.index == 1) then
pendingChunks[#pendingChunks+1] = event
global.pendingChunks[#global.pendingChunks+1] = event
end
end
@ -97,59 +88,57 @@ function onTick(event)
-- game.players[1].cheat_mode = true
-- end
accumulatePoints(natives)
accumulatePoints(global.natives)
-- put down player pheromone for player hunters
playerScent(regionMap, game.players)
playerScent(global.regionMap, game.players)
regroupSquads(natives)
regroupSquads(global.natives)
scouting(regionMap, surface, natives)
-- scouting(regionMap, surface, natives)
squadAttackPlayer(regionMap, surface, natives, game.players)
squadAttackPlayer(global.natives, game.players)
squadBeginAttack(natives)
squadAttackLocation(regionMap, surface, natives)
-- print(natives.points)
squadBeginAttack(global.natives)
squadAttackLocation(global.regionMap, surface, global.natives)
end
processPendingChunks(regionMap, surface, natives, pendingChunks)
processPendingChunks(global.regionMap, surface, global.natives, global.pendingChunks)
processMap(regionMap, surface, natives, game.evolution_factor)
processMap(global.regionMap, surface, global.natives, game.evolution_factor)
end
end
function onBuild(event)
addRemoveObject(regionMap, event.created_entity, natives, true)
addRemoveObject(global.regionMap, event.created_entity, global.natives, true)
end
function onPickUp(event)
addRemoveObject(regionMap, event.entity, natives, false)
addRemoveObject(global.regionMap, event.entity, global.natives, false)
end
function onDeath(event)
local entity = event.entity
if (entity.force.name == "enemy") then
if (entity.type == "unit") then
local entityPosition = entity.position
-- drop death pheromone where unit died
local surface = game.surfaces[1]
deathScent(regionMap, surface, entityPosition.x, entityPosition.y)
if (event.force ~= nil) and (event.force.name == "player") then
local squad = convertUnitGroupToSquad(natives, entity.unit_group)
retreatUnits(entityPosition, squad, regionMap, surface, natives)
if (entity.surface.index == 1) then
if (entity.force.name == "enemy") then
if (entity.type == "unit") then
local entityPosition = entity.position
-- drop death pheromone where unit died
deathScent(global.regionMap, entityPosition.x, entityPosition.y)
if (event.force ~= nil) and (event.force.name == "player") then
local squad = convertUnitGroupToSquad(global.natives, entity.unit_group)
retreatUnits(entityPosition, squad, global.regionMap, game.surfaces[1], global.natives)
end
-- removeScout(entity, global.natives)
elseif (entity.type == "unit-spawner") then
addRemoveObject(global.regionMap, entity, global.natives, false)
end
removeScout(entity, natives)
elseif (entity.type == "unit-spawner") then
addRemoveObject(regionMap, entity, natives, false)
elseif (entity.force.name == "player") then
addRemoveObject(global.regionMap, entity, global.natives, false)
end
elseif (entity.force.name == "player") then
addRemoveObject(regionMap, entity, natives, false)
end
end

View File

@ -31,15 +31,6 @@ local CHUNK_SIZE = constants.CHUNK_SIZE
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
local GROUP_STATE_FINISHED = defines.group_state.finished
local GROUP_STATE_GATHERING = defines.group_state.gathering
local GROUP_STATE_MOVING = defines.group_state.moving
local COMMAND_ATTACK_AREA = defines.command.attack_area
local COMMAND_ATTACK = defines.command.attack
local DISTRACTION_BY_ANYTHING = defines.distraction.by_anything
-- imported functions
local getCardinalChunks = mapUtils.getCardinalChunks
@ -55,25 +46,19 @@ local mRandom = math.random
-- module code
function aiAttack.squadAttackLocation(regionMap, surface, natives)
local squads = natives.squads
for i=1, #squads do
local squad = squads[i]
for _,squad in ipairs(natives.squads) do
local group = squad.group
if group.valid and ((squad.status == SQUAD_RAIDING) or (squad.status == SQUAD_SUICIDE_RAID)) then
local groupState = group.state
if (groupState == GROUP_STATE_FINISHED) or (groupState == GROUP_STATE_GATHERING) or ((groupState == GROUP_STATE_MOVING) and (squad.cycles == 0)) then
if group.valid and ((squad.status == SQUAD_RAIDING) or (squad.status == SQUAD_SUICIDE_RAID)) 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
local chunk = positionToChunk(regionMap, group.position.x, group.position.y)
if (chunk ~= nil) then
addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
local attackLocationNeighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
local attackChunk
local attackScore = -MAGIC_MAXIMUM_NUMBER
local attackDirection
local attackPosition = {x=0, y=0}
-- print("------")
for x=1, #attackLocationNeighbors do
local neighborChunk = attackLocationNeighbors[x]
if (neighborChunk ~= nil) and canMove(x, chunk, neighborChunk) then
for x,neighborChunk in pairs(getCardinalChunks(regionMap, chunk.cX, chunk.cY)) do
if canMove(x, chunk, neighborChunk) then
attackPosition.x = neighborChunk.pX
attackPosition.y = neighborChunk.pY
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
@ -85,25 +70,19 @@ function aiAttack.squadAttackLocation(regionMap, surface, natives)
attackChunk = neighborChunk
attackDirection = x
end
-- print(x, score, damageScore, avoidScore, neighborChunk.cX, neighborChunk.cY)
end
end
if (attackChunk ~= nil) then
-- print("==")
-- print (attackDirection, chunk.cX, chunk.cY)
if ((attackChunk[PLAYER_BASE_GENERATOR] == 0) or (attackChunk[PLAYER_DEFENSE_GENERATOR] == 0)) or
((groupState == GROUP_STATE_FINISHED) or (groupState == GROUP_STATE_GATHERING)) then
-- print("attacking")
attackPosition = positionDirectionToChunkCornerCardinal(attackDirection, attackChunk)
squad.cX = attackChunk.cX
squad.cY = attackChunk.cY
squad.cycles = 2
squad.direction = attackDirection
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
group.set_command({type=COMMAND_ATTACK_AREA,
attackPosition = positionDirectionToChunkCornerCardinal(attackDirection, attackChunk)
squad.cycles = 2
group.set_command({type=defines.command.attack_area,
destination=attackPosition,
radius=HALF_CHUNK_SIZE,
distraction=DISTRACTION_BY_ANYTHING})
radius=16,
distraction=defines.distraction.by_anything})
group.start_moving()
end
end
@ -114,25 +93,19 @@ function aiAttack.squadAttackLocation(regionMap, surface, natives)
end
function aiAttack.squadAttackPlayer(regionMap, surface, natives, players)
local squads = natives.squads
for si=1, #squads do
local squad = squads[si]
function aiAttack.squadAttackPlayer(natives, players)
for _,squad in ipairs(natives.squads) do
local group = squad.group
if (group.valid) and (squad.status == SQUAD_GUARDING) then
local closestPlayer
local closestDistance = MAGIC_MAXIMUM_NUMBER
for pi=1, #players do
local player = players[pi]
if (player.connected) then
local playerCharacer = player.character
if (playerCharacer ~= nil) then
local distance = findDistance(playerCharacer.position, group.position)
if (distance < closestDistance) then
closestPlayer = playerCharacer
closestDistance = distance
end
for _,player in pairs(players) do
if player.connected and (player.character ~= nil) and (player.character.surface.index == 1) then
local playerCharacter = player.character
local distance = findDistance(playerCharacter.position, group.position)
if (distance < closestDistance) then
closestPlayer = playerCharacter
closestDistance = distance
end
end
end
@ -142,7 +115,7 @@ function aiAttack.squadAttackPlayer(regionMap, surface, natives, players)
squadType = SQUAD_SUICIDE_HUNT
end
squad.status = squadType
group.set_command({type=COMMAND_ATTACK,
group.set_command({type=defines.command.attack,
target=closestPlayer})
end
end
@ -150,11 +123,8 @@ function aiAttack.squadAttackPlayer(regionMap, surface, natives, players)
end
function aiAttack.squadBeginAttack(natives)
local squads = natives.squads
for i=1,#squads do
local squad = squads[i]
if (squad.status == SQUAD_GUARDING) and (mRandom() < 0.7) then
for _,squad in ipairs(natives.squads) do
if (squad.status == SQUAD_GUARDING) and (mRandom() < 0.70) then
if (mRandom() < 0.05) then
squad.status = SQUAD_SUICIDE_RAID
else

View File

@ -64,17 +64,20 @@ function aiBuilding.removeScout(entity, natives)
end
end
function aiBuilding.sendScouts(regionMap, surface, natives, chunk, neighbors, evolution_factor)
if (natives.points > AI_SCOUT_COST) then
local scouts = natives.scouts
if (#scouts < 5) and (mRandom() < 0.05) then -- TODO scaled with evolution factor
local enemy = surface.find_nearest_enemy({ position = {x = chunk.pX + HALF_CHUNK_SIZE,
y = chunk.pY + HALF_CHUNK_SIZE },
max_distance = HALF_CHUNK_SIZE})
function aiBuilding.sendScouts(surface, natives, chunk, evolution_factor)
if (natives.points > constants.AI_SCOUT_COST) then
-- local scouts = natives.scouts
if (#natives.scouts < 5) and (mRandom() < 0.05) then -- TODO scaled with evolution factor
local enemy = surface.find_nearest_enemy({ position = { x = chunk.pX + constants.HALF_CHUNK_SIZE,
y = chunk.pY + constants.HALF_CHUNK_SIZE },
max_distance = constants.HALF_CHUNK_SIZE})
if (enemy ~= nil) and (enemy.type == "unit") then
natives.points = natives.points - AI_SCOUT_COST
scouts[#scouts+1] = enemy
if (enemy ~= nil) and enemy.valid and (enemy.type == "unit") then
natives.points = natives.points - constants.AI_SCOUT_COST
natives.scouts[#natives.scouts+1] = enemy
-- enemy.set_command({type=defines.command.attack_area,
-- destination={0,0},
-- radius=32})
end
end
end
@ -85,10 +88,10 @@ function aiBuilding.scouting(regionMap, surface, natives)
end
function aiBuilding.formSquads(regionMap, surface, natives, chunk, neighbors, evolution_factor)
function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor)
if (natives.points > AI_SQUAD_COST) then
local score = chunk[PLAYER_BASE_PHEROMONE] + chunk[PLAYER_PHEROMONE] + chunk[PLAYER_DEFENSE_PHEROMONE] + surface.get_pollution({chunk.pX, chunk.pY})
if (score > 20) and (chunk[ENEMY_BASE_GENERATOR] ~= 0) and (#natives.squads < AI_MAX_SQUAD_COUNT * evolution_factor) and (mRandom() < 0.03) then
if (score > 20) and (chunk[ENEMY_BASE_GENERATOR] ~= 0) and (#natives.squads < AI_MAX_SQUAD_COUNT * evolution_factor) and (mRandom(0, 100) < 3) then
local squadNeighbors = getNeighborChunks(regionMap,
chunk.cX,
chunk.cY)

View File

@ -29,6 +29,8 @@ local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local RETREAT_FILTER = constants.RETREAT_FILTER
-- imported functions
local getChunkByPosition = mapUtils.getChunkByPosition
@ -39,15 +41,13 @@ local findNearBySquad = unitGroupUtils.findNearBySquad
local createSquad = unitGroupUtils.createSquad
local membersToSquad = unitGroupUtils.membersToSquad
-- premade tables
local retreatFilter = {[SQUAD_RETREATING] = true}
local mfloor = math.floor
-- module code
function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
local chunk = getChunkByPosition(regionMap, position.x, position.y)
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > (game.evolution_factor * RETREAT_DEATH_PHEROMONE_LEVEL)) then
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > mfloor(game.evolution_factor * RETREAT_DEATH_PHEROMONE_LEVEL)) then
local performRetreat = false
local enemiesToSquad
@ -63,15 +63,11 @@ function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
end
if performRetreat then
local retreatNeighbors = getCardinalChunks(regionMap,
chunk.cX,
chunk.cY)
local exitPath
local exitScore = -MAGIC_MAXIMUM_NUMBER
local exitDirection
local retreatPosition = {x=0, y=0}
for i=1, #retreatNeighbors do
local neighborChunk = retreatNeighbors[i]
for i, neighborChunk in pairs(getCardinalChunks(regionMap, chunk.cX, chunk.cY)) do
if (neighborChunk ~= nil) then
retreatPosition.x = neighborChunk.pX
retreatPosition.y = neighborChunk.pY
@ -88,11 +84,9 @@ function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
end
retreatPosition = positionDirectionToChunkCornerCardinal(exitDirection, exitPath)
-- 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
-- retreatPosition.x = exitPath.pX + constants.HALF_CHUNK_SIZE
-- retreatPosition.y = exitPath.pY + constants.HALF_CHUNK_SIZE
local newSquad = findNearBySquad(natives,
retreatPosition,
@ -107,11 +101,6 @@ function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
if (enemiesToSquad ~= nil) then
membersToSquad(newSquad, enemiesToSquad, false, DISTRACTION_NONE)
else
-- newSquad.penalties = squad.penalties
-- newSquad.lastCX = squad.cX
-- newSquad.lastCY = squad.cY
-- newSquad.lastDirection = squad.direction
-- newSquad.canTunnel = true
membersToSquad(newSquad, squad.group.members, true, DISTRACTION_NONE)
end
end

View File

@ -5,7 +5,7 @@ local constants = {}
constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest/highest score
constants.RETREAT_DEATH_PHEROMONE_LEVEL = 10000
constants.CHUNK_MAX_QUEUE_SIZE = 400
constants.CHUNK_MAX_QUEUE_SIZE = 350
-- ai
@ -107,6 +107,9 @@ constants.DEFENSE_PHEROMONES["turret"] = 3
-- constants.deathPheromones = {}
-- constants.deathPheromones[""]
constants.retreatFilter = {}
constants.retreatFilter[constants.SQUAD_RETREATING] = true
return constants
--[[ types

View File

@ -25,27 +25,27 @@ local mRandom = math.random
-- 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, evolution_factor)
local roll = regionMap.pR
local index = regionMap.pP
if (regionMap.pP == 1) then
regionMap.pR = mRandom()
roll = regionMap.pR
end
local roll = regionMap.pR
local chunkQueue = regionMap.pQ[regionMap.pP]
for x=1, #chunkQueue do
local chunk = chunkQueue[x]
local cardinalArray = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
local chunkQueue = regionMap.pQ[index]
for x,chunk in ipairs(chunkQueue) do
scents(regionMap, surface, natives, chunk, cardinalArray, evolution_factor)
scents(chunk)
if (0.05 <= roll) and (roll <= 0.10) then
sendScouts(regionMap, surface, natives, chunk, cardinalArray, evolution_factor)
sendScouts(surface, natives, chunk, evolution_factor)
end
if (0.11 <= roll) and (roll <= 0.25) then
formSquads(regionMap, surface, natives, chunk, cardinalArray, evolution_factor)
formSquads(regionMap, surface, natives, chunk, evolution_factor)
end
processPheromone(regionMap, surface, natives, chunk, cardinalArray, evolution_factor)
processPheromone(chunk, getCardinalChunks(regionMap, chunk.cX, chunk.cY))
end
regionMap.pP = regionMap.pP + 1

View File

@ -28,8 +28,7 @@ local mFloor = math.floor
-- module code
function mapUtils.getChunkByPosition(regionMap, x, y)
local cX = mFloor(x * 0.03125)
local chunkX = regionMap[cX]
local chunkX = regionMap[mFloor(x * 0.03125)]
if (chunkX ~= nil) then
return chunkX[mFloor(y * 0.03125)]
end

View File

@ -36,7 +36,7 @@ local mFloor = math.floor
-- module code
function pheromoneUtils.scents(regionMap, surface, natives, chunk, neighbors, evolution_factor)
function pheromoneUtils.scents(chunk)
local amount = chunk[PLAYER_DEFENSE_GENERATOR]
if (amount > 0) then
chunk[PLAYER_DEFENSE_PHEROMONE] = chunk[PLAYER_DEFENSE_PHEROMONE] + amount
@ -53,7 +53,7 @@ function pheromoneUtils.scents(regionMap, surface, natives, chunk, neighbors, ev
end
end
function pheromoneUtils.deathScent(regionMap, surface, x, y)
function pheromoneUtils.deathScent(regionMap, x, y)
local chunk = getChunkByPosition(regionMap, x, y)
if (chunk ~= nil) then
chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + DEATH_PHEROMONE_GENERATOR_AMOUNT
@ -61,19 +61,21 @@ function pheromoneUtils.deathScent(regionMap, surface, x, y)
end
function pheromoneUtils.playerScent(regionMap, players)
for i=1, #players do
local playerPosition = players[i].position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if (playerChunk ~= nil) then
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
for _,player in pairs(players) do
if player.connected and (player.character ~= nil) and (player.surface.index == 1) then
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if (playerChunk ~= nil) then
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
end
end
end
end
function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, neighbors, evolution_factor)
function pheromoneUtils.processPheromone(chunk, neighbors)
local diffusionAmount
local persistence
for x=1,6 do
local diffusionAmount
local persistence
if (x == DEATH_PHEROMONE) then
diffusionAmount = DEATH_PHEROMONE_DIFFUSION_AMOUNT
persistence = DEATH_PHEROMONE_PERSISTANCE
@ -82,16 +84,13 @@ function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, nei
persistence = STANDARD_PHEROMONE_PERSISTANCE
end
local totalDiffused = 0
for i=1,#neighbors do
local neighborChunk = neighbors[i]
if (neighborChunk ~= nil) then
local diffusedAmount = (chunk[x] * diffusionAmount)
totalDiffused = totalDiffused + diffusedAmount
neighborChunk[x] = neighborChunk[x] + diffusedAmount
end
local chunkValue = chunk[x]
for _,neighborChunk in pairs(neighbors) do
local diffusedAmount = chunkValue * diffusionAmount
totalDiffused = totalDiffused + diffusedAmount
neighborChunk[x] = neighborChunk[x] + diffusedAmount
end
chunk[x] = chunk[x] - totalDiffused
chunk[x] = chunk[x] * persistence
chunk[x] = (chunkValue - totalDiffused) * persistence
end
end

View File

@ -9,8 +9,6 @@ local constants = require("Constants")
local MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local GROUP_STATE_FINISHED = defines.group_state.finished
local SQUAD_RETREATING = constants.SQUAD_RETREATING
@ -26,8 +24,7 @@ local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
function unitGroupUtils.findNearBySquad(natives, position, distance, filter)
local squads = natives.squads
local i = 1
while (i <= #squads) do
for i=1, #squads do
local squad = squads[i]
local unitGroup = squad.group
if (unitGroup ~= nil) and unitGroup.valid and ((filter == nil) or (filter ~= nil and filter[squad.status])) then
@ -35,7 +32,6 @@ function unitGroupUtils.findNearBySquad(natives, position, distance, filter)
return squad
end
end
i = i + 1
end
end
@ -68,23 +64,17 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
local returnSquad
if (unitGroup ~= nil) then
local squads = natives.squads
local addUnitGroup = true
local i = 1
while (i <= #squads) and addUnitGroup do
for i=1, #squads do
local squad = squads[i]
if (squad.group == unitGroup) then
addUnitGroup = false
returnSquad = squad
return squad
end
i = i + 1
end
if addUnitGroup then
returnSquad = { group = unitGroup,
status = SQUAD_GUARDING,
penalties = {},
cycles = 0 }
squads[#squads+1] = returnSquad
end
returnSquad = { group = unitGroup,
status = SQUAD_GUARDING,
penalties = {},
cycles = 0 }
squads[#squads+1] = returnSquad
end
return returnSquad
@ -128,7 +118,7 @@ function unitGroupUtils.regroupSquads(natives)
for x=i+1, #squads do
local mergeSquad = squads[x]
local mergeGroup = mergeSquad.group
if mergeGroup.valid and (mergeSquad.status == squad.status) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < HALF_CHUNK_SIZE) then
if mergeGroup.valid and (mergeSquad.status == squad.status) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < 16) then
unitGroupUtils.membersToSquad(squad, mergeGroup.members, true)
mergeGroup.destroy()
end

View File

@ -27,32 +27,27 @@ local EAST_WEST = constants.EAST_WEST
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
local CHUNK_SIZE = constants.CHUNK_SIZE
local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
-- module code
function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, chunkSize, surface)
function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface)
local get_tile = surface.get_tile
local deadEnd = false
local x = iteratingCoordinate
while not deadEnd and (x < iteratingCoordinate + chunkSize) do
for x=iteratingCoordinate, iteratingCoordinate + 31 do
local tile
if (direction == NORTH_SOUTH) then
tile = get_tile(constantCoordinate, x)
else
tile = get_tile(x, constantCoordinate)
end
if (tile.collides_with("player-layer")) then
deadEnd = true
if tile.collides_with("player-layer") then
return true
-- else
-- surface.set_tiles({{name="sand-dark", position=tile.position}}, false)
end
x = x + 1
end
return deadEnd
return false
end
function chunkUtils.checkChunkPassability(chunk, surface, natives)
@ -61,19 +56,17 @@ function chunkUtils.checkChunkPassability(chunk, surface, natives)
local passableNorthSouth = false
local passableEastWest = false
local xi = x
while not passableNorthSouth and (xi < x + CHUNK_SIZE) do
if (not chunkUtils.checkForDeadendTiles(xi, y, NORTH_SOUTH, CHUNK_SIZE, surface)) then
for xi=x, x + 31 do
if (not chunkUtils.checkForDeadendTiles(xi, y, NORTH_SOUTH, surface)) then
passableNorthSouth = true
break
end
xi = xi + 1
end
local yi = y
while not passableEastWest and (yi < y + CHUNK_SIZE) do
if (not chunkUtils.checkForDeadendTiles(yi, x, EAST_WEST, CHUNK_SIZE, surface)) then
for yi=y, y + 31 do
if (not chunkUtils.checkForDeadendTiles(yi, x, EAST_WEST, surface)) then
passableEastWest = true
break
end
yi = yi + 1
end
-- if passableNorthSouth and passableEastWest then
-- chunkUtils.colorChunk(x, y, "grass", surface)
@ -85,16 +78,8 @@ function chunkUtils.checkChunkPassability(chunk, surface, natives)
-- chunkUtils.colorChunk(x, y, "concrete", surface)
-- end
if passableEastWest then
chunk[EAST_WEST_PASSABLE] = true
else
chunk[EAST_WEST_PASSABLE] = false
end
if passableNorthSouth then
chunk[NORTH_SOUTH_PASSABLE] = true
else
chunk[NORTH_SOUTH_PASSABLE] = false
end
chunk[EAST_WEST_PASSABLE] = passableEastWest
chunk[NORTH_SOUTH_PASSABLE] = passableNorthSouth
end
function chunkUtils.scoreChunk(chunk, surface, natives)
@ -102,7 +87,7 @@ function chunkUtils.scoreChunk(chunk, surface, natives)
local y = chunk.pY
local areaBoundingBox = {{x, y},
{x + CHUNK_SIZE, y + CHUNK_SIZE}}
{x + 32, y + 32}}
local enemyChunkQuery = {area=areaBoundingBox,
type="unit-spawner",
force="enemy"}
@ -154,8 +139,8 @@ end
function chunkUtils.colorChunk(x, y, tileType, surface)
local tiles = {}
for xi=x+5, x + CHUNK_SIZE-5 do
for yi=y+5, y + CHUNK_SIZE-5 do
for xi=x+5, x + 27 do
for yi=y+5, y + 27 do
tiles[#tiles+1] = {name=tileType, position={xi, yi}}
end
end

View File

@ -3,7 +3,7 @@ local tests = {}
local constants = require("libs/Constants")
function tests.test1()
local player = game.players[1]
local player = game.player.character
local playerChunkX = math.floor(player.position.x / 32)
local playerChunkY = math.floor(player.position.y / 32)
print("------")
@ -69,7 +69,7 @@ function tests.test4()
end
function tests.test5()
print(global.natives.points)
print(global.natives.points, game.tick)
end
function tests.test6()