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

added logic for built, mined, and destroyed entity pheromone generators

This commit is contained in:
veden
2016-08-17 22:55:08 -07:00
parent a1401d5285
commit e410b9e2f5
13 changed files with 801 additions and 319 deletions

View File

@@ -5,7 +5,8 @@ local chunkProcessor = require("libs/ChunkProcessor")
local mapProcessor = require("libs/MapProcessor") local mapProcessor = require("libs/MapProcessor")
local constants = require("libs/Constants") local constants = require("libs/Constants")
local pheromoneUtils = require("libs/PheromoneUtils") local pheromoneUtils = require("libs/PheromoneUtils")
local ai = require("libs/AI") local aiDefense = require("libs/AIDefense")
local aiAttack = require("libs/AIAttack")
local tests = require("Tests") local tests = require("Tests")
local mapRoutine --coroutine holding state of in progress processing local mapRoutine --coroutine holding state of in progress processing
@@ -30,15 +31,9 @@ function onInit()
pendingChunks = global.pendingChunks pendingChunks = global.pendingChunks
natives = global.natives natives = global.natives
natives.squads = {} natives.squads = {}
natives.troopToSquad = {}
natives.scouts = {} natives.scouts = {}
-- game.map_settings.enemy_expansion.enabled = false
-- turn off enemy ai
-- game.surfaces[1].peaceful_mode = true
-- remove enemies that aren't off
-- game.forces.enemy.kill_all_units()
-- queue all current chunks that wont be generated during play -- queue all current chunks that wont be generated during play
surface = game.surfaces[1] surface = game.surfaces[1]
for chunk in surface.get_chunks() do for chunk in surface.get_chunks() do
@@ -82,9 +77,12 @@ function onTick(event)
pheromoneUtils.playerScent(regionMap, game.players) pheromoneUtils.playerScent(regionMap, game.players)
unitGroupUtils.regroupSquads(natives) unitGroupUtils.regroupSquads(natives)
-- ai.scouting(regionMap, surface, natives) -- ai.scouting(regionMap, surface, natives)
ai.squadAttackPlayer(regionMap, surface, natives, game.players) aiAttack.squadAttackPlayer(regionMap, surface, natives, game.players)
aiAttack.squadBeginAttack(natives)
aiAttack.squadAttackLocation(regionMap, surface, natives)
if (mapRoutine ~= nil) and (coroutine.status(mapRoutine) ~= "dead") then if (mapRoutine ~= nil) and (coroutine.status(mapRoutine) ~= "dead") then
working, errorMsg = coroutine.resume(mapRoutine) working, errorMsg = coroutine.resume(mapRoutine)
@@ -98,26 +96,37 @@ function onTick(event)
end end
end end
function onBuild(event)
mapUtils.addRemoveObject(regionMap, event.created_entity, true)
end
function onPickUp(event)
mapUtils.addRemoveObject(regionMap, event.entity, false)
end
function onDeath(event) function onDeath(event)
local entity = event.entity local entity = event.entity
if (entity.force.name == "enemy") then if (entity.force.name == "enemy") then
if (entity.type == "unit") then if (entity.type == "unit") then
local entityPosition = entity.position local entityPosition = entity.position
-- drop death pheromone where unit died -- drop death pheromone where unit died
pheromoneUtils.deathScent(regionMap, pheromoneUtils.deathScent(regionMap,
surface,
entityPosition.x, entityPosition.x,
entityPosition.y, entityPosition.y,
200) constants.DEATH_PHEROMONE_GENERATOR_AMOUNT)
local squad = unitGroupUtils.convertUnitGroupToSquad(natives, entity.unit_group) if (event.force ~= nil) and (event.force.name == "player") then
local squad = unitGroupUtils.convertUnitGroupToSquad(natives, entity.unit_group)
ai.retreatUnits(entityPosition, squad, regionMap, surface, natives) aiDefense.retreatUnits(entityPosition, squad, regionMap, surface, natives)
end
-- ai.removeScout(regionMap, surface, entity, natives) -- ai.removeScout(regionMap, surface, entity, natives)
elseif (entity.type == "unit-spawner") then elseif (entity.type == "unit-spawner") then
local entityPosition = entity.position mapUtils.addRemoveObject(regionMap, entity, false)
mapUtils.removeUnitSpawner(regionMap, entityPosition.x, entityPosition.y)
end end
elseif (entity.force.name == "player") then
mapUtils.addRemoveObject(regionMap, entity, false)
end end
end end
@@ -128,18 +137,18 @@ function onInitialTick(event)
surface = game.surfaces[1] surface = game.surfaces[1]
end end
game.forces.player.research_all_technologies() -- game.forces.player.research_all_technologies()
game.players[1].cheat_mode = true -- game.players[1].cheat_mode = true
-- turn off enemy ai -- turn off enemy ai
-- game.surfaces[1].peaceful_mode = true -- game.surfaces[1].peaceful_mode = true
-- game.surfaces[1].peaceful_mode = false -- game.surfaces[1].peaceful_mode = false
-- remove enemies that aren't off -- remove enemies that aren't off
-- game.forces.enemy.kill_all_units() -- game.forces.enemy.kill_all_units()
-- turn off base expansion -- turn off base expansion
-- game.forces.enemy.ai_controllable = false game.forces.enemy.ai_controllable = false
game.map_settings.enemy_expansion.enabled = false -- game.map_settings.enemy_expansion.enabled = false
-- add processing handler into generated chunk event loop -- add processing handler into generated chunk event loop
chunkProcessor.install(chunkUtils.checkChunkPassability) chunkProcessor.install(chunkUtils.checkChunkPassability)
@@ -147,8 +156,10 @@ function onInitialTick(event)
-- add processing handler into chunk map processing -- add processing handler into chunk map processing
mapProcessor.install(pheromoneUtils.enemyBaseScent) mapProcessor.install(pheromoneUtils.enemyBaseScent)
mapProcessor.install(ai.sendScouts) mapProcessor.install(pheromoneUtils.playerDefenseScent)
mapProcessor.install(pheromoneUtils.playerBaseScent)
mapProcessor.install(pheromoneUtils.processPheromone) mapProcessor.install(pheromoneUtils.processPheromone)
-- mapProcessor.install(ai.sendScouts)
-- used for debugging -- used for debugging
tests.initTester() tests.initTester()
@@ -162,11 +173,19 @@ end
script.on_init(onInit) script.on_init(onInit)
script.on_load(onLoad) script.on_load(onLoad)
script.on_event({defines.events.on_preplayer_mined_item,
defines.events.on_robot_pre_mined},
onPickUp)
script.on_event({defines.events.on_built_entity,
defines.events.on_robot_built_entity},
onBuild)
script.on_event(defines.events.on_entity_died, onDeath) script.on_event(defines.events.on_entity_died, onDeath)
script.on_event(defines.events.on_tick, onInitialTick) script.on_event(defines.events.on_tick, onInitialTick)
script.on_event(defines.events.on_chunk_generated, onChunkGenerated) script.on_event(defines.events.on_chunk_generated, onChunkGenerated)
remote.add_interface("rampant", { remote.add_interface("rampant", {
test1 = tests.test1, test1 = tests.test1,
test2 = tests.test2 test2 = tests.test2,
test3 = tests.test3
}) })

View File

@@ -1,148 +0,0 @@
local ai = {}
local retreatNeighbors = {1,2,3,4,5,6,7,8} -- used to minimize garbage generation
local retreatPosition = {x=0, y=0} -- used to minimize garbage generation
local constants = require("Constants")
local mapUtils = require("MapUtils")
local utils = require("Utils")
local unitGroupUtils = require("UnitGroupUtils")
function ai.squadAttackPlayer(regionMap, surface, natives, players)
local SQUAD_RETREATING = constants.SQUAD_RETREATING
local SQUAD_ATTACKING = constants.SQUAD_ATTACKING
local SQUAD_GUARDING = constants.SQUAD_GUARDING
local SQUAD_SUICIDE = constants.SQUAD_SUICIDE
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local findDistance = utils.euclideanDistanceNamed
local squads = natives.squads
for si=1, #squads do
local squad = squads[si]
if (squad.group.valid) and (squad.status == SQUAD_GUARDING) then
local closestPlayer
local closestDistance = MAGIC_MAXIMUM_NUMBER
for pi=1, #players do
local playerCharacer = players[pi].character
local distance = findDistance(playerCharacer.position, squad.group.position)
if (distance < closestDistance) then
closestPlayer = playerCharacer
closestDistance = distance
end
end
if (closestDistance < 60) then
local squadType = SQUAD_ATTACKING
if (math.random() < 0.10) then -- TODO add sliding scale based on number of members and evolution
squadType = SQUAD_SUICIDE
end
unitGroupUtils.setSquadCommand(squad,
{type=defines.command.attack,
target=closestPlayer},
squadType,
0)
end
end
end
end
function ai.retreatUnits(position, squad, regionMap, surface, natives)
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
local chunk = mapUtils.getChunkByPosition(regionMap, position.x, position.y)
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > 1500) then -- TODO sliding scale of death based on evolution
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local performRetreat = false
local enemiesToSquad
if (squad == nil) then
enemiesToSquad = surface.find_enemy_units(position, 15)
if (#enemiesToSquad > 0) then
performRetreat = true
end
elseif (squad ~= nil) and squad.group.valid and (squad.status ~= constants.SQUAD_RETREATING) and (squad.status ~= constants.SQUAD_SUICIDE) then
if (#squad.group.members ~= 0) then
performRetreat = true
end
end
if performRetreat then
mapUtils.getNeighborChunks(regionMap,
chunk.cX,
chunk.cY,
retreatNeighbors)
local exitPath
local exitScore = constants.MAGIC_MAXIMUM_NUMBER
local exitDirection
for i=1, 8 do
local neighborChunk = retreatNeighbors[i]
if (neighborChunk ~= nil) then
retreatPosition.x = neighborChunk.pX
retreatPosition.y = neighborChunk.pY
local dangerScore = neighborChunk[DEATH_PHEROMONE] + surface.get_pollution(retreatPosition) + neighborChunk[PLAYER_PHEROMONE] +
-- putting a unit group in a nest causing pathing and disbanding issues
(neighborChunk.bG * 200) - neighborChunk[ENEMY_BASE_PHEROMONE]
if (dangerScore < exitScore) then
exitScore = dangerScore
exitPath = neighborChunk
exitDirection = i
end
end
end
-- center position in chunk for retreat
retreatPosition.x = exitPath.pX + constants.HALF_CHUNK_SIZE
retreatPosition.y = exitPath.pY + constants.HALF_CHUNK_SIZE
-- 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
local filter = {}
filter[constants.SQUAD_RETREATING] = true
local newSquad = unitGroupUtils.findNearBySquad(natives,
retreatPosition,
18,
filter)
if (newSquad == nil) then
newSquad = unitGroupUtils.createSquad(retreatPosition, surface, natives)
newSquad.status = constants.SQUAD_RETREATING
newSquad.cycles = 2
end
if (enemiesToSquad ~= nil) then
unitGroupUtils.membersToSquad(newSquad, enemiesToSquad, false)
else
unitGroupUtils.membersToSquad(newSquad, squad.group.members, true)
end
end
end
end
--[[ not used due to being unable to stop unit group formation by the computer ai
function ai.removeScout(regionMap, surface, entity, natives)
for i=#natives.scouts, 1, -1 do
local scout = natives.scouts[i]
if (scout == entity) then
table.remove(natives.scouts, i)
end
end
end
function ai.sendScouts(regionMap, surface, natives, chunk, neighbors, validNeighbors)
if (#natives.scouts < 5) 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=16})
if (enemy ~= nil) and (enemy.type == "unit") then
natives.scouts[#natives.scouts+1] = enemy
enemy.set_command({type=defines.command.attack,
target=game.players[1].character})
-- print("scounting")
end
end
return validNeighbors
end
]]--
return ai

151
libs/AIAttack.lua Executable file
View File

@@ -0,0 +1,151 @@
local aiAttack = {}
-- local attackLocationNeighbors = {1,2,3,4}
local factorio_defined = defines
local constants = require("Constants")
local mapUtils = require("MapUtils")
local utils = require("Utils")
local unitGroupUtils = require("UnitGroupUtils")
local attackPosition = {x=0, y=0} -- used to minimize garbage generation
local attackLocationNeighbors = {1,2,3,4,5,6,7,8}
local attackLocationCommand = {type=defines.command.attack_area,
destination=attackPosition,
radius=constants.HALF_CHUNK_SIZE,
distraction=defines.distraction.by_damage}
local attackPlayerCommand = {type=defines.command.attack,
target=1}
local mRandom = math.random
function aiAttack.squadAttackLocation(regionMap, surface, natives)
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
local SQUAD_RAIDING = constants.SQUAD_RAIDING
local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local CHUNK_SIZE = constants.CHUNK_SIZE
local group_states = factorio_defined.group_state
local mathRandom = mRandom
local getNeighborChunks = mapUtils.getNeighborChunks
local positionToChunk = mapUtils.positionToChunkOffset
local squads = natives.squads
for i=1, #squads do
local squad = squads[i]
local group = squad.group
local squadStatus = squad.status
if group.valid and ((squadStatus == SQUAD_RAIDING) or (squadStatus == SQUAD_SUICIDE_RAID)) then
if (group.state == group_states.finished) or (group.state == group_states.gathering) then
local cX, cY = positionToChunk(group.position)
getNeighborChunks(regionMap, cX, cY, attackLocationNeighbors)
local attackChunk
local attackScore = -MAGIC_MAXIMUM_NUMBER
local attackDirection
-- print("------")
for x=1, 8 do
local neighborChunk = attackLocationNeighbors[x]
if (neighborChunk ~= nil) then
attackPosition.x = neighborChunk.pX
attackPosition.y = neighborChunk.pY
local damageScore = surface.get_pollution(attackPosition) + neighborChunk[PLAYER_BASE_PHEROMONE] + neighborChunk[PLAYER_PHEROMONE] --+ neighborChunk[PLAYER_DEFENSE_PHEROMONE]
local avoidScore = neighborChunk[DEATH_PHEROMONE] --+ neighborChunk[ENEMY_BASE_GENERATOR] + neighborChunk[ENEMY_BASE_PHEROMONE]
local score = damageScore - avoidScore
if (score > attackScore) then
attackScore = score
attackChunk = neighborChunk
attackDirection = x
end
-- print(x, score, damageScore, avoidScore, neighborChunk.cX, neighborChunk.cY)
end
end
if (attackChunk ~= nil) then
-- print("==")
-- print (attackDirection, cX, cY)
-- utils.positionDirectionToChunkCorner(attackDirection, attackChunk, attackPosition)
attackPosition.x = attackChunk.pX + HALF_CHUNK_SIZE
attackPosition.y = attackChunk.pY + HALF_CHUNK_SIZE
group.set_command(attackLocationCommand)
group.start_moving()
end
elseif (group.state == group_states.attacking_distraction) and (mathRandom() < 0.3) then
local playerTarget = surface.find_nearest_enemy({position=group.position,
max_distance=CHUNK_SIZE,
force="enemy"})
if (playerTarget ~= nil) then
group.set_command({type=defines.command.attack,
target=playerTarget})
end
end
end
end
end
function aiAttack.squadAttackPlayer(regionMap, surface, natives, players)
local SQUAD_HUNTING = constants.SQUAD_HUNTING
local SQUAD_GUARDING = constants.SQUAD_GUARDING
local SQUAD_SUICIDE_HUNT = constants.SQUAD_SUICIDE_HUNT
local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local findDistance = utils.euclideanDistanceNamed
-- local commandAttack =
local mathRandom = mRandom
local squads = natives.squads
for si=1, #squads do
local squad = squads[si]
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 playerCharacer = players[pi].character
local distance = findDistance(playerCharacer.position, group.position)
if (distance < closestDistance) then
closestPlayer = playerCharacer
closestDistance = distance
end
end
if (closestDistance < 75) then
local squadType = SQUAD_HUNTING
if (mathRandom() < 0.10) then -- TODO add sliding scale based on number of members and evolution
squadType = SQUAD_SUICIDE_HUNT
end
squad.status = squadType
attackPlayerCommand.target = closestPlayer
group.set_command(attackPlayerCommand)
end
end
end
end
function aiAttack.squadBeginAttack(natives)
local SQUAD_GUARDING = constants.SQUAD_GUARDING
local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID
local SQUAD_RAIDING = constants.SQUAD_RAIDING
local mathRandom = mRandom
for i=1,#natives.squads do
local squad = natives.squads[i]
if (squad.status == SQUAD_GUARDING) and (mathRandom() < 0.7) then
if (mathRandom() < 0.05) then
squad.status = SQUAD_SUICIDE_RAID
else
squad.status = SQUAD_RAIDING
end
end
end
end
return aiAttack

30
libs/AIBuilding.lua Executable file
View File

@@ -0,0 +1,30 @@
local aiBuilding = {}
--[[ not used due to being unable to stop unit group formation by the computer ai
function ai.removeScout(regionMap, surface, entity, natives)
for i=#natives.scouts, 1, -1 do
local scout = natives.scouts[i]
if (scout == entity) then
table.remove(natives.scouts, i)
end
end
end
function ai.sendScouts(regionMap, surface, natives, chunk, neighbors, validNeighbors)
if (#natives.scouts < 5) 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=16})
if (enemy ~= nil) and (enemy.type == "unit") then
natives.scouts[#natives.scouts+1] = enemy
enemy.set_command({type=defines.command.attack,
target=game.players[1].character})
-- print("scounting")
end
end
return validNeighbors
end
]]--
return aiBuilding

83
libs/AIDefense.lua Executable file
View File

@@ -0,0 +1,83 @@
local aiDefense = {}
local factorio_defined = defines
local constants = require("Constants")
local mapUtils = require("MapUtils")
local utils = require("Utils")
local unitGroupUtils = require("UnitGroupUtils")
local retreatFilter = {[constants.SQUAD_RETREATING] = true}
local retreatNeighbors = {1,2,3,4,5,6,7,8} -- used to minimize garbage generation
local retreatPosition = {x=0, y=0} -- used to minimize garbage generation
function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
local chunk = mapUtils.getChunkByPosition(regionMap, position.x, position.y)
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > (game.evolution_factor * constants.RETREAT_LEVEL_DEATH_PHEROMONE)) then -- TODO sliding scale of death based on evolution
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
local performRetreat = false
local enemiesToSquad
if (squad == nil) then
enemiesToSquad = surface.find_enemy_units(position, 15)
if (#enemiesToSquad > 0) then
performRetreat = true
end
elseif squad.group.valid and (squad.status ~= constants.SQUAD_RETREATING) and (squad.status ~= constants.SQUAD_SUICIDE_HUNT) and (squad.status ~= constants.SQUAD_SUICIDE_RAID) then
if (#squad.group.members ~= 0) then
performRetreat = true
end
end
if performRetreat then
mapUtils.getNeighborChunks(regionMap,
chunk.cX,
chunk.cY,
retreatNeighbors)
local exitPath
local exitScore = constants.MAGIC_MAXIMUM_NUMBER
local exitDirection
for i=1, 4 do
local neighborChunk = retreatNeighbors[i]
if (neighborChunk ~= nil) then
retreatPosition.x = neighborChunk.pX
retreatPosition.y = neighborChunk.pY
local dangerScore = neighborChunk[DEATH_PHEROMONE] + surface.get_pollution(retreatPosition) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_PHEROMONE] - neighborChunk[ENEMY_BASE_PHEROMONE] + neighborChunk[ENEMY_BASE_GENERATOR]
if (dangerScore < exitScore) then
exitScore = dangerScore
exitPath = neighborChunk
exitDirection = i
end
end
end
utils.positionDirectionToChunkCorner(exitDirection, exitPath, retreatPosition)
-- 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
local newSquad = unitGroupUtils.findNearBySquad(natives,
retreatPosition,
constants.HALF_CHUNK_SIZE,
retreatFilter)
if (newSquad == nil) then
newSquad = unitGroupUtils.createSquad(retreatPosition, surface, natives)
newSquad.status = constants.SQUAD_RETREATING
newSquad.cycles = 4
end
if (enemiesToSquad ~= nil) then
unitGroupUtils.membersToSquad(newSquad, enemiesToSquad, false, factorio_defined.distraction.none)
else
unitGroupUtils.membersToSquad(newSquad, squad.group.members, true, factorio_defined.distraction.none)
end
end
end
end
return aiDefense

View File

@@ -1,27 +1,159 @@
local constants = {} local constants = {}
constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest score -- misc
constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest score
-- constants.MAX_PHEROMONE = 20000
constants.RETREAT_LEVEL_DEATH_PHEROMONE = 15000
-- chunk properties
constants.MAX_PHEROMONE = 7000
constants.BASE_PHEROMONE_PRODUCTION = 35
constants.DIFFUSION_AMOUNT = 0.02
constants.DEATH_DIFFUSION_AMOUNT = 0.01
constants.CHUNK_SIZE = 32 constants.CHUNK_SIZE = 32
constants.HALF_CHUNK_SIZE = constants.CHUNK_SIZE / 2 constants.HALF_CHUNK_SIZE = constants.CHUNK_SIZE / 2
constants.NORTH_SOUTH = true constants.NORTH_SOUTH = 1
constants.EAST_WEST = false constants.EAST_WEST = 2
-- pheromone amounts
constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 150
constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 35
constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 400
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 75
-- pheromone diffusion amounts
constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT = 0.03
constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT = 0.03
-- chunk attributes
constants.DEATH_PHEROMONE = 1 constants.DEATH_PHEROMONE = 1
constants.ENEMY_BASE_PHEROMONE = 2 constants.ENEMY_BASE_PHEROMONE = 2
constants.PLAYER_PHEROMONE = 3 constants.PLAYER_PHEROMONE = 3
constants.PLAYER_BASE_PHEROMONE = 4
constants.PLAYER_DEFENSE_PHEROMONE = 5
-- constants.MOVEMENT_PHEROMONE = 6
constants.SQUAD_RETREATING = 1 constants.ENEMY_BASE_GENERATOR = 6
constants.SQUAD_GUARDING = 2 constants.PLAYER_BASE_GENERATOR = 7
constants.SQUAD_SIEGE = 3 constants.PLAYER_DEFENSE_GENERATOR = 8
constants.SQUAD_HUNTING = 4
constants.SQUAD_SUICIDE = 5
constants.SQUAD_ATTACKING = 6
constants.SQUAD_BURROWING = 7
constants.SQUAD_SCOUTING = 8
return constants constants.NORTH_SOUTH_PASSABLE = 9
constants.EAST_WEST_PASSABLE = 10
-- Squad status
constants.SQUAD_RETREATING = 1 -- used during squad retreat
constants.SQUAD_GUARDING = 2 -- used when squad is idle
constants.SQUAD_ATTACKING = 3 -- used as an attack state to be transitioned into hunt, raid, siege, burrow
-- constants.SQUAD_SIEGE = 3
constants.SQUAD_HUNTING = 4 -- used when player is close to unit group
constants.SQUAD_SUICIDE_HUNT = 5 -- used when player is close with no retreat
-- constants.SQUAD_BURROWING = 6
-- constants.SQUAD_SCOUTING = 7
constants.SQUAD_RAIDING = 8 -- used when player stuff is close
constants.SQUAD_SUICIDE_RAID = 9 -- when player stuff is close with no retreat
-- player building pheromones
constants.buildingPheromones = {}
-- constants.buildingPheromones["container"] = 1
-- constants.buildingPheromones["storage-tank"] = 1
-- constants.buildingPheromones["transport-belt"] = 1
constants.buildingPheromones["generator"] = 35
-- constants.buildingPheromones["electric-pole"] = 1
constants.buildingPheromones["pump"] = 10
constants.buildingPheromones["offshore-pump"] = 10
-- constants.buildingPheromones["constant-combinator"] = 1
-- constants.buildingPheromones["train-stop"] = 2
-- constants.buildingPheromones["rail-signal"] = 1
constants.buildingPheromones["accumulator"] = 20
constants.buildingPheromones["solar-panel"] = 10
constants.buildingPheromones["boiler"] = 30
constants.buildingPheromones["assembling-machine"] = 25
constants.buildingPheromones["roboport"] = 20
constants.buildingPheromones["beacon"] = 15
constants.buildingPheromones["furnace"] = 20
constants.buildingPheromones["mining-drill"] = 40
-- player defense pheromones
constants.defensePheromones = {}
constants.defensePheromones["ammo-turret"] = 10
constants.defensePheromones["electric-turret"] = 10
constants.defensePheromones["fluid-turret"] = 15
constants.defensePheromones["turret"] = 5
-- enemy units
-- constants.deathPheromones = {}
-- constants.deathPheromones[""]
return constants
--[[ types
inserter
loader
offshore-pump
accumulator
power-switch
generator
pump
boiler
solar-panel
constant-combinator
arithmetic-combinator
decider-combinator
player-port
rocket-silo
roboport
assembling-machine
mining-drill
lab
beacon
radar
furnace
unit-spawner
lamp
land-mine
ammo-turret
wall
gate
electric-turret
fluid-turret
turret
resource
logistic-robot
construction-robot
unit
player
combat-robot
locomotive
cargo-wagon
car
smart-container
logistic-container
container
storage-tank
transport-belt
underground-belt
splitter
pipe-to-ground
electric-pole
curved-rail
straight-rail
train-stop
rail-signal
rail-chain-signal
pipe
]]--

View File

@@ -1,25 +1,28 @@
local mapProcessor = {} local mapProcessor = {}
local mapUtils = require("MapUtils")
local neighborsArray = {1,2,3,4,5,6,7,8} local neighborsArray = {1,2,3,4,5,6,7,8}
local cardinalArray = {1,2,3,4}
local processors = {} local processors = {}
function mapProcessor.processMap(regionMap, surface, natives) function mapProcessor.processMap(regionMap, surface, natives)
local neighbors = neighborsArray local getNeighborChunks = mapUtils.getCardinalChunks
local validNeighbors = false
local neighbors = cardinalArray
local count = 0 local count = 0
for _,ys in pairs(regionMap) do for _,ys in pairs(regionMap) do
for _,chunk in pairs(ys) do for _,chunk in pairs(ys) do
validNeighbors = false getNeighborChunks(regionMap, chunk.cX, chunk.cY, neighbors)
-- validNeighbors flag if the processor retrieved the neighbors of the chunk then true -- validNeighbors flag if the processor retrieved the neighbors of the chunk then true
for i=1, #processors do for i=1, #processors do
validNeighbors = processors[i](regionMap, surface, natives, chunk, neighbors, validNeighbors) validNeighbors = processors[i](regionMap, surface, natives, chunk, neighbors)
end end
count = count + 1 count = count + 1
if (count % 1100 == 0) then if (count % 1000 == 0) then
coroutine.yield() coroutine.yield()
end end
end end

View File

@@ -3,21 +3,119 @@ local mapUtils = {}
local constants = require("Constants") local constants = require("Constants")
local mFloor = math.floor local mFloor = math.floor
local mMin = math.min local mAbs = math.abs
local mMax = math.max
function mapUtils.getChunkByPosition(regionMap, x, y) function mapUtils.getChunkByPosition(regionMap, x, y)
local cX = mFloor(x * 0.03125) local cX = mFloor(x * 0.03125)
if (regionMap[cX] ~= nil) then local chunkX = regionMap[cX]
return regionMap[cX][mFloor(y * 0.03125)] if (chunkX ~= nil) then
return chunkX[mFloor(y * 0.03125)]
end end
return nil return nil
end end
function mapUtils.removeUnitSpawner(regionMap, x, y) function mapUtils.getChunkByIndex(regionMap, x, y)
local bases = mapUtils.getChunkByPosition(regionMap, x, y) local chunkX = regionMap[x]
if (bases ~= nil) then if (chunkX ~= nil) then
bases.bG = mMax(0, bases.bG - 1) return chunkX[y]
end
return nil
end
function mapUtils.positionToChunkOffset(position)
return mFloor(position.x * 0.03125), mFloor(position.y * 0.03125)
end
function mapUtils.getEntityOverlapChunks(regionMap, entity)
local mathFloor = mFloor
local mathAbs = mAbs
local boundingBox = entity.prototype.selection_box;
local leftTopChunk
local rightTopChunk
local leftBottomChunk
local rightBottomChunk
if (boundingBox ~= nil) then
local center = entity.position
local topXOffset
local topYOffset
local bottomXOffset
local bottomYOffset
if (entity.direction == defines.direction.east) then
topXOffset = boundingBox.left_top.y
topYOffset = boundingBox.left_top.x
bottomXOffset = boundingBox.right_bottom.y
bottomYOffset = boundingBox.right_bottom.x
else
topXOffset = boundingBox.left_top.x
topYOffset = boundingBox.left_top.y
bottomXOffset = boundingBox.right_bottom.x
bottomYOffset = boundingBox.right_bottom.y
end
local leftTopChunkX = mathFloor((center.x + topXOffset) * 0.03125)
local leftTopChunkY = mathFloor((center.y + topYOffset) * 0.03125)
-- used to force things on chunk boundary to not spill over 0.0001
local rightTopChunkX = mathFloor((center.x + bottomXOffset - 0.0001) * 0.03125)
local rightTopChunkY = leftTopChunkY
-- used to force things on chunk boundary to not spill over 0.0001
local leftBottomChunkX = leftTopChunkX
local leftBottomChunkY = mathFloor((center.y + bottomYOffset - 0.0001) * 0.03125)
local rightBottomChunkX = rightTopChunkX
local rightBottomChunkY = leftBottomChunkY
leftTopChunk = mapUtils.getChunkByIndex(regionMap, leftTopChunkX, leftTopChunkY)
if (leftTopChunkX ~= rightTopChunkX) then
rightTopChunk = mapUtils.getChunkByIndex(regionMap, rightTopChunkX, rightTopChunkY)
end
if (leftTopChunkY ~= leftBottomChunkY) then
leftBottomChunk = mapUtils.getChunkByIndex(regionMap, leftBottomChunkX, leftBottomChunkY)
end
if (leftTopChunkX ~= rightBottomChunkX) and (leftTopChunkY ~= rightBottomChunkY) then
rightBottomChunk = mapUtils.getChunkByIndex(regionMap, rightBottomChunkX, rightBottomChunkY)
end
end
return leftTopChunk, rightTopChunk, leftBottomChunk, rightBottomChunk
end
function mapUtils.addRemoveObject(regionMap, entity, addObject)
local leftTop, rightTop, leftBottom, rightBottom
local entityValue
local pheromoneType
if (constants.buildingPheromones[entity.type] ~= nil) then
entityValue = constants.buildingPheromones[entity.type]
pheromoneType = constants.PLAYER_BASE_GENERATOR
elseif (constants.defensePheromones[entity.type] ~= nil) then
entityValue = constants.defensePheromones[entity.type]
pheromoneType = constants.PLAYER_DEFENSE_GENERATOR
elseif (entity.type == "unit-spawner") and (entity.force.name == "enemy") then
entityValue = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
pheromoneType = constants.ENEMY_BASE_GENERATOR
end
if (entityValue ~= nil) then
leftTop, rightTop, leftBottom, rightBottom = mapUtils.getEntityOverlapChunks(regionMap, entity)
if not addObject then
entityValue = -entityValue
end
if (leftTop ~= nil) then
leftTop[pheromoneType] = leftTop[pheromoneType] + entityValue
end
if (rightTop ~= nil) then
rightTop[pheromoneType] = rightTop[pheromoneType] + entityValue
end
if (leftBottom ~= nil) then
leftBottom[pheromoneType] = leftBottom[pheromoneType] + entityValue
end
if (rightBottom ~= nil) then
rightBottom[pheromoneType] = rightBottom[pheromoneType] + entityValue
end
end end
end end
@@ -44,8 +142,37 @@ function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY, neighbors)
end end
xChunks = regionMap[chunkX] xChunks = regionMap[chunkX]
neighbors[2] = xChunks[chunkY-1] if (xChunks ~= nil) then
neighbors[7] = xChunks[chunkY+1] neighbors[2] = xChunks[chunkY-1]
neighbors[7] = xChunks[chunkY+1]
end
end
--[[
1
|
2- -3
|
4
]]--
function mapUtils.getCardinalChunks(regionMap, chunkX, chunkY, neighbors)
local xChunks = regionMap[chunkX]
if (xChunks ~= nil) then
neighbors[1] = xChunks[chunkY-1]
neighbors[4] = xChunks[chunkY+1]
end
xChunks = regionMap[chunkX-1]
if (xChunks ~= nil) then
neighbors[2] = xChunks[chunkY]
end
xChunks = regionMap[chunkX+1]
if (xChunks ~= nil) then
neighbors[3] = xChunks[chunkY]
end
end end
return mapUtils return mapUtils

View File

@@ -5,82 +5,96 @@ local constants = require("Constants")
local mMin = math.min local mMin = math.min
local mFloor = math.floor local mFloor = math.floor
function pheromoneUtils.deathScent(regionMap, x, y, amount) local nearestEnemyPosition = {x=1,y=2}
local mathFloor = mFloor local nearestTable = {position=nearestEnemyPosition,
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE max_distance=constants.CHUNK_SIZE,
force="enemy"}
function pheromoneUtils.deathScent(regionMap, surface, x, y, amount)
local chunk = regionMap[mathFloor(x * 0.03125)] -- nearestEnemyPosition.x = x
-- nearestEnemyPosition.y = y
-- local playerKiller = surface.find_nearest_enemy(nearestTable)
-- if (playerKiller ~= nil) then
-- local chunk = regionMap[mathFloor(playerKiller.position.x * 0.03125)]
-- if (chunk ~= nil) then
-- chunk = chunk[mathFloor(playerKiller.position.y * 0.03125)]
-- if (chunk ~= nil) then
-- chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + amount
-- end
-- end
-- end
local chunk = mapUtils.getChunkByPosition(regionMap, x, y)
if (chunk ~= nil) then if (chunk ~= nil) then
chunk = chunk[mathFloor(y * 0.03125)] chunk[constants.DEATH_PHEROMONE] = chunk[constants.DEATH_PHEROMONE] + amount
if (chunk ~= nil) then
chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + amount
end
end end
end end
function pheromoneUtils.enemyBaseScent(regionMap, surface, natives, chunk, neighbors, validNeighbors) function pheromoneUtils.playerDefenseScent(regionMap, surface, natives, chunk, neighbors)
local BASE_PHEROMONE_PRODUCTION = constants.BASE_PHEROMONE_PRODUCTION local baseScore = chunk[constants.PLAYER_DEFENSE_GENERATOR]
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE if (baseScore > 0) then
chunk[constants.PLAYER_DEFENSE_PHEROMONE] = chunk[constants.PLAYER_DEFENSE_PHEROMONE] + baseScore
local spawners = chunk.bG end
if (spawners > 0) then end
chunk[ENEMY_BASE_PHEROMONE] = chunk[ENEMY_BASE_PHEROMONE] + (spawners * constants.BASE_PHEROMONE_PRODUCTION)
function pheromoneUtils.playerBaseScent(regionMap, surface, natives, chunk, neighbors)
local baseScore = chunk[constants.PLAYER_BASE_GENERATOR]
if (baseScore > 0) then
chunk[constants.PLAYER_BASE_PHEROMONE] = chunk[constants.PLAYER_BASE_PHEROMONE] + baseScore
end
end
function pheromoneUtils.enemyBaseScent(regionMap, surface, natives, chunk, neighbors)
local spawners = chunk[constants.ENEMY_BASE_GENERATOR]
if (spawners > 0) then
chunk[constants.ENEMY_BASE_PHEROMONE] = chunk[constants.ENEMY_BASE_PHEROMONE] + spawners
end end
return validNeighbors
end end
function pheromoneUtils.playerScent(regionMap, players) function pheromoneUtils.playerScent(regionMap, players)
local placePheromoneByPosition = pheromoneUtils.placePheromoneByPosition local PLAYER_PHEROMONE_GENERATOR_AMOUNT = constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local getChunkByPosition = mapUtils.getChunkByPosition
local mathFloor = mFloor local mathFloor = mFloor
for i=1, #players do for i=1, #players do
local playerPosition = players[i].position local playerPosition = players[i].position
local playerChunk = regionMap[mathFloor(playerPosition.x * 0.03125)][mathFloor(playerPosition.y * 0.03125)] local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + 300 if (playerChunk ~= nil) then
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
end
end end
end end
function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, neighbors, validNeighbors) function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, neighbors)
local mathMin = mMin local STANDARD_PHERONOME_DIFFUSION_AMOUNT = constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT
local getNeighborChunks = mapUtils.getNeighborChunks local DEATH_PHEROMONE_DIFFUSION_AMOUNT = constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT
local DIFFUSION_AMOUNT = constants.DIFFUSION_AMOUNT
local DEATH_DIFFUSION_AMOUNT = constants.DEATH_DIFFUSION_AMOUNT
local MAX_PHEROMONE = constants.MAX_PHEROMONE
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
-- local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
for x=1,3 do for x=1,5 do
local threshold
local diffusionAmount local diffusionAmount
local persistence
if (x == DEATH_PHEROMONE) then if (x == DEATH_PHEROMONE) then
threshold = 125 diffusionAmount = DEATH_PHEROMONE_DIFFUSION_AMOUNT
diffusionAmount = DEATH_DIFFUSION_AMOUNT persistence = 0.99
else else
threshold = 75 diffusionAmount = STANDARD_PHERONOME_DIFFUSION_AMOUNT
diffusionAmount = DIFFUSION_AMOUNT persistence = 0.98
end end
if (chunk[x] > threshold) then local totalDiffused = 0
if not validNeighbors then for i=1,4 do
getNeighborChunks(regionMap, chunk.cX, chunk.cY, neighbors) local neighborChunk = neighbors[i]
validNeighbors = true if (neighborChunk ~= nil) then
local diffusedAmount = (chunk[x] * diffusionAmount)
totalDiffused = totalDiffused + diffusedAmount
neighborChunk[x] = neighborChunk[x] + diffusedAmount
end end
local totalDiffused = 0
for i=1,8 do
local neighborChunk = neighbors[i]
if (neighborChunk ~= nil) then
local diffusedAmount = (chunk[x] * diffusionAmount)
totalDiffused = totalDiffused + diffusedAmount
neighborChunk[x] = mathMin(MAX_PHEROMONE, neighborChunk[x] + diffusedAmount)
end
end
chunk[x] = chunk[x] - totalDiffused
end
chunk[x] = chunk[x] * 0.995
if (chunk[x] < 2) then
chunk[x] = 0
end end
chunk[x] = chunk[x] - totalDiffused
chunk[x] = chunk[x] * persistence
end end
return validNeighbors
end end
return pheromoneUtils return pheromoneUtils

View File

@@ -3,6 +3,10 @@ local unitGroupUtils = {}
local utils = require("Utils") local utils = require("Utils")
local constants = require("Constants") local constants = require("Constants")
local groupingCommand = {type=defines.command.group,
group=1,
distraction=0}
function unitGroupUtils.findNearBySquad(natives, position, distance, filter) function unitGroupUtils.findNearBySquad(natives, position, distance, filter)
local getDistance = utils.euclideanDistanceNamed local getDistance = utils.euclideanDistanceNamed
local squads = natives.squads local squads = natives.squads
@@ -24,20 +28,20 @@ function unitGroupUtils.createSquad(position, surface, natives)
local squad = { group = unitGroup, local squad = { group = unitGroup,
status = constants.SQUAD_GUARDING, status = constants.SQUAD_GUARDING,
cycles = -1 } cycles = 0 }
natives.squads[#natives.squads+1] = squad natives.squads[#natives.squads+1] = squad
return squad return squad
end end
function unitGroupUtils.membersToSquad(squad, members, overwriteGroup) function unitGroupUtils.membersToSquad(squad, members, overwriteGroup, distraction)
if (members ~= nil) then if (members ~= nil) then
local group = squad.group local group = squad.group
for i=1,#members do for i=1,#members do
local member = members[i] local member = members[i]
if (member ~= nil) and member.valid and (overwriteGroup or (not overwriteGroup and (member.unit_group == nil))) then if (member ~= nil) and member.valid and (overwriteGroup or (not overwriteGroup and (member.unit_group == nil))) then
member.set_command({type=defines.command.group, groupingCommand.group = group
group=group, groupingCommand.distraction = distraction
distraction=defines.distraction.none}) member.set_command(groupingCommand)
end end
end end
end end
@@ -60,7 +64,7 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
if addUnitGroup then if addUnitGroup then
returnSquad = { group = unitGroup, returnSquad = { group = unitGroup,
status = constants.SQUAD_GUARDING, status = constants.SQUAD_GUARDING,
cycles = -1 } cycles = 0 }
squads[#squads+1] = returnSquad squads[#squads+1] = returnSquad
end end
end end
@@ -68,15 +72,15 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup)
return returnSquad return returnSquad
end end
function unitGroupUtils.setSquadCommand(squad, command, state, cycles) -- function unitGroupUtils.setSquadCommand(squad, command, state, cycles)
local group = squad.group -- local group = squad.group
if (group ~= nil) and group.valid then -- if (group ~= nil) and group.valid then
squad.status = state -- squad.status = state
squad.cycles = cycles -- squad.cycles = cycles
group.set_command(command) -- group.set_command(command)
-- group.start_moving() -- group.start_moving()
end -- end
end -- end
function unitGroupUtils.regroupSquads(natives) function unitGroupUtils.regroupSquads(natives)
local SQUAD_RETREATING = constants.SQUAD_RETREATING local SQUAD_RETREATING = constants.SQUAD_RETREATING
@@ -92,7 +96,7 @@ function unitGroupUtils.regroupSquads(natives)
for x=i+1, #squads do for x=i+1, #squads do
local mergeSquad = squads[x] local mergeSquad = squads[x]
local mergeGroup = mergeSquad.group local mergeGroup = mergeSquad.group
if mergeGroup.valid and (mergeSquad.status == squad.status) and (findDistance(squadPosition, mergeGroup.position) < 3) then if mergeGroup.valid and (mergeSquad.status == squad.status) and (findDistance(squadPosition, mergeGroup.position) < constants.HALF_CHUNK_SIZE) then
mergeSquadMembers(squad, mergeGroup.members, true) mergeSquadMembers(squad, mergeGroup.members, true)
mergeGroup.destroy() mergeGroup.destroy()
end end

View File

@@ -1,5 +1,7 @@
local utils = {} local utils = {}
local constants = require("Constants")
function utils.euclideanDistanceNamed(p1, p2) function utils.euclideanDistanceNamed(p1, p2)
local xs = p1.x - p2.x local xs = p1.x - p2.x
local ys = p1.y - p2.y local ys = p1.y - p2.y
@@ -12,4 +14,34 @@ function utils.euclideanDistanceArray(p1, p2)
return ((xs * xs) + (ys * ys)) ^ 0.5 return ((xs * xs) + (ys * ys)) ^ 0.5
end end
function utils.positionDirectionToChunkCorner(direction, chunk, position)
-- local position = {}
if (direction == 1) then
position.x = chunk.pX
position.y = chunk.pY
elseif (direction == 2) then
position.x = chunk.pX + constants.HALF_CHUNK_SIZE
position.y = chunk.pY
elseif (direction == 3) then
position.x = chunk.pX + constants.CHUNK_SIZE
position.y = chunk.pY
elseif (direction == 4) then
position.x = chunk.pX
position.y = chunk.pY + constants.HALF_CHUNK_SIZE
elseif (direction == 5) then
position.x = chunk.pX + constants.CHUNK_SIZE
position.y = chunk.pY + constants.HALF_CHUNK_SIZE
elseif (direction == 6) then
position.x = chunk.pX
position.y = chunk.pY + constants.CHUNK_SIZE
elseif (direction == 7) then
position.x = chunk.pX + constants.HALF_CHUNK_SIZE
position.y = chunk.pY + constants.CHUNK_SIZE
elseif (direction == 8) then
position.x = chunk.pX + constants.CHUNK_SIZE
position.y = chunk.pY + constants.CHUNK_SIZE
end
return position
end
return utils return utils

View File

@@ -3,9 +3,15 @@ local chunkUtils = {}
local mapUtils = require("MapUtils") local mapUtils = require("MapUtils")
local constants = require("Constants") local constants = require("Constants")
local natives -- optimize table creation and referencing
local regionMaps local areaBoundingBox = {{1,2},
local chunkProcessingQueue {3,4}}
local enemyChunkQuery = {area=areaBoundingBox,
type="unit-spawner",
force="enemy"}
local playerChunkQuery = {area=areaBoundingBox,
force="player"}
function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, chunkSize, surface) function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, chunkSize, surface)
local NORTH_SOUTH = constants.NORTH_SOUTH local NORTH_SOUTH = constants.NORTH_SOUTH
@@ -32,6 +38,7 @@ end
function chunkUtils.checkChunkPassability(chunk, surface, natives) function chunkUtils.checkChunkPassability(chunk, surface, natives)
local checkForDeadendTiles = chunkUtils.checkForDeadendTiles local checkForDeadendTiles = chunkUtils.checkForDeadendTiles
local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
local NORTH_SOUTH = constants.NORTH_SOUTH local NORTH_SOUTH = constants.NORTH_SOUTH
local EAST_WEST = constants.EAST_WEST local EAST_WEST = constants.EAST_WEST
local CHUNK_SIZE = constants.CHUNK_SIZE local CHUNK_SIZE = constants.CHUNK_SIZE
@@ -55,34 +62,65 @@ function chunkUtils.checkChunkPassability(chunk, surface, natives)
end end
yi = yi + 1 yi = yi + 1
end end
if passableNorthSouth and passableEastWest then -- if passableNorthSouth and passableEastWest then
chunkUtils.colorChunk(x, y, "grass", surface) -- chunkUtils.colorChunk(x, y, "grass", surface)
elseif passableNorthSouth then -- elseif passableNorthSouth then
chunkUtils.colorChunk(x, y, "dirt", surface) -- chunkUtils.colorChunk(x, y, "dirt", surface)
elseif passableEastWest then -- elseif passableEastWest then
chunkUtils.colorChunk(x, y, "sand", surface) -- chunkUtils.colorChunk(x, y, "sand", surface)
else -- else
chunkUtils.colorChunk(x, y, "concrete", surface) -- chunkUtils.colorChunk(x, y, "concrete", surface)
end -- end
chunk.eW = passableEastWest if passableEastWest then
chunk.nS = passableNorthSouth chunk[constants.EAST_WEST_PASSABLE] = true
else
chunk[constants.EAST_WEST_PASSABLE] = false
end
if passableNorthSouth then
chunk[constants.NORTH_SOUTH_PASSABLE] = true
else
chunk[constants.NORTH_SOUTH_PASSABLE] = false
end
end end
local spawnCount = 0
function chunkUtils.scoreChunk(chunk, surface, natives) function chunkUtils.scoreChunk(chunk, surface, natives)
local PLAYER_DEFENSE_PHEROMONES = constants.defensePheromones
local PLAYER_BASE_PHEROMONES = constants.buildingPheromones
local x = chunk.pX local x = chunk.pX
local y = chunk.pY local y = chunk.pY
local cX = chunk.cX
local cY = chunk.cY areaBoundingBox[1][1] = x
local CHUNK_SIZE = constants.CHUNK_SIZE areaBoundingBox[1][2] = y
areaBoundingBox[2][1] = x+constants.CHUNK_SIZE
areaBoundingBox[2][2] = y+constants.CHUNK_SIZE
local entities = surface.count_entities_filtered(enemyChunkQuery)
local spawners = 0
local playerObjects = 0
local playerDefenses = 0
local spawners = surface.count_entities_filtered({area={{x, y}, spawners = entities * constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
{x+CHUNK_SIZE, y+CHUNK_SIZE}},
type="unit-spawner", entities = surface.find_entities_filtered(playerChunkQuery)
force="enemy"})
chunk.bG = spawners for i=1, #entities do
local entityType = entities[i].type
local entityScore = PLAYER_DEFENSE_PHEROMONES[entityType]
if (entityScore ~= nil) then
playerDefenses = playerDefenses + entityScore
end
entityScore = PLAYER_BASE_PHEROMONES[entityType]
if (entityScore ~= nil) then
playerObjects = playerObjects + entityScore
end
end
chunk[constants.PLAYER_BASE_GENERATOR] = playerObjects
chunk[constants.PLAYER_DEFENSE_GENERATOR] = playerDefenses
chunk[constants.ENEMY_BASE_GENERATOR] = spawners
end end
function chunkUtils.createChunk(topX, topY) function chunkUtils.createChunk(topX, topY)
@@ -92,9 +130,11 @@ function chunkUtils.createChunk(topX, topY)
cX = topX * 0.03125, cX = topX * 0.03125,
cY = topY * 0.03125 cY = topY * 0.03125
} }
chunk[constants.DEATH_PHEROMONE] = 0
chunk[constants.ENEMY_BASE_PHEROMONE] = 0 chunk[constants.ENEMY_BASE_PHEROMONE] = 0
chunk[constants.PLAYER_PHEROMONE] = 0 chunk[constants.PLAYER_PHEROMONE] = 0
chunk[constants.DEATH_PHEROMONE] = 0 chunk[constants.PLAYER_BASE_PHEROMONE] = 0
chunk[constants.PLAYER_DEFENSE_PHEROMONE] = 0
return chunk return chunk
end end

View File

@@ -1,9 +1,13 @@
local tests = {} local tests = {}
local constants = require("libs/Constants")
local regionMap local regionMap
local natives
function tests.initTester() function tests.initTester()
regionMap = global.regionMap regionMap = global.regionMap
natives = global.natives
end end
function tests.test1() function tests.test1()
@@ -26,34 +30,25 @@ function tests.test1()
end end
function tests.test2() function tests.test2()
local position = game.players[1].position for i=1, #natives.squads do
local squad = natives.squads[i]
local spawners = game.surfaces[1].find_entities_filtered({type="unit-spawner"}) if squad.group.valid then
for i=1, #spawners do print(math.floor(squad.group.position.x * 0.03125), math.floor(squad.group.position.y * 0.03125), squad.status, squad.group.state)
local spawner = spawners[i]
if (spawner ~= nil) and spawner.valid then
spawner.destroy()
end end
end end
game.forces.enemy.kill_all_units()
position.x = position.x + 10
position.y = position.y - 40
for i=position.x, position.x+30, 5 do
game.surfaces[1].create_entity({name="biter-spawner",
position={i, position.y}})
end
-- local playerPosition = game.players[1].position
-- playerPosition.x = playerPosition.x + 10
-- local turret = game.surfaces[1].create_entity({name="small-worm-turret", position=playerPosition})
-- turret
end end
-- function test3() function tests.test3()
-- local playerPosition = game.players[1].position local playerPosition = game.players[1].position
-- decayPheromone(regionMaps[1], playerPosition.x, playerPosition.y, 3) local chunkX = math.floor(playerPosition.x * 0.03125) * 32
-- end local chunkY = math.floor(playerPosition.y * 0.03125) * 32
local entities = game.surfaces[1].find_entities_filtered({area={{chunkX, chunkY},
{chunkX + constants.CHUNK_SIZE, chunkY + constants.CHUNK_SIZE}},
force="player"})
for i=1, #entities do
print(entities[i].name)
end
print("--")
end
return tests return tests