2016-08-18 07:55:08 +02:00
|
|
|
local aiAttack = {}
|
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- imports
|
2016-08-18 07:55:08 +02:00
|
|
|
|
|
|
|
local constants = require("Constants")
|
|
|
|
local mapUtils = require("MapUtils")
|
|
|
|
local unitGroupUtils = require("UnitGroupUtils")
|
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- 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 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
|
|
|
|
|
2016-08-20 21:04:04 +02:00
|
|
|
local AI_TUNNEL_COST = constants.AI_TUNNEL_COST
|
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
-- imported functions
|
|
|
|
|
|
|
|
local getCardinalChunks = mapUtils.getCardinalChunks
|
|
|
|
local positionToChunk = mapUtils.getChunkByPosition
|
|
|
|
local canMove = mapUtils.canMoveChunkDirectionCardinal
|
|
|
|
local addSquadMovementPenalty = unitGroupUtils.addSquadMovementPenalty
|
|
|
|
local lookupSquadMovementPenalty = unitGroupUtils.lookupSquadMovementPenalty
|
|
|
|
local positionDirectionToChunkCornerCardinal = mapUtils.positionDirectionToChunkCornerCardinal
|
|
|
|
local findDistance = mapUtils.euclideanDistanceNamed
|
2016-08-19 00:14:40 +02:00
|
|
|
|
2016-08-18 07:55:08 +02:00
|
|
|
local mRandom = math.random
|
|
|
|
|
2016-08-20 04:52:27 +02:00
|
|
|
-- module code
|
|
|
|
|
2016-08-18 07:55:08 +02:00
|
|
|
function aiAttack.squadAttackLocation(regionMap, surface, natives)
|
2016-08-25 01:30:45 +02:00
|
|
|
for _,squad in ipairs(natives.squads) do
|
2016-08-18 07:55:08 +02:00
|
|
|
local group = squad.group
|
2016-08-25 01:30:45 +02:00
|
|
|
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
|
2016-08-20 04:52:27 +02:00
|
|
|
local chunk = positionToChunk(regionMap, group.position.x, group.position.y)
|
2016-08-23 05:26:56 +02:00
|
|
|
if (chunk ~= nil) then
|
|
|
|
addSquadMovementPenalty(squad, chunk.cX, chunk.cY)
|
|
|
|
local attackChunk
|
|
|
|
local attackScore = -MAGIC_MAXIMUM_NUMBER
|
|
|
|
local attackDirection
|
|
|
|
local attackPosition = {x=0, y=0}
|
2016-08-25 01:30:45 +02:00
|
|
|
for x,neighborChunk in pairs(getCardinalChunks(regionMap, chunk.cX, chunk.cY)) do
|
|
|
|
if canMove(x, chunk, neighborChunk) then
|
2016-08-23 05:26:56 +02:00
|
|
|
attackPosition.x = neighborChunk.pX
|
|
|
|
attackPosition.y = neighborChunk.pY
|
|
|
|
local squadMovementPenalty = lookupSquadMovementPenalty(squad, neighborChunk.cX, neighborChunk.cY)
|
|
|
|
local damageScore = surface.get_pollution(attackPosition) + neighborChunk[PLAYER_BASE_PHEROMONE] + neighborChunk[PLAYER_PHEROMONE] + neighborChunk[PLAYER_DEFENSE_GENERATOR]
|
|
|
|
local avoidScore = neighborChunk[DEATH_PHEROMONE] + neighborChunk[ENEMY_BASE_PHEROMONE]
|
|
|
|
local score = damageScore - avoidScore - squadMovementPenalty
|
|
|
|
if (score > attackScore) then
|
|
|
|
attackScore = score
|
|
|
|
attackChunk = neighborChunk
|
|
|
|
attackDirection = x
|
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
end
|
2016-08-23 05:26:56 +02:00
|
|
|
if (attackChunk ~= nil) then
|
|
|
|
if ((attackChunk[PLAYER_BASE_GENERATOR] == 0) or (attackChunk[PLAYER_DEFENSE_GENERATOR] == 0)) or
|
2016-08-25 01:30:45 +02:00
|
|
|
((group.state == defines.group_state.finished) or (group.state == defines.group_state.gathering)) then
|
|
|
|
|
2016-08-23 05:26:56 +02:00
|
|
|
attackPosition = positionDirectionToChunkCornerCardinal(attackDirection, attackChunk)
|
|
|
|
squad.cycles = 2
|
|
|
|
|
2016-08-25 01:30:45 +02:00
|
|
|
group.set_command({type=defines.command.attack_area,
|
2016-08-23 05:26:56 +02:00
|
|
|
destination=attackPosition,
|
2016-08-25 01:30:45 +02:00
|
|
|
radius=16,
|
|
|
|
distraction=defines.distraction.by_anything})
|
2016-08-23 05:26:56 +02:00
|
|
|
group.start_moving()
|
|
|
|
end
|
2016-08-19 00:14:40 +02:00
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2016-08-25 01:30:45 +02:00
|
|
|
function aiAttack.squadAttackPlayer(natives, players)
|
|
|
|
for _,squad in ipairs(natives.squads) do
|
2016-08-18 07:55:08 +02:00
|
|
|
local group = squad.group
|
|
|
|
if (group.valid) and (squad.status == SQUAD_GUARDING) then
|
|
|
|
local closestPlayer
|
|
|
|
local closestDistance = MAGIC_MAXIMUM_NUMBER
|
2016-08-25 01:30:45 +02:00
|
|
|
for _,player in pairs(players) do
|
|
|
|
if player.connected and (player.character ~= nil) and (player.character.surface.index == 1) then
|
|
|
|
local playerCharacter = player.character
|
|
|
|
local distance = findDistance(playerCharacter.position, group.position)
|
|
|
|
if (distance < closestDistance) then
|
|
|
|
closestPlayer = playerCharacter
|
|
|
|
closestDistance = distance
|
2016-08-20 04:52:27 +02:00
|
|
|
end
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
if (closestDistance < 75) then
|
|
|
|
local squadType = SQUAD_HUNTING
|
2016-08-20 04:52:27 +02:00
|
|
|
if (mRandom() < 0.10) then -- TODO add sliding scale based on number of members and evolution
|
2016-08-18 07:55:08 +02:00
|
|
|
squadType = SQUAD_SUICIDE_HUNT
|
|
|
|
end
|
|
|
|
squad.status = squadType
|
2016-08-25 01:30:45 +02:00
|
|
|
group.set_command({type=defines.command.attack,
|
2016-08-20 04:52:27 +02:00
|
|
|
target=closestPlayer})
|
2016-08-18 07:55:08 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function aiAttack.squadBeginAttack(natives)
|
2016-08-25 01:30:45 +02:00
|
|
|
for _,squad in ipairs(natives.squads) do
|
|
|
|
if (squad.status == SQUAD_GUARDING) and (mRandom() < 0.70) then
|
2016-08-20 04:52:27 +02:00
|
|
|
if (mRandom() < 0.05) then
|
2016-08-18 07:55:08 +02:00
|
|
|
squad.status = SQUAD_SUICIDE_RAID
|
|
|
|
else
|
|
|
|
squad.status = SQUAD_RAIDING
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return aiAttack
|