Skip to content

Commit 7f009e1

Browse files
Uvesoshalkya
authored andcommitted
AI-Update V4
Changelog: ------------------------------------------------------------------------------------ AIBehaviors.lua function TempestBehavior() -Opt: Removed obsolete IsOpponentAIRunning() function call ------------------------------------------------------------------------------------ aibuildstructures.lua function AIExecuteBuildStructure() -New: Added validation for building templates. (T4Artillery can't be build from Seraphim etc) function AIBuildAdjacency() -Fix: making sure, the AI is not building adjacencies closer then 8 map-units to the map border. ------------------------------------------------------------------------------------ aiutilities.lua function GenerateAmphibiousMarkerList() -Fix: Added a failsafe in case a marker has no valid adjacentTo entry. function EngineerTryReclaimCaptureArea() -Fix: Added ReclaimInProgress and CaptureInProgress flag to prevent attacking from own units. function EngineerTryReclaimCaptureAreaSorian() -Fix: Added ReclaimInProgress and CaptureInProgress flag to prevent attacking from own units. ------------------------------------------------------------------------------------ AttackManager.lua function AttackManagerThread() -Opt: Removed obsolete IsOpponentAIRunning() function call ------------------------------------------------------------------------------------ aibrain.lua function OnDefeat() -Opt: AI PathCache will now be deleted if an AI is defeated. function EvaluateAIPlanList() -Opt: Removed obsolete IsOpponentAIRunning() function call function ExecuteAIThread() -Opt: Removed obsolete IsOpponentAIRunning() function call function InitializeSkirmishSystems() -Fix: Deleted duplicated ForkThread for EnemyPickerThread function PlatoonBuildManagerThread() -Opt: Removed obsolete IsOpponentAIRunning() function call function BaseMonitorPlatoonDistressThread() -Fix: Deleted duplicated function ------------------------------------------------------------------------------------ defaultunits.lua function DestroyIdleEffects() -Fix: Validating the existens of TimedSonarEffectsThread before destroying it. ------------------------------------------------------------------------------------ EffectUtilities.lua function CreateSeraphimFactoryBuildingEffects() -Fix: Added check for the existens of "slider" instead of checking if the unit is dead. ------------------------------------------------------------------------------------ platoon.lua function PlatoonDisband() -Fix: Deleting ReclaimInProgress and CaptureInProgress flag in case the platoon is disbanded/transfered. function HuntAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function GuardBase() -Opt: Removed obsolete IsOpponentAIRunning() function call function BaseManagersDistressAI() -Fix: DistressCall is now saved in the right place (locData.DistressCall instead of locData.BaseSettings.DistressCall) function CaptureAI() -Fix: Added CaptureInProgress flag to units while capturing is in progress function ReclaimStructuresAI() -Fix: Set ReclaimInProgress flag before starting reclaim -Fix: Exit function with return after disbanding the platoon. function ReclaimUnitsAI() -Fix: Set ReclaimInProgress flag before starting reclaim function RepairAI() -Fix: Exit function with return after disbanding the platoon. function EconUnfinishedBody() -Fix: Exit function with return after disbanding the platoon. function EngineerBuildAI() -Fix: Exit function with return after disbanding the platoon. (if we can't find a location to build) function UnitUpgradeAI() -Fix: Changed faction index to real names in warn/debug texts. function GunshipHuntAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function InterceptorAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function BaseManagersDistressAISorian() -Fix: DistressCall is now saved in the right place (locData.DistressCall instead of locData.BaseSettings.DistressCall) function ArtilleryAISorian() -Opt: Removed obsolete IsOpponentAIRunning() function call function SatelliteAISorian() -Opt: Removed obsolete IsOpponentAIRunning() function call function AirHuntAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function FighterHuntAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function GuardBaseSorian() -Opt: Removed obsolete IsOpponentAIRunning() function call function NavalHuntAI() -Opt: Removed obsolete IsOpponentAIRunning() function call function CDRHuntAISorian() -Opt: Removed obsolete IsOpponentAIRunning() function call function AttackForceAISorian() -Opt: Removed obsolete IsOpponentAIRunning() function call ------------------------------------------------------------------------------------ EngineerManager.lua function AssignEngineerTask() Fix: Enginners will now delay a new task if they are still assisting or building Fix: Calling now "self:DelayAssign()" instead of "DelayAssign()" Opt: Changed function call "builder:GetPriority()" to get variable "builder.Priority" ------------------------------------------------------------------------------------ FactoryBuilderManager.lua function GetFactoryTemplate() Fix: Changed error() call on missing templatedata to a SPEW message and returning false. ------------------------------------------------------------------------------------ Unit.lua function OnStopBeingBuilt() Opt: Deleted duplicated "local bp = self:GetBlueprint()" call. ------------------------------------------------------------------------------------ simInit.lua function DefaultPrefetchSet() Fix: Corrected syntax for DiskFindFiles calls.
1 parent 1cec8d3 commit 7f009e1

12 files changed

Lines changed: 488 additions & 469 deletions

lua/AI/AIBehaviors.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,7 @@ TempestBehavior = function(self)
11181118
numNaval = aiBrain:GetNumUnitsAroundPoint((categories.MOBILE * categories.NAVAL) * (categories.EXPERIMENTAL + categories.TECH3 + categories.TECH2), position, 65, 'Enemy')
11191119
end
11201120

1121-
if aiBrain:PlatoonExists(self) and self:IsOpponentAIRunning() and not self.Patrolling then
1121+
if aiBrain:PlatoonExists(self) and not self.Patrolling then
11221122
self:Stop()
11231123
self.Patrolling = true
11241124
scoutPath = AIUtils.AIGetSortedNavalLocations(self:GetBrain())

lua/AI/AttackManager.lua

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,9 @@ AttackManager = Class({
6666
local alertLocation, alertLevel, tempLevel
6767
while true do
6868
WaitSeconds(ad.AttackCheckInterval)
69-
if self.brain:IsOpponentAIRunning() then
70-
if ad.AttackManagerState == 'ACTIVE' and self.Platoons then
71-
self:AttackManageAttackVectors()
72-
self:FormAttackPlatoon()
73-
end
69+
if ad.AttackManagerState == 'ACTIVE' and self.Platoons then
70+
self:AttackManageAttackVectors()
71+
self:FormAttackPlatoon()
7472
end
7573
end
7674
end,

lua/AI/aibuildstructures.lua

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,83 @@ function IsResource(buildingType)
105105
buildingType == 'T1Resource' or buildingType == 'T2Resource' or buildingType == 'T3Resource'
106106
end
107107

108+
local AntiSpamList = {}
108109
function AIExecuteBuildStructure(aiBrain, builder, buildingType, closeToBuilder, relative, buildingTemplate, baseTemplate, reference, NearMarkerType)
109110
local factionIndex = aiBrain:GetFactionIndex()
110111
local whatToBuild = aiBrain:DecideWhatToBuild(builder, buildingType, buildingTemplate)
112+
-- If the c-engine can't decide what to build, then search the build template manually.
111113
if not whatToBuild then
112-
SPEW('*AIExecuteBuildStructure: We cant decide whatToBuild! Building Type: '..repr(buildingType)..' not present as template for faction: '..repr(builder.factionCategory))
114+
if AntiSpamList[buildingType] then
115+
return
116+
end
117+
SPEW('*AIExecuteBuildStructure: We cant decide whatToBuild! Building Type: '..repr(buildingType)..', faction: '..repr(builder.factionCategory))
118+
-- Get the UnitId for the actual buildingType
119+
local BuildUnitWithID
120+
for Key, Data in buildingTemplate do
121+
if Data[1] and Data[2] and Data[1] == buildingType then
122+
--SPEW('*AIExecuteBuildStructure: Found template: '..repr(Data[1])..' - Using UnitID: '..repr(Data[2]))
123+
BuildUnitWithID = Data[2]
124+
break
125+
end
126+
end
127+
-- If we can't find a template, then return
128+
if not BuildUnitWithID then
129+
AntiSpamList[buildingType] = true
130+
WARN('*AIExecuteBuildStructure: No '..repr(builder.factionCategory)..' unit found for template: '..repr(buildingType)..'! ')
131+
return
132+
end
133+
-- get the needed tech level to build buildingType
134+
local BBC = __blueprints[BuildUnitWithID].CategoriesHash
135+
local NeedTech
136+
if BBC.BUILTBYCOMMANDER or BBC.BUILTBYTIER1COMMANDER or BBC.BUILTBYTIER1ENGINEER then
137+
NeedTech = 1
138+
elseif BBC.BUILTBYTIER2COMMANDER or BBC.BUILTBYTIER2ENGINEER then
139+
NeedTech = 2
140+
elseif BBC.BUILTBYTIER3COMMANDER or BBC.BUILTBYTIER3ENGINEER then
141+
NeedTech = 3
142+
end
143+
-- If we can't find a techlevel for the building we want to build, then return
144+
if not NeedTech then
145+
WARN('*AIExecuteBuildStructure: Cant find techlevel for BuildUnitWithID: '..repr(BuildUnitWithID))
146+
return
147+
end
148+
-- get the actual tech level from the builder
149+
local BC = builder:GetBlueprint().CategoriesHash
150+
if BC.TECH1 or BC.COMMAND then
151+
HasTech = 1
152+
elseif BC.TECH2 then
153+
HasTech = 2
154+
elseif BC.TECH3 then
155+
HasTech = 3
156+
end
157+
-- If we can't find a techlevel for the building we want to build, return
158+
if not HasTech then
159+
WARN('*AIExecuteBuildStructure: Cant find techlevel for Builder: '..__blueprints[BuildUnitWithID].Description or "Unknown")
160+
return
161+
end
162+
--LOG('*AIExecuteBuildStructure: We have TECH'..HasTech..' engineer.')
163+
if HasTech < NeedTech then
164+
WARN('*AIExecuteBuildStructure: TECH'..NeedTech..' Unit "'..BuildUnitWithID..'" is assigned to TECH'..HasTech..' buildplatoon! ('..repr(buildingType)..')')
165+
return
166+
end
167+
local IsRestricted = import('/lua/game.lua').IsRestricted
168+
if IsRestricted(BuildUnitWithID, GetFocusArmy()) then
169+
WARN('*AIExecuteBuildStructure: Unit is Restricted!!! Building Type: '..repr(buildingType)..', faction: '..repr(builder.factionCategory)..' - Unit:'..BuildUnitWithID)
170+
AntiSpamList[buildingType] = true
171+
return
172+
end
113173
return
174+
else
175+
-- Sometimes the AI is building a unit that is different from the buildingTemplate table. So we validate the unitID here.
176+
for Key, Data in buildingTemplate do
177+
if Data[1] and Data[2] and Data[1] == buildingType then
178+
if whatToBuild ~= Data[2] then
179+
WARN('*AIExecuteBuildStructure: Missmatch whatToBuild: '..whatToBuild..' ~= buildingTemplate.Data[2]: '..repr(Data[2]))
180+
end
181+
break
182+
end
183+
end
114184
end
115-
116185
-- find a place to build it (ignore enemy locations if it's a resource)
117186
-- build near the base the engineer is part of, rather than the engineer location
118187
local relativeTo
@@ -173,8 +242,7 @@ function AIExecuteBuildStructure(aiBrain, builder, buildingType, closeToBuilder,
173242
AddToBuildQueue(aiBrain, builder, whatToBuild, NormalToBuildLocation(relativeLoc), false)
174243
return
175244
end
176-
--otherwise, we're SOL, so move on to the next thing
177-
--SPEW('*AIExecuteBuildStructure: Find no place to Build! - buildingType '..repr(buildingType)..' - UnitID: '..whatToBuild..'')
245+
-- At this point we're out of options, so move on to the next thing
178246
end
179247

180248
function AIBuildBaseTemplate(aiBrain, builder, buildingType , closeToBuilder, relative, buildingTemplate, baseTemplate, reference, NearMarkerType)
@@ -263,10 +331,8 @@ function AIBuildBaseTemplateFromLocation(baseTemplate, location)
263331
end
264332

265333
function AIBuildAdjacency(aiBrain, builder, buildingType , closeToBuilder, relative, buildingTemplate, baseTemplate, reference, NearMarkerType)
266-
local factionIndex = aiBrain:GetFactionIndex()
267334
local whatToBuild = aiBrain:DecideWhatToBuild(builder, buildingType, buildingTemplate)
268335
if whatToBuild then
269-
local upperString = ParseEntityCategory(string.upper(whatToBuild))
270336
local unitSize = aiBrain:GetUnitBlueprint(whatToBuild).Physics
271337
local template = {}
272338
table.insert(template, {})
@@ -277,36 +343,48 @@ function AIBuildAdjacency(aiBrain, builder, buildingType , closeToBuilder, relat
277343
local targetPos = v:GetPosition()
278344
targetPos[1] = targetPos[1] - (targetSize.SkirtSizeX/2)
279345
targetPos[3] = targetPos[3] - (targetSize.SkirtSizeZ/2)
280-
# Top/bottom of unit
346+
-- Top/bottom of unit
281347
for i=0,((targetSize.SkirtSizeX/2)-1) do
282348
local testPos = { targetPos[1] + 1 + (i * 2), targetPos[3]-(unitSize.SkirtSizeZ/2), 0 }
283349
local testPos2 = { targetPos[1] + 1 + (i * 2), targetPos[3]+targetSize.SkirtSizeZ+(unitSize.SkirtSizeZ/2), 0 }
284-
table.insert(template[1], testPos)
285-
table.insert(template[1], testPos2)
350+
-- check if the buildplace is to close to the border or inside buildable area
351+
if testPos[1] > 8 and testPos[1] < ScenarioInfo.size[1] - 8 and testPos[2] > 8 and testPos[2] < ScenarioInfo.size[2] - 8 then
352+
table.insert(template[1], testPos)
353+
end
354+
if testPos2[1] > 8 and testPos2[1] < ScenarioInfo.size[1] - 8 and testPos2[2] > 8 and testPos2[2] < ScenarioInfo.size[2] - 8 then
355+
table.insert(template[1], testPos2)
356+
end
286357
end
287-
# Sides of unit
358+
-- Sides of unit
288359
for i=0,((targetSize.SkirtSizeZ/2)-1) do
289360
local testPos = { targetPos[1]+targetSize.SkirtSizeX + (unitSize.SkirtSizeX/2), targetPos[3] + 1 + (i * 2), 0 }
290361
local testPos2 = { targetPos[1]-(unitSize.SkirtSizeX/2), targetPos[3] + 1 + (i*2), 0 }
291-
table.insert(template[1], testPos)
292-
table.insert(template[1], testPos2)
362+
if testPos[1] > 8 and testPos[1] < ScenarioInfo.size[1] - 8 and testPos[2] > 8 and testPos[2] < ScenarioInfo.size[2] - 8 then
363+
table.insert(template[1], testPos)
364+
end
365+
if testPos2[1] > 8 and testPos2[1] < ScenarioInfo.size[1] - 8 and testPos2[2] > 8 and testPos2[2] < ScenarioInfo.size[2] - 8 then
366+
table.insert(template[1], testPos2)
367+
end
293368
end
294369
end
295370
end
296-
# build near the base the engineer is part of, rather than the engineer location
371+
-- build near the base the engineer is part of, rather than the engineer location
297372
local baseLocation = {nil, nil, nil}
298373
if builder.BuildManagerData and builder.BuildManagerData.EngineerManager then
299374
baseLocation = builder.BuildManagerdata.EngineerManager.Location
300375
end
301376
local location = aiBrain:FindPlaceToBuild(buildingType, whatToBuild, template, false, builder, baseLocation[1], baseLocation[3])
302377
if location then
303-
AddToBuildQueue(aiBrain, builder, whatToBuild, location, false)
304-
return
378+
if location[1] > 8 and location[1] < ScenarioInfo.size[1] - 8 and location[2] > 8 and location[2] < ScenarioInfo.size[2] - 8 then
379+
--LOG('Build '..repr(buildingType)..' at adjacency: '..repr(location) )
380+
AddToBuildQueue(aiBrain, builder, whatToBuild, location, false)
381+
return true
382+
end
305383
end
306-
## Build in a regular spot if adjacency not found
384+
-- Build in a regular spot if adjacency not found
307385
return AIExecuteBuildStructure(aiBrain, builder, buildingType, builder, true, buildingTemplate, baseTemplate)
308386
end
309-
return false, false
387+
return false
310388
end
311389

312390
function AINewExpansionBase(aiBrain, baseName, position, builder, constructionData)

lua/AI/aiutilities.lua

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -354,22 +354,24 @@ function GenerateAmphibiousMarkerList(markerList,markers,markerType)
354354
for k, v in markers do
355355
local marker = table.copy(v)
356356
if marker.type == markerType then
357-
-- transform adjacentTo to Amphibious marker names
358-
local adjacentTo = ''
359-
for i, node in STR_GetTokens(marker.adjacentTo, ' ') do
360-
if adjacentTo == '' then
361-
adjacentTo = 'Amph'..node
362-
else
363-
adjacentTo = adjacentTo..' '..'Amph'..node
357+
if marker.adjacentTo and marker.adjacentTo ~= '' then
358+
-- transform adjacentTo to Amphibious marker names
359+
local adjacentTo = ''
360+
for i, node in STR_GetTokens(marker.adjacentTo or '', ' ') do
361+
if adjacentTo == '' then
362+
adjacentTo = 'Amph'..node
363+
else
364+
adjacentTo = adjacentTo..' '..'Amph'..node
365+
end
364366
end
367+
marker.adjacentTo = adjacentTo
368+
-- Add 'Amph' to marker name
369+
marker.name = 'Amph'..k
370+
marker.graph = 'DefaultAmphibious'
371+
marker.type = 'Amphibious Path Node'
372+
marker.color = 'ff00FFFF'
373+
table.insert(markerList, marker)
365374
end
366-
marker.adjacentTo = adjacentTo
367-
-- Add 'Amph' to marker name
368-
marker.name = 'Amph'..k
369-
marker.graph = 'DefaultAmphibious'
370-
marker.type = 'Amphibious Path Node'
371-
marker.color = 'ff00FFFF'
372-
table.insert(markerList, marker)
373375
end
374376
end
375377
return markerList
@@ -1818,9 +1820,11 @@ function EngineerTryReclaimCaptureArea(aiBrain, eng, pos)
18181820
end
18191821
if unit:IsCapturable() then
18201822
-- if we can capture the unit/building then do so
1823+
unit.CaptureInProgress = true
18211824
IssueCapture({eng}, unit)
18221825
else
18231826
-- if we can't capture then reclaim
1827+
unit.ReclaimInProgress = true
18241828
IssueReclaim({eng}, unit)
18251829
end
18261830
end
@@ -1912,9 +1916,11 @@ function EngineerTryReclaimCaptureAreaSorian(aiBrain, eng, pos)
19121916
local checkUnits = aiBrain:GetUnitsAroundPoint(v, pos, 10, 'Enemy')
19131917
for num, unit in checkUnits do
19141918
if not unit.Dead and EntityCategoryContains(categories.ENGINEER, unit) then
1919+
unit.CaptureInProgress = true
19151920
IssueCapture({eng}, unit)
19161921
return true
19171922
elseif not unit.Dead and not EntityCategoryContains(categories.ENGINEER, unit) then
1923+
unit.ReclaimInProgress = true
19181924
IssueReclaim({eng}, unit)
19191925
return true
19201926
end

lua/EffectUtilities.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,8 @@ function CreateSeraphimFactoryBuildingEffects(builder, unitBeingBuilt, BuildEffe
661661
slider:SetGoal(0, sy, 0)
662662
slider:SetSpeed(-1)
663663
WaitFor(slider)
664-
if not unitBeingBuilt.Dead and not unitBeingBuilt:BeenDestroyed() then
664+
665+
if not slider:BeenDestroyed() then
665666
slider:SetGoal(0, 0, 0)
666667
slider:SetSpeed(0.05)
667668
end

0 commit comments

Comments
 (0)