2017-06-12 20:16:43 -07:00
|
|
|
local aiAttackWave = {}
|
2016-08-17 22:55:08 -07:00
|
|
|
|
2016-08-19 19:52:27 -07:00
|
|
|
-- imports
|
|
|
|
|
2016-08-18 19:02:13 -07:00
|
|
|
local constants = require("Constants")
|
|
|
|
local mapUtils = require("MapUtils")
|
2018-01-14 23:41:55 -08:00
|
|
|
local chunkPropetyUtils = require("ChunkPropertyUtils")
|
2016-08-18 19:02:13 -07:00
|
|
|
local unitGroupUtils = require("UnitGroupUtils")
|
2017-11-20 23:27:03 -08:00
|
|
|
local movementUtils = require("MovementUtils")
|
2016-10-07 07:30:31 -07:00
|
|
|
package.path = "../?.lua;" .. package.path
|
|
|
|
local config = require("config")
|
2016-08-17 22:55:08 -07:00
|
|
|
|
2016-08-19 19:52:27 -07:00
|
|
|
-- constants
|
|
|
|
|
2016-10-14 17:00:18 -07:00
|
|
|
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
2016-08-19 19:52:27 -07:00
|
|
|
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
2016-10-14 17:00:18 -07:00
|
|
|
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
2016-08-19 19:52:27 -07:00
|
|
|
|
2016-10-14 17:00:18 -07:00
|
|
|
local AI_SQUAD_COST = constants.AI_SQUAD_COST
|
2016-11-04 00:26:19 -07:00
|
|
|
local AI_VENGENCE_SQUAD_COST = constants.AI_VENGENCE_SQUAD_COST
|
2016-10-14 17:00:18 -07:00
|
|
|
|
2017-05-23 23:46:23 -07:00
|
|
|
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
2017-05-13 15:32:16 -07:00
|
|
|
|
2017-05-31 18:46:53 -07:00
|
|
|
local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE
|
2017-06-10 01:38:20 -07:00
|
|
|
local CHUNK_ALL_DIRECTIONS = constants.CHUNK_ALL_DIRECTIONS
|
2016-08-19 19:52:27 -07:00
|
|
|
|
2017-11-20 23:27:03 -08:00
|
|
|
local CHUNK_SIZE = constants.CHUNK_SIZE
|
|
|
|
|
2017-05-26 17:58:33 -07:00
|
|
|
local RALLY_CRY_DISTANCE = constants.RALLY_CRY_DISTANCE
|
|
|
|
|
|
|
|
local DEFINES_COMMAND_GROUP = defines.command.group
|
|
|
|
local DEFINES_DISTRACTION_NONE = defines.distraction.none
|
2017-01-19 21:58:36 -08:00
|
|
|
|
2018-02-09 23:57:04 -08:00
|
|
|
local RAIDING_MINIMUM_BASE_THRESHOLD = constants.RAIDING_MINIMUM_BASE_THRESHOLD
|
|
|
|
|
|
|
|
local AI_STATE_RAIDING = constants.AI_STATE_RAIDING
|
|
|
|
|
2017-11-20 23:27:03 -08:00
|
|
|
local SENTINEL_IMPASSABLE_CHUNK = constants.SENTINEL_IMPASSABLE_CHUNK
|
|
|
|
|
|
|
|
local PASSABLE = constants.PASSABLE
|
2017-05-11 21:50:06 -07:00
|
|
|
|
2016-08-19 19:52:27 -07:00
|
|
|
-- imported functions
|
|
|
|
|
2017-06-30 21:36:23 -07:00
|
|
|
local mRandom = math.random
|
|
|
|
|
2017-06-07 17:57:24 -07:00
|
|
|
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
|
|
|
|
2018-01-14 23:41:55 -08:00
|
|
|
local getNestCount = chunkPropetyUtils.getNestCount
|
|
|
|
local getRallyTick = chunkPropetyUtils.getRallyTick
|
|
|
|
local setRallyTick = chunkPropetyUtils.setRallyTick
|
2017-11-20 23:27:03 -08:00
|
|
|
|
2016-08-19 19:52:27 -07:00
|
|
|
local getNeighborChunks = mapUtils.getNeighborChunks
|
2017-12-28 21:38:10 -08:00
|
|
|
local getChunkByXY = mapUtils.getChunkByXY
|
2017-11-20 23:27:03 -08:00
|
|
|
local scoreNeighborsForFormation = movementUtils.scoreNeighborsForFormation
|
2016-08-19 19:52:27 -07:00
|
|
|
local createSquad = unitGroupUtils.createSquad
|
2016-10-07 07:30:31 -07:00
|
|
|
local attackWaveScaling = config.attackWaveScaling
|
2016-08-19 19:52:27 -07:00
|
|
|
|
|
|
|
-- module code
|
2016-08-18 19:02:13 -07:00
|
|
|
|
2017-05-31 18:46:53 -07:00
|
|
|
local function attackWaveValidCandidate(chunk, natives, surface)
|
2016-10-07 07:30:31 -07:00
|
|
|
local total = 0;
|
|
|
|
|
2017-06-10 01:38:20 -07:00
|
|
|
local hasPlayerPheromone = false
|
2017-05-06 02:03:28 -07:00
|
|
|
if natives.attackUsePlayer then
|
2017-04-21 16:14:04 -07:00
|
|
|
local playerPheromone = chunk[PLAYER_PHEROMONE]
|
2017-05-31 18:46:53 -07:00
|
|
|
if (playerPheromone > natives.attackPlayerThreshold) then
|
2017-04-21 16:14:04 -07:00
|
|
|
total = total + chunk[PLAYER_PHEROMONE]
|
2017-06-10 01:38:20 -07:00
|
|
|
hasPlayerPheromone = true
|
|
|
|
elseif (playerPheromone > 0) then
|
|
|
|
hasPlayerPheromone = true
|
2017-04-21 16:14:04 -07:00
|
|
|
end
|
2016-10-07 07:30:31 -07:00
|
|
|
end
|
2017-06-10 01:38:20 -07:00
|
|
|
local hasBasePheromone = false
|
2018-02-09 23:57:04 -08:00
|
|
|
local basePheromone = chunk[BASE_PHEROMONE]
|
|
|
|
if (basePheromone > 0) then
|
2017-06-10 01:38:20 -07:00
|
|
|
hasBasePheromone = true
|
2018-02-09 23:57:04 -08:00
|
|
|
if (natives.state == AI_STATE_RAIDING) then
|
|
|
|
if (basePheromone > RAIDING_MINIMUM_BASE_THRESHOLD) then
|
|
|
|
total = total + basePheromone
|
|
|
|
end
|
|
|
|
end
|
2017-06-10 01:38:20 -07:00
|
|
|
end
|
2017-05-06 02:03:28 -07:00
|
|
|
if natives.attackUsePollution then
|
2017-05-27 21:50:37 -07:00
|
|
|
total = total + surface.get_pollution(chunk)
|
2016-10-07 07:30:31 -07:00
|
|
|
end
|
|
|
|
|
2017-06-10 17:59:06 -07:00
|
|
|
return (total > natives.attackWaveThreshold) and (hasBasePheromone or hasPlayerPheromone)
|
2016-10-07 07:30:31 -07:00
|
|
|
end
|
|
|
|
|
2017-06-10 17:59:06 -07:00
|
|
|
local function scoreUnitGroupLocation(neighborChunk)
|
|
|
|
return neighborChunk[PLAYER_PHEROMONE] + neighborChunk[MOVEMENT_PHEROMONE] + neighborChunk[BASE_PHEROMONE]
|
2016-08-26 23:44:17 -07:00
|
|
|
end
|
|
|
|
|
2018-01-13 21:48:21 -08:00
|
|
|
local function validUnitGroupLocation(map, neighborChunk)
|
|
|
|
return neighborChunk[PASSABLE] == CHUNK_ALL_DIRECTIONS and (getNestCount(map, neighborChunk) == 0)
|
2016-08-26 23:44:17 -07:00
|
|
|
end
|
|
|
|
|
2018-01-13 21:48:21 -08:00
|
|
|
function aiAttackWave.rallyUnits(chunk, map, surface, natives, tick)
|
2018-02-10 00:42:17 -08:00
|
|
|
if ((tick - getRallyTick(map, chunk) > INTERVAL_LOGIC) and (natives.points >= AI_VENGENCE_SQUAD_COST)
|
2018-01-13 21:48:21 -08:00
|
|
|
) then
|
|
|
|
setRallyTick(map, chunk, tick)
|
2017-11-20 23:27:03 -08:00
|
|
|
local cX = chunk.x
|
|
|
|
local cY = chunk.y
|
|
|
|
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE, 32 do
|
|
|
|
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE, 32 do
|
2017-06-10 17:59:06 -07:00
|
|
|
if (x ~= cX) and (y ~= cY) then
|
2018-01-13 21:48:21 -08:00
|
|
|
local rallyChunk = getChunkByXY(map, x, y)
|
|
|
|
if (rallyChunk ~= SENTINEL_IMPASSABLE_CHUNK) and (getNestCount(map, rallyChunk) > 0) then
|
|
|
|
aiAttackWave.formSquads(map, surface, natives, rallyChunk, AI_VENGENCE_SQUAD_COST)
|
2018-02-10 00:42:17 -08:00
|
|
|
if (natives.points < AI_VENGENCE_SQUAD_COST) then
|
2017-06-10 17:59:06 -07:00
|
|
|
return
|
|
|
|
end
|
2017-05-31 18:46:53 -07:00
|
|
|
end
|
2017-05-23 23:46:23 -07:00
|
|
|
end
|
2017-01-19 21:58:36 -08:00
|
|
|
end
|
|
|
|
end
|
2017-03-25 14:46:30 -07:00
|
|
|
end
|
2017-01-19 21:58:36 -08:00
|
|
|
end
|
|
|
|
|
2018-01-13 21:48:21 -08:00
|
|
|
function aiAttackWave.formSquads(map, surface, natives, chunk, cost)
|
2017-06-10 17:59:06 -07:00
|
|
|
local valid = (cost == AI_VENGENCE_SQUAD_COST) or ((cost == AI_SQUAD_COST) and attackWaveValidCandidate(chunk, natives, surface))
|
2017-05-31 18:46:53 -07:00
|
|
|
|
2017-06-30 21:36:23 -07:00
|
|
|
if valid and (mRandom() < natives.formSquadThreshold) then
|
2017-05-31 18:46:53 -07:00
|
|
|
|
2018-01-13 21:48:21 -08:00
|
|
|
local squadPath, squadDirection = scoreNeighborsForFormation(getNeighborChunks(map, chunk.x, chunk.y),
|
2017-06-10 17:59:06 -07:00
|
|
|
validUnitGroupLocation,
|
2017-11-20 23:27:03 -08:00
|
|
|
scoreUnitGroupLocation,
|
2018-01-13 21:48:21 -08:00
|
|
|
map)
|
2017-11-20 23:27:03 -08:00
|
|
|
if (squadPath ~= SENTINEL_IMPASSABLE_CHUNK) then
|
2018-01-19 23:15:13 -08:00
|
|
|
local squadPosition = surface.find_non_colliding_position("chunk-scanner-squad-rampant",
|
2017-06-15 18:30:26 -07:00
|
|
|
positionFromDirectionAndChunk(squadDirection,
|
|
|
|
chunk,
|
2018-01-13 21:48:21 -08:00
|
|
|
map.position,
|
2017-06-15 18:30:26 -07:00
|
|
|
0.98),
|
2017-11-20 23:27:03 -08:00
|
|
|
CHUNK_SIZE,
|
2017-06-15 18:30:26 -07:00
|
|
|
4)
|
2017-06-08 22:18:59 -07:00
|
|
|
if squadPosition then
|
|
|
|
local squad = createSquad(squadPosition, surface, natives)
|
|
|
|
|
2017-06-30 21:36:23 -07:00
|
|
|
squad.rabid = mRandom() < 0.03
|
2017-06-08 22:18:59 -07:00
|
|
|
|
|
|
|
local scaledWaveSize = attackWaveScaling(natives)
|
|
|
|
local foundUnits = surface.set_multi_command({ command = { type = DEFINES_COMMAND_GROUP,
|
|
|
|
group = squad.group,
|
|
|
|
distraction = DEFINES_DISTRACTION_NONE },
|
|
|
|
unit_count = scaledWaveSize,
|
|
|
|
unit_search_distance = TRIPLE_CHUNK_SIZE })
|
|
|
|
if (foundUnits > 0) then
|
|
|
|
natives.points = natives.points - cost
|
|
|
|
end
|
2016-10-07 07:30:31 -07:00
|
|
|
end
|
|
|
|
end
|
2016-08-18 19:02:13 -07:00
|
|
|
end
|
|
|
|
end
|
2016-08-17 22:55:08 -07:00
|
|
|
|
2017-06-12 20:16:43 -07:00
|
|
|
return aiAttackWave
|