The 3rd Age

The Horse Lords

The Horse Lords

A mod intended to enhance The Rise of the Witch King and add a new campaign

Button for The 3rd AgeButton for The Dwarf HoldsButton for The Elven AllianceButton for Helm's Deep Last HopeButton for GothmogtheOrcButton for BFME+Button for The Four AgesButton for HDR HeadquartersButton for Middle Earth CenterButton for Project Perfect Mod

Become an affiliate!


Quick Lists

Top Rated Popular New Updated Last Comments Users

Register and log in to move these advertisements down

In-depth AI Coding

Avatar of Sulherokhh


Category: Code
Level: Expert
Created: Wednesday October 3, 2007 - 6:28
Updated: Friday August 27, 2010 - 19:26
Views: 26767
Summary: The beginning of a comprehensive guide to AI-modding for BfME2


Staff says


Members say




20 votes

Page 1 2 3 4 5 6 7 8 9 10 11
B3. Complicating the issue.

Let's say you want Faramir to dismount when there are a lot of Pikemen around. He is pretty vulnerable to Pikemen when mounted, so this would make sense.
This is 'one' way of dealing with the issue. A similiar way can be implemented to make him mount again, replacing the above described rather simple procedure of letting him mount.
Bear with me.

Let's have a look at one of the most interesting modules. It was used originally just to let Sting glow when orcs where near:

Behavior = SpecialEnemySenseUpdate ModuleTag_StingSeesOrcs
    SpecialEnemyFilter = ANY +ORC +URUK +MordorShelob
    ScanRange = 200
    ScanInterval = 2000

This Module lets Frodo sense specific enemies when they are at a range of 200 or less. The module checks for enemies ever 2 seconds.

Faramir needs this to be a bit modifier. In the end, it should look like this:

Behavior = SpecialEnemySenseUpdate ModuleTag_FaramirSeesPikemen
    SpecialEnemyFilter = ANY +PIKEMAN ENEMIES
    ScanRange = 100
    ScanInterval = 2000

He will now sense Enemy Pikemen at a range of 100 'feet' (roughly the diameter of standard horde).
This module does one thing, and one thing only. It sets the ModelCondition 'SPECIAL_ENEMY_NEAR' when it's conditions are met.
Now we need this ModelCondition to actually DO something.
With Frodo, it made Sting glow. This was done with and additional W3DDraw-module.
But to make it trigger a SpecialPower, we will need an upgrade. And we also want it removed when the conditions are gone, so it can be reacquired and once again trigger the dismount when the conditions are met again at a later date.
AND we want Faramir to mount again when the Pikemen are gone.
This is the way to do it:

First we need two OBJECT-upgrades. There are some suitable unused ones already defined, but for clarity's sake, i will make up new ones.

Upgrade Upgrade_DismountNOW
    Type = OBJECT

Upgrade Upgrade_MountNOW
    Type = OBJECT

Next, we need to adjust Faramir's LUAFunctions, or rather add two more to his set.

To explain briefly, the LUAFunctions of an object continuously check during the game if certain conditions are met. If they are, they will trigger a scripted response.
There are quite some useful triggers that can be used for the function, specifically a ModelCondition (or the sudden absence of a ModelCondition) can be used as a trigger!

Which 'EventLists' is used is defined in the object's module called 'AIUpdateInterface'

This is what we have for Faramir:
Behavior = AIUpdateInterface ModuleTag_03
    AutoAcquireEnemiesWhenIdle = Yes ATTACK_BUILDINGS STEALTHED
    MoodAttackCheckRate = 500
    HoldGroundCloseRangeDistance = 41

Many other objects have an additional line which defines the LUAFunction-list used. Like Frodo:
Behavior = AIUpdateInterface ModuleTag_03
    AutoAcquireEnemiesWhenIdle = Yes ATTACK_BUILDINGS
    MoodAttackCheckRate = 500
    AILuaEventsList = FrodoFunctions
    HoldGroundCloseRangeDistance = 40
    CanAttackWhileContained = Yes

So, i'll add a line with a new (yet undefined) list:
AILuaEventsList = FaramirFunctions

My new module for Faramir will now look like this:
Behavior = AIUpdateInterface ModuleTag_03
    AutoAcquireEnemiesWhenIdle = Yes ATTACK_BUILDINGS STEALTHED
    MoodAttackCheckRate = 500
    AILuaEventsList = FaramirFunctions
    HoldGroundCloseRangeDistance = 41

Now it's time to define Faramir's LUAFunction-set (in 'data\scripts\scriptevents.xml')

At the top of the file, you'll find a list of common triggers. Some are system triggers (so called 'InternalEvents' like 'OnCreated') some are ModelConditionTriggers ('ModelConditionEvent' like 'Moving').
The last ones have a set of condition definitions, listing ModelConditions with a '+' (to signify this ModelCondition must be present) and '-' (to signify it is not allowed to be present).

I'll make two new ones:
<ModelConditionEvent Name="OnEnemyNear">

<ModelConditionEvent Name="OnEnemyNOTNear">

Scroll down. You'll find a lot of EventLists. I'll make a new one for Faramir by copying one that inherits the BaseScriptFunctions (that contain nothing), for exaxmple:
<EventList Name="InfantryFunctions" Inherit="BaseScriptFunctions">
    <EventHandler EventName="BeAfraidOfBalrog" ScriptFunctionName="BecomeAfraidOfBalrog" DebugSingleStep="false"/>
    <EventHandler EventName="BeAfraidOfRampage" ScriptFunctionName="BecomeAfraidOfRampage" DebugSingleStep="false"/>
    <EventHandler EventName="BeTerrified" ScriptFunctionName="BecomeTerrified" DebugSingleStep="false"/>
    <EventHandler EventName="BeUncontrollablyAfraid" ScriptFunctionName="BecomeUncontrollablyAfraid" DebugSingleStep="false"/>

Now i have this:
<EventList Name="FaramirFunctions" Inherit="BaseScriptFunctions">
    <EventHandler EventName="OnEnemyNear" ScriptFunctionName="BecomeDismounted" DebugSingleStep="false"/>
    <EventHandler EventName="OnEnemyNOTNear" ScriptFunctionName="BecomeMounted" DebugSingleStep="false"/>

As you can see, i already inserted two new ScriptFunctions, 'BecomeDismounted' and 'BecomeMounted'.
Now i will need to define them.

Open up 'scripts.lua' (in 'data\scripts\')

You'll see a list of functions that can be triggered by any condition in 'scriptevents.xml'
Now i insert my new functions, which would look like this:

function BecomeDismounted(self)
    ObjectRemoveUpgrade( self, "Upgrade_MountNOW" )
    ObjectGrantUpgrade( self, "Upgrade_DismountNOW" )

function BecomeMounted(self)
    ObjectRemoveUpgrade( self, "Upgrade_DismountNOW" )
    ObjectGrantUpgrade( self, "Upgrade_MountNOW" )

Pretty self-explanatory, right?

All we need to do now is redo our DoCommand modules:

We already have this:
// Switch CommandSet when MOUNTED
Behavior = MonitorConditionUpdate ModuleTag_CommandSetSwapper
    WeaponSetFlags = MOUNTED
    WeaponToggleCommandSet = GondorFaramirCommandSetMounted

Now we add two modified modules to the object code:
Behavior = DoCommandUpgrade Module_DoCommandMount    
    TriggeredBy = Upgrade_ObjectLevel3 Upgrade_ObjectUnderAIControl Upgrade_MountNOW
    RequiresAllTriggers = Yes
    GetUpgradeCommandButtonName = Command_ToggleMount

Behavior = DoCommandUpgrade Module_DoCommandDismount
    TriggeredBy = Upgrade_ObjectUnderAIControl Upgrade_DismountNOW
    RequiresAllTriggers = Yes
    GetUpgradeCommandButtonName = Command_ToggleDismount

As mentioned earlier, you may need two differently named CommandButtons and two different CommandSets for it to work flawlessly.


When created, the LUAscripts immediately recognize the missing 'SPECIAL_ENEMY_NEAR' ModelCondition and give the yet unmounted Faramir the upgrade 'Upgrade_MountNOW' which will do nothing (yet) until he is level 3.
Then he will immediately mount his horse. If Pikemen are near, the flag 'SPECIAL_ENEMY_NEAR' is set, 'Upgrade_MountNOW' is removed, 'Upgrade_DismountNOW' is granted, this in turn triggers the dismount. The reverse happens as soon as the PIKEMEN are gone for at least 2 seconds.
And all of this will only work in the presence of the upgrade 'Upgrade_ObjectUnderAIControl' and so is only set into motion for AI-PLAYERS ONLY!

Next page: Making Faramir use 'Wounding Arrow' ONLY when appropriate (good for many other abilities as well)



Display order: Newest first | Page: 1, 2

Prolong - Thursday July 29, 2010 - 9:21

Very nice guide, even though it never got finished there is still a ton of great information here.

Elrond99 - Sunday February 15, 2009 - 7:52

Thanks for updating the Tutorial
It´s great to hear that it´s possible to make a new AI from scratch

Can´t wait for section F, custom AI scripts, that sounds really interesting
Especially since I know D and E already ;)

Sulherokhh (Team Chamber Member) - Saturday February 14, 2009 - 21:19

After 'D. The Faction Base and Fortress', i guess.
If you are asking for a date, you are asking the wrong guy. I don't have one. I work on modding related stuff mostly when i find the time and the mood strikes me. It's supposed to be fun, right? :)

Edit: But i might do it before the fortress and base setup. Depends on, well, which kind of work is going to be most interesting to me at the time. Scripts should be easier to do then the Basebuilding stuff, but a bit more to write as well, at least if i am going to do it right. I am starting to ramble... :O

jakonic - Saturday February 14, 2009 - 12:05

when will be finished Spell Purchase Scripts???please answer

Sulherokhh (Team Chamber Member) - Thursday November 29, 2007 - 17:26

I sure will...

Edit: Do you have any particular requests? If i have done it already, it shouldn't be hard to post a solution here. If it's not, chances are that i was going to look into it anyway. Except for the general skirmishsetup and bases, since those will require extesive explanations which i was planning to do anyway when i find the time.

So shoot! :)

Rob38 (Team Chamber Member) - Thursday November 29, 2007 - 11:00

This is by far one of my favorite tutorials on T3A! Please continue to add more :)

Sulherokhh (Team Chamber Member) - Wednesday October 3, 2007 - 23:07

I am glad you can put it to use, Rob! Your feedback means a lot to me. :D

Rob38 (Team Chamber Member) - Wednesday October 3, 2007 - 22:27

Amazing! I also found a way to recognize if a player is controlled by the AI, but this looks to be a much easier method to use. Thank you for all your wonderful knowledge as there is some really cool stuff in here.

Sulherokhh (Team Chamber Member) - Wednesday October 3, 2007 - 19:18

I'll split it up. Let's see what would be a good way. - Edit: Done. I hope you like it.

Crashdoc - Wednesday October 3, 2007 - 16:48

Nice findings and interesting ways to use them. Thanks for sharing the knowledge!

Go to top


"One site to rule them all, one site to find them,
one site to host them all, and on the network bind them."