1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-14 02:23:01 +02:00

see changelog 0.14.4

This commit is contained in:
Aaron Veden 2016-10-14 17:00:18 -07:00
parent 04c184078d
commit d989322407
20 changed files with 578 additions and 452 deletions

1
.gitignore vendored
View File

@ -47,3 +47,4 @@ luac.out
*.dumpjump *.dumpjump
/.emacs.desktop /.emacs.desktop
/.emacs.desktop.lock /.emacs.desktop.lock
/README.html

View File

@ -7,6 +7,7 @@ https://forums.factorio.com/viewtopic.php?f=94&t=31445
# Notes # Notes
0.14.14 factorio version fixed save corruption
0.14.10 factorio version fixed more pathing issues 0.14.10 factorio version fixed more pathing issues
0.14.4 factorio version fixed some issues with unit groups commands 0.14.4 factorio version fixed some issues with unit groups commands
@ -33,36 +34,56 @@ Base Expansion
# Version History # Version History
0.14.3 - slightly lowered Rampant attack wave frequency 0.14.4 -
Altered attack wave size to ramp up slower - Fixed a bug in the processing queue when upgrading mod
Added configuration options for: - Greatly decreased Player pheromone radius, now sits at roughly 4 chunks around the player
attack wave generation area - Reworked pheromone pathfinding
attack wave threshold - Removed base and defense attack wave trigger, in favor of using player pheromone and pollution
attack wave size - Added periods of time where the enemy is not sending Rampant attack waves
turn off rampant attack waves - Adjusted retreat percentage to suit the reduced attack wave size
- Improved responsiveness on larger maps
- Reduced AI max build points
- Fixed player iteration bug
0.14.2 - adjusted unit retreat group size threshold 0.14.3 -
adjusted squad attack pattern (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=20#p203861) - Slightly lowered Rampant attack wave frequency
Fixed migration issue - Altered attack wave size to ramp up slower
- Added configuration options for:
- - Attack wave generation area
- - Attack wave threshold
- - Attack wave size
- - Turn off rampant attack waves
0.14.1 - fixed ai created bases not being counted in logic 0.14.2 -
Optimization to offset ai created bases scanning - Adjusted unit retreat group size threshold
- Adjusted squad attack pattern (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=20#p203861)
- Fixed migration issue
0.14.1 -
- Fixed ai created bases not being counted in logic
- Optimization to offset ai created bases scanning
0.13.4 = 0.14.4
0.13.3 = 0.14.3 0.13.3 = 0.14.3
0.13.2 = 0.14.2 0.13.2 = 0.14.2
0.13.1 - backported 0.14 factorio version to 0.13 factorio version 0.13.1 - Backported 0.14 factorio version to 0.13 factorio version
0.0.8 - fixed retreat oscillations (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=10#p198750) 0.0.8 -
added scaling for kamikaze attack (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=10#p199401) - Fixed retreat oscillations (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=10#p198750)
increased squad size max from 125 to 150, (larger waves) - Added scaling for kamikaze attack (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=10#p199401)
- Increased squad size max from 125 to 150, (larger waves)
0.0.6 - some speed improvements 0.0.6 -
MP is working (https://github.com/veden/Rampant/issues/1) - Some speed improvements
- MP is working (https://github.com/veden/Rampant/issues/1)
0.0.5 - fix for nil chunk in ai attack (https://mods.factorio.com/mods/Veden/Rampant/discussion/2512) 0.0.5 -
checks for main surface (https://forums.factorio.com/viewtopic.php?f=94&t=31445&p=198228#p198563) - Fix for nil chunk in ai attack (https://mods.factorio.com/mods/Veden/Rampant/discussion/2512)
updated info with forum homepage - Xhecks for main surface (https://forums.factorio.com/viewtopic.php?f=94&t=31445&p=198228#p198563)
- Updated info with forum homepage
0.0.4 - initial release 0.0.4 - initial release

View File

@ -4,29 +4,37 @@ local config = {}
the attackWaveGenerationUse* options are used to score chunks with biter nests that will generate a Rampant attack wave. the attackWaveGenerationUse* options are used to score chunks with biter nests that will generate a Rampant attack wave.
Pollution, the vanilla pollution mechanic (shown on the minimap). Pollution, the vanilla pollution mechanic (shown on the minimap).
Player Proximity, if a player moves near a biter nest there is a chance for the nest to spawn attack waves (not shown on the minimap). Player Proximity, if a player moves near a biter nest there is a chance for the nest to spawn attack waves (not shown on the minimap).
Player Base Proximity, if the player builds near biters nest there is a chance for the nest to spawn attack waves (not shown on the minimap). switching all to false will turn off Rampant biter waves
Player Defense Proximity, if the player builds defense near biters nest there is a chance for the nest to spawn attack waves (not shown on the minimap). DOES NOT affect vanilla biters waves
switching all to false will turn off Rampant biter waves, does not turn off vanilla biter waves.
--]] --]]
config.attackWaveGenerationUsePollution = true config.attackWaveGenerationUsePollution = true
config.attackWaveGenerationUsePlayerProximity = true config.attackWaveGenerationUsePlayerProximity = true
config.attackWaveGenerationUsePlayerBaseProximity = true
config.attackWaveGenerationUsePlayerDefenseProximity = true
--[[ --[[
attackWaveGenerationThreshold is the score that the attackWaveGenerationUse* has to reach in order for an attack wave to spawn. attackWaveGenerationThreshold is the score that the attackWaveGenerationUse* has to reach in order for an attack wave to spawn.
increasing this will reduce the radius of attack wave generation. increasing this will reduce the radius of attack wave generation.
default number is 70 DOES NOT affect vanilla biters waves
scaling linearly with evolution factor
starts 20 @ 0.0 evolution
ends 0 @ 100.0 evolution
default max is 20
default min is 00
--]] --]]
config.attackWaveGenerationThreshold = 70 config.attackWaveGenerationThresholdMax = 20
config.attackWaveGenerationThresholdMin = 0
--[[
attackWaveMaxSize is the largest size that can be initially spawned by Rampant
--]]
config.attackWaveMaxSize = 150
--[[ --[[
attackWaveScaling is used to calculate the attack wave size from the evolutionFactor attackWaveScaling is used to calculate the attack wave size from the evolutionFactor
default is 150 * (evolutionFactor ^ 1.666667) default is config.attackWaveMaxSize * (evolutionFactor ^ 1.666667)
150 is the max group size DOES NOT affect vanilla biters waves
--]] --]]
config.attackWaveScaling = function (evolutionFactor) config.attackWaveScaling = function (evolutionFactor)
return math.ceil(150 * (evolutionFactor ^ 1.666667)) return math.ceil(config.attackWaveMaxSize * (evolutionFactor ^ 1.666667))
end end
return config return config

View File

@ -9,20 +9,27 @@ local pheromoneUtils = require("libs/PheromoneUtils")
local aiDefense = require("libs/AIDefense") local aiDefense = require("libs/AIDefense")
local aiAttack = require("libs/AIAttack") local aiAttack = require("libs/AIAttack")
local aiBuilding = require("libs/AIBuilding") local aiBuilding = require("libs/AIBuilding")
local aiPlanning = require("libs/AIPlanning")
local mathUtils = require("libs/MathUtils")
local tests = require("tests") local tests = require("tests")
-- constants
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
-- imported functions -- imported functions
local processPendingChunks = chunkProcessor.processPendingChunks local processPendingChunks = chunkProcessor.processPendingChunks
local processMap = mapProcessor.processMap local processMap = mapProcessor.processMap
local processPlayers = mapProcessor.processPlayers
local scanMap = mapProcessor.scanMap local scanMap = mapProcessor.scanMap
local accumulatePoints = aiBuilding.accumulatePoints local planning = aiPlanning.planning
local removeScout = aiBuilding.removeScout local removeScout = aiBuilding.removeScout
-- local scouting = aiBuilding.scouting -- local scouting = aiBuilding.scouting
local playerScent = pheromoneUtils.playerScent
local deathScent = pheromoneUtils.deathScent local deathScent = pheromoneUtils.deathScent
local regroupSquads = unitGroupUtils.regroupSquads local regroupSquads = unitGroupUtils.regroupSquads
@ -35,6 +42,8 @@ local retreatUnits = aiDefense.retreatUnits
local addRemoveEntity = entityUtils.addRemoveEntity local addRemoveEntity = entityUtils.addRemoveEntity
local roundToNearest = mathUtils.roundToNearest
-- local references to global -- local references to global
local regionMap local regionMap
@ -44,11 +53,9 @@ local pendingChunks
-- hook functions -- hook functions
local function onLoad() local function onLoad()
-- print("load")
regionMap = global.regionMap regionMap = global.regionMap
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks pendingChunks = global.pendingChunks
-- pheromoneTotals = global.pheromoneTotals
end end
local function onChunkGenerated(event) local function onChunkGenerated(event)
@ -60,7 +67,6 @@ local function onChunkGenerated(event)
end end
local function onConfigChanged() local function onConfigChanged()
-- print("reprocess")
if (global.version == nil) then if (global.version == nil) then
-- removed in version 9 -- removed in version 9
@ -84,11 +90,6 @@ local function onConfigChanged()
regionMap.pP = nil regionMap.pP = nil
regionMap.pR = nil regionMap.pR = nil
regionMap.processQueue = {}
regionMap.processPointer = 1
regionMap.scanPointer = 1
regionMap.processRoll = -1
global.version = constants.VERSION_9 global.version = constants.VERSION_9
end end
if (global.version < constants.VERSION_10) then if (global.version < constants.VERSION_10) then
@ -98,40 +99,64 @@ local function onConfigChanged()
squad.rabid = false squad.rabid = false
end end
-- queue all current chunks that wont be generated during play
local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
onChunkGenerated({ surface = surface,
area = { left_top = { x = chunk.x * 32,
y = chunk.y * 32 }}})
end
global.version = constants.VERSION_10 global.version = constants.VERSION_10
end end
if (global.version < constants.VERSION_11) then
for _,squad in pairs(natives.squads) do
squad.status = constants.SQUAD_GUARDING
end
natives.state = constants.AI_STATE_AGGRESSIVE
natives.temperament = 0
-- needs to be on inner logic tick loop interval
natives.stateTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
natives.temperamentTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
-- clear old regionMap processing Queue
-- prevents queue adding duplicate chunks
-- chunks are by key, so should overwrite old
regionMap.processQueue = {}
regionMap.processPointer = 1
regionMap.scanPointer = 1
-- clear pending chunks, will be added when loop runs below
pendingChunks = {}
-- queue all current chunks that wont be generated during play
local surface = game.surfaces[1]
for chunk in surface.get_chunks() do
onChunkGenerated({ surface = surface,
area = { left_top = { x = chunk.x * 32,
y = chunk.y * 32 }}})
end
global.version = constants.VERSION_11
end
end end
local function onTick(event) local function onTick(event)
if (event.tick % 20 == 0) then if (event.tick % INTERVAL_PROCESS == 0) then
local surface = game.surfaces[1] local surface = game.surfaces[1]
local evolutionFactor = game.evolution_factor
local players = game.players
processPendingChunks(regionMap, surface, pendingChunks) processPendingChunks(regionMap, surface, pendingChunks)
scanMap(regionMap, surface) scanMap(regionMap, surface)
if (event.tick % 40 == 0) then if (event.tick % INTERVAL_LOGIC == 0) then
local tick = game.tick
planning(natives, evolutionFactor, tick)
accumulatePoints(natives) regroupSquads(natives)
-- put down player pheromone for player hunters processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
playerScent(regionMap, game.players)
regroupSquads(natives) -- scouting(regionMap, natives)
-- scouting(regionMap, natives) squadBeginAttack(natives, players, evolutionFactor)
squadAttack(regionMap, surface, natives)
end
squadBeginAttack(natives, game.players, game.evolution_factor) processMap(regionMap, surface, natives, evolutionFactor)
squadAttack(regionMap, surface, natives)
end
processMap(regionMap, surface, natives, game.evolution_factor)
end end
end end
@ -181,16 +206,13 @@ local function onSurfaceTileChange(event)
end end
local function onInit() local function onInit()
-- print("init")
global.regionMap = {} global.regionMap = {}
global.pendingChunks = {} global.pendingChunks = {}
global.natives = {} global.natives = {}
-- global.pheromoneTotals = {}
regionMap = global.regionMap regionMap = global.regionMap
natives = global.natives natives = global.natives
pendingChunks = global.pendingChunks pendingChunks = global.pendingChunks
-- pheromoneTotals = global.pheromoneTotals
onConfigChanged() onConfigChanged()
end end
@ -216,15 +238,15 @@ script.on_event(defines.events.on_tick, onTick)
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, test3 = tests.test3,
test4 = tests.test4, test4 = tests.test4,
test5 = tests.test5, test5 = tests.test5,
test6 = tests.test6, test6 = tests.test6,
test7 = tests.test7, test7 = tests.test7,
test8 = tests.test8, test8 = tests.test8,
test9 = tests.test9, test9 = tests.test9,
test10 = tests.test10, test10 = tests.test10,
test11 = tests.test11 test11 = tests.test11
}) })

View File

@ -1,7 +1,7 @@
{ {
"name" : "Rampant", "name" : "Rampant",
"factorio_version" : "0.14", "factorio_version" : "0.14",
"version" : "0.14.3", "version" : "0.14.4",
"title" : "Rampant AI", "title" : "Rampant AI",
"author" : "Veden", "author" : "Veden",
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",

View File

@ -7,29 +7,26 @@ local mapUtils = require("MapUtils")
local unitGroupUtils = require("UnitGroupUtils") local unitGroupUtils = require("UnitGroupUtils")
local playerUtils = require("PlayerUtils") local playerUtils = require("PlayerUtils")
local neighborUtils = require("NeighborUtils") local neighborUtils = require("NeighborUtils")
package.path = "../?.lua;" .. package.path
local config = require("config")
-- constants -- constants
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
--local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
local SQUAD_RAIDING = constants.SQUAD_RAIDING local SQUAD_RAIDING = constants.SQUAD_RAIDING
local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID
local SQUAD_HUNTING = constants.SQUAD_HUNTING
local SQUAD_GUARDING = constants.SQUAD_GUARDING local SQUAD_GUARDING = constants.SQUAD_GUARDING
local SQUAD_SUICIDE_HUNT = constants.SQUAD_SUICIDE_HUNT
--local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
--local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
--local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
--local CHUNK_SIZE = constants.CHUNK_SIZE
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
local NO_RETREAT_BASE_PERCENT = constants.NO_RETREAT_BASE_PERCENT
local NO_RETREAT_EVOLUTION_BONUS_MAX = constants.NO_RETREAT_EVOLUTION_BONUS_MAX
local NO_RETREAT_SQUAD_SIZE_BONUS_MAX = constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX
local CONFIG_ATTACK_WAVE_MAX_SIZE = config.attackWaveMaxSize
-- imported functions -- imported functions
@ -46,7 +43,7 @@ local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPos
local scoreNeighborsWithDirection = neighborUtils.scoreNeighborsWithDirection local scoreNeighborsWithDirection = neighborUtils.scoreNeighborsWithDirection
local mLog = math.log10
-- module code -- module code
@ -56,16 +53,8 @@ end
local function scoreAttackLocation(position, squad, neighborChunk, surface) local function scoreAttackLocation(position, squad, neighborChunk, surface)
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY) local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
local damageScore = surface.get_pollution(position) + neighborChunk[PLAYER_BASE_PHEROMONE] + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_GENERATOR] local r = surface.get_pollution(position) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + neighborChunk[PLAYER_PHEROMONE]
local avoidScore = neighborChunk[DEATH_PHEROMONE] + neighborChunk[ENEMY_BASE_PHEROMONE] return r - squadMovementPenalty
return damageScore - avoidScore - squadMovementPenalty
end
local function scoreHuntPlayerLocation(position, squad, neighborChunk, surface)
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
local damageScore = neighborChunk[PLAYER_PHEROMONE]
local avoidScore = neighborChunk[DEATH_PHEROMONE] + neighborChunk[ENEMY_BASE_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_GENERATOR]
return damageScore - avoidScore - squadMovementPenalty
end end
function aiAttack.squadAttack(regionMap, surface, natives) function aiAttack.squadAttack(regionMap, surface, natives)
@ -82,17 +71,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
for i=1,#squads do for i=1,#squads do
local squad = squads[i] local squad = squads[i]
local group = squad.group local group = squad.group
local raiding = false if group.valid and ((squad.status == SQUAD_RAIDING) or (squad.status == SQUAD_SUICIDE_RAID)) then
local hunting = false
local scoreLocation
if (squad.status == SQUAD_RAIDING) or (squad.status == SQUAD_SUICIDE_RAID) then
raiding = true
scoreLocation = scoreAttackLocation
elseif (squad.status == SQUAD_HUNTING) or (squad.status == SQUAD_SUICIDE_HUNT) then
hunting = true
scoreLocation = scoreHuntPlayerLocation
end
if group.valid and (raiding or hunting) then
if (group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering) or ((group.state == defines.group_state.moving) and (squad.cycles == 0)) then if (group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering) or ((group.state == defines.group_state.moving) and (squad.cycles == 0)) then
local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y) local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y)
if (chunk ~= nil) then if (chunk ~= nil) then
@ -100,15 +79,15 @@ function aiAttack.squadAttack(regionMap, surface, natives)
local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk, local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk,
getCardinalChunksWithDirection(regionMap, chunk.cX, chunk.cY), getCardinalChunksWithDirection(regionMap, chunk.cX, chunk.cY),
validLocation, validLocation,
scoreLocation, scoreAttackLocation,
squad, squad,
surface, surface,
attackPosition) attackPosition)
if (attackChunk ~= nil) then if (attackChunk ~= nil) then
if ((attackChunk[PLAYER_BASE_GENERATOR] == 0) and (attackChunk[PLAYER_DEFENSE_GENERATOR] == 0)) or if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then ((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
positionFromDirectionAndChunkCardinal(attackDirection, squad.group.position, attackPosition) positionFromDirectionAndChunkCardinal(attackDirection, squad.group.position, attackPosition)
squad.cycles = 3 squad.cycles = 3
@ -122,14 +101,14 @@ function aiAttack.squadAttack(regionMap, surface, natives)
attackCmd.distraction = defines.distraction.by_enemy attackCmd.distraction = defines.distraction.by_enemy
end end
group.set_command(attackCmd) group.set_command(attackCmd)
group.start_moving() group.start_moving()
elseif not squad.frenzy and not squad.rabid and elseif not squad.frenzy and not squad.rabid and
(((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_distraction)) or ((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_distraction) or
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0) or (attackChunk[PLAYER_DEFENSE_GENERATOR] ~= 0)) then (attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
squad.frenzy = true squad.frenzy = true
squad.frenzyPosition.x = squad.group.position.x squad.frenzyPosition.x = squad.group.position.x
squad.frenzyPosition.y = squad.group.position.y squad.frenzyPosition.y = squad.group.position.y
end end
end end
end end
@ -143,7 +122,10 @@ function aiAttack.squadBeginAttack(natives, players, evolution_factor)
for i=1,#squads do for i=1,#squads do
local squad = squads[i] local squad = squads[i]
if (squad.status == SQUAD_GUARDING) and squad.group.valid then if (squad.status == SQUAD_GUARDING) and squad.group.valid then
local threshold = 0.05 + (evolution_factor * 0.20) + (#squad.group.members * 0.0033) local threshold = NO_RETREAT_BASE_PERCENT + (evolution_factor * NO_RETREAT_EVOLUTION_BONUS_MAX)
local a = (#squad.group.members / CONFIG_ATTACK_WAVE_MAX_SIZE) ^ 1.4
local squadSizeBonus = mLog(a + 0.1) + 1
threshold = threshold + (NO_RETREAT_SQUAD_SIZE_BONUS_MAX * squadSizeBonus)
local playerNearby = playersWithinProximityToPosition(players, squad.group.position, 100) local playerNearby = playersWithinProximityToPosition(players, squad.group.position, 100)
if playerNearby then if playerNearby then
@ -152,24 +134,15 @@ function aiAttack.squadBeginAttack(natives, players, evolution_factor)
squad.frenzyPosition.y = squad.group.position.y squad.frenzyPosition.y = squad.group.position.y
end end
-- check to hunt player -- check to raid base
if (math.random() < 0.30) and playerNearby then if (math.random() < 0.70) then
if (math.random() < threshold) then
squad.status = SQUAD_SUICIDE_HUNT
else
squad.status = SQUAD_HUNTING
end
end
-- check to raid base
if (squad.status == SQUAD_GUARDING) and (math.random() < 0.70) then
if (math.random() < threshold) then if (math.random() < threshold) then
squad.status = SQUAD_SUICIDE_RAID squad.status = SQUAD_SUICIDE_RAID
else else
squad.status = SQUAD_RAIDING squad.status = SQUAD_RAIDING
end end
end end
end end
end end
end end

View File

@ -11,42 +11,26 @@ local config = require("config")
-- constants -- constants
-- local SQUAD_GUARDING = constants.SQUAD_GUARDING local BASE_PHEROMONE = constants.BASE_PHEROMONE
-- local SQUAD_BURROWING = constants.SQUAD_BURROWING
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
-- local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
local AI_POINT_GENERATOR_AMOUNT = constants.AI_POINT_GENERATOR_AMOUNT
local AI_MAX_POINTS = constants.AI_MAX_POINTS
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
-- local AI_SCOUT_COST = constants.AI_SCOUT_COST
local AI_SQUAD_COST = constants.AI_SQUAD_COST
-- local AI_TUNNEL_COST = constants.AI_TUNNEL_COST
local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT local AI_MAX_SQUAD_COUNT = constants.AI_MAX_SQUAD_COUNT
local AI_SQUAD_COST = constants.AI_SQUAD_COST
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
local CHUNK_SIZE = constants.CHUNK_SIZE local CHUNK_SIZE = constants.CHUNK_SIZE
-- local MAGIC_MAXIMUM_NUMBER = constants.MAGIC_MAXIMUM_NUMBER
local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE local EAST_WEST_PASSABLE = constants.EAST_WEST_PASSABLE
-- local COMMAND_GROUP = defines.command.group
-- local DISTRACTION_BY_DAMAGE = defines.distraction.by_damage
local CONFIG_USE_PLAYER_PROXIMITY = config.attackWaveGenerationUsePlayerProximity local CONFIG_USE_PLAYER_PROXIMITY = config.attackWaveGenerationUsePlayerProximity
local CONFIG_USE_PLAYER_BASE_PROXIMITY = config.attackWaveGenerationUsePlayerBaseProximity
local CONFIG_USE_PLAYER_DEFENSE_PROXIMITY = config.attackWaveGenerationUsePlayerDefenseProximity
local CONFIG_USE_POLLUTION_PROXIMITY = config.attackWaveGenerationUsePollution local CONFIG_USE_POLLUTION_PROXIMITY = config.attackWaveGenerationUsePollution
local CONFIG_USE_THRESHOLD = config.attackWaveGenerationThreshold local CONFIG_USE_THRESHOLD_MIN = config.attackWaveGenerationThresholdMin
local CONFIG_USE_THRESHOLD_MAX = config.attackWaveGenerationThresholdMax
local CONFIG_USE_THRESHOLD_RANGE = CONFIG_USE_THRESHOLD_MAX - CONFIG_USE_THRESHOLD_MIN
-- imported functions -- imported functions
@ -55,25 +39,23 @@ local scoreNeighbors = neighborUtils.scoreNeighbors
local createSquad = unitGroupUtils.createSquad local createSquad = unitGroupUtils.createSquad
local attackWaveScaling = config.attackWaveScaling local attackWaveScaling = config.attackWaveScaling
local mMax = math.max
-- module code -- module code
local function attackWaveValidCandidate(chunk, surface) local function attackWaveValidCandidate(chunk, surface, evolutionFactor)
local total = 0; local total = 0;
if CONFIG_USE_PLAYER_PROXIMITY then if CONFIG_USE_PLAYER_PROXIMITY then
total = total + chunk[PLAYER_PHEROMONE] total = total + chunk[PLAYER_PHEROMONE]
end end
if CONFIG_USE_PLAYER_BASE_PROXIMITY then
total = total + chunk[PLAYER_BASE_PHEROMONE]
end
if CONFIG_USE_PLAYER_DEFENSE_PROXIMITY then
total = total + chunk[PLAYER_DEFENSE_PHEROMONE]
end
if CONFIG_USE_POLLUTION_PROXIMITY then if CONFIG_USE_POLLUTION_PROXIMITY then
total = total + surface.get_pollution({chunk.pX, chunk.pY}) total = total + surface.get_pollution({chunk.pX, chunk.pY})
end end
if (total >= CONFIG_USE_THRESHOLD) then local delta = CONFIG_USE_THRESHOLD_RANGE * evolutionFactor
if (total > (CONFIG_USE_THRESHOLD_MAX - delta)) then
return true return true
else else
return false return false
@ -81,21 +63,13 @@ local function attackWaveValidCandidate(chunk, surface)
end end
local function scoreUnitGroupLocation(position, squad, neighborChunk, surface) local function scoreUnitGroupLocation(position, squad, neighborChunk, surface)
local attackScore = surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_PHEROMONE] return surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
local avoidScore = neighborChunk[DEATH_PHEROMONE]
return attackScore - avoidScore
end end
local function validUnitGroupLocation(x, chunk, neighborChunk) local function validUnitGroupLocation(x, chunk, neighborChunk)
return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE] return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE]
end end
function aiBuilding.accumulatePoints(natives)
if (natives.points < AI_MAX_POINTS) then
natives.points = natives.points + math.floor(AI_POINT_GENERATOR_AMOUNT * math.random())
end
end
function aiBuilding.removeScout(entity, natives) function aiBuilding.removeScout(entity, natives)
--[[ --[[
local scouts = natives.scouts local scouts = natives.scouts
@ -142,12 +116,10 @@ function aiBuilding.scouting(regionMap, natives)
--]] --]]
end end
function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor) function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor)
if (natives.points > AI_SQUAD_COST) and (chunk[ENEMY_BASE_GENERATOR] ~= 0) and (#natives.squads < (AI_MAX_SQUAD_COUNT * evolution_factor)) then if (natives.points > AI_SQUAD_COST) and (chunk[ENEMY_BASE_GENERATOR] ~= 0) and (#natives.squads < (AI_MAX_SQUAD_COUNT * evolution_factor)) then
local valid = attackWaveValidCandidate(chunk, surface) local valid = attackWaveValidCandidate(chunk, surface, evolution_factor)
if valid and (math.random() < 0.03) then if valid and (math.random() < mMax((0.25 * evolution_factor), 0.10)) then
local squadPosition = {x=0, y=0} local squadPosition = {x=0, y=0}
local squadPath, squadScore = scoreNeighbors(chunk, local squadPath, squadScore = scoreNeighbors(chunk,
getNeighborChunks(regionMap, chunk.cX, chunk.cY), getNeighborChunks(regionMap, chunk.cX, chunk.cY),

View File

@ -9,12 +9,11 @@ local neighborUtils = require("NeighborUtils")
-- constants -- constants
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
local RETREAT_DEATH_PHEROMONE_LEVEL = constants.RETREAT_DEATH_PHEROMONE_LEVEL local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
@ -46,14 +45,14 @@ local function validRetreatLocation(x, chunk, neighborChunk)
end end
local function scoreRetreatLocation(position, squad, neighborChunk, surface) local function scoreRetreatLocation(position, squad, neighborChunk, surface)
local safeScore = neighborChunk[ENEMY_BASE_PHEROMONE] local safeScore = -neighborChunk[BASE_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE]
local dangerScore = neighborChunk[DEATH_PHEROMONE] + surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_PHEROMONE] + (neighborChunk[ENEMY_BASE_GENERATOR] * 6) local dangerScore = surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + (neighborChunk[ENEMY_BASE_GENERATOR] * 6)
return safeScore - dangerScore return safeScore - dangerScore
end end
function aiDefense.retreatUnits(position, squad, regionMap, surface, natives) function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
local chunk = getChunkByPosition(regionMap, position.x, position.y) local chunk = getChunkByPosition(regionMap, position.x, position.y)
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > (game.evolution_factor * RETREAT_DEATH_PHEROMONE_LEVEL)) then if (chunk ~= nil) and (chunk[MOVEMENT_PHEROMONE] > -(game.evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
local performRetreat = false local performRetreat = false
local enemiesToSquad local enemiesToSquad

51
libs/AIPlanning.lua Normal file
View File

@ -0,0 +1,51 @@
local aiPlanning = {}
-- imports
local constants = require("Constants")
local mathUtils = require("MathUtils")
-- constants
local AI_STATE_PEACEFUL = constants.AI_STATE_PEACEFUL
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
local AI_MAX_POINTS = constants.AI_MAX_POINTS
local AI_POINT_GENERATOR_AMOUNT = constants.AI_POINT_GENERATOR_AMOUNT
local AI_MIN_STATE_DURATION = constants.AI_MIN_STATE_DURATION
local AI_MIN_TEMPERAMENT_DURATION = constants.AI_MIN_TEMPERAMENT_DURATION
local AI_MAX_STATE_DURATION = constants.AI_MAX_STATE_DURATION
local AI_MAX_TEMPERAMENT_DURATION = constants.AI_MAX_TEMPERAMENT_DURATION
-- imported functions
local randomTickEvent = mathUtils.randomTickEvent
local mMax = math.max
-- module code
function aiPlanning.planning(natives, evolution_factor, tick)
local maxPoints = AI_MAX_POINTS * evolution_factor
if (natives.points < maxPoints) then
natives.points = natives.points + math.floor(AI_POINT_GENERATOR_AMOUNT * math.random())
end
if (natives.temperamentTick == tick) then
natives.temperament = math.random()
natives.temperamentTick = randomTickEvent(tick, AI_MIN_TEMPERAMENT_DURATION, AI_MAX_TEMPERAMENT_DURATION)
end
if (natives.stateTick == tick) then
local roll = math.random() * mMax(1 - evolution_factor, 0.15)
if (roll > natives.temperament) then
natives.state = AI_STATE_PEACEFUL
else
natives.state = AI_STATE_AGGRESSIVE
end
natives.stateTick = randomTickEvent(tick, AI_MIN_STATE_DURATION, AI_MAX_STATE_DURATION)
end
end
return aiPlanning

View File

@ -13,6 +13,7 @@ local scoreChunk = chunkUtils.scoreChunk
-- module code -- module code
function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack) function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
local processQueue = regionMap.processQueue
for _=#pendingStack, 1, -1 do for _=#pendingStack, 1, -1 do
local event = pendingStack[#pendingStack] local event = pendingStack[#pendingStack]
@ -29,8 +30,6 @@ function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
checkChunkPassability(chunk, surface) checkChunkPassability(chunk, surface)
scoreChunk(chunk, surface) scoreChunk(chunk, surface)
local processQueue = regionMap.processQueue
processQueue[#processQueue+1] = chunk processQueue[#processQueue+1] = chunk
end end
end end

View File

@ -2,22 +2,15 @@ local chunkUtils = {}
-- imports -- imports
-- local mapUtils = require("MapUtils")
local constants = require("Constants") local constants = require("Constants")
-- constants -- constants
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local DEFENSE_PHEROMONES = constants.DEFENSE_PHEROMONES
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
@ -29,6 +22,8 @@ local NORTH_SOUTH_PASSABLE = constants.NORTH_SOUTH_PASSABLE
local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
local CHUNK_TICK = constants.CHUNK_TICK
-- module code -- module code
function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface) function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface)
@ -85,7 +80,6 @@ function chunkUtils.scoreChunk(chunk, surface)
local entities = surface.count_entities_filtered(enemyChunkQuery) local entities = surface.count_entities_filtered(enemyChunkQuery)
local playerObjects = 0 local playerObjects = 0
local playerDefenses = 0
chunk[ENEMY_BASE_GENERATOR] = entities * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT chunk[ENEMY_BASE_GENERATOR] = entities * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
@ -94,44 +88,41 @@ function chunkUtils.scoreChunk(chunk, surface)
for i=1, #entities do for i=1, #entities do
local entityType = entities[i].type local entityType = entities[i].type
local entityScore = DEFENSE_PHEROMONES[entityType] local entityScore = BUILDING_PHEROMONES[entityType]
if (entityScore ~= nil) then
playerDefenses = playerDefenses + entityScore
end
entityScore = BUILDING_PHEROMONES[entityType]
if (entityScore ~= nil) then if (entityScore ~= nil) then
playerObjects = playerObjects + entityScore playerObjects = playerObjects + entityScore
end end
end end
chunk[PLAYER_BASE_GENERATOR] = playerObjects chunk[PLAYER_BASE_GENERATOR] = playerObjects
chunk[PLAYER_DEFENSE_GENERATOR] = playerDefenses
end end
function chunkUtils.createChunk(topX, topY) function chunkUtils.createChunk(topX, topY)
local chunk = { local chunk = {
pX = topX, pX = topX,
pY = topY, pY = topY,
cX = topX * 0.03125, cX = topX * 0.03125,
cY = topY * 0.03125 cY = topY * 0.03125
} }
chunk[DEATH_PHEROMONE] = 0
chunk[ENEMY_BASE_PHEROMONE] = 0
chunk[PLAYER_PHEROMONE] = 0
chunk[PLAYER_BASE_PHEROMONE] = 0
chunk[PLAYER_DEFENSE_PHEROMONE] = 0
chunk[MOVEMENT_PHEROMONE] = 0 chunk[MOVEMENT_PHEROMONE] = 0
chunk[BASE_PHEROMONE] = 0
chunk[PLAYER_PHEROMONE] = 0
chunk[ENEMY_BASE_GENERATOR] = 0
chunk[PLAYER_BASE_GENERATOR] = 0
chunk[NORTH_SOUTH_PASSABLE] = false
chunk[EAST_WEST_PASSABLE] = false
chunk[CHUNK_TICK] = 0
return chunk return chunk
end end
-- function chunkUtils.colorChunk(x, y, tileType, surface) -- function chunkUtils.colorChunk(x, y, tileType, surface)
-- local tiles = {} -- local tiles = {}
-- for xi=x+5, x + 27 do -- for xi=x+5, x + 27 do
-- for yi=y+5, y + 27 do -- for yi=y+5, y + 27 do
-- tiles[#tiles+1] = {name=tileType, position={xi, yi}} -- tiles[#tiles+1] = {name=tileType, position={xi, yi}}
-- end -- end
-- end -- end
-- surface.set_tiles(tiles, false) -- surface.set_tiles(tiles, false)
-- end -- end
return chunkUtils return chunkUtils

View File

@ -5,44 +5,49 @@ local constants = {}
constants.VERSION_5 = 5 constants.VERSION_5 = 5
constants.VERSION_9 = 9 constants.VERSION_9 = 9
constants.VERSION_10 = 10 constants.VERSION_10 = 10
constants.VERSION_11 = 11
-- misc -- misc
constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest/highest score constants.MAGIC_MAXIMUM_NUMBER = 1e99 -- used in loops trying to find the lowest/highest score
constants.RETREAT_DEATH_PHEROMONE_LEVEL = 10000 constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL = 10000
constants.PROCESS_QUEUE_SIZE = 350 constants.PROCESS_QUEUE_SIZE = 500
constants.SCAN_QUEUE_SIZE = 10 constants.SCAN_QUEUE_SIZE = 10
constants.PROCESS_PLAYER_BOUND = 3
-- temps constants.TICKS_A_SECOND = 60
constants.TICKS_A_MINUTE = constants.TICKS_A_SECOND * 60
-- constants.ATTACK_POSITION = 1 constants.INTERVAL_PROCESS = 20
-- constants.ATTACK_COMMAND = 2 constants.INTERVAL_LOGIC = 40
-- constants.ATTACK_DIRECTION = 3
-- constants.GROUP_COMMAND = 4
-- constants.SQUAD_POSITION = 5
-- constants.RETREAT_POSITION = 6
-- constants.RETREAT_NEIGHBORS_WITH_DIRECTION = 7
-- -- constants.RETREAT_COMMAND = 8
-- constants.MULTI_GROUP_COMMAND = 8
-- ai -- ai
constants.AI_POINT_GENERATOR_AMOUNT = 6 constants.AI_POINT_GENERATOR_AMOUNT = 6
constants.AI_SCOUT_COST = 45 constants.AI_SCOUT_COST = 45
constants.AI_SQUAD_COST = 150 constants.AI_SQUAD_COST = 175
constants.AI_SETTLER_COST = 75 constants.AI_SETTLER_COST = 75
constants.AI_BASE_BUILDING_COST = 500 constants.AI_BASE_BUILDING_COST = 500
constants.AI_TUNNEL_COST = 100 constants.AI_TUNNEL_COST = 100
constants.AI_MAX_POINTS = 30000 constants.AI_MAX_POINTS = 10000
--constants.AI_MAX_SQUAD_SIZE = 150
constants.AI_MAX_SQUAD_COUNT = 30 constants.AI_MAX_SQUAD_COUNT = 30
constants.AI_STATE_PEACEFUL = 1
constants.AI_STATE_AGGRESSIVE = 2
constants.AI_MIN_STATE_DURATION = 1
constants.AI_MAX_STATE_DURATION = 4
constants.AI_MIN_TEMPERAMENT_DURATION = 5
constants.AI_MAX_TEMPERAMENT_DURATION = 15
-- ai retreat
constants.NO_RETREAT_BASE_PERCENT = 0.10
constants.NO_RETREAT_EVOLUTION_BONUS_MAX = 0.25
constants.NO_RETREAT_SQUAD_SIZE_BONUS_MAX = 0.40
-- chunk properties -- chunk properties
constants.CHUNK_SIZE = 32 constants.CHUNK_SIZE = 32
@ -53,46 +58,41 @@ constants.EAST_WEST = 2
-- pheromone amounts -- pheromone amounts
constants.MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT = 500
constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500 constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = 500
constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 175 constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = 15
constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 100 constants.DEATH_PHEROMONE_GENERATOR_AMOUNT = 100
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 300 constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 100
-- pheromone diffusion amounts -- pheromone diffusion amounts
constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT = 0.10 constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT = 0.05
constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT = 0.02 constants.MOVEMENT_PHEROMONE_DIFFUSION_AMOUNT = 0.02
constants.DEATH_PHEROMONE_PERSISTANCE = 0.99 constants.MOVEMENT_PHEROMONE_PERSISTANCE = 0.98
constants.STANDARD_PHEROMONE_PERSISTANCE = 0.98 constants.STANDARD_PHEROMONE_PERSISTANCE = 0.98
-- chunk attributes -- chunk attributes
constants.DEATH_PHEROMONE = 1 constants.MOVEMENT_PHEROMONE = 1
constants.ENEMY_BASE_PHEROMONE = 2 constants.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.ENEMY_BASE_GENERATOR = 7 constants.ENEMY_BASE_GENERATOR = 4
constants.PLAYER_BASE_GENERATOR = 8 constants.PLAYER_BASE_GENERATOR = 5
constants.PLAYER_DEFENSE_GENERATOR = 9
constants.NORTH_SOUTH_PASSABLE = 10 constants.NORTH_SOUTH_PASSABLE = 6
constants.EAST_WEST_PASSABLE = 11 constants.EAST_WEST_PASSABLE = 7
constants.CHUNK_TICK = 8
-- Squad status -- Squad status
constants.SQUAD_RETREATING = 1 -- used during squad retreat constants.SQUAD_RETREATING = 1 -- used during squad retreat
constants.SQUAD_GUARDING = 2 -- used when squad is idle 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_ATTACKING = 3 -- used as an attack state to be transitioned into hunt, raid, siege, burrow
constants.SQUAD_HUNTING = 4 -- used when player is close to unit group constants.SQUAD_BURROWING = 4
constants.SQUAD_SUICIDE_HUNT = 5 -- used when player is close with no retreat constants.SQUAD_RAIDING = 5 -- used when player stuff is close
constants.SQUAD_BURROWING = 6 constants.SQUAD_SUICIDE_RAID = 6 -- when player stuff is close with no retreat
constants.SQUAD_RAIDING = 8 -- used when player stuff is close
constants.SQUAD_SUICIDE_RAID = 9 -- when player stuff is close with no retreat
-- constants.SQUAD_SCOUTING = 7 -- constants.SQUAD_SCOUTING = 7
-- constants.SQUAD_SIEGE = 3 -- constants.SQUAD_SIEGE = 3
@ -101,36 +101,30 @@ constants.SQUAD_SUICIDE_RAID = 9 -- when player stuff is close with no retreat
constants.BUILDING_PHEROMONES = {} constants.BUILDING_PHEROMONES = {}
-- constants.buildingPheromones["container"] = 1 -- constants.buildingPheromones["container"] = 1
-- constants.buildingPheromones["storage-tank"] = 1 -- constants.buildingPheromones["storage-tank"] = 1
constants.BUILDING_PHEROMONES["generator"] = 60 constants.BUILDING_PHEROMONES["generator"] = 8
constants.BUILDING_PHEROMONES["pump"] = 8 constants.BUILDING_PHEROMONES["pump"] = 2
constants.BUILDING_PHEROMONES["offshore-pump"] = 8 constants.BUILDING_PHEROMONES["offshore-pump"] = 2
-- constants.buildingPheromones["constant-combinator"] = 1 -- constants.buildingPheromones["constant-combinator"] = 1
-- constants.buildingPheromones["train-stop"] = 2 -- constants.buildingPheromones["train-stop"] = 2
-- constants.buildingPheromones["rail-signal"] = 1 -- constants.buildingPheromones["rail-signal"] = 1
-- constants.BUILDING_PHEROMONES["electric-pole"] = 4 -- constants.BUILDING_PHEROMONES["electric-pole"] = 4
constants.BUILDING_PHEROMONES["transport-belt"] = 4 constants.BUILDING_PHEROMONES["transport-belt"] = 1
constants.BUILDING_PHEROMONES["accumulator"] = 40 constants.BUILDING_PHEROMONES["accumulator"] = 10
constants.BUILDING_PHEROMONES["solar-panel"] = 32 constants.BUILDING_PHEROMONES["solar-panel"] = 8
constants.BUILDING_PHEROMONES["boiler"] = 60 constants.BUILDING_PHEROMONES["boiler"] = 12
constants.BUILDING_PHEROMONES["assembling-machine"] = 48 constants.BUILDING_PHEROMONES["assembling-machine"] = 12
constants.BUILDING_PHEROMONES["roboport"] = 40 constants.BUILDING_PHEROMONES["roboport"] = 10
constants.BUILDING_PHEROMONES["beacon"] = 40 constants.BUILDING_PHEROMONES["beacon"] = 10
constants.BUILDING_PHEROMONES["furnace"] = 60 constants.BUILDING_PHEROMONES["furnace"] = 12
constants.BUILDING_PHEROMONES["mining-drill"] = 80 constants.BUILDING_PHEROMONES["mining-drill"] = 15
-- player defense pheromones -- player defense pheromones
constants.DEFENSE_PHEROMONES = {} constants.BUILDING_PHEROMONES["ammo-turret"] = 2.5
constants.DEFENSE_PHEROMONES["ammo-turret"] = 5 constants.BUILDING_PHEROMONES["wall"] = 0.25
constants.DEFENSE_PHEROMONES["wall"] = 0.5 constants.BUILDING_PHEROMONES["electric-turret"] = 4.25
constants.DEFENSE_PHEROMONES["electric-turret"] = 7.5 constants.BUILDING_PHEROMONES["fluid-turret"] = 5
constants.DEFENSE_PHEROMONES["fluid-turret"] = 10 constants.BUILDING_PHEROMONES["turret"] = 3.5
constants.DEFENSE_PHEROMONES["turret"] = 3
-- enemy units
-- constants.deathPheromones = {}
-- constants.deathPheromones[""]
constants.retreatFilter = {} constants.retreatFilter = {}
constants.retreatFilter[constants.SQUAD_RETREATING] = true constants.retreatFilter[constants.SQUAD_RETREATING] = true

View File

@ -8,10 +8,8 @@ local constants = require("Constants")
-- constants -- constants
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
local DEFENSE_PHEROMONES = constants.DEFENSE_PHEROMONES
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT local ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT = constants.ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
@ -87,9 +85,6 @@ function entityUtils.addRemoveEntity(regionMap, entity, natives, addObject)
if (BUILDING_PHEROMONES[entity.type] ~= nil) then if (BUILDING_PHEROMONES[entity.type] ~= nil) then
entityValue = BUILDING_PHEROMONES[entity.type] entityValue = BUILDING_PHEROMONES[entity.type]
pheromoneType = PLAYER_BASE_GENERATOR pheromoneType = PLAYER_BASE_GENERATOR
elseif (DEFENSE_PHEROMONES[entity.type] ~= nil) then
entityValue = DEFENSE_PHEROMONES[entity.type]
pheromoneType = PLAYER_DEFENSE_GENERATOR
elseif (entity.type == "unit-spawner") and (entity.force.name == "enemy") then elseif (entity.type == "unit-spawner") and (entity.force.name == "enemy") then
entityValue = ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT entityValue = ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
pheromoneType = ENEMY_BASE_GENERATOR pheromoneType = ENEMY_BASE_GENERATOR

View File

@ -2,10 +2,10 @@ local mapProcessor = {}
-- imports -- imports
local mapUtils = require("MapUtils")
local pheromoneUtils = require("PheromoneUtils") local pheromoneUtils = require("PheromoneUtils")
local aiBuilding = require("AIBuilding") local aiBuilding = require("AIBuilding")
local constants = require("Constants") local constants = require("Constants")
local mapUtils = require("MapUtils")
-- constants -- constants
@ -15,6 +15,11 @@ local SCAN_QUEUE_SIZE = constants.SCAN_QUEUE_SIZE
local CHUNK_SIZE = constants.CHUNK_SIZE local CHUNK_SIZE = constants.CHUNK_SIZE
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
local AI_STATE_AGGRESSIVE = constants.AI_STATE_AGGRESSIVE
local PROCESS_PLAYER_BOUND = constants.PROCESS_PLAYER_BOUND
local CHUNK_TICK = constants.CHUNK_TICK
-- imported functions -- imported functions
@ -24,17 +29,38 @@ local processPheromone = pheromoneUtils.processPheromone
local makeScouts = aiBuilding.makeScouts local makeScouts = aiBuilding.makeScouts
local formSquads = aiBuilding.formSquads local formSquads = aiBuilding.formSquads
local getCardinalChunks = mapUtils.getCardinalChunks local getChunkByIndex = mapUtils.getChunkByIndex
local getChunkByPosition = mapUtils.getChunkByPosition
local playerScent = pheromoneUtils.playerScent
local mMin = math.min local mMin = math.min
-- module code -- module code
-- processing is not consistant as it depends on the number of chunks that have been generated
-- so 200 chunks is processed 3 times a second and 1200 chunks is processed once a second local function nonRepeatingRandom(players)
-- In theory, this might be fine as smaller bases have less surface to attack and need to have local ordering = {}
-- pheromone dissipate at a faster rate. for _,player in pairs(players) do
function mapProcessor.processMap(regionMap, surface, natives, evolution_factor, temps) ordering[#ordering+1] = player.index
end
for i=#ordering,1,-1 do
local s = math.random(i)
local t = ordering[i]
ordering[i] = ordering[s]
ordering[s] = t
end
return ordering
end
--[[
processing is not consistant as it depends on the number of chunks that have been generated
so if we process 400 chunks an iteration and 200 chunks have been generated than these are
processed 3 times a second and 1200 generated chunks would be processed once a second
In theory, this might be fine as smaller bases have less surface to attack and need to have
pheromone dissipate at a faster rate.
--]]
function mapProcessor.processMap(regionMap, surface, natives, evolution_factor)
local roll = regionMap.processRoll local roll = regionMap.processRoll
local index = regionMap.processPointer local index = regionMap.processPointer
local scouts = false local scouts = false
@ -49,8 +75,8 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
scouts = true scouts = true
end end
if (0.11 <= roll) and (roll <= 0.35) then if (natives.state == AI_STATE_AGGRESSIVE) and (0.11 <= roll) and (roll <= 0.35) then
squads = true squads = true
end end
local processQueue = regionMap.processQueue local processQueue = regionMap.processQueue
@ -64,10 +90,10 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
makeScouts(surface, natives, chunk, evolution_factor) makeScouts(surface, natives, chunk, evolution_factor)
end end
if squads then if squads then
formSquads(regionMap, surface, natives, chunk, evolution_factor, temps) formSquads(regionMap, surface, natives, chunk, evolution_factor)
end end
processPheromone(chunk, getCardinalChunks(regionMap, chunk.cX, chunk.cY)) processPheromone(regionMap, chunk)
end end
if (endIndex == #processQueue) then if (endIndex == #processQueue) then
@ -77,25 +103,90 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
end end
end end
--[[
Localized player radius were processing takes place in realtime, doesn't store state
between calls.
vs
the slower passive version processing the entire map in multiple passes.
--]]
function mapProcessor.processPlayers(players, regionMap, surface, natives, evolution_factor, tick)
-- put down player pheromone for player hunters
-- randomize player order to ensure a single player isn't singled out
local playerOrdering = nonRepeatingRandom(players)
local scouts = false
local squads = false
local roll = math.random()
if (0.05 <= roll) and (roll <= 0.7) then
scouts = true
end
if (natives.state == AI_STATE_AGGRESSIVE) and (0.11 <= roll) and (roll <= 0.20) then
squads = true
end
for i=1,#playerOrdering do
local player = players[playerOrdering[i]]
if (player ~= nil) and player.connected and (player.character ~= nil) and player.character.valid and (player.character.surface.index == 1) then
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if (playerChunk ~= nil) then
playerScent(playerChunk)
end
end
end
for i=1,#playerOrdering do
local player = players[playerOrdering[i]]
if (player ~= nil) and player.connected and (player.character ~= nil) and player.character.valid and (player.character.surface.index == 1) then
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if (playerChunk ~= nil) then
for x=playerChunk.cX - PROCESS_PLAYER_BOUND, playerChunk.cX + PROCESS_PLAYER_BOUND do
for y=playerChunk.cY - PROCESS_PLAYER_BOUND, playerChunk.cY + PROCESS_PLAYER_BOUND do
local chunk = getChunkByIndex(regionMap, x, y)
if (chunk ~= nil) and (chunk[CHUNK_TICK] ~= tick) then
chunk[CHUNK_TICK] = tick
scents(chunk)
if scouts then
makeScouts(surface, natives, chunk, evolution_factor)
end
if squads then
formSquads(regionMap, surface, natives, chunk, evolution_factor)
end
processPheromone(regionMap, chunk)
end
end
end
end
end
end
end
function mapProcessor.scanMap(regionMap, surface) function mapProcessor.scanMap(regionMap, surface)
local index = regionMap.scanPointer local index = regionMap.scanPointer
local processQueue = regionMap.processQueue local processQueue = regionMap.processQueue
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue) local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
for x=index,endIndex do for x=index,endIndex do
local chunk = processQueue[x] local chunk = processQueue[x]
local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY}, local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}}, {chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
type = "unit-spawner", type = "unit-spawner",
force = "enemy"}) force = "enemy"})
chunk[ENEMY_BASE_GENERATOR] = spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT chunk[ENEMY_BASE_GENERATOR] = spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
end end
if (endIndex == #processQueue) then if (endIndex == #processQueue) then
regionMap.scanPointer = 1 regionMap.scanPointer = 1
else else
regionMap.scanPointer = endIndex + 1 regionMap.scanPointer = endIndex + 1
end end
end end

28
libs/MathUtils.lua Normal file
View File

@ -0,0 +1,28 @@
local mathUtils = {}
-- imports
local constants = require("Constants")
-- constants
local TICKS_A_MINUTE = constants.TICKS_A_MINUTE
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
-- imported functions
local mMax = math.max
function mathUtils.roundToNearest(number, multiple)
local num = number + (multiple * 0.5)
return num - (num % multiple)
end
function mathUtils.randomTickEvent(tick, low, high)
local minutesToTick = mMax(high * math.random(), low)
local nextTick = mathUtils.roundToNearest(TICKS_A_MINUTE * minutesToTick, INTERVAL_LOGIC)
return tick + nextTick
end
return mathUtils

View File

@ -7,96 +7,76 @@ local constants = require("Constants")
-- constants -- constants
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE local BASE_PHEROMONE = constants.BASE_PHEROMONE
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
local PLAYER_PHEROMONE_GENERATOR_AMOUNT = constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT local PLAYER_PHEROMONE_GENERATOR_AMOUNT = constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT
local DEATH_PHEROMONE_GENERATOR_AMOUNT = constants.DEATH_PHEROMONE_GENERATOR_AMOUNT local DEATH_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
local STANDARD_PHERONOME_DIFFUSION_AMOUNT = constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT local STANDARD_PHERONOME_DIFFUSION_AMOUNT = constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT
local DEATH_PHEROMONE_DIFFUSION_AMOUNT = constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT local MOVEMENT_PHEROMONE_DIFFUSION_AMOUNT = constants.MOVEMENT_PHEROMONE_DIFFUSION_AMOUNT
local DEATH_PHEROMONE_PERSISTANCE = constants.DEATH_PHEROMONE_PERSISTANCE local MOVEMENT_PHEROMONE_PERSISTANCE = constants.MOVEMENT_PHEROMONE_PERSISTANCE
local STANDARD_PHEROMONE_PERSISTANCE = constants.STANDARD_PHEROMONE_PERSISTANCE local STANDARD_PHEROMONE_PERSISTANCE = constants.STANDARD_PHEROMONE_PERSISTANCE
-- imported functions -- imported functions
local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByPosition = mapUtils.getChunkByPosition
local getCardinalChunks = mapUtils.getCardinalChunks
-- module code -- module code
function pheromoneUtils.scents(chunk) function pheromoneUtils.scents(chunk)
local amount = chunk[PLAYER_DEFENSE_GENERATOR] chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR] - chunk[ENEMY_BASE_GENERATOR]
if (amount > 0) then
chunk[PLAYER_DEFENSE_PHEROMONE] = chunk[PLAYER_DEFENSE_PHEROMONE] + amount
end
amount = chunk[PLAYER_BASE_GENERATOR]
if (amount > 0) then
chunk[PLAYER_BASE_PHEROMONE] = chunk[PLAYER_BASE_PHEROMONE] + amount
end
amount = chunk[ENEMY_BASE_GENERATOR]
if (amount > 0) then
chunk[ENEMY_BASE_PHEROMONE] = chunk[ENEMY_BASE_PHEROMONE] + amount
end
end end
function pheromoneUtils.deathScent(regionMap, position) function pheromoneUtils.deathScent(regionMap, position)
local chunk = getChunkByPosition(regionMap, position.x, position.y) local chunk = getChunkByPosition(regionMap, position.x, position.y)
if (chunk ~= nil) then if (chunk ~= nil) then
chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + DEATH_PHEROMONE_GENERATOR_AMOUNT chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
-- pheromoneTotals[DEATH_PHEROMONE] = pheromoneTotals[DEATH_PHEROMONE] + DEATH_PHEROMONE_GENERATOR_AMOUNT
end end
end end
function pheromoneUtils.playerScent(regionMap, players) function pheromoneUtils.playerScent(playerChunk)
for i=1,#players do playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
local player = players[i]
if (player ~= nil) and player.connected and (player.character ~= nil) and player.character.valid and (player.character.surface.index == 1) then
local playerPosition = player.character.position
local playerChunk = getChunkByPosition(regionMap, playerPosition.x, playerPosition.y)
if (playerChunk ~= nil) then
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
end
end
end
end end
function pheromoneUtils.processPheromone(chunk, neighbors) function pheromoneUtils.processPheromone(regionMap, chunk)
local neighbors
-- pheromone level indexes on chunks are 1 - 6 -- pheromone level indexes on chunks are 1 - 3
-- unrolled loop one level -- unrolled loop one level
local diffusionAmount = DEATH_PHEROMONE_DIFFUSION_AMOUNT local diffusionAmount = MOVEMENT_PHEROMONE_DIFFUSION_AMOUNT
local persistence = DEATH_PHEROMONE_PERSISTANCE local persistence = MOVEMENT_PHEROMONE_PERSISTANCE
local totalDiffused = 0 local totalDiffused = 0
local chunkValue = chunk[DEATH_PHEROMONE] * persistence local chunkValue = chunk[MOVEMENT_PHEROMONE] * persistence
local diffusedAmount = chunkValue * diffusionAmount local diffusedAmount = chunkValue * diffusionAmount
if (chunkValue > 2) then if (diffusedAmount > 1.5) or (diffusedAmount < -1.5) then
neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
for i=1,#neighbors do for i=1,#neighbors do
local neighborChunk = neighbors[i] local neighborChunk = neighbors[i]
if (neighborChunk ~= nil) then if (neighborChunk ~= nil) then
totalDiffused = totalDiffused + diffusedAmount totalDiffused = totalDiffused + diffusedAmount
neighborChunk[DEATH_PHEROMONE] = neighborChunk[DEATH_PHEROMONE] + diffusedAmount neighborChunk[MOVEMENT_PHEROMONE] = neighborChunk[MOVEMENT_PHEROMONE] + diffusedAmount
end end
end end
end end
chunk[DEATH_PHEROMONE] = (chunkValue - totalDiffused) chunk[MOVEMENT_PHEROMONE] = (chunkValue - totalDiffused)
diffusionAmount = STANDARD_PHERONOME_DIFFUSION_AMOUNT diffusionAmount = STANDARD_PHERONOME_DIFFUSION_AMOUNT
persistence = STANDARD_PHEROMONE_PERSISTANCE persistence = STANDARD_PHEROMONE_PERSISTANCE
for x=2,6 do for x=2,3 do
totalDiffused = 0 totalDiffused = 0
chunkValue = chunk[x] * persistence chunkValue = chunk[x] * persistence
diffusedAmount = chunkValue * diffusionAmount diffusedAmount = chunkValue * diffusionAmount
if (chunkValue > 2) then if (diffusedAmount > 1.5) then
if (neighbors == nil) then
neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
end
for i=1,#neighbors do for i=1,#neighbors do
local neighborChunk = neighbors[i] local neighborChunk = neighbors[i]
if (neighborChunk ~= nil) then if (neighborChunk ~= nil) then
@ -105,7 +85,7 @@ function pheromoneUtils.processPheromone(chunk, neighbors)
end end
end end
end end
chunk[x] = (chunkValue - totalDiffused) chunk[x] = (chunkValue - totalDiffused)
end end
end end

View File

@ -11,13 +11,12 @@ local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
-- module code -- module code
function playerUtils.playersWithinProximityToPosition(players, position, distance) function playerUtils.playersWithinProximityToPosition(players, position, distance)
for x=1,#players do for _,player in pairs(players) do
local player = players[x] if (player ~= nil) and player.connected and (player.character ~= nil) and player.character.valid and (player.character.surface.index == 1) then
if (player ~= nil) and player.connected and (player.character ~= nil) and player.character.valid and (player.character.surface.index == 1) then if (euclideanDistanceNamed(player.character.position, position) < distance) then
if (euclideanDistanceNamed(player.character.position, position) < distance) then return true
return true end
end end
end
end end
return false return false
end end

View File

@ -7,7 +7,7 @@ local constants = require("Constants")
-- constants -- constants
local MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
local GROUP_STATE_FINISHED = defines.group_state.finished local GROUP_STATE_FINISHED = defines.group_state.finished
@ -93,14 +93,14 @@ function unitGroupUtils.addSquadMovementPenalty(squad, chunkX, chunkY)
for i=1,#penalties do for i=1,#penalties do
local penalty = penalties[i] local penalty = penalties[i]
if (penalty.x == chunkX) and (penalty.y == chunkY) then if (penalty.x == chunkX) and (penalty.y == chunkY) then
penalty.v = penalty.v + MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT penalty.v = penalty.v + MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
return return
end end
end end
if (#penalties == 10) then if (#penalties == 10) then
tableRemove(penalties, 10) tableRemove(penalties, 10)
end end
tableInsert(penalties, 1, { v = MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT, tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
x = chunkX, x = chunkX,
y = chunkY }) y = chunkY })
end end

113
make.rkt
View File

@ -6,74 +6,75 @@
;(define modFolder "C:/Users/veden/AppData/Roaming/Factorio/mods/") ;(define modFolder "C:/Users/veden/AppData/Roaming/Factorio/mods/")
;(define zipModFolder "C:/Program Files/Factorio_0.14.1/mods/") ;(define zipModFolder "C:/Program Files/Factorio_0.14.1/mods/")
(define modFolder "/home/veden/.factorio/mods/") (define modFolder "/home/veden/.factorio/mods/")
(define zipModFolder "/data/games/factorio14.13/mods/") (define zipModFolder "/data/games/factorio14.14/mods/")
(define configuration (call-with-input-file "info.json" (define configuration (call-with-input-file "info.json"
(lambda (port) (lambda (port)
(string->jsexpr (port->string port))))) (string->jsexpr (port->string port)))))
(define packageName (string-append (string-replace (hash-ref configuration 'name) " " "_") (define packageName (string-append (string-replace (hash-ref configuration 'name) " " "_")
"_" "_"
(hash-ref configuration 'version))) (hash-ref configuration 'version)))
(define (makeZip) (define (makeZip folder)
(let ((packagePath (string->path (string-append modFolder (let ((packagePath (string->path (string-append folder
packageName packageName
".zip")))) ".zip"))))
(when (file-exists? packagePath) (when (file-exists? packagePath)
(delete-file packagePath))) (delete-file packagePath)))
(zip (string-append modFolder (zip (string-append folder
packageName packageName
".zip") ".zip")
#:path-prefix packageName #:path-prefix packageName
(string->path "info.json") (string->path "info.json")
(string->path "control.lua") (string->path "control.lua")
(string->path "config.lua") (string->path "config.lua")
(string->path "data.lua") (string->path "data.lua")
(string->path "LICENSE.md") (string->path "LICENSE.md")
(string->path "tests.lua") (string->path "tests.lua")
; (string->path "setupUtils.lua") ; (string->path "setupUtils.lua")
(string->path "README.md") (string->path "README.md")
; (string->path "setup.lua") ; (string->path "setup.lua")
(string->path "NOTICE") (string->path "NOTICE")
(string->path "libs") (string->path "libs")
(string->path "locale") (string->path "locale")
(string->path "graphics") (string->path "graphics")
(string->path "prototypes"))) (string->path "prototypes")))
;(current-directory "..") ;(current-directory "..")
(define (copyFile fileName modFolder) (define (copyFile fileName modFolder)
(copy-file (string->path fileName) (copy-file (string->path fileName)
(string->path (string-append modFolder (string->path (string-append modFolder
packageName packageName
"/" "/"
fileName)))) fileName))))
(define (copyDirectory directoryName modFolder) (define (copyDirectory directoryName modFolder)
(copy-directory/files (string->path directoryName) (copy-directory/files (string->path directoryName)
(string->path (string-append modFolder (string->path (string-append modFolder
packageName packageName
"/" "/"
directoryName)))) directoryName))))
(define (copyFiles modFolder) (define (copyFiles modFolder)
(let ((packagePath (string->path (string-append modFolder (let ((packagePath (string->path (string-append modFolder
packageName)))) packageName))))
(when (directory-exists? packagePath) (when (directory-exists? packagePath)
(delete-directory/files packagePath)) (delete-directory/files packagePath))
(sleep 0.1) (sleep 0.1)
(make-directory packagePath) (make-directory packagePath)
(copyFile "control.lua" modFolder) (copyFile "control.lua" modFolder)
(copyFile "config.lua" modFolder) (copyFile "config.lua" modFolder)
(copyFile "info.json" modFolder) (copyFile "info.json" modFolder)
; (copyFile "setupUtils.lua" modFolder) ; (copyFile "setupUtils.lua" modFolder)
(copyFile "data.lua" modFolder) (copyFile "data.lua" modFolder)
(copyFile "tests.lua" modFolder) (copyFile "tests.lua" modFolder)
(copyDirectory "libs" modFolder) (copyDirectory "libs" modFolder)
(copyDirectory "locale" modFolder) (copyDirectory "locale" modFolder)
(copyDirectory "graphics" modFolder) (copyDirectory "graphics" modFolder)
(copyDirectory "prototypes" modFolder))) (copyDirectory "prototypes" modFolder)))
;; (copyFiles modFolder) ;; (copyFiles modFolder)
;; (copyFiles zipModFolder) ;; (copyFiles zipModFolder)
(makeZip) (makeZip modFolder)
(makeZip zipModFolder)
) )

View File

@ -10,8 +10,8 @@ function tests.test1()
print(#global.regionMap.processQueue) print(#global.regionMap.processQueue)
print(playerChunkX .. ", " .. playerChunkY) print(playerChunkX .. ", " .. playerChunkY)
print("--") print("--")
for x=playerChunkX-3, playerChunkX+3 do for x=playerChunkX-9, playerChunkX+9 do
for y=playerChunkY-3, playerChunkY+3 do for y=playerChunkY-9, playerChunkY+9 do
if (global.regionMap[x] ~= nil) then if (global.regionMap[x] ~= nil) then
local chunk = global.regionMap[x][y] local chunk = global.regionMap[x][y]
if (chunk ~= nil) then if (chunk ~= nil) then
@ -19,13 +19,14 @@ function tests.test1()
for i=1,#chunk do for i=1,#chunk do
str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i]) str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i])
end end
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then str = str .. " " .. "p/" .. game.surfaces[1].get_pollution({x=chunk.pX, y=chunk.pY})
print("*", chunk.cX, chunk.cY, str) if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
else print("*", chunk.cX, chunk.cY, str)
print(chunk.cX, chunk.cY, str) else
end print(chunk.cX, chunk.cY, str)
-- print(str) end
print("-") -- print(str)
print("-")
end end
end end
end end