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:
69
control.lua
69
control.lua
@@ -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
|
||||||
})
|
})
|
||||||
|
148
libs/AI.lua
148
libs/AI.lua
@@ -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
151
libs/AIAttack.lua
Executable 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
30
libs/AIBuilding.lua
Executable 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
83
libs/AIDefense.lua
Executable 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
|
@@ -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
|
||||||
|
]]--
|
@@ -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
|
||||||
|
@@ -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
|
@@ -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
|
@@ -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
|
||||||
|
@@ -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
|
@@ -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
|
||||||
|
|
||||||
|
45
tests.lua
45
tests.lua
@@ -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
|
Reference in New Issue
Block a user