mirror of
https://github.com/veden/Rampant.git
synced 2026-06-19 22:15:20 +02:00
see readme
This commit is contained in:
@@ -36,6 +36,18 @@ Base Expansion
|
||||
|
||||
# Version History
|
||||
|
||||
0.14.8 -
|
||||
- Feature: Rallying death cry, when a native dies on a chunk past the death threshold it will attempt to summon reinforcements from nearby nests
|
||||
- Tweak: Increased unit group merge distance from 16 to 28 tiles
|
||||
- Tweak: Increased retreat grab radius from 15 tiles to 24 tiles
|
||||
- Tweak: Decreased vengence squad cost from 50 to 45
|
||||
- Improvement: On group merge recalculate the kamikaze threshold, so groups that become large have a chance to kamikaze before attacking
|
||||
- Improvement: Disallow group merges when units are taking and receiving damage
|
||||
- Fix: Corrected unit group frenzy trigger based on engaging a target
|
||||
- Optimization: Switched to increment tick counter for processing and logic event
|
||||
- Optimization: Rate limited rally cry to 3/0.75 sec
|
||||
- Optimization: Rate limited retreat to 8/0.75 sec
|
||||
|
||||
0.14.7 -
|
||||
- Feature: Counterattack waves trigger when the player is standing in a chunk with the death pheromone past the retreat threshold
|
||||
- Feature: Reinforcement waves trigger when the player is standind in a chunk that contains a nest
|
||||
|
||||
+59
-8
@@ -1,6 +1,7 @@
|
||||
-- imports
|
||||
|
||||
local entityUtils = require("libs/EntityUtils")
|
||||
local mapUtils = require("libs/MapUtils")
|
||||
local unitGroupUtils = require("libs/UnitGroupUtils")
|
||||
local chunkProcessor = require("libs/ChunkProcessor")
|
||||
local mapProcessor = require("libs/MapProcessor")
|
||||
@@ -18,8 +19,20 @@ local tests = require("tests")
|
||||
local INTERVAL_LOGIC = constants.INTERVAL_LOGIC
|
||||
local INTERVAL_PROCESS = constants.INTERVAL_PROCESS
|
||||
|
||||
local MAX_RALLY_CRIES = constants.MAX_RALLY_CRIES
|
||||
local MAX_RETREATS = constants.MAX_RETREATS
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
|
||||
local BASE_RALLY_CHANCE = constants.BASE_RALLY_CHANCE
|
||||
local BONUS_RALLY_CHANCE = constants.BONUS_RALLY_CHANCE
|
||||
|
||||
local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
|
||||
local processPendingChunks = chunkProcessor.processPendingChunks
|
||||
|
||||
local processMap = mapProcessor.processMap
|
||||
@@ -27,9 +40,11 @@ local processPlayers = mapProcessor.processPlayers
|
||||
local scanMap = mapProcessor.scanMap
|
||||
|
||||
local planning = aiPlanning.planning
|
||||
local removeScout = aiBuilding.removeScout
|
||||
-- local removeScout = aiBuilding.removeScout
|
||||
-- local scouting = aiBuilding.scouting
|
||||
|
||||
local rallyUnits = aiBuilding.rallyUnits
|
||||
|
||||
local deathScent = pheromoneUtils.deathScent
|
||||
|
||||
local regroupSquads = unitGroupUtils.regroupSquads
|
||||
@@ -138,11 +153,23 @@ local function onConfigChanged()
|
||||
|
||||
global.version = constants.VERSION_12
|
||||
end
|
||||
if (global.version <= constants.VERSION_13) then
|
||||
-- switched over to tick event
|
||||
regionMap.logicTick = roundToNearest(game.tick + INTERVAL_LOGIC, INTERVAL_LOGIC)
|
||||
regionMap.processTick = roundToNearest(game.tick + INTERVAL_PROCESS, INTERVAL_PROCESS)
|
||||
|
||||
-- used to rate limit the number of rally cries during a period of time
|
||||
natives.rallyCries = MAX_RALLY_CRIES
|
||||
natives.retreats = MAX_RETREATS
|
||||
|
||||
global.version = constants.VERSION_13
|
||||
end
|
||||
end
|
||||
|
||||
local function onTick(event)
|
||||
local tick = event.tick
|
||||
if (tick % INTERVAL_PROCESS == 0) then
|
||||
if (tick == regionMap.processTick) then
|
||||
regionMap.processTick = regionMap.processTick + INTERVAL_PROCESS
|
||||
local surface = game.surfaces[1]
|
||||
local evolutionFactor = game.evolution_factor
|
||||
local players = game.players
|
||||
@@ -150,10 +177,16 @@ local function onTick(event)
|
||||
processPendingChunks(regionMap, surface, pendingChunks)
|
||||
scanMap(regionMap, surface)
|
||||
|
||||
if (tick % INTERVAL_LOGIC == 0) then
|
||||
if (tick == regionMap.logicTick) then
|
||||
regionMap.logicTick = regionMap.logicTick + INTERVAL_LOGIC
|
||||
|
||||
natives.rallyCries = MAX_RALLY_CRIES
|
||||
|
||||
natives.retreats = MAX_RETREATS
|
||||
|
||||
planning(natives, evolutionFactor, tick)
|
||||
|
||||
regroupSquads(natives)
|
||||
regroupSquads(natives, evolutionFactor)
|
||||
|
||||
processPlayers(players, regionMap, surface, natives, evolutionFactor, tick)
|
||||
|
||||
@@ -182,20 +215,38 @@ local function onDeath(event)
|
||||
if (entity.force.name == "enemy") then
|
||||
if (entity.type == "unit") then
|
||||
local entityPosition = entity.position
|
||||
local deathChunk = getChunkByPosition(regionMap, entityPosition.x, entityPosition.y)
|
||||
|
||||
if (deathChunk ~= nil) then
|
||||
-- drop death pheromone where unit died
|
||||
deathScent(regionMap, entityPosition)
|
||||
deathScent(deathChunk)
|
||||
|
||||
if (event.force ~= nil) and (event.force.name == "player") then
|
||||
retreatUnits(entityPosition,
|
||||
if ((event.force ~= nil) and (event.force.name == "player")) then
|
||||
local evolutionFactor = game.evolution_factor
|
||||
|
||||
if (deathChunk[MOVEMENT_PHEROMONE] < -(evolutionFactor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) then
|
||||
if (natives.retreats >= 0) then
|
||||
retreatUnits(deathChunk,
|
||||
convertUnitGroupToSquad(natives,
|
||||
entity.unit_group),
|
||||
regionMap,
|
||||
surface,
|
||||
natives)
|
||||
end
|
||||
local rallyThreshold = BASE_RALLY_CHANCE + (evolutionFactor * BONUS_RALLY_CHANCE)
|
||||
if (natives.rallyCries >= 0) and (math.random() < rallyThreshold) then
|
||||
natives.rallyCries = natives.rallyCries - 1
|
||||
rallyUnits(deathChunk,
|
||||
regionMap,
|
||||
surface,
|
||||
natives,
|
||||
evolutionFactor)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
removeScout(entity, global.natives)
|
||||
-- removeScout(entity, natives)
|
||||
elseif (entity.type == "unit-spawner") then
|
||||
addRemoveEntity(regionMap, entity, natives, false, false)
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name" : "Rampant",
|
||||
"factorio_version" : "0.14",
|
||||
"version" : "0.14.7",
|
||||
"version" : "0.14.8",
|
||||
"title" : "Rampant AI",
|
||||
"author" : "Veden",
|
||||
"homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445",
|
||||
|
||||
+3
-14
@@ -7,8 +7,6 @@ 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
|
||||
|
||||
@@ -21,12 +19,6 @@ local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
|
||||
local PLAYER_BASE_GENERATOR = constants.PLAYER_BASE_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
|
||||
|
||||
local getNeighborChunksWithDirection = mapUtils.getNeighborChunksWithDirection
|
||||
@@ -34,6 +26,7 @@ local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local canMoveChunkDirection = mapUtils.canMoveChunkDirection
|
||||
local addSquadMovementPenalty = unitGroupUtils.addSquadMovementPenalty
|
||||
local lookupSquadMovementPenalty = unitGroupUtils.lookupSquadMovementPenalty
|
||||
local calculateKamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold
|
||||
local positionFromDirectionAndChunk = mapUtils.positionFromDirectionAndChunk
|
||||
|
||||
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
|
||||
@@ -42,8 +35,6 @@ local playersWithinProximityToPosition = playerUtils.playersWithinProximityToPos
|
||||
|
||||
local scoreNeighborsWithDirection = neighborUtils.scoreNeighborsWithDirection
|
||||
|
||||
local mLog = math.log10
|
||||
|
||||
-- module code
|
||||
|
||||
local function validLocation(x, chunk, neighborChunk)
|
||||
@@ -104,7 +95,7 @@ function aiAttack.squadAttack(regionMap, surface, natives)
|
||||
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
|
||||
((group.state == defines.group_state.attacking_distraction) or (group.state == defines.group_state.attacking_target) or
|
||||
(attackChunk[PLAYER_BASE_GENERATOR] ~= 0)) then
|
||||
squad.frenzy = true
|
||||
squad.frenzyPosition.x = squad.group.position.x
|
||||
@@ -122,9 +113,7 @@ 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 kamikazeThreshold = NO_RETREAT_BASE_PERCENT + (evolution_factor * NO_RETREAT_EVOLUTION_BONUS_MAX)
|
||||
local squadSizeBonus = mLog((#squad.group.members / CONFIG_ATTACK_WAVE_MAX_SIZE) + 0.1) + 1
|
||||
kamikazeThreshold = kamikazeThreshold + (NO_RETREAT_SQUAD_SIZE_BONUS_MAX * squadSizeBonus)
|
||||
local kamikazeThreshold = calculateKamikazeThreshold(squad, evolution_factor)
|
||||
|
||||
local playerNearby = playersWithinProximityToPosition(players, squad.group.position, 100)
|
||||
if playerNearby then
|
||||
|
||||
@@ -33,9 +33,15 @@ 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
|
||||
|
||||
local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
|
||||
|
||||
local RALLY_CRY_DISTANCE = 3
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getNeighborChunks = mapUtils.getNeighborChunks
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local getChunkByIndex = mapUtils.getChunkByIndex
|
||||
local scoreNeighbors = neighborUtils.scoreNeighbors
|
||||
local createSquad = unitGroupUtils.createSquad
|
||||
local attackWaveScaling = config.attackWaveScaling
|
||||
@@ -117,6 +123,19 @@ function aiBuilding.scouting(regionMap, natives)
|
||||
--]]
|
||||
end
|
||||
|
||||
function aiBuilding.rallyUnits(chunk, regionMap, surface, natives, evolutionFactor)
|
||||
local cX = chunk.cX
|
||||
local cY = chunk.cY
|
||||
for x=cX - RALLY_CRY_DISTANCE, cX + RALLY_CRY_DISTANCE do
|
||||
for y=cY - RALLY_CRY_DISTANCE, cY + RALLY_CRY_DISTANCE do
|
||||
local rallyChunk = getChunkByIndex(regionMap, x, y)
|
||||
if (x ~= cX) and (y ~= cY) and (rallyChunk[ENEMY_BASE_GENERATOR] ~= 0) then
|
||||
aiBuilding.formSquads(regionMap, surface, natives, rallyChunk, evolutionFactor, AI_VENGENCE_SQUAD_COST)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function aiBuilding.formSquads(regionMap, surface, natives, chunk, evolution_factor, cost)
|
||||
if (natives.points > cost) and (chunk[ENEMY_BASE_GENERATOR] ~= 0) and (#natives.squads < (AI_MAX_SQUAD_COUNT * evolution_factor)) then
|
||||
local valid = false
|
||||
|
||||
+6
-7
@@ -9,12 +9,12 @@ local neighborUtils = require("NeighborUtils")
|
||||
|
||||
-- constants
|
||||
|
||||
local RETREAT_GRAB_RADIUS = constants.RETREAT_GRAB_RADIUS
|
||||
|
||||
local MOVEMENT_PHEROMONE = constants.MOVEMENT_PHEROMONE
|
||||
local PLAYER_PHEROMONE = constants.PLAYER_PHEROMONE
|
||||
local BASE_PHEROMONE = constants.BASE_PHEROMONE
|
||||
|
||||
local RETREAT_MOVEMENT_PHEROMONE_LEVEL = constants.RETREAT_MOVEMENT_PHEROMONE_LEVEL
|
||||
|
||||
local ENEMY_BASE_GENERATOR = constants.ENEMY_BASE_GENERATOR
|
||||
|
||||
local HALF_CHUNK_SIZE = constants.HALF_CHUNK_SIZE
|
||||
@@ -25,7 +25,6 @@ local RETREAT_FILTER = constants.RETREAT_FILTER
|
||||
|
||||
-- imported functions
|
||||
|
||||
local getChunkByPosition = mapUtils.getChunkByPosition
|
||||
local getNeighborChunksWithDirection = mapUtils.getNeighborChunksWithDirection
|
||||
local findNearBySquad = unitGroupUtils.findNearBySquad
|
||||
local addSquadMovementPenalty = unitGroupUtils.addSquadMovementPenalty
|
||||
@@ -46,14 +45,14 @@ local function scoreRetreatLocation(position, squad, neighborChunk, surface)
|
||||
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[MOVEMENT_PHEROMONE] < -(game.evolution_factor * RETREAT_MOVEMENT_PHEROMONE_LEVEL)) and (chunk[ENEMY_BASE_GENERATOR] == 0) then
|
||||
function aiDefense.retreatUnits(chunk, squad, regionMap, surface, natives)
|
||||
if (chunk[ENEMY_BASE_GENERATOR] == 0) then
|
||||
local performRetreat = false
|
||||
local enemiesToSquad
|
||||
|
||||
if (squad == nil) then
|
||||
enemiesToSquad = surface.find_enemy_units(position, 15)
|
||||
enemiesToSquad = surface.find_enemy_units({x=chunk.pX,
|
||||
y=chunk.pY}, RETREAT_GRAB_RADIUS)
|
||||
if (#enemiesToSquad > 0) then
|
||||
performRetreat = true
|
||||
end
|
||||
|
||||
+16
-1
@@ -7,6 +7,7 @@ constants.VERSION_9 = 9
|
||||
constants.VERSION_10 = 10
|
||||
constants.VERSION_11 = 11
|
||||
constants.VERSION_12 = 12
|
||||
constants.VERSION_13 = 13
|
||||
|
||||
-- misc
|
||||
|
||||
@@ -28,7 +29,7 @@ constants.INTERVAL_LOGIC = 40
|
||||
constants.AI_POINT_GENERATOR_AMOUNT = 6
|
||||
constants.AI_SCOUT_COST = 45
|
||||
constants.AI_SQUAD_COST = 175
|
||||
constants.AI_VENGENCE_SQUAD_COST = 50
|
||||
constants.AI_VENGENCE_SQUAD_COST = 45
|
||||
constants.AI_SETTLER_COST = 75
|
||||
constants.AI_BASE_BUILDING_COST = 500
|
||||
constants.AI_TUNNEL_COST = 100
|
||||
@@ -95,6 +96,20 @@ constants.SQUAD_GUARDING = 2 -- used when squad is idle
|
||||
constants.SQUAD_BURROWING = 3
|
||||
constants.SQUAD_RAIDING = 4 -- used when player stuff is close
|
||||
|
||||
-- Squad Related
|
||||
|
||||
constants.RETREAT_GRAB_RADIUS = 24
|
||||
|
||||
constants.BASE_RALLY_CHANCE = 0.01
|
||||
constants.BONUS_RALLY_CHANCE = 0.01
|
||||
|
||||
constants.MAX_RETREATS = 7
|
||||
|
||||
constants.MAX_RALLY_CRIES = 2
|
||||
constants.RALLY_CRY_DISTANCE = 3
|
||||
|
||||
constants.GROUP_MERGE_DISTANCE = 28
|
||||
|
||||
-- player building pheromones
|
||||
|
||||
constants.BUILDING_PHEROMONES = {}
|
||||
|
||||
@@ -35,12 +35,9 @@ function pheromoneUtils.scents(chunk)
|
||||
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
|
||||
function pheromoneUtils.deathScent(chunk)
|
||||
chunk[MOVEMENT_PHEROMONE] = chunk[MOVEMENT_PHEROMONE] - DEATH_PHEROMONE_GENERATOR_AMOUNT
|
||||
end
|
||||
end
|
||||
|
||||
function pheromoneUtils.playerScent(playerChunk)
|
||||
playerChunk[PLAYER_PHEROMONE] = playerChunk[PLAYER_PHEROMONE] + PLAYER_PHEROMONE_GENERATOR_AMOUNT
|
||||
|
||||
+34
-4
@@ -4,18 +4,31 @@ local unitGroupUtils = {}
|
||||
|
||||
local mapUtils = require("MapUtils")
|
||||
local constants = require("Constants")
|
||||
package.path = "../?.lua;" .. package.path
|
||||
local config = require("config")
|
||||
|
||||
-- constants
|
||||
|
||||
local MOVEMENT_PHEROMONE_GENERATOR_AMOUNT = constants.MOVEMENT_PHEROMONE_GENERATOR_AMOUNT
|
||||
|
||||
local GROUP_STATE_FINISHED = defines.group_state.finished
|
||||
local GROUP_STATE_ATTACKING_TARGET = defines.group_state.attacking_target
|
||||
local GROUP_STATE_ATTACKING_DISTRACTION = defines.group_state.attacking_distraction
|
||||
|
||||
local SQUAD_RETREATING = constants.SQUAD_RETREATING
|
||||
local SQUAD_GUARDING = constants.SQUAD_GUARDING
|
||||
local GROUP_MERGE_DISTANCE = constants.GROUP_MERGE_DISTANCE
|
||||
|
||||
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
|
||||
|
||||
local mLog = math.log10
|
||||
|
||||
local tableRemove = table.remove
|
||||
local tableInsert = table.insert
|
||||
local euclideanDistanceNamed = mapUtils.euclideanDistanceNamed
|
||||
@@ -118,23 +131,41 @@ function unitGroupUtils.lookupSquadMovementPenalty(squad, chunkX, chunkY)
|
||||
return 0
|
||||
end
|
||||
|
||||
function unitGroupUtils.regroupSquads(natives)
|
||||
function unitGroupUtils.calculateKamikazeThreshold(squad, evolution_factor)
|
||||
local kamikazeThreshold = NO_RETREAT_BASE_PERCENT + (evolution_factor * NO_RETREAT_EVOLUTION_BONUS_MAX)
|
||||
local squadSizeBonus = mLog((#squad.group.members / CONFIG_ATTACK_WAVE_MAX_SIZE) + 0.1) + 1
|
||||
return kamikazeThreshold + (NO_RETREAT_SQUAD_SIZE_BONUS_MAX * squadSizeBonus)
|
||||
end
|
||||
|
||||
local function isAttacking(squad)
|
||||
return (squad.state == GROUP_STATE_ATTACKING_TARGET) or (squad.state == GROUP_STATE_ATTACKING_DISTRACTION)
|
||||
end
|
||||
|
||||
function unitGroupUtils.regroupSquads(natives, evolution_factor)
|
||||
local squads = natives.squads
|
||||
for i=1,#squads do
|
||||
local squad = squads[i]
|
||||
if squad.group.valid then
|
||||
if squad.group.valid and not isAttacking(squad) then
|
||||
local squadPosition = squad.group.position
|
||||
local mergedSquads = false
|
||||
for x=i+1, #squads do
|
||||
local mergeSquad = squads[x]
|
||||
local mergeGroup = mergeSquad.group
|
||||
if mergeGroup.valid and (mergeSquad.status == squad.status) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < 16) then
|
||||
if mergeGroup.valid and (mergeSquad.status == squad.status) and not isAttacking(mergeSquad) and (euclideanDistanceNamed(squadPosition, mergeGroup.position) < GROUP_MERGE_DISTANCE) then
|
||||
unitGroupUtils.membersToSquad(squad, mergeGroup.members, true)
|
||||
if mergeSquad.kamikaze then
|
||||
squad.kamikaze = true
|
||||
end
|
||||
mergedSquads = true
|
||||
mergeGroup.destroy()
|
||||
end
|
||||
end
|
||||
if mergedSquads and not squad.kamikaze then
|
||||
local kamikazeThreshold = unitGroupUtils.calculateKamikazeThreshold(squad, evolution_factor)
|
||||
if (math.random() < kamikazeThreshold) then
|
||||
squad.kamikaze = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -158,7 +189,6 @@ function unitGroupUtils.regroupSquads(natives)
|
||||
elseif (squad.cycles > 0) then
|
||||
squad.cycles = squad.cycles - 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user