Find attached also my summarized DoW AI functions list which sums up all .ai files. Its more a work-in-progress but should provide an idea towards the structure of the DoW AI system.
I am also, hopefully, getting some info from Relic regarding DoW's API so we can understand the terrain.analyser system so we can script building placements on a map. At present its hit-and-miss but I assured Relic will make it more understood.
In any case here is our project goals...
Objectives
~~~~~~~
1) Build defensive turrets + 1-2 mines on expansions especially on LPs near the front-line?
This, to me at least, is one of the great "golden eggs" of having the AI protect its assets. I have yet to determine how to get the AI to build these defensive turrets (or even mines) off expansion he captures and build upon. Ideally, I like to see the AI build 1-2 turrets on each expansion and the same amount of mines.
The AI *does* build other buildings (energy reactors, vehicle factories, etc) off expansions but never defensive turrets (only exception is the ORKs where he builds Waagh Banners).
Here are some scripts that may assist:
File: /ai/plans/buildbuildingplan.ai
Script:
--try to build toward or away from enemy, depending on what type of building it is
if not cpu_manager.terrain_analyzer:FindClosestFreePosition( self.item_id, self.build_pos, bias, self.bestPosition ) then
aitrace("cannot place building: "..self.item_name)
return
Note the area: "self.item_id, self.build_pos, bias, self.bestPosition" - we need to determine what gives extra weight to each value.
The next ones determine the nearest AI-owned ListeningPost closest to the enemy..
File: \ai\strategies\defendstrategy.ai
Script:
function DefendStrategy:CalculateNewChokepoint()
and
function DefendStrategy:FindClosestStrategicPoint( from_pos, functor )
Also..
File: /ai/cpu_manager.ai
Script:
--utility function used to account for defensive buildings
function CpuManager:GetDefensiveBuildingsCostAt( player, pos, tolerance )
profile_start( "GetDefensiveCost" )
local cost = 0
local tolerance_sqr = tolerance*tolerance
--for every defensive building in range, add 150
for building in player:GetBuildingsWithGuns() do
if distance_sqr( building:GetPosition(), pos ) < tolerance_sqr then
cost = cost + 150
end
end
profile_end( "GetDefensiveCost" )
return cost
2) A random script that only upgrades a certain % of those LPs and defensive turrets. LPs I can live with at Tier2 but its pretty dumb to update all turrets to Tier1 (Tier2 for Orks) anti-vehicle especially since DoW is half about infantry!
Essentially, the script that runs the Turret addons are here (ie. Space Marines):
File: \ai\strategies\marinebuildbasestrategy.ai
Scripts:
self.turret_id = cpu_manager.stats:GetBuildingID( "space_marine_turret_bolter" )
self.turret_name = "space_marine_turret_bolter"
self.turret_addon_2_id = cpu_manager.stats:GetAddOnID( "space_marine_turret_addon" )
function MarineBuildBaseStrategy:DoUpgradesAndAddons()
if self:IsInSecondTier() then
local id_2 = self.turret_addon_2_id
if( self:PlanExists("Build AddOn Plan", id_2) == false ) then
self.AddPlan( self, BuildAddOnPlan( id_2 ) )
end
What we need to have happen is to have the scripts just below "IsInSecondTier()" to run randomly so every game you play different % of turrets are upgraded.
Below are two examples of a randomizer:
local rand = math.random()
--say a greeting some of the time
if rand > (1.0 - frequency) then
--randomize what to say
local rand = math.random()
rand = (rand * num)
local final_local_id = start_id + math.floor( rand )
if self.lippy then
self.cpu_player:NetSay( final_local_id, allied_talk )
end
-- randomly choose one in the set of squad limits
local count = 0
for i in self.info.SquadLimits do
count = count + 1
end
local rand = math.random( 1, count )
local chosen_strat = nil
--choose the one
local index = 1
for i in self.info.SquadLimits do
if index == rand then
chosen_strat = i
break
end
index = index + 1
end
dbAssert( chosen_strat ~= nil )
print( "player "..cpu_manager.player_id.." has chosen strategy: "..chosen_strat )
Anyone know how to accomplish this?
3) Create a team of 1-2 builders to either help build buildings OR be on repair duty to heal damaged buildings.
Another golden egg.. I think it would be better to have ALL engineers designated to "repair-buildings-when-idle" but having 1-2 of them assigned solely for repair duty would be great.
Repair Priority should be given in this order:
a) HQ
b) ListeningPosts
c) Defensive turrets
d) all other buildings
If any of the above falls below a certain health percentage then an engineer will arrive for repair. Once repaired or no repair is realized, then the next building type in the repair-queue is started.
Here are the files that seem to be relevant for this:
\ai\plans\buildbuildingplan.ai
\ai\tactics\engineertactic.ai
Also an interesting script regarding the HealthPercentage of something:
This is for the Space Marines' Apothecary, as example..
File: /ai/tactics/spacemarines/apothecarytactic.ai
Script:
function ApothecaryTactic:Update()
local hurt_filter = function( squad_ai )
return self.squad_ai:CanAttachTo( squad_ai ) and squad_ai:GetHealthPercentage() <= 0.8
end
local attach_to = cpu_manager:GetClosestSquad( self.squad_ai:GetPosition(), 40, hurt_filter );
if attach_to ~= nil then
self.squad_ai:DoAttachSquad( attach_to )
end
4) Ensure Large Energy Reactor construction + 3-4 defense placements around it (its an important structure after all!)
Very similar to 1) except specifying the empty Slag Heaps on a map to build a Large Generator. The AI player should only build one and I was thinking of giving the AI a one-time cash incentive to build it in Tier2 (earlier the better). This is to ensure the AI *will* build it early on. I would also like to have a check to ensure that if he loses it to the enemy that we re-give him the same cash incentive to build it again BUT only if the area is safe.
The scripts that determine the location and need for a Large Generator are here:
File: \ai\strategiesbuildbasestrategy.ai
Script: function BuildBaseStrategy:DoBuildGenerators()
Example script on how to give the AI an infusion of the requisition resource:
--here we're going to add the rule in every 30 seconds
Rule_AddInterval( Rule_GivePlayerMoney, 30 )
function Rule_GivePlayerMoney( )
--this checks to see how much requisition the indicated player has
if Player_GetResource(playerID, RT_Requisition) < 1000 then
Player_AddResource(playerID, RT_Requisition, 500)
else
Rule_Remove(Rule_GivePlayerMoney )
end
end
This example, if implemented, would check every 30 seconds to see how much Requisition the indicated player had. If the amount is less than 1000 units it will add 500 more on. If the player has more than 1000 Requisition points, the Rule will remove itself.
5) When relic is captured and fortified I would like to have AI build more defensive turrets around it than usual due to its significance for getting uber-units.
Same as 1) and 4) although it is important, like 4) for the AI to acknowledge a Relic and ensure its well protected.
6) Check to see why independant units (ie. Space Marines' Apothecary or Librarian) sometimes do not attach themselves to squads.
Have to test this myself (see if such units on occasion don't attach themselves) but generally I don't have a problem with this. Nevertheless, will need to see how often certain "independant" units are likely to attach themselves.
Files of interest:
File: \ai\tactics\spacemarines\apothecarytactic.ai
Script:
function ApothecaryTactic:Update()
--state machine
if not InfantryTactic.Update( self ) then
return
end
--if I'm in combat
if self.squad_ai:IsInCombat() then
--attach to hurt squads
local hurt_filter = function( squad_ai )
return self.squad_ai:CanAttachTo( squad_ai ) and squad_ai:GetHealthPercentage() <= 0.8
end
local attach_to = cpu_manager:GetClosestSquad( self.squad_ai:GetPosition(), 40, hurt_filter );
if attach_to ~= nil then
self.squad_ai:DoAttachSquad( attach_to )
end
Other files of interest that deal with attached units:
\ai\tactics\infantrytactic.ai
\ai\tactics\tactic.ai
Longer term objectives
~~~~~~~~~~~~~~
1) Rebuilding destroyed Base Defenses at either original main base or second emergency base!
I have yet to test this fully but will get on it. I think its incredibly important for the AI to rebuild ALL BUILDINGS lost provided they a) have the income b) have the prequistes to do so, and c) are not threatened so its safe to build back what was lost.
2) If enough surplus cash allows, will create a secondary HQ including minor unit production buildings + defensive turrets all built after Tier3 HQ is achieved at main base.
This will likely be doeable provided we can determine how to have the AI build more reliably off expansions (captured and built-upon checkpoints). If we can get the AI to build defensive turrets on expansions, then this should be possible. We would require various checks to determine income, threat assessment, proximity to enemy, etc.. NOTE: This objective also may have relevance in the UNKNOWNS section under 1) [see below].
3) Better troop combinations (this may not be a problem as the AI generally is decent at selecting squad-level weapon upgrades).
Not too concerned about this one as the AI, as mentioned, is pretty good at a) randomly upgrading his squads with a good selection of weapons and b) has a decent-sized force mixing up unit-types. It also helps that now the AIs will research upgrades/techologies where they couldn't before.
The only area that this may benefit is to have the AI analyse what the enemy prefers in terms of unit choices and have the AI build/upgrade accordingly. This file controls that:
File: \ai\strategies\buildbasestrategy.ai
Script(s):
function BuildBaseStrategy:CalculateEffectivenessDemand( enemy_id )
function BuildBaseStrategy:CalculateClassDemand( enemy_id )
4) Troop dancing
This is where a squad can "dance around" while under fire so as to greatly reduce the # of projectiles that hit them. This is more a *very nice* perk for the AI squads to preform but how to imnplement it would be a challenge. It also might look rather silly to see enemy AI squads walking back and force in circles while firing back at the enemy. Still, it is worth trying.
Files that may be key to getting the AI squads to react to being attacked:
\ai\tactics\infantrytactic.ai
\ai\strategies\attackstrategy.ai
5) AI could use Cover on maps more effectively to bait players into a situation that leads them to their enemy's disadvantage. Whomever uses their troops in "covered" parts of the map gives those troops a defensive advantage. We want the SquadAI to use cover more frequently. How to accomplish this?
Here is the only reference for cover in the .ai files:
File: \ai\plansdefendchokepointplan.ai
Script: squadai:DoMoveToClosestCover( self.waypoint_pos, self.proximity )
6) Better acknowledgement of threats against fellow allied players (will come to the rescue more effectively when an ally, like me, is under heavy attack!)
This is somewhat a key feature of the AI - the ability to quickly help another allied player *IF* the AI player himself is *NOT* under attack himself. We need to try and get the AI players to first acknowledge all allied players in a game (both AI and human) then keep checking on each other's state and if that state changes to being under attack (could depend on how heavy the attack is) then if the AI is not being threatened it could send its forces to assist the player.
The files that seem to control this are:
File: \ai\cpu_manager.ai
Scripts(s):
function CpuManager:FindFirstFriendly( functor )
for squad in military_manager:GetSquads() do
--fulfills requirements
if squad:IsValid() and functor( squad ) then
return squad
end
function CpuManager:IsFriendly( player_id )
for player in self.stats:GetPlayerStats() do
if player:GetPlayerID() == player_id then
return not cpu_manager.player_stats:IsEnemy( player )
end
end
return false
Other files of interest that relate here:
\ai\plans\attackplan.ai
\ai\plans\defendplan.ai
\ai\strategies\attackstrategy.ai
\ai\strategies\defendstrategy.ai
\ai\strategies\strategy.ai
7) Fix Assassinate Win Condition where AI gets his Commander Unit prematurely killed by associating it with a squad (which goes into combat). This should be easy to fix. Basically, we want this Commander Unit to stay put and NOT get involved in combat. Probably the best course of action is to ensure the unit stays inside the confines of the main base! Further, if this Commander Unit is under attack it should seek a safer location outside or deep within main base.
We use the example of the Space Marine's FORCE COMMANDER:
File: \ai\tactics\forcecommandertactic.ai
Script(s):
function ForceCommanderTactic:IsAttacker()
--assassinate win condition -- never attack
return not cpu_manager.assassinate
end
function ForceCommanderTactic:Update()
if self:IsComplete() then
return
end
if cpu_manager.assassinate then
local attachable_filter = function( squad_ai )
return squad_ai:GetProRatedCost() >= 200 and self.squad_ai:CanAttachTo( squad_ai )
end
--assassinate win condition -- always attach to a squad
local attach_to = cpu_manager:GetClosestSquad( self.squad_ai:GetPosition(), 50, attachable_filter );
if attach_to ~= nil then
self.squad_ai:DoAttachSquad( attach_to )
attach_to:DoSetMeleeStance( SquadAI.MSTANCE_Ranged )
end
return
8) Apart from the Eldar race, the Space Marines, Chaos Space Marines, and Ork are NOT aggressive enough in the "Control Area" and "Take&Hold" Winning conditions. This will have to be quickly looked at as I have no clue why the Eldar race is different in these two game modes compared to the other three. These two game modes basically require the player to conquer and keep key map points (Control Area requires the player to hold a set percentage of the maps' strategic points for an amount of time - you win once you control 66% and over of these points in a period of elapsed time, Take&Hold requires you to capture over half of the Critical Locations on a map and hold them for a specifc amount of time).
There are references to these game modes and only an AI reference for the Control Area winning condition located in the W40kdata.sga\scar\winconditions\controlarea.scar (Control Area) and strategicobjective.scar (Take and Hold).
Will have to look into this to see how to beef up the AI's ability to keep points and to try and aggressively re-take points if lost to enemies.
9) Look into adding vehicles that Relic removed for the AI to use (ie. SM/CSM Rhino and ORK WarTrukk)
This is no biggie as the /ai/unitstats.ai file controls the usage of what units/upgrades the AI generally uses. This is *NOT* priority as those units (ie. Rhino) are transports and we all know how useless such units are in the game!
Unknowns
~~~~~~~
1) When AI's main base is destroyed yet has successfully made a secondary backup one, does he upgrade his HQ to Tier2 (SM, CSM, ORK)? Or when he created defensive turrents does he update them to Tier1 (Ork to Tier2)?
I know the AI is fairly good at relocating his main base elsewhere once his HQ is destroyed although I'm not sure how to go about having him re-create it with all new buildings from scratch? I'll have to look to see how the AI knows how to build a second HQ building once the old one is destroyed. The ai\strategies\<skillset>\buildorderstrategyinfo.ai file is there to create all the main base buildings so I'd have to see if the AI builds a backup base if it re-uses that template a second time in the same game.
2) Prevent game from crashing when my troops get near to the Mines that AI has built? Wierd.. (still testing this one!)
Will have to test this one a little more but I suspect somewhere the AI doesn't have building information regarding mines. It may need to be aware of what mines are and their effectiveness stats. I have yet to find a file that Relic may have omitted that disallows the AI to be aware of them.
Mine field info is stored here (Space Marines used as example):
W40kdata.sga\ebps\races\space_marines\structures\space_marine_mine_field.lua
Attached Files
Edited by thudo, 14 January 2005 - 09:25 PM.