From e410b9e2f50eea8fd39c638a834254ad15a901cc Mon Sep 17 00:00:00 2001 From: veden Date: Wed, 17 Aug 2016 22:55:08 -0700 Subject: [PATCH] added logic for built, mined, and destroyed entity pheromone generators --- control.lua | 69 +++++++++++------ libs/AI.lua | 148 ------------------------------------ libs/AIAttack.lua | 151 ++++++++++++++++++++++++++++++++++++ libs/AIBuilding.lua | 30 ++++++++ libs/AIDefense.lua | 83 ++++++++++++++++++++ libs/Constants.lua | 164 ++++++++++++++++++++++++++++++++++++---- libs/MapProcessor.lua | 13 ++-- libs/MapUtils.lua | 147 ++++++++++++++++++++++++++++++++--- libs/PheromoneUtils.lua | 114 ++++++++++++++++------------ libs/UnitGroupUtils.lua | 34 +++++---- libs/Utils.lua | 32 ++++++++ libs/chunkUtils.lua | 90 ++++++++++++++++------ tests.lua | 45 +++++------ 13 files changed, 801 insertions(+), 319 deletions(-) delete mode 100755 libs/AI.lua create mode 100755 libs/AIAttack.lua create mode 100755 libs/AIBuilding.lua create mode 100755 libs/AIDefense.lua diff --git a/control.lua b/control.lua index 6533d45..722a2b5 100755 --- a/control.lua +++ b/control.lua @@ -5,7 +5,8 @@ local chunkProcessor = require("libs/ChunkProcessor") local mapProcessor = require("libs/MapProcessor") local constants = require("libs/Constants") 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 mapRoutine --coroutine holding state of in progress processing @@ -30,15 +31,9 @@ function onInit() pendingChunks = global.pendingChunks natives = global.natives natives.squads = {} + natives.troopToSquad = {} 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 surface = game.surfaces[1] for chunk in surface.get_chunks() do @@ -82,9 +77,12 @@ function onTick(event) pheromoneUtils.playerScent(regionMap, game.players) unitGroupUtils.regroupSquads(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 working, errorMsg = coroutine.resume(mapRoutine) @@ -98,26 +96,37 @@ function onTick(event) 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) local entity = event.entity if (entity.force.name == "enemy") then if (entity.type == "unit") then - local entityPosition = entity.position + local entityPosition = entity.position -- drop death pheromone where unit died - pheromoneUtils.deathScent(regionMap, + pheromoneUtils.deathScent(regionMap, + surface, entityPosition.x, entityPosition.y, - 200) + constants.DEATH_PHEROMONE_GENERATOR_AMOUNT) - local squad = unitGroupUtils.convertUnitGroupToSquad(natives, entity.unit_group) - - ai.retreatUnits(entityPosition, squad, regionMap, surface, natives) + if (event.force ~= nil) and (event.force.name == "player") then + local squad = unitGroupUtils.convertUnitGroupToSquad(natives, entity.unit_group) + aiDefense.retreatUnits(entityPosition, squad, regionMap, surface, natives) + end -- ai.removeScout(regionMap, surface, entity, natives) elseif (entity.type == "unit-spawner") then - local entityPosition = entity.position - mapUtils.removeUnitSpawner(regionMap, entityPosition.x, entityPosition.y) + mapUtils.addRemoveObject(regionMap, entity, false) end + elseif (entity.force.name == "player") then + mapUtils.addRemoveObject(regionMap, entity, false) end end @@ -128,18 +137,18 @@ function onInitialTick(event) surface = game.surfaces[1] end - game.forces.player.research_all_technologies() - game.players[1].cheat_mode = true + -- game.forces.player.research_all_technologies() + -- 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 = false -- remove enemies that aren't off -- game.forces.enemy.kill_all_units() -- turn off base expansion - -- game.forces.enemy.ai_controllable = false - game.map_settings.enemy_expansion.enabled = false + game.forces.enemy.ai_controllable = false + -- game.map_settings.enemy_expansion.enabled = false -- add processing handler into generated chunk event loop chunkProcessor.install(chunkUtils.checkChunkPassability) @@ -147,8 +156,10 @@ function onInitialTick(event) -- add processing handler into chunk map processing mapProcessor.install(pheromoneUtils.enemyBaseScent) - mapProcessor.install(ai.sendScouts) + mapProcessor.install(pheromoneUtils.playerDefenseScent) + mapProcessor.install(pheromoneUtils.playerBaseScent) mapProcessor.install(pheromoneUtils.processPheromone) + -- mapProcessor.install(ai.sendScouts) -- used for debugging tests.initTester() @@ -162,11 +173,19 @@ end script.on_init(onInit) 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_tick, onInitialTick) script.on_event(defines.events.on_chunk_generated, onChunkGenerated) remote.add_interface("rampant", { test1 = tests.test1, - test2 = tests.test2 + test2 = tests.test2, + test3 = tests.test3 }) diff --git a/libs/AI.lua b/libs/AI.lua deleted file mode 100755 index 5269801..0000000 --- a/libs/AI.lua +++ /dev/null @@ -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 \ No newline at end of file diff --git a/libs/AIAttack.lua b/libs/AIAttack.lua new file mode 100755 index 0000000..30d2ede --- /dev/null +++ b/libs/AIAttack.lua @@ -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 \ No newline at end of file diff --git a/libs/AIBuilding.lua b/libs/AIBuilding.lua new file mode 100755 index 0000000..5ad0443 --- /dev/null +++ b/libs/AIBuilding.lua @@ -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 \ No newline at end of file diff --git a/libs/AIDefense.lua b/libs/AIDefense.lua new file mode 100755 index 0000000..e327da3 --- /dev/null +++ b/libs/AIDefense.lua @@ -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 \ No newline at end of file diff --git a/libs/Constants.lua b/libs/Constants.lua index 42e2911..ffe7229 100755 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -1,27 +1,159 @@ 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.HALF_CHUNK_SIZE = constants.CHUNK_SIZE / 2 -constants.NORTH_SOUTH = true -constants.EAST_WEST = false +constants.NORTH_SOUTH = 1 +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.ENEMY_BASE_PHEROMONE = 2 constants.PLAYER_PHEROMONE = 3 +constants.PLAYER_BASE_PHEROMONE = 4 +constants.PLAYER_DEFENSE_PHEROMONE = 5 +-- constants.MOVEMENT_PHEROMONE = 6 -constants.SQUAD_RETREATING = 1 -constants.SQUAD_GUARDING = 2 -constants.SQUAD_SIEGE = 3 -constants.SQUAD_HUNTING = 4 -constants.SQUAD_SUICIDE = 5 -constants.SQUAD_ATTACKING = 6 -constants.SQUAD_BURROWING = 7 -constants.SQUAD_SCOUTING = 8 +constants.ENEMY_BASE_GENERATOR = 6 +constants.PLAYER_BASE_GENERATOR = 7 +constants.PLAYER_DEFENSE_GENERATOR = 8 -return constants \ No newline at end of file +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 +]]-- \ No newline at end of file diff --git a/libs/MapProcessor.lua b/libs/MapProcessor.lua index 334440c..974d655 100755 --- a/libs/MapProcessor.lua +++ b/libs/MapProcessor.lua @@ -1,25 +1,28 @@ local mapProcessor = {} +local mapUtils = require("MapUtils") + local neighborsArray = {1,2,3,4,5,6,7,8} +local cardinalArray = {1,2,3,4} local processors = {} function mapProcessor.processMap(regionMap, surface, natives) - local neighbors = neighborsArray - local validNeighbors = false + local getNeighborChunks = mapUtils.getCardinalChunks + local neighbors = cardinalArray local count = 0 for _,ys in pairs(regionMap) 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 for i=1, #processors do - validNeighbors = processors[i](regionMap, surface, natives, chunk, neighbors, validNeighbors) + validNeighbors = processors[i](regionMap, surface, natives, chunk, neighbors) end count = count + 1 - if (count % 1100 == 0) then + if (count % 1000 == 0) then coroutine.yield() end end diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index b5a0372..c1bc1ba 100755 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -3,21 +3,119 @@ local mapUtils = {} local constants = require("Constants") local mFloor = math.floor -local mMin = math.min -local mMax = math.max +local mAbs = math.abs function mapUtils.getChunkByPosition(regionMap, x, y) local cX = mFloor(x * 0.03125) - if (regionMap[cX] ~= nil) then - return regionMap[cX][mFloor(y * 0.03125)] + local chunkX = regionMap[cX] + if (chunkX ~= nil) then + return chunkX[mFloor(y * 0.03125)] end return nil end -function mapUtils.removeUnitSpawner(regionMap, x, y) - local bases = mapUtils.getChunkByPosition(regionMap, x, y) - if (bases ~= nil) then - bases.bG = mMax(0, bases.bG - 1) +function mapUtils.getChunkByIndex(regionMap, x, y) + local chunkX = regionMap[x] + if (chunkX ~= nil) then + 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 @@ -44,8 +142,37 @@ function mapUtils.getNeighborChunks(regionMap, chunkX, chunkY, neighbors) end xChunks = regionMap[chunkX] - neighbors[2] = xChunks[chunkY-1] - neighbors[7] = xChunks[chunkY+1] + if (xChunks ~= nil) then + 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 return mapUtils \ No newline at end of file diff --git a/libs/PheromoneUtils.lua b/libs/PheromoneUtils.lua index ad8c715..8049695 100755 --- a/libs/PheromoneUtils.lua +++ b/libs/PheromoneUtils.lua @@ -5,82 +5,96 @@ local constants = require("Constants") local mMin = math.min local mFloor = math.floor -function pheromoneUtils.deathScent(regionMap, x, y, amount) - local mathFloor = mFloor - local DEATH_PHEROMONE = constants.DEATH_PHEROMONE +local nearestEnemyPosition = {x=1,y=2} +local nearestTable = {position=nearestEnemyPosition, + 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 - chunk = chunk[mathFloor(y * 0.03125)] - if (chunk ~= nil) then - chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + amount - end + chunk[constants.DEATH_PHEROMONE] = chunk[constants.DEATH_PHEROMONE] + amount end end -function pheromoneUtils.enemyBaseScent(regionMap, surface, natives, chunk, neighbors, validNeighbors) - local BASE_PHEROMONE_PRODUCTION = constants.BASE_PHEROMONE_PRODUCTION - local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE - - local spawners = chunk.bG - if (spawners > 0) then - chunk[ENEMY_BASE_PHEROMONE] = chunk[ENEMY_BASE_PHEROMONE] + (spawners * constants.BASE_PHEROMONE_PRODUCTION) +function pheromoneUtils.playerDefenseScent(regionMap, surface, natives, chunk, neighbors) + local baseScore = chunk[constants.PLAYER_DEFENSE_GENERATOR] + if (baseScore > 0) then + chunk[constants.PLAYER_DEFENSE_PHEROMONE] = chunk[constants.PLAYER_DEFENSE_PHEROMONE] + baseScore + end +end + +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 - return validNeighbors end 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 getChunkByPosition = mapUtils.getChunkByPosition local mathFloor = mFloor for i=1, #players do local playerPosition = players[i].position - local playerChunk = regionMap[mathFloor(playerPosition.x * 0.03125)][mathFloor(playerPosition.y * 0.03125)] - playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + 300 + 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 -function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, neighbors, validNeighbors) - local mathMin = mMin - local getNeighborChunks = mapUtils.getNeighborChunks - local DIFFUSION_AMOUNT = constants.DIFFUSION_AMOUNT - local DEATH_DIFFUSION_AMOUNT = constants.DEATH_DIFFUSION_AMOUNT - local MAX_PHEROMONE = constants.MAX_PHEROMONE +function pheromoneUtils.processPheromone(regionMap, surface, natives, chunk, neighbors) + local STANDARD_PHERONOME_DIFFUSION_AMOUNT = constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT + local DEATH_PHEROMONE_DIFFUSION_AMOUNT = constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT local DEATH_PHEROMONE = constants.DEATH_PHEROMONE + -- local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE - for x=1,3 do - local threshold + for x=1,5 do local diffusionAmount + local persistence if (x == DEATH_PHEROMONE) then - threshold = 125 - diffusionAmount = DEATH_DIFFUSION_AMOUNT + diffusionAmount = DEATH_PHEROMONE_DIFFUSION_AMOUNT + persistence = 0.99 else - threshold = 75 - diffusionAmount = DIFFUSION_AMOUNT + diffusionAmount = STANDARD_PHERONOME_DIFFUSION_AMOUNT + persistence = 0.98 end - if (chunk[x] > threshold) then - if not validNeighbors then - getNeighborChunks(regionMap, chunk.cX, chunk.cY, neighbors) - validNeighbors = true + local totalDiffused = 0 + for i=1,4 do + local neighborChunk = neighbors[i] + if (neighborChunk ~= nil) then + local diffusedAmount = (chunk[x] * diffusionAmount) + totalDiffused = totalDiffused + diffusedAmount + neighborChunk[x] = neighborChunk[x] + diffusedAmount 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 + chunk[x] = chunk[x] - totalDiffused + chunk[x] = chunk[x] * persistence end - return validNeighbors end return pheromoneUtils \ No newline at end of file diff --git a/libs/UnitGroupUtils.lua b/libs/UnitGroupUtils.lua index db4967a..fd69239 100755 --- a/libs/UnitGroupUtils.lua +++ b/libs/UnitGroupUtils.lua @@ -3,6 +3,10 @@ local unitGroupUtils = {} local utils = require("Utils") local constants = require("Constants") +local groupingCommand = {type=defines.command.group, + group=1, + distraction=0} + function unitGroupUtils.findNearBySquad(natives, position, distance, filter) local getDistance = utils.euclideanDistanceNamed local squads = natives.squads @@ -24,20 +28,20 @@ function unitGroupUtils.createSquad(position, surface, natives) local squad = { group = unitGroup, status = constants.SQUAD_GUARDING, - cycles = -1 } + cycles = 0 } natives.squads[#natives.squads+1] = squad return squad end -function unitGroupUtils.membersToSquad(squad, members, overwriteGroup) +function unitGroupUtils.membersToSquad(squad, members, overwriteGroup, distraction) if (members ~= nil) then local group = squad.group for i=1,#members do local member = members[i] if (member ~= nil) and member.valid and (overwriteGroup or (not overwriteGroup and (member.unit_group == nil))) then - member.set_command({type=defines.command.group, - group=group, - distraction=defines.distraction.none}) + groupingCommand.group = group + groupingCommand.distraction = distraction + member.set_command(groupingCommand) end end end @@ -60,7 +64,7 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup) if addUnitGroup then returnSquad = { group = unitGroup, status = constants.SQUAD_GUARDING, - cycles = -1 } + cycles = 0 } squads[#squads+1] = returnSquad end end @@ -68,15 +72,15 @@ function unitGroupUtils.convertUnitGroupToSquad(natives, unitGroup) return returnSquad end -function unitGroupUtils.setSquadCommand(squad, command, state, cycles) - local group = squad.group - if (group ~= nil) and group.valid then - squad.status = state - squad.cycles = cycles - group.set_command(command) +-- function unitGroupUtils.setSquadCommand(squad, command, state, cycles) + -- local group = squad.group + -- if (group ~= nil) and group.valid then + -- squad.status = state + -- squad.cycles = cycles + -- group.set_command(command) -- group.start_moving() - end -end + -- end +-- end function unitGroupUtils.regroupSquads(natives) local SQUAD_RETREATING = constants.SQUAD_RETREATING @@ -92,7 +96,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 (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) mergeGroup.destroy() end diff --git a/libs/Utils.lua b/libs/Utils.lua index afc6b55..5eb1ae1 100755 --- a/libs/Utils.lua +++ b/libs/Utils.lua @@ -1,5 +1,7 @@ local utils = {} +local constants = require("Constants") + function utils.euclideanDistanceNamed(p1, p2) local xs = p1.x - p2.x local ys = p1.y - p2.y @@ -12,4 +14,34 @@ function utils.euclideanDistanceArray(p1, p2) return ((xs * xs) + (ys * ys)) ^ 0.5 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 \ No newline at end of file diff --git a/libs/chunkUtils.lua b/libs/chunkUtils.lua index 6653b96..8ed9eb2 100755 --- a/libs/chunkUtils.lua +++ b/libs/chunkUtils.lua @@ -3,9 +3,15 @@ local chunkUtils = {} local mapUtils = require("MapUtils") local constants = require("Constants") -local natives -local regionMaps -local chunkProcessingQueue +-- optimize table creation and referencing +local areaBoundingBox = {{1,2}, + {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) local NORTH_SOUTH = constants.NORTH_SOUTH @@ -32,6 +38,7 @@ end function chunkUtils.checkChunkPassability(chunk, surface, natives) local checkForDeadendTiles = chunkUtils.checkForDeadendTiles + local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT local NORTH_SOUTH = constants.NORTH_SOUTH local EAST_WEST = constants.EAST_WEST local CHUNK_SIZE = constants.CHUNK_SIZE @@ -55,34 +62,65 @@ function chunkUtils.checkChunkPassability(chunk, surface, natives) end yi = yi + 1 end - if passableNorthSouth and passableEastWest then - chunkUtils.colorChunk(x, y, "grass", surface) - elseif passableNorthSouth then - chunkUtils.colorChunk(x, y, "dirt", surface) - elseif passableEastWest then - chunkUtils.colorChunk(x, y, "sand", surface) - else - chunkUtils.colorChunk(x, y, "concrete", surface) - end + -- if passableNorthSouth and passableEastWest then + -- chunkUtils.colorChunk(x, y, "grass", surface) + -- elseif passableNorthSouth then + -- chunkUtils.colorChunk(x, y, "dirt", surface) + -- elseif passableEastWest then + -- chunkUtils.colorChunk(x, y, "sand", surface) + -- else + -- chunkUtils.colorChunk(x, y, "concrete", surface) + -- end - chunk.eW = passableEastWest - chunk.nS = passableNorthSouth + if passableEastWest then + 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 -local spawnCount = 0 - function chunkUtils.scoreChunk(chunk, surface, natives) + local PLAYER_DEFENSE_PHEROMONES = constants.defensePheromones + local PLAYER_BASE_PHEROMONES = constants.buildingPheromones + local x = chunk.pX local y = chunk.pY - local cX = chunk.cX - local cY = chunk.cY - local CHUNK_SIZE = constants.CHUNK_SIZE + + areaBoundingBox[1][1] = x + 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}, - {x+CHUNK_SIZE, y+CHUNK_SIZE}}, - type="unit-spawner", - force="enemy"}) - chunk.bG = spawners + spawners = entities * constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT + + entities = surface.find_entities_filtered(playerChunkQuery) + + 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 function chunkUtils.createChunk(topX, topY) @@ -92,9 +130,11 @@ function chunkUtils.createChunk(topX, topY) cX = topX * 0.03125, cY = topY * 0.03125 } + chunk[constants.DEATH_PHEROMONE] = 0 chunk[constants.ENEMY_BASE_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 end diff --git a/tests.lua b/tests.lua index 516c1fa..34633d2 100755 --- a/tests.lua +++ b/tests.lua @@ -1,9 +1,13 @@ local tests = {} +local constants = require("libs/Constants") + local regionMap +local natives function tests.initTester() regionMap = global.regionMap + natives = global.natives end function tests.test1() @@ -26,34 +30,25 @@ function tests.test1() end function tests.test2() - local position = game.players[1].position - - local spawners = game.surfaces[1].find_entities_filtered({type="unit-spawner"}) - for i=1, #spawners do - local spawner = spawners[i] - if (spawner ~= nil) and spawner.valid then - spawner.destroy() + for i=1, #natives.squads do + local squad = natives.squads[i] + if squad.group.valid then + print(math.floor(squad.group.position.x * 0.03125), math.floor(squad.group.position.y * 0.03125), squad.status, squad.group.state) 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 --- function test3() - -- local playerPosition = game.players[1].position - -- decayPheromone(regionMaps[1], playerPosition.x, playerPosition.y, 3) --- end +function tests.test3() + local playerPosition = game.players[1].position + local chunkX = math.floor(playerPosition.x * 0.03125) * 32 + 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 \ No newline at end of file