1
0
mirror of https://github.com/veden/Rampant.git synced 2025-01-22 03:08:51 +02:00
Rampant/libs/SquadAttack.lua

380 lines
14 KiB
Lua
Raw Normal View History

2019-02-15 20:17:30 -08:00
if (squadAttackG) then
return squadAttackG
end
local squadAttack = {}
-- imports
local constants = require("Constants")
local mapUtils = require("MapUtils")
local unitGroupUtils = require("UnitGroupUtils")
local movementUtils = require("MovementUtils")
local mathUtils = require("MathUtils")
local chunkPropertyUtils = require("ChunkPropertyUtils")
local chunkUtils = require("ChunkUtils")
-- constants
2017-05-13 15:32:16 -07:00
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
2016-10-14 17:00:18 -07:00
local BASE_PHEROMONE = constants.BASE_PHEROMONE
2018-02-12 23:10:17 -08:00
local RESOURCE_PHEROMONE = constants.RESOURCE_PHEROMONE
2020-05-23 14:29:56 -07:00
local TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT = constants.TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT
2019-02-16 10:45:42 -08:00
local ATTACK_SCORE_KAMIKAZE = constants.ATTACK_SCORE_KAMIKAZE
2019-05-15 22:11:43 -07:00
local DIVISOR_DEATH_TRAIL_TABLE = constants.DIVISOR_DEATH_TRAIL_TABLE
2019-04-07 22:22:02 -07:00
local BASE_CLEAN_DISTANCE = constants.BASE_CLEAN_DISTANCE
local SQUAD_BUILDING = constants.SQUAD_BUILDING
local SQUAD_RAIDING = constants.SQUAD_RAIDING
2018-02-12 23:10:17 -08:00
local SQUAD_SETTLING = constants.SQUAD_SETTLING
local SQUAD_GUARDING = constants.SQUAD_GUARDING
2019-03-06 22:12:39 -08:00
local SQUAD_RETREATING = constants.SQUAD_RETREATING
local AI_MAX_BITER_GROUP_SIZE = constants.AI_MAX_BITER_GROUP_SIZE
2019-10-19 12:13:48 -07:00
local ATTACK_QUEUE_SIZE = constants.ATTACK_QUEUE_SIZE
local AI_STATE_SIEGE = constants.AI_STATE_SIEGE
2017-06-10 17:59:06 -07:00
local PLAYER_PHEROMONE_MULTIPLER = constants.PLAYER_PHEROMONE_MULTIPLER
2017-05-26 17:58:33 -07:00
local DEFINES_GROUP_FINISHED = defines.group_state.finished
local DEFINES_GROUP_GATHERING = defines.group_state.gathering
local DEFINES_GROUP_MOVING = defines.group_state.moving
2019-03-06 17:06:50 -08:00
local DEFINES_DISTRACTION_NONE = defines.distraction.none
2017-05-26 17:58:33 -07:00
local DEFINES_DISTRACTION_BY_ENEMY = defines.distraction.by_enemy
local DEFINES_DISTRACTION_BY_ANYTHING = defines.distraction.by_anything
-- imported functions
local mRandom = math.random
2019-05-15 22:11:43 -07:00
local mMin = math.min
2019-03-06 22:12:39 -08:00
local tRemove = table.remove
2020-05-15 13:51:38 -07:00
local euclideanDistancePoints = mathUtils.euclideanDistancePoints
local findMovementPosition = movementUtils.findMovementPosition
2019-03-06 22:12:39 -08:00
local removeSquadFromChunk = chunkPropertyUtils.removeSquadFromChunk
2019-05-15 22:11:43 -07:00
local addDeathGenerator = chunkPropertyUtils.addDeathGenerator
local getDeathGenerator = chunkPropertyUtils.getDeathGenerator
2019-03-06 22:12:39 -08:00
local getNestCount = chunkPropertyUtils.getNestCount
2018-02-16 19:31:29 -08:00
2017-06-07 17:57:24 -07:00
local getNeighborChunks = mapUtils.getNeighborChunks
local addSquadToChunk = chunkPropertyUtils.addSquadToChunk
2018-01-13 21:48:21 -08:00
local getChunkByXY = mapUtils.getChunkByXY
local positionToChunkXY = mapUtils.positionToChunkXY
local addMovementPenalty = movementUtils.addMovementPenalty
local lookupMovementPenalty = movementUtils.lookupMovementPenalty
2017-01-19 21:58:36 -08:00
local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold
2016-10-30 20:24:14 -07:00
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
local positionFromDirectionAndFlat = mapUtils.positionFromDirectionAndFlat
local euclideanDistanceNamed = mathUtils.euclideanDistanceNamed
local getPlayerBaseGenerator = chunkPropertyUtils.getPlayerBaseGenerator
local getResourceGenerator = chunkPropertyUtils.getResourceGenerator
2017-11-20 23:27:03 -08:00
2019-10-19 12:13:48 -07:00
local getChunkByPosition = mapUtils.getChunkByPosition
2017-11-20 23:27:03 -08:00
local scoreNeighborsForAttack = movementUtils.scoreNeighborsForAttack
2018-09-23 21:56:45 -07:00
local scoreNeighborsForSettling = movementUtils.scoreNeighborsForSettling
-- module code
2020-05-23 20:47:14 -07:00
local function scoreResourceLocationKamikaze(map, squad, neighborChunk)
local settle = neighborChunk[RESOURCE_PHEROMONE]
return settle - (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
end
local function scoreSiegeLocationKamikaze(map, squad, neighborChunk)
local settle = neighborChunk[BASE_PHEROMONE] +
neighborChunk[RESOURCE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
return settle
end
2020-05-23 14:29:56 -07:00
local function scoreResourceLocation(map, squad, neighborChunk)
local settle = -getDeathGenerator(map, neighborChunk) + neighborChunk[RESOURCE_PHEROMONE]
return settle - (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
2018-02-12 23:10:17 -08:00
end
2020-05-23 14:29:56 -07:00
local function scoreSiegeLocation(map, squad, neighborChunk)
2020-05-23 20:47:14 -07:00
local settle = -getDeathGenerator(map, neighborChunk) + neighborChunk[BASE_PHEROMONE] +
2020-05-23 14:29:56 -07:00
neighborChunk[RESOURCE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
return settle
end
2020-05-23 14:29:56 -07:00
local function scoreAttackLocation(map, squad, neighborChunk)
local damage = -getDeathGenerator(map, neighborChunk) + neighborChunk[BASE_PHEROMONE] +
(neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
return damage
2019-02-10 22:14:17 -08:00
end
local function scoreAttackKamikazeLocation(natives, squad, neighborChunk)
local damage = neighborChunk[BASE_PHEROMONE] + (neighborChunk[PLAYER_PHEROMONE] * PLAYER_PHEROMONE_MULTIPLER)
return damage
end
2019-02-10 22:14:17 -08:00
2019-11-29 16:49:22 -08:00
local function settleMove(map, squad, surface)
local targetPosition = map.position
2019-10-19 12:13:48 -07:00
local targetPosition2 = map.position2
2019-03-08 23:13:36 -08:00
local group = squad.group
2019-03-08 23:13:36 -08:00
local groupPosition = group.position
local x, y = positionToChunkXY(groupPosition)
local chunk = getChunkByXY(map, x, y)
local scoreFunction = scoreResourceLocation
2019-10-19 12:13:48 -07:00
local groupState = group.state
2019-11-29 16:49:22 -08:00
local natives = map.natives
2019-03-08 23:13:36 -08:00
if (natives.state == AI_STATE_SIEGE) then
2020-05-23 20:47:14 -07:00
if squad.kamikaze then
scoreFunction = scoreSiegeLocationKamikaze
else
scoreFunction = scoreSiegeLocation
end
elseif squad.kamikaze then
scoreFunction = scoreResourceLocationKamikaze
2019-03-08 23:13:36 -08:00
end
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, chunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
2020-05-15 13:51:38 -07:00
addSquadToChunk(map, chunk, squad)
2020-05-23 21:17:18 -07:00
addMovementPenalty(map, squad, chunk)
2019-04-07 22:22:02 -07:00
local distance = euclideanDistancePoints(groupPosition.x,
groupPosition.y,
squad.originPosition.x,
squad.originPosition.y)
local cmd
local position
2019-10-19 12:13:48 -07:00
local position2
2020-05-16 15:34:54 -07:00
2019-10-19 12:13:48 -07:00
if (distance >= squad.maxDistance) or ((getResourceGenerator(map, chunk) ~= 0) and (getNestCount(map, chunk) == 0))
2019-04-07 22:22:02 -07:00
then
position = findMovementPosition(surface, groupPosition)
if not position then
position = groupPosition
end
targetPosition.x = position.x
2020-05-16 15:34:54 -07:00
targetPosition.y = position.y
2019-04-07 22:22:02 -07:00
cmd = map.settleCommand
if squad.kamikaze then
cmd.distraction = DEFINES_DISTRACTION_NONE
else
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
end
2019-04-07 22:22:02 -07:00
squad.status = SQUAD_BUILDING
2019-10-19 12:13:48 -07:00
group.set_command(cmd)
2019-04-07 22:22:02 -07:00
else
2019-10-19 12:13:48 -07:00
local attackChunk, attackDirection, nextAttackChunk, nextAttackDirection = scoreNeighborsForSettling(map,
chunk,
getNeighborChunks(map, x, y),
scoreFunction,
squad)
2020-05-19 19:37:16 -07:00
2020-05-15 13:51:38 -07:00
if (attackChunk == -1) then
2019-10-19 12:13:48 -07:00
cmd = map.wonderCommand
group.set_command(cmd)
2019-04-07 22:22:02 -07:00
return
2020-05-19 19:37:16 -07:00
elseif (attackDirection ~= 0) then
2019-11-29 16:49:22 -08:00
local attackPlayerThreshold = natives.attackPlayerThreshold
2020-05-16 15:34:54 -07:00
2020-05-19 19:37:16 -07:00
if (nextAttackChunk ~= -1) then
attackChunk = nextAttackChunk
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
position = findMovementPosition(surface, targetPosition2)
2019-10-19 12:13:48 -07:00
else
2020-05-19 19:37:16 -07:00
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
position = findMovementPosition(surface, targetPosition)
end
if position then
2019-10-19 12:13:48 -07:00
targetPosition.x = position.x
targetPosition.y = position.y
if nextAttackChunk then
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, nextAttackChunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
else
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, attackChunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
end
2020-05-19 19:37:16 -07:00
else
cmd = map.wonderCommand
group.set_command(cmd)
return
2019-10-19 12:13:48 -07:00
end
2019-10-20 13:45:43 -07:00
2020-05-19 19:37:16 -07:00
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) or
(attackChunk[PLAYER_PHEROMONE] >= attackPlayerThreshold)
then
cmd = map.attackCommand
2019-10-20 13:45:43 -07:00
2020-05-19 19:37:16 -07:00
if not squad.rabid then
squad.frenzy = true
squad.frenzyPosition.x = groupPosition.x
squad.frenzyPosition.y = groupPosition.y
end
else
cmd = map.moveCommand
if squad.rabid or squad.kamikaze then
cmd.distraction = DEFINES_DISTRACTION_NONE
else
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
2019-10-19 12:13:48 -07:00
end
end
2020-05-19 19:37:16 -07:00
else
2019-10-19 12:13:48 -07:00
cmd = map.settleCommand
cmd.destination.x = groupPosition.x
cmd.destination.y = groupPosition.y
2019-10-19 12:13:48 -07:00
if squad.kamikaze then
2019-03-08 23:13:36 -08:00
cmd.distraction = DEFINES_DISTRACTION_NONE
else
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
end
2019-03-08 23:13:36 -08:00
2019-10-19 12:13:48 -07:00
squad.status = SQUAD_BUILDING
2019-10-19 12:13:48 -07:00
end
2020-05-19 19:37:16 -07:00
group.set_command(cmd)
2018-02-12 23:10:17 -08:00
end
end
2019-11-29 16:49:22 -08:00
local function attackMove(map, squad, surface)
2020-05-19 19:37:16 -07:00
local targetPosition = map.position
local targetPosition2 = map.position2
2019-03-07 19:40:55 -08:00
local group = squad.group
2020-05-19 19:37:16 -07:00
local position
2019-03-07 19:40:55 -08:00
local groupPosition = group.position
local x, y = positionToChunkXY(groupPosition)
local chunk = getChunkByXY(map, x, y)
2020-05-16 22:06:55 -07:00
local attackScorer = scoreAttackLocation
if squad.kamikaze then
attackScorer = scoreAttackKamikazeLocation
end
local squadChunk = squad.chunk
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, squadChunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
2020-05-15 13:51:38 -07:00
addSquadToChunk(map, chunk, squad)
2020-05-23 21:17:18 -07:00
addMovementPenalty(map, squad, chunk)
squad.frenzy = (squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100))
local attackChunk, attackDirection, nextAttackChunk, nextAttackDirection = scoreNeighborsForAttack(map,
chunk,
getNeighborChunks(map, x, y),
attackScorer,
squad)
2020-05-15 13:51:38 -07:00
if (attackChunk == -1) then
2019-10-19 12:13:48 -07:00
cmd = map.wonderCommand
group.set_command(cmd)
return
2020-05-19 19:37:16 -07:00
elseif (nextAttackChunk ~= -1) then
attackChunk = nextAttackChunk
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
positionFromDirectionAndFlat(nextAttackDirection, targetPosition, targetPosition2)
position = findMovementPosition(surface, targetPosition2)
2019-10-19 12:13:48 -07:00
else
positionFromDirectionAndFlat(attackDirection, groupPosition, targetPosition)
2020-05-19 19:37:16 -07:00
position = findMovementPosition(surface, targetPosition)
end
2020-05-19 19:37:16 -07:00
if not position then
cmd = map.wonderCommand
group.set_command(cmd)
return
else
targetPosition.x = position.x
targetPosition.y = position.y
if nextAttackChunk then
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, nextAttackChunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
else
2020-05-23 14:29:56 -07:00
addDeathGenerator(map, attackChunk, TEN_DEATH_PHEROMONE_GENERATOR_AMOUNT)
end
2020-05-19 19:37:16 -07:00
end
2019-10-20 13:45:43 -07:00
2020-05-19 19:37:16 -07:00
if (getPlayerBaseGenerator(map, attackChunk) ~= 0) and
(attackChunk[PLAYER_PHEROMONE] >= map.natives.attackPlayerThreshold)
then
cmd = map.attackCommand
2020-05-19 19:37:16 -07:00
if not squad.rabid then
squad.frenzy = true
squad.frenzyPosition.x = groupPosition.x
squad.frenzyPosition.y = groupPosition.y
2019-10-19 12:13:48 -07:00
end
2020-05-19 19:37:16 -07:00
else
cmd = map.moveCommand
if squad.rabid or squad.frenzy then
cmd.distraction = DEFINES_DISTRACTION_BY_ANYTHING
else
cmd.distraction = DEFINES_DISTRACTION_BY_ENEMY
2019-02-16 10:45:42 -08:00
end
2018-02-12 23:10:17 -08:00
end
2020-05-19 19:37:16 -07:00
group.set_command(cmd)
2018-02-12 23:10:17 -08:00
end
2020-05-16 22:06:55 -07:00
local function buildMove(map, squad, surface)
local group = squad.group
local position = map.position
local groupPosition = findMovementPosition(surface, group.position)
2020-05-16 22:06:55 -07:00
if not groupPosition then
groupPosition = group.position
end
2019-03-08 16:42:20 -08:00
2020-05-16 22:06:55 -07:00
position.x = groupPosition.x
position.y = groupPosition.y
2019-10-20 13:45:43 -07:00
2020-05-16 22:06:55 -07:00
group.set_command(map.compoundSettleCommand)
end
2020-05-16 22:06:55 -07:00
function squadAttack.squadDispatch(map, surface, squad)
2020-05-19 19:37:16 -07:00
-- local profiler = game.create_profiler()
2020-05-16 22:06:55 -07:00
local group = squad.group
if group and group.valid then
2020-05-19 19:37:16 -07:00
local status = squad.status
if (status == SQUAD_RAIDING) then
attackMove(map, squad, surface)
elseif (status == SQUAD_SETTLING) then
settleMove(map, squad, surface)
elseif (status == SQUAD_RETREATING) then
if squad.settlers then
squad.status = SQUAD_SETTLING
settleMove(map, squad, surface)
else
squad.status = SQUAD_RAIDING
attackMove(map, squad, surface)
2020-02-02 11:30:50 -08:00
end
2020-05-19 19:37:16 -07:00
elseif (status == SQUAD_BUILDING) then
2020-05-16 22:06:55 -07:00
removeSquadFromChunk(map, squad)
2020-05-19 19:37:16 -07:00
buildMove(map, squad, surface)
elseif (status == SQUAD_GUARDING) then
if squad.settlers then
squad.status = SQUAD_SETTLING
2020-05-16 22:06:55 -07:00
settleMove(map, squad, surface)
2020-05-19 19:37:16 -07:00
else
squad.status = SQUAD_RAIDING
attackMove(map, squad, surface)
2019-10-20 13:45:43 -07:00
end
2019-03-06 22:12:39 -08:00
end
end
2020-05-19 19:37:16 -07:00
-- game.print({"", "--dispatch4 ", profiler})
end
2019-02-15 20:17:30 -08:00
squadAttackG = squadAttack
return squadAttack