Greetings, and welcome
This is another guide for scripting an AI for the great game Age of Empires III. You can find the first (and the only in the whole AoEIIIHeaven Forum) two guides here:
http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=ct&f=14,38878,,all
http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=ct&f=14,38885,,all
Even though my guide would not be as great as murdilator's ones, I will try my best to make it understandable by everybody, even the non-advanced people.
Do not hesitate to ask if you have questions, because depending on the number of people who will participate, this guide may be more or less a great means of informations for medium and beginning AI scripters.
My guide will be based on the original AI. Yeah, I know this AI is well known for itsmediocrity, but it will serve for lessons only. For the rest, you can improve it yourself and show us what have you done, to help the others to improve their own AIs. By the way, you can find the main AI file in the folder AI3, in the installation folder of your aoe3 game. It is called "aiMain.xs". You can open it with Notepad, Notepad++ or any other text editor. A final couple of notes : we will need a reference for remembering codes faster; you can download the Complete AI Reference for TAD by Panmaster2014 here : http://aoe3.heavengames.com/downloads/showfile.php?fileid=3750&ci=02ccb454475cf0d3b61fcec17f14f73eYToxOntpOjA7YToyOntpOjA7czoxNDoiU2VhcmNoIFJlc3VsdHMiO2k6MTtzOjM5OiJsaXN0ZXIucGhwP3N0YXJ0PTAmYW1wO3NlYXJjaD1yZWZlcmVuY2UiO319 . Also, all the examples I will give here are a very simplified version of how should the code be. If you are a full beginner and don't know what to do, you can request a full code for those examples in the comments, and even ask for explanations for it.
The auto-created base
There are some hard-coded features, related to AIs, inside the game executable. One of them is related to base. For a computer player, even without any AI file, base is created automatically when a Town Center is found. That's why settlers are automatically garrisoned inside the Town Center when we shot at them, even if there is no AI file controlling them, or even when the AI file failed to compile. This is a bug, since we do not have any function for controlling garrison/ungarrison. We cannot prevent the game from garrisoning attacked villagers through the use of a garrison-related function (unless we use a plan with cPlanTransport, but I have done no test yet). To fix this issue, there is only a single solution: destroying the auto-created base with the functionkbBaseDestroyAll(), then create it manually after. Thanks for Panmaster2014 for the trick. That should definitively fix the town bell bug.
The attack goals
Attack goals are a high level way to perform an attack. "High level"does not mean it is the best way, it only means you will do a superficial work and it's for the AI to look deeper and decide if yes or no, he will be able to attack. Thus you just create the goal, and the AI creates the appropriate plans and any other action for you. It has the bad inconvenience of breaking in very late games (mostly one and half hours of skirmish, or later, depending on how much the scripter improved his AI), and sometimes it is blocked, or at least slowed down, by opportunities (we will discussed about opportunities later). A better alternative would be to create attack plans, which have the advantage of being more "independent":
For artillery units, a simpleaiTask is the best thing to do concerning attacks :
Opportunities
Opportunities are kind of orders from which you decide which action should the AI perform. Orders from trigger scripts take the priority over any other order/decision. Then come ally requests. And finally, if no one ordered them to do something, AIs continue on their own. The only types of opportunity that exist areDestroy ("Hey, send your army to attack in this location!"), Defend ("Hey, take control of this point!"), Claim ("Hey, build a trading post here!"), Raid (which I don't know much things) and Rescue explorer. When giving an order to the AI, there is a target type to be mentioned. Target types are Base, Resource, Point radius, and Unit List. AI's decision change according to target types.
An example : human player sent an "attack" order to Napoleon, next to a trade post socket. This means "Napoleon, go build a trading post here".
Source : Ally Request.
Type : Claim.
There is a handler,cXSScoreOppHandler, called "scoreOpportunity". When some opportunities need to be scored, this handler is called, and according to the score, planned action should be performed or not, which is sometimes a problem. I cannot give any example about this subject, as I am not really agreeing with opportunity usage and did not study it too much. AoE_Badger (here : http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=st&fn=14&tn=38842&f=14,38842,0,10&st=25 ) have found a way to manipulate the scoring to force the accomplishment of certain actions. Look at his code, you might be interested.
Progressions
Progressions are kind of high level way to reach whatever objective you want to reach. For example, a progression to get the Blockade will Age up until reaching Age V, then build a capitol and try to get the Blockade, without forcing you to create any build plan or anything else. I decided to explain it here because I think that this method is not really optimized and not always efficient, but may be useful according to the method you adopt and the way you implement your ideas. Therefore you have 2 choices : improving existing progression plans (see the rule econUpgrades to get an (overcomplicated) example), or abandoning them completely and create manually research plan (like Felix Hermansson did in the Draugur AI with all the rules called "[...]UpgradeMonitor") with the appropriate checks and conditions.
The unit picker
Unit Picks are a high level way to decide what kind of units you wish to train. You only need to mention the unit type to train, the unit to counter, the minimum/maximum population and age authorized for training, and the rest is decided by the AI. Murdilator's AIs make a great and efficient use of the unit picker, so I suggest you to download them here :http://aoe3.heavengames.com/downloads/showfile.php?fileid=3363
http://aoe3.heavengames.com/downloads/showfile.php?fileid=3818&ci=dee46a6da0d22c8b4e9df7f9b9352e9bYToxOntpOjA7YToyOntpOjA7czoxNDoiU2VhcmNoIFJlc3VsdHMiO2k6MTtzOjM2OiJsaXN0ZXIucGhwP3N0YXJ0PTAmYW1wO3NlYXJjaD1Db3dhcmQiO319
http://aoe3.heavengames.com/downloads/showfile.php?fileid=3847&ci=dee46a6da0d22c8b4e9df7f9b9352e9bYToxOntpOjA7YToyOntpOjA7czoxNDoiU2VhcmNoIFJlc3VsdHMiO2k6MTtzOjM2OiJsaXN0ZXIucGhwP3N0YXJ0PTAmYW1wO3NlYXJjaD1Db3dhcmQiO319
and study them a little. Ask me for some examples if you are blocked.
However, if you are not proceeding like murdilator, the unit picker is not always efficient. At last it avoids you, sometimes, to do complex checks to not ruin the economic calculus... If you want, you can always force the AI to use maintain plans :
More details will be added after a month or so, like deck personalizing, works with vectors, informations about plans (their works, their issues and limits...), and much more. Also, I will make this topic to look more like a "real" guide than just a monotone presentation. For now, I just hope to see more contributors to help building up a big "knowledge base" about AI scripting here. So, see you soon!
This is another guide for scripting an AI for the great game Age of Empires III. You can find the first (and the only in the whole AoEIIIHeaven Forum) two guides here:
Even though my guide would not be as great as murdilator's ones, I will try my best to make it understandable by everybody, even the non-advanced people.
Do not hesitate to ask if you have questions, because depending on the number of people who will participate, this guide may be more or less a great means of informations for medium and beginning AI scripters.
My guide will be based on the original AI. Yeah, I know this AI is well known for its
There are some hard-coded features, related to AIs, inside the game executable. One of them is related to base. For a computer player, even without any AI file, base is created automatically when a Town Center is found. That's why settlers are automatically garrisoned inside the Town Center when we shot at them, even if there is no AI file controlling them, or even when the AI file failed to compile. This is a bug, since we do not have any function for controlling garrison/ungarrison. We cannot prevent the game from garrisoning attacked villagers through the use of a garrison-related function (unless we use a plan with cPlanTransport, but I have done no test yet). To fix this issue, there is only a single solution: destroying the auto-created base with the function
Attack goals are a high level way to perform an attack. "High level"
planID = aiPlanCreate("APN", cPlanAttack);
aiPlanSetDesiredPriority(planID, 95);
aiPlanSetUnitStance(planID, cUnitStanceAggressive);
aiPlanSetAllowUnderAttackResponse(planID, true);
aiPlanSetVariableInt(planID, cAttackPlanPlayerID, 0, enemyPlayerID);
aiPlanSetVariableVector(planID, cAttackPlanAttackPoint, 0, v);
aiPlanSetVariableFloat(planID, cAttackPlanAttackPointEngageRange, 0, 60.0);
aiPlanSetNumberVariableValues(planID, cAttackPlanTargetTypeID, 3, true);
aiPlanSetVariableInt(planID, cAttackPlanTargetTypeID, 0, MainUnitToBeCountered);
aiPlanSetVariableInt(planID, cAttackPlanTargetTypeID, 1, UnitWhichIsNotACounterOfOurAttacker);
aiPlanSetVariableInt(planID, cAttackPlanTargetTypeID, 2, cUnitTypeLogicalTypeBuildingsNotWalls);
aiPlanSetVariableInt(planID, cAttackPlanAttackRoutePattern, 0, cAttackPlanAttackRoutePatternBest);
aiPlanSetVariableBool(planID, cAttackPlanMoveAttack, 0, true);
aiPlanSetVariableInt(planID, cAttackPlanRefreshFrequency, 0, 6);
aiPlanSetVariableInt(planID, cAttackPlanHandleDamageFrequency, 0, 6);
aiPlanSetVariableInt(planID, cAttackPlanBaseAttackMode, 0, cAttackPlanBaseAttackModeRandom);
aiPlanSetVariableInt(planID, cAttackPlanRetreatMode, 0, cAttackPlanRetreatModeNone);
aiPlanSetVariableInt(planID, cAttackPlanGatherWaitTime, 0, 0);
aiPlanAddUnitType(planID, OurAttackerUnit, numberNeed, numberWant, numberMax);
aiPlanSetActive(planID, true);
For artillery units, a simple
unitID = getUnit(cUnitTypeCulverin, cMyID, i);
v = kbUnitGetPosition(unitID);
enemyID = getNearestUnitAroundLoc(cUnitTypeAbstractArtillery, cPlayerRelationEnemyNotGaia, v, 40.0, 0);
if(enemyID >-1)
aiTaskUnitWork(unitID, enemyID);
else
aiUnitSetTactic(unitID, cTacticLimber);
Opportunities are kind of orders from which you decide which action should the AI perform. Orders from trigger scripts take the priority over any other order/decision. Then come ally requests. And finally, if no one ordered them to do something, AIs continue on their own. The only types of opportunity that exist are
An example : human player sent an "attack" order to Napoleon, next to a trade post socket. This means "Napoleon, go build a trading post here".
Source : Ally Request.
Type : Claim.
There is a handler,
Progressions are kind of high level way to reach whatever objective you want to reach. For example, a progression to get the Blockade will Age up until reaching Age V, then build a capitol and try to get the Blockade, without forcing you to create any build plan or anything else. I decided to explain it here because I think that this method is not really optimized and not always efficient, but may be useful according to the method you adopt and the way you implement your ideas. Therefore you have 2 choices : improving existing progression plans (see the rule econUpgrades to get an (overcomplicated) example), or abandoning them completely and create manually research plan (like Felix Hermansson did in the Draugur AI with all the rules called "
Unit Picks are a high level way to decide what kind of units you wish to train. You only need to mention the unit type to train, the unit to counter, the minimum/maximum population and age authorized for training, and the rest is decided by the AI. Murdilator's AIs make a great and efficient use of the unit picker, so I suggest you to download them here :
and study them a little. Ask me for some examples if you are blocked.
However, if you are not proceeding like murdilator, the unit picker is not always efficient. At last it avoids you, sometimes, to do complex checks to not ruin the economic calculus... If you want, you can always force the AI to use maintain plans :
int planID = aiPlanCreate("MaintainPlanPlanName", cPlanTrain);
if(planID <0)
return(-1); // if plan creation failed, return "-1"
aiPlanSetVariableInt(planID, cTrainPlanUnitType, 0, cUnitTypeProtoUnitToTrain);
aiPlanSetVariableInt(planID, cTrainPlanNumberToMaintain, 0, numberToMaintain);
aiPlanSetVariableInt(planID, cTrainPlanBatchSize, 0, batchSize);
if(baseID >= 0)
aiPlanSetBaseID(planID, baseID); // Add base if any
aiPlanSetVariableVector(planID, cTrainPlanGatherPoint, 0, kbBaseGetMilitaryGatherPoint(cMyID, baseID));
aiPlanSetActive(planID);
More details will be added after a month or so, like deck personalizing, works with vectors, informations about plans (their works, their issues and limits...), and much more. Also, I will make this topic to look more like a "real" guide than just a monotone presentation. For now, I just hope to see more contributors to help building up a big "knowledge base" about AI scripting here. So, see you soon!
[This message has been edited by SkyOne578 (edited 07-28-2017 @ 03:27 AM).]