RDNWiki: DOWScar/AI/CreationTemplate ...

RDN Wiki Home | Page Index | Recent Changes | Recently Commented | Users | Registration | Login:  Password:  

Creation Template and Checklist


Contents

Introduction


The following is a highly useful template and checklist to build your DoW AI from scratch in a well-organized fashion.


PLEASE NOTE: This template/checklist is meant for us with the Dawn of Skirmish Advanced AI v1.2 Mod as it contains some custom scripts not found in the regular commercial AI.

1) cpu_manager.ai

import( 'Strategies/<modname>BuildBaseStrategy.ai' )

import( 'Tactics/<modname>/<unitname>Tactic.ai' )


function CpuManager:Initialize()
		self.player_stats:GetPlayerRaceName() == "<mod_race>" or

		self.player_stats:GetPlayerRaceName() == "<mod_race>" or


function CpuManager:AddStrategy( strategy_name, priority )
		elseif self.player_stats:GetPlayerRaceName() == "<mod_race>" then
		strategy = <modname>BuildBaseStrategy( BuildBaseStrategyInfo )


function CpuManager:ForceAttack( player_id )
	AttackStrategyInfo.<mod_race>.stop_attack_rating = -INT_MAX
	AttackStrategyInfo.<mod_race>.prefer_player = player_id


function CpuManager:CreateTactic( squad_ai )

	if squad_ai:IsEngineer() then
		elseif stats:GetSquadName() == "<mod's builder unit>" then
		return <unitname>Tactic( squad_ai )


	if 	class == UnitStatsAI.UC_LightInfantryLow or  
		class == UnitStatsAI.UC_LightInfantryMed or
		class == UnitStatsAI.UC_LightInfantryHigh then

		elseif squad_name == "<mod's light infantry squad>" then
		tactic = <unitname>Tactic( squad_ai )


	elseif 	class == UnitStatsAI.UC_HeavyInfantryMed or
       		class == UnitStatsAI.UC_HeavyInfantryHigh then

	elseif squad_name == "<mod's heavy infantry squad>" then
		tactic = <unitname>Tactic( squad_ai )


	elseif 	class == UnitStatsAI.UC_Commander then

	elseif squad_name == "<mod's commander unit>" then
		tactic = <unitname>Tactic( squad_ai )


	elseif 	class == UnitStatsAI.UC_VehicleLow or
		class == UnitStatsAI.UC_VehicleMed or
		class == UnitStatsAI.UC_VehicleHigh then

	elseif squad_name == "<mod's vehicle unit>" then
		tactic = <unitname>Tactic( squad_ai )


	elseif 	class == UnitStatsAI.UC_MonsterMed or  
       		class == UnitStatsAI.UC_MonsterHigh then

	elseif squad_name == "<mod's monster unit>" then
		tactic = <unitname>Tactic( squad_ai )


function CpuManager:IsBiggerGenerator( build_id )

   elseif build_id == cpu_manager.stats:GetBuildingID( "<your big power generator building>" ) then
	  return true

function CpuManager:IsGenerator( build_id )

   elseif build_id == cpu_manager.stats:GetBuildingID( "<your power generator building>" ) then
	  return true

function CpuManager:IsTurret( build_id )

   elseif build_id == cpu_manager.stats:GetBuildingID( "<your turret building>" ) then
	  return true

2) unistats.ai

race = "<mod name>_race",
		{
			name = "<Unit name>",
			attack_role = "<R, M, or RM>",
			sbp_name = "<SBPS Unit name>",
			ebp_name = "<EBPS Unit name>",
			class = UnitStatsAI.UC_<UnitClass>,
			rating = <insert #>,
			potential = 
			{
				{
					name = "<weapon name>",
					effectiveness = GenerateUnitEffectiveness(0,0,0,0,0,0,0,0,0,0,0),
					range = UnitStatsAI.RT_<None, Melee, ShortRanged, or Ranged>,
				},
			}
		},
		{
			name = "<Unit name>",
			attack_role = "<R, M, or RM>",
			sbp_name = "<SBPS Unit name>",
			ebp_name = "<EBPS Unit name>",
			class = UnitStatsAI.UC_<UnitClass>,
			rating = <insert #>,
			potential = 
			{
				{
					name = "<weapon name>",
					effectiveness = GenerateUnitEffectiveness(0,0,0,0,0,0,0,0,0,0,0),
					range = UnitStatsAI.RT_<None, Melee, ShortRanged, or Ranged>,
				},
				{
					name = "<weapon name>",
					effectiveness = GenerateUnitEffectiveness(0,0,0,0,0,0,0,0,0,0,0),
					range = UnitStatsAI.RT_<None, Melee, ShortRanged, or Ranged>,
				},

			}
		},
		{

3) <race_name>buildbasestrategy.ai

class '<race_name>BuildBaseStrategy' (BuildBaseStrategy)

function <race_name>BuildBaseStrategy:__init( baseinfo ) super( baseinfo )

function <race_name>BuildBaseStrategy:EvaluateSquadCap()

function <race_name>BuildBaseStrategy:DoBuildUnits() --optional!

function <race_name>BuildBaseStrategy:DoBuildBuildings() --here only due to AI prereq issues with v1.30 game-code!

function <race_name>BuildBaseStrategy:DoSecondaryBuildings()

function <race_name>BuildBaseStrategy:IsInSecondTier()

function <race_name>BuildBaseStrategy:IsInThirdTier()

function <race_name>BuildBaseStrategy:DoUpgradesAndAddons()

function <race_name>BuildBaseStrategy:AddOnNotify( addon_id, notify_code , build_channel )

4) attackstrategyinfo.ai

<mod name>_race =
	{
		--my prorate against yours before I stop attacking you and retreat
		stop_attack_rating = -100,
		min_units = 2,
	},

5) buildbasestrategyinfo.ai

<mod name>_race =
	{
		--how much requisition I have before I try to build an uber unit
		uber_unit_cost = <insert value, if applicable>,

		--minimum amount of power before I build another generator
		min_power = 100,

		resourcers = 2,
		
		--reserve this amount for building units/buildings (not for use in upgrading/ reinforcing)
		req_reserve = 200,
		
		ETA =
		{
			cost = 250,
		},
		
		--attack rating needs to be greater than this prorated to attack
		attack_rating = 200,
		
		--need at least 3 at all times
		squad_cap_threshold = 3,

		--need at least 4 at all times
		support_cap_threshold = 4,

                --tolerance attacking turrets
                turret_tolerance = 150,
		
		--used to calculate wants for engineers
		Engineers =
		{
			--number of engineers we're aiming for
			want = 3,
		},

		Turrets =
		{
			--limit of turrets
			limit = math.random( 6,10 ),
			
			req = 400,
			
			power = 400,
		},
		
		ResearchOrder =
                --X items 
		{

		},
		
		SquadLimits = 
		{
			standard = 
			{

			},
			standard2 = 
			{

			},

6) buildorderstrategy.ai

function BuildOrderStrategy:__init( info ) super( info )

    if map_size == small or closest_enemy < 275 then
        aitrace("Map is "..map_size)
        aitrace("Closest enemy is "..closest_enemy.."metres away")

        elseif cpu_manager.player_stats:GetPlayerRaceName() == "<mod name>_race" then
            table.insert ( self.info, { "squad", "<your first-tier infantry unit>" } )

7) infantrytactic.ai


Note: Use this file instead of defining individual tactic.ai files when different unit types plan to use the same ability.


-target ability table
InfantryTactic.TargetAbilities = 

{ nil, "<infantry anti-infantry weapon ability>",            Ability.Filters.CloseInfantryEnemy },
{ nil, "<infantry anti-vehicle weapon ability>",             Ability.Filters.CloseVehicleEnemy },


function InfantryTactic:DoAbilities()

		--check if I can use <this ability name>
		local <ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )
		Ability.DoAbilityArea( self.squad_ai, ability shortname>_id, Ability.Filters.<check filter section below> )

	if self.squad_ai:IsAttached() then

		<Commander Unit>Tactic.DoAbilities( self )


function InfantryTactic:Update()

		--check if I can use <this ability name>
		local <ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )

		if self.squad_ai:CanDoAbility( <ability shortname>_id ) then
			self.squad_ai:DoSpecialAbility( <ability shortname>_id )

	if cpu_manager.assassinate and 
		( self.squad_ai:HasSquadAttached( "<your commander unit>" ) or

8) vehicletactic.ai


Note: Use this if applicable (you may not have vehicles that require abilities so this is optional)

function VehicleTactic:DoAbilities()

	--check if I can use <this ability name>
	   
		local <ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )
		if self.squad_ai:CanDoAbility( <ability shortname>_id ) then
		self.squad_ai:DoSpecialAbility( <ability shortname>_id )

9) tactic.ai Specific Units


The following are templates for various types of units that require specific scripts

a) <engineer-unit>tactic.ai

Purpose: FOR ENGINEER/BUILDER UNITS THAT CAN REINFORCE BUT NOT ATTACK

class '<engineer-unit>Tactic' (EngineerTactic)

function <engineer-unit>Tactic:__init( squad_ai ) super( squad_ai )

end

function <engineer-unit>Tactic:Update()

	--state machine
	if not EngineerTactic.Update( self ) then
		return
	end
end

function <engineer-unit>Tactic:GetName()
	return "<engineer-unit> Tactic"
end

function <engineer-unit>Tactic:Reinforce()

	--don't reinforce more than 4 <specific-unit> -- they get stuck
	if not self.squad_ai:IsReinforcing() and self.squad_ai:GetNumTroopers() < 4 then
		local use_leader = false
		if self.squad_ai:CanReinforce( use_leader ) then
			self.squad_ai:DoReinforce( use_leader )
		end
	end

end

function <engineer-unit>Tactic:IsAttacker()

	--<engineer-unit> useless!
	if true then
		return false
	end
	
	--check if there are at least 2 free pioneer (leave one behind to build stuff)
	local num_<engineer-unit> = 0
	
	for squad_ai in military_manager:GetUnlockedSquads() do
	
			if squad_ai:IsEngineer() then
				num_<engineer-unit> = num_<engineer-unit> + 1
			end
			
			if num_<engineer-unit> > 1 then
				break
			end
	
	end
	
	--only use this as an offensive unit if I've reinforced enough
	if num_<engineer-unit> > 1 and self.squad_ai:GetNumTroopers() > 10 then
		return true
	end
	
	return false

end

b) <military-unit>tactic.ai

Purpose: FOR REGULAR UNITS THAT CAN ATTACH (NO ABILITIES)
Note: This can also be applied to Vehicles as well ie. (Vehicle Tactic?)

class '<military-unit>Tactic' (InfantryTactic)

<military-unit> = {}

function <military-unit>Tactic:__init( squad_ai ) super( squad_ai )

end

function <military-unit>Tactic:GetName()
	return "<military-unit> Tactic"
end

function <military-unit>Tactic:Update()

	--state machine
	if not InfantryTactic.Update( self ) then
		return
	end

    --if I'm in combat
    if self.squad_ai:IsInCombat() and not self.squad_ai:IsBroken() then

        local attachable_filter = function( squad_ai )
 
        	return ( self.squad_ai:CanAttachTo( squad_ai ) and squad_ai:IsRanged() and not squad_ai:IsBroken() ) 
 		end
 
    	--find close by squads
    	local attach_to = cpu_manager:GetClosestSquad( self.squad_ai:GetPosition(), 40, attachable_filter )
    	if attach_to ~= nil then
    	
    		self.squad_ai:DoAttachSquad( attach_to ) 
    	end
 
   end
	
end

c) <vehicle-unit>tactic.ai

Purpose: FOR REGULAR VEHICLES THAT CAN USE ABILITIES

class '<vehicle-unit>Tactic' (VehicleTactic)

<vehicle-unit> = {}

function <vehicle-unit>Tactic:__init( squad_ai ) super( squad_ai )

end

function <vehicle-unit>Tactic:UpdateAbilities()

	if <vehicle-unit>.<ability shortname>_id == nil then
		<vehicle-unit>.<ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )
	end
end

function <vehicle-unit>Tactic:GetName()
	return "<vehicle-unit> Tactic"
end

function <vehicle-unit>Tactic:DoAbilities()

	<vehicle-unit>Tactic.UpdateAbilities( self )
	
	dbAssert( <vehicle-unit>.<ability shortname>_id ~= nil )
	
	Ability.<SelectBehaviour>( self.squad_ai, <vehicle-unit>.<ability shortname>_id, Ability.Filters.<SelectFilter>, <# of enemy units nearby> ) 

end

function <vehicle-unit>Tactic:Update()

	--state machine
	if not VehicleTactic.Update( self ) then
		return
	end
end

d) <sub-commander unit>tactic.ai

Purpose: FOR IMPORTANT (SUB-COMMANDER) UNITS THAT CAN ATTACH AND USE ABILITIES

class '<sub-commander unit>Tactic' (InfantryTactic)

<sub-commander unit> = {}

function <sub-commander unit>Tactic:__init( squad_ai ) super( squad_ai )

	   if <sub-commander unit>.rally_id == nil then
	   <sub-commander unit>.<ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )	
	 end

end

function <sub-commander unit>Tactic:GetName()
	return "<sub-commander unit> Tactic"
end

function <sub-commander unit>Tactic:DoAbilities()

	--return if I didn't initialize myself
	if <sub-commander unit>.<ability shortname>_id == nil then
		return
	end
	
	dbAssert( <sub-commander unit>.<ability shortname>_id ~= nil )
	
	Ability.<SelectBehaviour>( self.squad_ai, <sub-commander unit>.<ability shortname>_id, Ability.Filters.<SelectFilter>, <# of enemy units nearby> ) 
	
end

function <sub-commander unit>Tactic:Update()

	if self:IsComplete() then
		return
	end
	
	if (self.squad_ai:GetHealthPercentage() <= 0.8 and cpu_manager.cpu_player:GetGameTime() > 10 * 60 * 8) or self.squad_ai:GetHealthPercentage() <= 0.5 then
		
		local attachable_filter = function( squad_ai )
		
			return squad_ai:GetProRatedCost() >= 200 and self.squad_ai:CanAttachTo( squad_ai ) and squad_ai:IsRanged()
		end
		
		local attach_to = cpu_manager:GetClosestSquad( self.squad_ai:GetPosition(), 60, attachable_filter );

		if attach_to ~= nil then 
			self.squad_ai:DoAttachSquad( attach_to )
		end
		
		return
		
	end

	--state machine
	if not InfantryTactic.Update( self ) then
		return
	end

	self:TryAttachSquadMelee()
	
end

e) <commander-unit>tactic.ai

Purpose: FOR COMMANDER UNITS THAT CAN ATTACH, USE ABILITIES, AND BE ASSASSINATED!

class '<commander-unit>Tactic' (InfantryTactic)

<commander-unit> = {}

function <commander-unit>Tactic:__init( squad_ai ) super( squad_ai )

	if <commander-unit>.<ability shortname>_id == nil then
	   <commander-unit>.<ability shortname>_id = cpu_manager.stats:GetAbilityID( "<actual ability name>" )	
	end
	
	<commander-unit>.<ability shortname> = cpu_manager.stats:GetAbilityID( "<actual ability name>" )

end

function <commander-unit>Tactic:GetName()
	return "<commander-unit> Tactic"
end

function <commander-unit>Tactic:DoAbilities()

	--return if I didn't initialize myself
        if <commander-unit>.<ability shortname>_id == nil then
		 return
 end

        dbAssert( <commander-unit>.<ability shortname> ~= nil )
	
	Ability.<SelectBehaviour>( self.squad_ai, <commander-unit>.<ability shortname>_id, Ability.Filters.<SelectFilter>, <# of enemy units nearby> ) 
	Ability.<SelectBehaviour>( self.squad_ai, <commander-unit>.<ability shortname>, Ability.Filters.<SelectFilter>, <# of enemy units nearby> ) 
	
end

function <commander-unit>Tactic:IsAttacker()
	
	--assassinate win condition -- never attack
	return not cpu_manager.assassinate

end

function <commander-unit>Tactic:Update()

	if self:IsComplete() then
		return
	end
	
	if cpu_manager.assassinate or (self.squad_ai:GetHealthPercentage() <= 0.8 and cpu_manager.cpu_player:GetGameTime() > 10 * 60 * 8) or self.squad_ai:GetHealthPercentage() <= 0.5 then
		
		local attachable_filter = function( squad_ai )
		
			return squad_ai:GetProRatedCost() >= 200 and self.squad_ai:CanAttachTo( squad_ai )
		
		end
		
		--assassinate win condition or hurt -- 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 )

			if cpu_manager.assassinate then
				attach_to:DoSetMeleeStance( SquadAI.MSTANCE_Ranged )
			end
		end
		
		return
		
	end

	--state machine
	if not InfantryTactic.Update( self ) then
		return
	end

	self:TryAttachSquadMelee()
	
end

Links


AI Home
SCAR Home
Wiki Home

End of Page


Referring pages: DOWScar/AI
DOWScar/AI/Advice

There are no files on this page. [Display files/form]
There is no comment on this page. [Display comments/form]