mirror of
https://github.com/veden/Rampant.git
synced 2024-12-26 20:54:12 +02:00
see changelog 0.14.4
This commit is contained in:
parent
04c184078d
commit
d989322407
1
.gitignore
vendored
1
.gitignore
vendored
@ -47,3 +47,4 @@ luac.out
|
||||
*.dumpjump
|
||||
/.emacs.desktop
|
||||
/.emacs.desktop.lock
|
||||
/README.html
|
||||
|
63
README.md
63
README.md
@ -7,6 +7,7 @@ https://forums.factorio.com/viewtopic.php?f=94&t=31445
|
||||
|
||||
# Notes
|
||||
|
||||
0.14.14 factorio version fixed save corruption
|
||||
0.14.10 factorio version fixed more pathing issues
|
||||
0.14.4 factorio version fixed some issues with unit groups commands
|
||||
|
||||
@ -33,36 +34,56 @@ Base Expansion
|
||||
|
||||
# Version History
|
||||
|
||||
0.14.3 - slightly lowered Rampant attack wave frequency
|
||||
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.4 -
|
||||
- Fixed a bug in the processing queue when upgrading mod
|
||||
- Greatly decreased Player pheromone radius, now sits at roughly 4 chunks around the player
|
||||
- Reworked pheromone pathfinding
|
||||
- Removed base and defense attack wave trigger, in favor of using player pheromone and pollution
|
||||
- Added periods of time where the enemy is not sending 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
|
||||
adjusted squad attack pattern (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=20#p203861)
|
||||
Fixed migration issue
|
||||
0.14.3 -
|
||||
- Slightly lowered Rampant attack wave frequency
|
||||
- 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
|
||||
Optimization to offset ai created bases scanning
|
||||
0.14.2 -
|
||||
- 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.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)
|
||||
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.8 -
|
||||
- Fixed retreat oscillations (https://forums.factorio.com/viewtopic.php?f=94&t=31445&start=10#p198750)
|
||||
- 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
|
||||
MP is working (https://github.com/veden/Rampant/issues/1)
|
||||
0.0.6 -
|
||||
- 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)
|
||||
checks for main surface (https://forums.factorio.com/viewtopic.php?f=94&t=31445&p=198228#p198563)
|
||||
updated info with forum homepage
|
||||
0.0.5 -
|
||||
- Fix for nil chunk in ai attack (https://mods.factorio.com/mods/Veden/Rampant/discussion/2512)
|
||||
- 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
|
||||
|
||||
|
28
config.lua
28
config.lua
@ -4,29 +4,37 @@ local config = {}
|
||||
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).
|
||||
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).
|
||||
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).
|
||||
switching all to false will turn off Rampant biter waves, does not turn off vanilla biter waves.
|
||||
switching all to false will turn off Rampant biter waves
|
||||
DOES NOT affect vanilla biters waves
|
||||
--]]
|
||||
config.attackWaveGenerationUsePollution = 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.
|
||||
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
|
||||
default is 150 * (evolutionFactor ^ 1.666667)
|
||||
150 is the max group size
|
||||
default is config.attackWaveMaxSize * (evolutionFactor ^ 1.666667)
|
||||
DOES NOT affect vanilla biters waves
|
||||
--]]
|
||||
config.attackWaveScaling = function (evolutionFactor)
|
||||
return math.ceil(150 * (evolutionFactor ^ 1.666667))
|
||||
return math.ceil(config.attackWaveMaxSize * (evolutionFactor ^ 1.666667))
|
||||
end
|
||||
|
||||
return config
|
||||
|
124
control.lua
124
control.lua
@ -9,20 +9,27 @@ local pheromoneUtils = require("libs/PheromoneUtils")
|
||||
local aiDefense = require("libs/AIDefense")
|
||||
local aiAttack = require("libs/AIAttack")
|
||||
local aiBuilding = require("libs/AIBuilding")
|
||||
local aiPlanning = require("libs/AIPlanning")
|
||||
local mathUtils = require("libs/MathUtils")
|
||||
local tests = require("tests")
|
||||
|
||||
-- constants
|
||||
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
||||
|
||||
-- imported functions
|
||||
|
||||
local processPendingChunks = chunkProcessor.processPendingChunks
|
||||
|
||||
local processMap = mapProcessor.processMap
|
||||
local processPlayers = mapProcessor.processPlayers
|
||||
local scanMap = mapProcessor.scanMap
|
||||
|
||||
local accumulatePoints = aiBuilding.accumulatePoints
|
||||
local planning = aiPlanning.planning
|
||||
local removeScout = aiBuilding.removeScout
|
||||
-- local scouting = aiBuilding.scouting
|
||||
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
local deathScent = pheromoneUtils.deathScent
|
||||
|
||||
local regroupSquads = unitGroupUtils.regroupSquads
|
||||
@ -35,6 +42,8 @@ local retreatUnits = aiDefense.retreatUnits
|
||||
|
||||
local addRemoveEntity = entityUtils.addRemoveEntity
|
||||
|
||||
local roundToNearest = mathUtils.roundToNearest
|
||||
|
||||
-- local references to global
|
||||
|
||||
local regionMap
|
||||
@ -44,11 +53,9 @@ local pendingChunks
|
||||
-- hook functions
|
||||
|
||||
local function onLoad()
|
||||
-- print("load")
|
||||
regionMap = global.regionMap
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
-- pheromoneTotals = global.pheromoneTotals
|
||||
end
|
||||
|
||||
local function onChunkGenerated(event)
|
||||
@ -60,7 +67,6 @@ local function onChunkGenerated(event)
|
||||
end
|
||||
|
||||
local function onConfigChanged()
|
||||
-- print("reprocess")
|
||||
if (global.version == nil) then
|
||||
|
||||
-- removed in version 9
|
||||
@ -83,11 +89,6 @@ local function onConfigChanged()
|
||||
regionMap.pI = nil
|
||||
regionMap.pP = nil
|
||||
regionMap.pR = nil
|
||||
|
||||
regionMap.processQueue = {}
|
||||
regionMap.processPointer = 1
|
||||
regionMap.scanPointer = 1
|
||||
regionMap.processRoll = -1
|
||||
|
||||
global.version = constants.VERSION_9
|
||||
end
|
||||
@ -98,40 +99,64 @@ local function onConfigChanged()
|
||||
squad.rabid = false
|
||||
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
|
||||
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
|
||||
|
||||
local function onTick(event)
|
||||
if (event.tick % 20 == 0) then
|
||||
if (event.tick % INTERVAL_PROCESS == 0) then
|
||||
local surface = game.surfaces[1]
|
||||
|
||||
processPendingChunks(regionMap, surface, pendingChunks)
|
||||
scanMap(regionMap, surface)
|
||||
local evolutionFactor = game.evolution_factor
|
||||
local players = game.players
|
||||
|
||||
processPendingChunks(regionMap, surface, pendingChunks)
|
||||
scanMap(regionMap, surface)
|
||||
|
||||
if (event.tick % 40 == 0) then
|
||||
|
||||
accumulatePoints(natives)
|
||||
|
||||
-- put down player pheromone for player hunters
|
||||
playerScent(regionMap, game.players)
|
||||
|
||||
regroupSquads(natives)
|
||||
|
||||
-- scouting(regionMap, natives)
|
||||
|
||||
squadBeginAttack(natives, game.players, game.evolution_factor)
|
||||
squadAttack(regionMap, surface, natives)
|
||||
end
|
||||
if (event.tick % INTERVAL_LOGIC == 0) then
|
||||
local tick = game.tick
|
||||
planning(natives, evolutionFactor, tick)
|
||||
|
||||
regroupSquads(natives)
|
||||
|
||||
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
|
||||
|
||||
-- scouting(regionMap, natives)
|
||||
|
||||
squadBeginAttack(natives, players, evolutionFactor)
|
||||
squadAttack(regionMap, surface, natives)
|
||||
end
|
||||
|
||||
processMap(regionMap, surface, natives, game.evolution_factor)
|
||||
processMap(regionMap, surface, natives, evolutionFactor)
|
||||
end
|
||||
end
|
||||
|
||||
@ -181,16 +206,13 @@ local function onSurfaceTileChange(event)
|
||||
end
|
||||
|
||||
local function onInit()
|
||||
-- print("init")
|
||||
global.regionMap = {}
|
||||
global.pendingChunks = {}
|
||||
global.natives = {}
|
||||
-- global.pheromoneTotals = {}
|
||||
|
||||
regionMap = global.regionMap
|
||||
natives = global.natives
|
||||
pendingChunks = global.pendingChunks
|
||||
-- pheromoneTotals = global.pheromoneTotals
|
||||
|
||||
onConfigChanged()
|
||||
end
|
||||
@ -216,15 +238,15 @@ script.on_event(defines.events.on_tick, onTick)
|
||||
script.on_event(defines.events.on_chunk_generated, onChunkGenerated)
|
||||
|
||||
remote.add_interface("rampant", {
|
||||
test1 = tests.test1,
|
||||
test2 = tests.test2,
|
||||
test3 = tests.test3,
|
||||
test4 = tests.test4,
|
||||
test5 = tests.test5,
|
||||
test6 = tests.test6,
|
||||
test7 = tests.test7,
|
||||
test8 = tests.test8,
|
||||
test9 = tests.test9,
|
||||
test10 = tests.test10,
|
||||
test11 = tests.test11
|
||||
})
|
||||
test1 = tests.test1,
|
||||
test2 = tests.test2,
|
||||
test3 = tests.test3,
|
||||
test4 = tests.test4,
|
||||
test5 = tests.test5,
|
||||
test6 = tests.test6,
|
||||
test7 = tests.test7,
|
||||
test8 = tests.test8,
|
||||
test9 = tests.test9,
|
||||
test10 = tests.test10,
|
||||
test11 = tests.test11
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name" : "Rampant",
|
||||
"factorio_version" : "0.14",
|
||||
"version" : "0.14.3",
|
||||
"version" : "0.14.4",
|
||||
"title" : "Rampant AI",
|
||||
"author" : "Veden",
|
||||
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
|
||||
|
@ -7,29 +7,26 @@ local mapUtils = require("MapUtils")
|
||||
local unitGroupUtils = require("UnitGroupUtils")
|
||||
local playerUtils = require("PlayerUtils")
|
||||
local neighborUtils = require("NeighborUtils")
|
||||
package.path = "../?.lua;" .. package.path
|
||||
local config = require("config")
|
||||
|
||||
-- constants
|
||||
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
|
||||
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
|
||||
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
|
||||
--local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
|
||||
local SQUAD_RAIDING = constants.SQUAD_RAIDING
|
||||
local SQUAD_SUICIDE_RAID = constants.SQUAD_SUICIDE_RAID
|
||||
local SQUAD_HUNTING = constants.SQUAD_HUNTING
|
||||
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_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
|
||||
|
||||
@ -46,7 +43,7 @@ local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPos
|
||||
|
||||
local scoreNeighborsWithDirection = neighborUtils.scoreNeighborsWithDirection
|
||||
|
||||
|
||||
local mLog = math.log10
|
||||
|
||||
-- module code
|
||||
|
||||
@ -56,16 +53,8 @@ end
|
||||
|
||||
local function scoreAttackLocation(position, squad, neighborChunk, surface)
|
||||
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 avoidScore = neighborChunk[DEATH_PHEROMONE] + neighborChunk[ENEMY_BASE_PHEROMONE]
|
||||
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
|
||||
local r = surface.get_pollution(position) + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE] + neighborChunk[PLAYER_PHEROMONE]
|
||||
return r - squadMovementPenalty
|
||||
end
|
||||
|
||||
function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
@ -82,17 +71,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
for i=1,#squads do
|
||||
local squad = squads[i]
|
||||
local group = squad.group
|
||||
local raiding = false
|
||||
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.valid and ((squad.status == SQUAD_RAIDING) or (squad.status == SQUAD_SUICIDE_RAID)) then
|
||||
if (group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering) or ((group.state == defines.group_state.moving) and (squad.cycles == 0)) then
|
||||
local chunk = getChunkByPosition(regionMap, group.position.x, group.position.y)
|
||||
if (chunk ~= nil) then
|
||||
@ -100,15 +79,15 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
local attackChunk, attackDirection = scoreNeighborsWithDirection(chunk,
|
||||
getCardinalChunksWithDirection(regionMap, chunk.cX, chunk.cY),
|
||||
validLocation,
|
||||
scoreLocation,
|
||||
scoreAttackLocation,
|
||||
squad,
|
||||
surface,
|
||||
attackPosition)
|
||||
if (attackChunk ~= nil) then
|
||||
if ((attackChunk[PLAYER_BASE_GENERATOR] == 0) and (attackChunk[PLAYER_DEFENSE_GENERATOR] == 0)) or
|
||||
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
|
||||
if (attackChunk[PLAYER_BASE_GENERATOR] == 0) or
|
||||
((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
|
||||
|
||||
@ -122,14 +101,14 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
attackCmd.distraction = defines.distraction.by_enemy
|
||||
end
|
||||
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
group.set_command(attackCmd)
|
||||
group.start_moving()
|
||||
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
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0) or (attackChunk[PLAYER_DEFENSE_GENERATOR] ~= 0)) then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squad.group.position.x
|
||||
squad.frenzyPosition.y = squad.group.position.y
|
||||
((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_distraction) or
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squad.group.position.x
|
||||
squad.frenzyPosition.y = squad.group.position.y
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -143,33 +122,27 @@ function aiAttack.squadBeginAttack(natives, players, evolution_factor)
|
||||
for i=1,#squads do
|
||||
local squad = squads[i]
|
||||
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)
|
||||
if playerNearby then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squad.group.position.x
|
||||
squad.frenzyPosition.y = squad.group.position.y
|
||||
end
|
||||
|
||||
-- check to hunt player
|
||||
if (math.random() < 0.30) and playerNearby 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
|
||||
|
||||
-- check to raid base
|
||||
if (math.random() < 0.70) then
|
||||
if (math.random() < threshold) then
|
||||
squad.status = SQUAD_SUICIDE_RAID
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
end
|
||||
end
|
||||
end
|
||||
squad.status = SQUAD_SUICIDE_RAID
|
||||
else
|
||||
squad.status = SQUAD_RAIDING
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -11,42 +11,26 @@ local config = require("config")
|
||||
|
||||
-- constants
|
||||
|
||||
-- local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
-- local SQUAD_BURROWING = constants.SQUAD_BURROWING
|
||||
|
||||
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_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 MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
|
||||
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_SQUAD_COST = constants.AI_SQUAD_COST
|
||||
|
||||
local HALF_CHUNK_SIZE = constants.HALF_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 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_BASE_PROXIMITY = config.attackWaveGenerationUsePlayerBaseProximity
|
||||
local CONFIG_USE_PLAYER_DEFENSE_PROXIMITY = config.attackWaveGenerationUsePlayerDefenseProximity
|
||||
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
|
||||
|
||||
@ -55,25 +39,23 @@ local scoreNeighbors = neighborUtils.scoreNeighbors
|
||||
local createSquad = unitGroupUtils.createSquad
|
||||
local attackWaveScaling = config.attackWaveScaling
|
||||
|
||||
local mMax = math.max
|
||||
|
||||
-- module code
|
||||
|
||||
local function attackWaveValidCandidate(chunk, surface)
|
||||
local function attackWaveValidCandidate(chunk, surface, evolutionFactor)
|
||||
local total = 0;
|
||||
|
||||
if CONFIG_USE_PLAYER_PROXIMITY then
|
||||
total = total + chunk[PLAYER_PHEROMONE]
|
||||
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
|
||||
total = total + surface.get_pollution({chunk.pX, chunk.pY})
|
||||
end
|
||||
|
||||
local delta = CONFIG_USE_THRESHOLD_RANGE * evolutionFactor
|
||||
|
||||
if (total >= CONFIG_USE_THRESHOLD) then
|
||||
if (total > (CONFIG_USE_THRESHOLD_MAX - delta)) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@ -81,21 +63,13 @@ local function attackWaveValidCandidate(chunk, surface)
|
||||
end
|
||||
|
||||
local function scoreUnitGroupLocation(position, squad, neighborChunk, surface)
|
||||
local attackScore = surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_PHEROMONE]
|
||||
local avoidScore = neighborChunk[DEATH_PHEROMONE]
|
||||
return attackScore - avoidScore
|
||||
return surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
|
||||
end
|
||||
|
||||
local function validUnitGroupLocation(x, chunk, neighborChunk)
|
||||
return neighborChunk[NORTH_SOUTH_PASSABLE] and neighborChunk[EAST_WEST_PASSABLE]
|
||||
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)
|
||||
--[[
|
||||
local scouts = natives.scouts
|
||||
@ -142,12 +116,10 @@ function aiBuilding.scouting(regionMap, natives)
|
||||
--]]
|
||||
end
|
||||
|
||||
|
||||
|
||||
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
|
||||
local valid = attackWaveValidCandidate(chunk, surface)
|
||||
if valid and (math.random() < 0.03) then
|
||||
local valid = attackWaveValidCandidate(chunk, surface, evolution_factor)
|
||||
if valid and (math.random() < mMax((0.25 * evolution_factor), 0.10)) then
|
||||
local squadPosition = {x=0, y=0}
|
||||
local squadPath, squadScore = scoreNeighbors(chunk,
|
||||
getNeighborChunks(regionMap, chunk.cX, chunk.cY),
|
||||
|
@ -9,12 +9,11 @@ local neighborUtils = require("NeighborUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
|
||||
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_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
|
||||
|
||||
@ -46,14 +45,14 @@ local function validRetreatLocation(x, chunk, neighborChunk)
|
||||
end
|
||||
|
||||
local function scoreRetreatLocation(position, squad, neighborChunk, surface)
|
||||
local safeScore = neighborChunk[ENEMY_BASE_PHEROMONE]
|
||||
local dangerScore = neighborChunk[DEATH_PHEROMONE] + surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_PHEROMONE] + (neighborChunk[ENEMY_BASE_GENERATOR] * 6)
|
||||
local safeScore = -neighborChunk[BASE_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE]
|
||||
local dangerScore = surface.get_pollution(position) + neighborChunk[PLAYER_PHEROMONE] + (neighborChunk[ENEMY_BASE_GENERATOR] * 6)
|
||||
return safeScore - dangerScore
|
||||
end
|
||||
|
||||
function aiDefense.retreatUnits(position, squad, regionMap, surface, natives)
|
||||
local chunk = getChunkByPosition(regionMap, position.x, position.y)
|
||||
if (chunk ~= nil) and (chunk[DEATH_PHEROMONE] > (game.evolution_factor * RETREAT_DEATH_PHEROMONE_LEVEL)) then
|
||||
if (chunk ~= nil) and (chunk[MOVEMENT_PHEROMONE] > -(game.evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
|
||||
local performRetreat = false
|
||||
local enemiesToSquad
|
||||
|
||||
|
51
libs/AIPlanning.lua
Normal file
51
libs/AIPlanning.lua
Normal 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
|
@ -13,7 +13,8 @@ local scoreChunk = chunkUtils.scoreChunk
|
||||
-- module code
|
||||
|
||||
function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
|
||||
|
||||
local processQueue = regionMap.processQueue
|
||||
|
||||
for _=#pendingStack, 1, -1 do
|
||||
local event = pendingStack[#pendingStack]
|
||||
pendingStack[#pendingStack] = nil
|
||||
@ -29,8 +30,6 @@ function chunkProcessor.processPendingChunks(regionMap, surface, pendingStack)
|
||||
|
||||
checkChunkPassability(chunk, surface)
|
||||
scoreChunk(chunk, surface)
|
||||
|
||||
local processQueue = regionMap.processQueue
|
||||
processQueue[#processQueue+1] = chunk
|
||||
end
|
||||
end
|
||||
|
@ -2,22 +2,15 @@ local chunkUtils = {}
|
||||
|
||||
-- imports
|
||||
|
||||
-- local mapUtils = require("MapUtils")
|
||||
local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
|
||||
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_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 DEFENSE_PHEROMONES = constants.DEFENSE_PHEROMONES
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
|
||||
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_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 CHUNK_TICK = constants.CHUNK_TICK
|
||||
|
||||
-- module code
|
||||
|
||||
function chunkUtils.checkForDeadendTiles(constantCoordinate, iteratingCoordinate, direction, surface)
|
||||
@ -85,7 +80,6 @@ function chunkUtils.scoreChunk(chunk, surface)
|
||||
|
||||
local entities = surface.count_entities_filtered(enemyChunkQuery)
|
||||
local playerObjects = 0
|
||||
local playerDefenses = 0
|
||||
|
||||
chunk[ENEMY_BASE_GENERATOR] = entities * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
|
||||
|
||||
@ -94,44 +88,41 @@ function chunkUtils.scoreChunk(chunk, surface)
|
||||
for i=1, #entities do
|
||||
local entityType = entities[i].type
|
||||
|
||||
local entityScore = DEFENSE_PHEROMONES[entityType]
|
||||
if (entityScore ~= nil) then
|
||||
playerDefenses = playerDefenses + entityScore
|
||||
end
|
||||
entityScore = BUILDING_PHEROMONES[entityType]
|
||||
local entityScore = BUILDING_PHEROMONES[entityType]
|
||||
if (entityScore ~= nil) then
|
||||
playerObjects = playerObjects + entityScore
|
||||
end
|
||||
end
|
||||
|
||||
chunk[PLAYER_BASE_GENERATOR] = playerObjects
|
||||
chunk[PLAYER_DEFENSE_GENERATOR] = playerDefenses
|
||||
end
|
||||
|
||||
function chunkUtils.createChunk(topX, topY)
|
||||
local chunk = {
|
||||
pX = topX,
|
||||
pY = topY,
|
||||
cX = topX * 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
|
||||
local chunk = {
|
||||
pX = topX,
|
||||
pY = topY,
|
||||
cX = topX * 0.03125,
|
||||
cY = topY * 0.03125
|
||||
}
|
||||
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
|
||||
end
|
||||
|
||||
-- function chunkUtils.colorChunk(x, y, tileType, surface)
|
||||
-- local tiles = {}
|
||||
-- for xi=x+5, x + 27 do
|
||||
-- for yi=y+5, y + 27 do
|
||||
-- tiles[#tiles+1] = {name=tileType, position={xi, yi}}
|
||||
-- end
|
||||
-- end
|
||||
-- surface.set_tiles(tiles, false)
|
||||
-- local tiles = {}
|
||||
-- for xi=x+5, x + 27 do
|
||||
-- for yi=y+5, y + 27 do
|
||||
-- tiles[#tiles+1] = {name=tileType, position={xi, yi}}
|
||||
-- end
|
||||
-- end
|
||||
-- surface.set_tiles(tiles, false)
|
||||
-- end
|
||||
|
||||
return chunkUtils
|
||||
|
@ -5,44 +5,49 @@ local constants = {}
|
||||
constants.VERSION_5 = 5
|
||||
constants.VERSION_9 = 9
|
||||
constants.VERSION_10 = 10
|
||||
constants.VERSION_11 = 11
|
||||
|
||||
-- misc
|
||||
|
||||
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.PROCESS_PLAYER_BOUND = 3
|
||||
|
||||
-- temps
|
||||
constants.TICKS_A_SECOND = 60
|
||||
constants.TICKS_A_MINUTE = constants.TICKS_A_SECOND * 60
|
||||
|
||||
-- constants.ATTACK_POSITION = 1
|
||||
-- constants.ATTACK_COMMAND = 2
|
||||
-- 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
|
||||
constants.INTERVAL_PROCESS = 20
|
||||
constants.INTERVAL_LOGIC = 40
|
||||
|
||||
-- ai
|
||||
|
||||
constants.AI_POINT_GENERATOR_AMOUNT = 6
|
||||
constants.AI_SCOUT_COST = 45
|
||||
constants.AI_SQUAD_COST = 150
|
||||
constants.AI_SQUAD_COST = 175
|
||||
constants.AI_SETTLER_COST = 75
|
||||
constants.AI_BASE_BUILDING_COST = 500
|
||||
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_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
|
||||
|
||||
constants.CHUNK_SIZE = 32
|
||||
@ -53,46 +58,41 @@ constants.EAST_WEST = 2
|
||||
|
||||
-- pheromone amounts
|
||||
|
||||
constants.MOVEMENT_PENALTY_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.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 300
|
||||
constants.PLAYER_PHEROMONE_GENERATOR_AMOUNT = 100
|
||||
|
||||
-- pheromone diffusion amounts
|
||||
|
||||
constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT = 0.10
|
||||
constants.DEATH_PHEROMONE_DIFFUSION_AMOUNT = 0.02
|
||||
constants.STANDARD_PHERONOME_DIFFUSION_AMOUNT = 0.05
|
||||
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
|
||||
|
||||
-- chunk attributes
|
||||
|
||||
constants.DEATH_PHEROMONE = 1
|
||||
constants.ENEMY_BASE_PHEROMONE = 2
|
||||
constants.MOVEMENT_PHEROMONE = 1
|
||||
constants.BASE_PHEROMONE = 2
|
||||
constants.PLAYER_PHEROMONE = 3
|
||||
constants.PLAYER_BASE_PHEROMONE = 4
|
||||
constants.PLAYER_DEFENSE_PHEROMONE = 5
|
||||
constants.MOVEMENT_PHEROMONE = 6
|
||||
|
||||
constants.ENEMY_BASE_GENERATOR = 7
|
||||
constants.PLAYER_BASE_GENERATOR = 8
|
||||
constants.PLAYER_DEFENSE_GENERATOR = 9
|
||||
constants.ENEMY_BASE_GENERATOR = 4
|
||||
constants.PLAYER_BASE_GENERATOR = 5
|
||||
|
||||
constants.NORTH_SOUTH_PASSABLE = 10
|
||||
constants.EAST_WEST_PASSABLE = 11
|
||||
constants.NORTH_SOUTH_PASSABLE = 6
|
||||
constants.EAST_WEST_PASSABLE = 7
|
||||
|
||||
constants.CHUNK_TICK = 8
|
||||
|
||||
-- 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_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_RAIDING = 8 -- used when player stuff is close
|
||||
constants.SQUAD_SUICIDE_RAID = 9 -- when player stuff is close with no retreat
|
||||
constants.SQUAD_BURROWING = 4
|
||||
constants.SQUAD_RAIDING = 5 -- used when player stuff is close
|
||||
constants.SQUAD_SUICIDE_RAID = 6 -- when player stuff is close with no retreat
|
||||
-- constants.SQUAD_SCOUTING = 7
|
||||
-- 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.buildingPheromones["container"] = 1
|
||||
-- constants.buildingPheromones["storage-tank"] = 1
|
||||
constants.BUILDING_PHEROMONES["generator"] = 60
|
||||
constants.BUILDING_PHEROMONES["pump"] = 8
|
||||
constants.BUILDING_PHEROMONES["offshore-pump"] = 8
|
||||
constants.BUILDING_PHEROMONES["generator"] = 8
|
||||
constants.BUILDING_PHEROMONES["pump"] = 2
|
||||
constants.BUILDING_PHEROMONES["offshore-pump"] = 2
|
||||
-- constants.buildingPheromones["constant-combinator"] = 1
|
||||
-- constants.buildingPheromones["train-stop"] = 2
|
||||
-- constants.buildingPheromones["rail-signal"] = 1
|
||||
-- constants.BUILDING_PHEROMONES["electric-pole"] = 4
|
||||
constants.BUILDING_PHEROMONES["transport-belt"] = 4
|
||||
constants.BUILDING_PHEROMONES["accumulator"] = 40
|
||||
constants.BUILDING_PHEROMONES["solar-panel"] = 32
|
||||
constants.BUILDING_PHEROMONES["boiler"] = 60
|
||||
constants.BUILDING_PHEROMONES["assembling-machine"] = 48
|
||||
constants.BUILDING_PHEROMONES["roboport"] = 40
|
||||
constants.BUILDING_PHEROMONES["beacon"] = 40
|
||||
constants.BUILDING_PHEROMONES["furnace"] = 60
|
||||
constants.BUILDING_PHEROMONES["mining-drill"] = 80
|
||||
constants.BUILDING_PHEROMONES["transport-belt"] = 1
|
||||
constants.BUILDING_PHEROMONES["accumulator"] = 10
|
||||
constants.BUILDING_PHEROMONES["solar-panel"] = 8
|
||||
constants.BUILDING_PHEROMONES["boiler"] = 12
|
||||
constants.BUILDING_PHEROMONES["assembling-machine"] = 12
|
||||
constants.BUILDING_PHEROMONES["roboport"] = 10
|
||||
constants.BUILDING_PHEROMONES["beacon"] = 10
|
||||
constants.BUILDING_PHEROMONES["furnace"] = 12
|
||||
constants.BUILDING_PHEROMONES["mining-drill"] = 15
|
||||
|
||||
-- player defense pheromones
|
||||
|
||||
constants.DEFENSE_PHEROMONES = {}
|
||||
constants.DEFENSE_PHEROMONES["ammo-turret"] = 5
|
||||
constants.DEFENSE_PHEROMONES["wall"] = 0.5
|
||||
constants.DEFENSE_PHEROMONES["electric-turret"] = 7.5
|
||||
constants.DEFENSE_PHEROMONES["fluid-turret"] = 10
|
||||
constants.DEFENSE_PHEROMONES["turret"] = 3
|
||||
|
||||
-- enemy units
|
||||
|
||||
-- constants.deathPheromones = {}
|
||||
-- constants.deathPheromones[""]
|
||||
constants.BUILDING_PHEROMONES["ammo-turret"] = 2.5
|
||||
constants.BUILDING_PHEROMONES["wall"] = 0.25
|
||||
constants.BUILDING_PHEROMONES["electric-turret"] = 4.25
|
||||
constants.BUILDING_PHEROMONES["fluid-turret"] = 5
|
||||
constants.BUILDING_PHEROMONES["turret"] = 3.5
|
||||
|
||||
constants.retreatFilter = {}
|
||||
constants.retreatFilter[constants.SQUAD_RETREATING] = true
|
||||
|
@ -8,10 +8,8 @@ local constants = require("Constants")
|
||||
-- constants
|
||||
|
||||
local BUILDING_PHEROMONES = constants.BUILDING_PHEROMONES
|
||||
local DEFENSE_PHEROMONES = constants.DEFENSE_PHEROMONES
|
||||
|
||||
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 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
|
||||
entityValue = BUILDING_PHEROMONES[entity.type]
|
||||
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
|
||||
entityValue = ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
|
||||
pheromoneType = ENEMY_BASE_GENERATOR
|
||||
@ -117,4 +112,4 @@ function entityUtils.addRemoveEntity(regionMap, entity, natives, addObject)
|
||||
end
|
||||
|
||||
|
||||
return entityUtils
|
||||
return entityUtils
|
||||
|
@ -2,10 +2,10 @@ local mapProcessor = {}
|
||||
|
||||
-- imports
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local pheromoneUtils = require("PheromoneUtils")
|
||||
local aiBuilding = require("AIBuilding")
|
||||
local constants = require("Constants")
|
||||
local mapUtils = require("MapUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
@ -15,6 +15,11 @@ local SCAN_QUEUE_SIZE = constants.SCAN_QUEUE_SIZE
|
||||
|
||||
local CHUNK_SIZE = constants.CHUNK_SIZE
|
||||
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
|
||||
|
||||
@ -24,17 +29,38 @@ local processPheromone = pheromoneUtils.processPheromone
|
||||
local makeScouts = aiBuilding.makeScouts
|
||||
local formSquads = aiBuilding.formSquads
|
||||
|
||||
local getCardinalChunks = mapUtils.getCardinalChunks
|
||||
local getChunkByIndex = mapUtils.getChunkByIndex
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local playerScent = pheromoneUtils.playerScent
|
||||
|
||||
local mMin = math.min
|
||||
|
||||
-- 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
|
||||
-- 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, temps)
|
||||
|
||||
local function nonRepeatingRandom(players)
|
||||
local ordering = {}
|
||||
for _,player in pairs(players) do
|
||||
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 index = regionMap.processPointer
|
||||
local scouts = false
|
||||
@ -49,8 +75,8 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
|
||||
scouts = true
|
||||
end
|
||||
|
||||
if (0.11 <= roll) and (roll <= 0.35) then
|
||||
squads = true
|
||||
if (natives.state == AI_STATE_AGGRESSIVE) and (0.11 <= roll) and (roll <= 0.35) then
|
||||
squads = true
|
||||
end
|
||||
|
||||
local processQueue = regionMap.processQueue
|
||||
@ -64,10 +90,10 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
|
||||
makeScouts(surface, natives, chunk, evolution_factor)
|
||||
end
|
||||
if squads then
|
||||
formSquads(regionMap, surface, natives, chunk, evolution_factor, temps)
|
||||
formSquads(regionMap, surface, natives, chunk, evolution_factor)
|
||||
end
|
||||
|
||||
processPheromone(chunk, getCardinalChunks(regionMap, chunk.cX, chunk.cY))
|
||||
processPheromone(regionMap, chunk)
|
||||
end
|
||||
|
||||
if (endIndex == #processQueue) then
|
||||
@ -77,25 +103,90 @@ function mapProcessor.processMap(regionMap, surface, natives, evolution_factor,
|
||||
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)
|
||||
local index = regionMap.scanPointer
|
||||
|
||||
local processQueue = regionMap.processQueue
|
||||
local endIndex = mMin(index + SCAN_QUEUE_SIZE, #processQueue)
|
||||
for x=index,endIndex do
|
||||
local chunk = processQueue[x]
|
||||
local chunk = processQueue[x]
|
||||
|
||||
local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
type = "unit-spawner",
|
||||
force = "enemy"})
|
||||
chunk[ENEMY_BASE_GENERATOR] = spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
|
||||
local spawners = surface.count_entities_filtered({area = {{chunk.pX, chunk.pY},
|
||||
{chunk.pX + CHUNK_SIZE, chunk.pY + CHUNK_SIZE}},
|
||||
type = "unit-spawner",
|
||||
force = "enemy"})
|
||||
chunk[ENEMY_BASE_GENERATOR] = spawners * ENEMY_BASE_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
|
||||
if (endIndex == #processQueue) then
|
||||
regionMap.scanPointer = 1
|
||||
regionMap.scanPointer = 1
|
||||
else
|
||||
regionMap.scanPointer = endIndex + 1
|
||||
regionMap.scanPointer = endIndex + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
28
libs/MathUtils.lua
Normal file
28
libs/MathUtils.lua
Normal 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
|
@ -7,96 +7,76 @@ local constants = require("Constants")
|
||||
|
||||
-- constants
|
||||
|
||||
local DEATH_PHEROMONE = constants.DEATH_PHEROMONE
|
||||
local PLAYER_DEFENSE_PHEROMONE = constants.PLAYER_DEFENSE_PHEROMONE
|
||||
local PLAYER_BASE_PHEROMONE = constants.PLAYER_BASE_PHEROMONE
|
||||
local ENEMY_BASE_PHEROMONE = constants.ENEMY_BASE_PHEROMONE
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
|
||||
local PLAYER_DEFENSE_GENERATOR = constants.PLAYER_DEFENSE_GENERATOR
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_GENERATOR
|
||||
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
|
||||
|
||||
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 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
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local getCardinalChunks = mapUtils.getCardinalChunks
|
||||
|
||||
-- module code
|
||||
|
||||
function pheromoneUtils.scents(chunk)
|
||||
local amount = chunk[PLAYER_DEFENSE_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
|
||||
chunk[BASE_PHEROMONE] = chunk[BASE_PHEROMONE] + chunk[PLAYER_BASE_GENERATOR] - chunk[ENEMY_BASE_GENERATOR]
|
||||
end
|
||||
|
||||
function pheromoneUtils.deathScent(regionMap, position)
|
||||
local chunk = getChunkByPosition(regionMap, position.x, position.y)
|
||||
if (chunk ~= nil) then
|
||||
chunk[DEATH_PHEROMONE] = chunk[DEATH_PHEROMONE] + DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
-- pheromoneTotals[DEATH_PHEROMONE] = pheromoneTotals[DEATH_PHEROMONE] + DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.playerScent(regionMap, players)
|
||||
for i=1,#players do
|
||||
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
|
||||
function pheromoneUtils.playerScent(playerChunk)
|
||||
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
|
||||
function pheromoneUtils.processPheromone(chunk, neighbors)
|
||||
|
||||
-- pheromone level indexes on chunks are 1 - 6
|
||||
function pheromoneUtils.processPheromone(regionMap, chunk)
|
||||
local neighbors
|
||||
|
||||
-- pheromone level indexes on chunks are 1 - 3
|
||||
-- unrolled loop one level
|
||||
local diffusionAmount = DEATH_PHEROMONE_DIFFUSION_AMOUNT
|
||||
local persistence = DEATH_PHEROMONE_PERSISTANCE
|
||||
local diffusionAmount = MOVEMENT_PHEROMONE_DIFFUSION_AMOUNT
|
||||
local persistence = MOVEMENT_PHEROMONE_PERSISTANCE
|
||||
local totalDiffused = 0
|
||||
local chunkValue = chunk[DEATH_PHEROMONE] * persistence
|
||||
local chunkValue = chunk[MOVEMENT_PHEROMONE] * persistence
|
||||
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
|
||||
local neighborChunk = neighbors[i]
|
||||
if (neighborChunk ~= nil) then
|
||||
totalDiffused = totalDiffused + diffusedAmount
|
||||
neighborChunk[DEATH_PHEROMONE] = neighborChunk[DEATH_PHEROMONE] + diffusedAmount
|
||||
neighborChunk[MOVEMENT_PHEROMONE] = neighborChunk[MOVEMENT_PHEROMONE] + diffusedAmount
|
||||
end
|
||||
end
|
||||
end
|
||||
chunk[DEATH_PHEROMONE] = (chunkValue - totalDiffused)
|
||||
chunk[MOVEMENT_PHEROMONE] = (chunkValue - totalDiffused)
|
||||
|
||||
diffusionAmount = STANDARD_PHERONOME_DIFFUSION_AMOUNT
|
||||
persistence = STANDARD_PHEROMONE_PERSISTANCE
|
||||
for x=2,6 do
|
||||
totalDiffused = 0
|
||||
chunkValue = chunk[x] * persistence
|
||||
diffusedAmount = chunkValue * diffusionAmount
|
||||
if (chunkValue > 2) then
|
||||
for x=2,3 do
|
||||
totalDiffused = 0
|
||||
chunkValue = chunk[x] * persistence
|
||||
diffusedAmount = chunkValue * diffusionAmount
|
||||
if (diffusedAmount > 1.5) then
|
||||
if (neighbors == nil) then
|
||||
neighbors = getCardinalChunks(regionMap, chunk.cX, chunk.cY)
|
||||
end
|
||||
for i=1,#neighbors do
|
||||
local neighborChunk = neighbors[i]
|
||||
if (neighborChunk ~= nil) then
|
||||
@ -105,7 +85,7 @@ function pheromoneUtils.processPheromone(chunk, neighbors)
|
||||
end
|
||||
end
|
||||
end
|
||||
chunk[x] = (chunkValue - totalDiffused)
|
||||
chunk[x] = (chunkValue - totalDiffused)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -11,16 +11,15 @@ local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
|
||||
-- module code
|
||||
|
||||
function playerUtils.playersWithinProximityToPosition(players, position, distance)
|
||||
for x=1,#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 (euclideanDistanceNamed(player.character.position, position) < distance) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
for _,player in pairs(players) do
|
||||
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
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
return playerUtils
|
||||
return playerUtils
|
||||
|
@ -7,7 +7,7 @@ local constants = require("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
|
||||
|
||||
@ -93,14 +93,14 @@ function unitGroupUtils.addSquadMovementPenalty(squad, chunkX, chunkY)
|
||||
for i=1,#penalties do
|
||||
local penalty = penalties[i]
|
||||
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
|
||||
end
|
||||
end
|
||||
if (#penalties == 10) then
|
||||
tableRemove(penalties, 10)
|
||||
end
|
||||
tableInsert(penalties, 1, { v = MOVEMENT_PENALTY_PHEROMONE_GENERATOR_AMOUNT,
|
||||
tableInsert(penalties, 1, { v = MOVEMENT_PHEROMONE_GENERATOR_AMOUNT,
|
||||
x = chunkX,
|
||||
y = chunkY })
|
||||
end
|
||||
|
115
make.rkt
115
make.rkt
@ -6,74 +6,75 @@
|
||||
;(define modFolder "C:/Users/veden/AppData/Roaming/Factorio/mods/")
|
||||
;(define zipModFolder "C:/Program Files/Factorio_0.14.1/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"
|
||||
(lambda (port)
|
||||
(string->jsexpr (port->string port)))))
|
||||
(define packageName (string-append (string-replace (hash-ref configuration 'name) " " "_")
|
||||
"_"
|
||||
(hash-ref configuration 'version)))
|
||||
"_"
|
||||
(hash-ref configuration 'version)))
|
||||
|
||||
(define (makeZip)
|
||||
(let ((packagePath (string->path (string-append modFolder
|
||||
packageName
|
||||
".zip"))))
|
||||
(when (file-exists? packagePath)
|
||||
(delete-file packagePath)))
|
||||
(zip (string-append modFolder
|
||||
packageName
|
||||
".zip")
|
||||
#:path-prefix packageName
|
||||
(string->path "info.json")
|
||||
(string->path "control.lua")
|
||||
(string->path "config.lua")
|
||||
(string->path "data.lua")
|
||||
(string->path "LICENSE.md")
|
||||
(string->path "tests.lua")
|
||||
; (string->path "setupUtils.lua")
|
||||
(string->path "README.md")
|
||||
; (string->path "setup.lua")
|
||||
(string->path "NOTICE")
|
||||
(string->path "libs")
|
||||
(string->path "locale")
|
||||
(string->path "graphics")
|
||||
(string->path "prototypes")))
|
||||
(define (makeZip folder)
|
||||
(let ((packagePath (string->path (string-append folder
|
||||
packageName
|
||||
".zip"))))
|
||||
(when (file-exists? packagePath)
|
||||
(delete-file packagePath)))
|
||||
(zip (string-append folder
|
||||
packageName
|
||||
".zip")
|
||||
#:path-prefix packageName
|
||||
(string->path "info.json")
|
||||
(string->path "control.lua")
|
||||
(string->path "config.lua")
|
||||
(string->path "data.lua")
|
||||
(string->path "LICENSE.md")
|
||||
(string->path "tests.lua")
|
||||
; (string->path "setupUtils.lua")
|
||||
(string->path "README.md")
|
||||
; (string->path "setup.lua")
|
||||
(string->path "NOTICE")
|
||||
(string->path "libs")
|
||||
(string->path "locale")
|
||||
(string->path "graphics")
|
||||
(string->path "prototypes")))
|
||||
|
||||
|
||||
;(current-directory "..")
|
||||
(define (copyFile fileName modFolder)
|
||||
(copy-file (string->path fileName)
|
||||
(string->path (string-append modFolder
|
||||
packageName
|
||||
"/"
|
||||
fileName))))
|
||||
(copy-file (string->path fileName)
|
||||
(string->path (string-append modFolder
|
||||
packageName
|
||||
"/"
|
||||
fileName))))
|
||||
|
||||
(define (copyDirectory directoryName modFolder)
|
||||
(copy-directory/files (string->path directoryName)
|
||||
(string->path (string-append modFolder
|
||||
packageName
|
||||
"/"
|
||||
directoryName))))
|
||||
(copy-directory/files (string->path directoryName)
|
||||
(string->path (string-append modFolder
|
||||
packageName
|
||||
"/"
|
||||
directoryName))))
|
||||
|
||||
(define (copyFiles modFolder)
|
||||
(let ((packagePath (string->path (string-append modFolder
|
||||
packageName))))
|
||||
(when (directory-exists? packagePath)
|
||||
(delete-directory/files packagePath))
|
||||
(sleep 0.1)
|
||||
(make-directory packagePath)
|
||||
(copyFile "control.lua" modFolder)
|
||||
(copyFile "config.lua" modFolder)
|
||||
(copyFile "info.json" modFolder)
|
||||
; (copyFile "setupUtils.lua" modFolder)
|
||||
(copyFile "data.lua" modFolder)
|
||||
(copyFile "tests.lua" modFolder)
|
||||
(copyDirectory "libs" modFolder)
|
||||
(copyDirectory "locale" modFolder)
|
||||
(copyDirectory "graphics" modFolder)
|
||||
(copyDirectory "prototypes" modFolder)))
|
||||
|
||||
;; (copyFiles modFolder)
|
||||
;; (copyFiles zipModFolder)
|
||||
(makeZip)
|
||||
(let ((packagePath (string->path (string-append modFolder
|
||||
packageName))))
|
||||
(when (directory-exists? packagePath)
|
||||
(delete-directory/files packagePath))
|
||||
(sleep 0.1)
|
||||
(make-directory packagePath)
|
||||
(copyFile "control.lua" modFolder)
|
||||
(copyFile "config.lua" modFolder)
|
||||
(copyFile "info.json" modFolder)
|
||||
; (copyFile "setupUtils.lua" modFolder)
|
||||
(copyFile "data.lua" modFolder)
|
||||
(copyFile "tests.lua" modFolder)
|
||||
(copyDirectory "libs" modFolder)
|
||||
(copyDirectory "locale" modFolder)
|
||||
(copyDirectory "graphics" modFolder)
|
||||
(copyDirectory "prototypes" modFolder)))
|
||||
|
||||
;; (copyFiles modFolder)
|
||||
;; (copyFiles zipModFolder)
|
||||
(makeZip modFolder)
|
||||
(makeZip zipModFolder)
|
||||
)
|
||||
|
21
tests.lua
21
tests.lua
@ -10,8 +10,8 @@ function tests.test1()
|
||||
print(#global.regionMap.processQueue)
|
||||
print(playerChunkX .. ", " .. playerChunkY)
|
||||
print("--")
|
||||
for x=playerChunkX-3, playerChunkX+3 do
|
||||
for y=playerChunkY-3, playerChunkY+3 do
|
||||
for x=playerChunkX-9, playerChunkX+9 do
|
||||
for y=playerChunkY-9, playerChunkY+9 do
|
||||
if (global.regionMap[x] ~= nil) then
|
||||
local chunk = global.regionMap[x][y]
|
||||
if (chunk ~= nil) then
|
||||
@ -19,13 +19,14 @@ function tests.test1()
|
||||
for i=1,#chunk do
|
||||
str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i])
|
||||
end
|
||||
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
|
||||
print("*", chunk.cX, chunk.cY, str)
|
||||
else
|
||||
print(chunk.cX, chunk.cY, str)
|
||||
end
|
||||
-- print(str)
|
||||
print("-")
|
||||
str = str .. " " .. "p/" .. game.surfaces[1].get_pollution({x=chunk.pX, y=chunk.pY})
|
||||
if (chunk.cX == playerChunkX) and (chunk.cY == playerChunkY) then
|
||||
print("*", chunk.cX, chunk.cY, str)
|
||||
else
|
||||
print(chunk.cX, chunk.cY, str)
|
||||
end
|
||||
-- print(str)
|
||||
print("-")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -118,4 +119,4 @@ function tests.test11()
|
||||
print(serpent.dump(global.pheromoneTotals))
|
||||
end
|
||||
|
||||
return tests
|
||||
return tests
|
||||
|
Loading…
Reference in New Issue
Block a user