Members | Sign In
All Forums > Mission Scripting

AI Scripting; The Facts

posted Jun 14, 2013 23:06:54 by xavierwise.tsn
After many hours of frustration and trial and error, I think I finally have AI scripting figured out. It has taken a lot of time, as there is a lot of contradictory information out there. Some of it works, much of it doesn't. Here I want to present the facts on adding AI in to a mission. I think this might be lengthy, so I am going to do a little bit at a time. I'm going to begin with one simple example, scripting AI for an enemy ship.

1. Create Ship event - the ship must be named manually when you create it (e.g. T26). The creation of the ship must occur in a separate event to any event in which you want to assign it AI commands. Set up a variable and a timer (only 1 second is needed) to trigger the AI event.

2. AI event - this event contains all the code for what you want the ship to do. When both the variable has been triggered and the timer has finished, this event will run. Note; the delay from the timer is essential. Without it, some events in this block will not activate properly; "Add_ai" and "Object_property" commands need the delay.

3. Script the AI - now you can add commands to your hearts content using the different commands.

- Base AI for a ship seems to be simply "Attack Player ship". The enemy vessel will set a course to attack your ship.

- "Clear AI" should be used if you want to completely rewrite the AI. The enemy ship will move towards coordinate 0,0,0 on the sector map (top right corner) ignoring everything. It will not attack anything, or retaliate if attacked. You must add new AI to make the ship function as you want. Ensure that it is the first instruction in the event if you want to completely rewrite a ship's AI.

- Order is key in AI scripting. "Clear_AI" (if used) should be your first action. Under that, "Add_AI" actions will be prioritised based on their actual order.
E.g. Setting "Attack Artemis when it is within 1000m" above "Attack friendly bases" will result in the following:
--- The enemy ship will move to attack your base if you are more than 1000m away from the enemy ship.
--- When you come to within 1000m of the enemy ship, it will turn to attack you.
--- When you move over 1000m away from the enemy ship, it will turn back to attack your base.

That's some of the basics. I will add and edit more later.

If you need anything clarified, please ask. The information has been gathered through observation, trial and error, and research and reading on what other people do. It has been tested and I have used it in my mission scripts successfully. The methods outlined above work. If for some reason you find they don't, please contact me directly and I will check and correct any errors.
[Last edited Jun 14, 2013 23:07:21]
page   1
12 replies
XHawk87 said Jun 14, 2013 23:52:52
Does this mean that instructions given first will have a higher priority than those given after, or the other way around?
xavierwise.tsn said Jun 15, 2013 09:03:55
The instructions given first have the higher priority. They will override other AI instructions given lower in the list.
XHawk87 said Jun 15, 2013 12:50:36
This is the opposite of what is indicated in the documentation, no wonder I haven't been able to get AI to work properly. Thanks a lot!
xavierwise.tsn said Jun 15, 2013 14:22:47
Like I say, I have found lots of contradictions and inaccurate information. Which documentation are you referring to?
XHawk87 said Jun 15, 2013 17:21:18
mission-file-docs.txt lines 47-50:


Now, all enemies and neutrals have a "Brain Stack". AI blocks get appended to the stack (using the add_ai command), and
the AI resolves each block from top (first) to bottom (last), so each AI block can supersede the AI blocks above it.

Reading it again it now sounds like its referring to the stack rather than the order in the event.
[Last edited Jun 15, 2013 17:24:07]
xavierwise.tsn said Jun 15, 2013 17:48:38
This is going to be hard to explain....

When an event triggers, it reads the actions within it from top to bottom and carries them out in that order (or at least that is what I have managed to deduce). The "add_ai" action at the top will be the first to be carried out and applied to the AI stack. However, as more "add_ai" actions are carried out, they will be added on top of it; they will be added to the top of ai stack.

Imagine it as a stack of paper. The first "add_ai" action is written on a piece of paper and put down on your desk to create a new stack of paper. The second "add_ai" action gets written and then is added on top of the stack. The third "add_ai" action gets written on a new piece of paper, then placed on top of the stack again and so on and so forth.

Although the first "add_ai" action is the one the event carries out first, it ends up being at the bottom of the stack.

That is as clear as I can make it I think. And this is based upon my own understanding of how the whole thing works.
XHawk87 said Jun 15, 2013 19:24:50
I am familiar with stacks in data structures, I just thought it was referring to the event and the position on the screen rather than the internal workings of the AI. For the benefit of those who haven't done a computing degree...

A stack is known as FILO (First In, Last Out). This means the first item you put into a stack is the last one you get out when reading them. Due to their nature, placing a sequence into a stack and pulling it all back out again will result in the sequence being reversed.

Extending the example above, the AI will then check the pieces of paper one by one from the top to bottom of the stack, and each time the conditions match those specified on the paper it overrides what it was going to do with the action specified on that sheet. By the time you reach the bottom of the stack, the last read matching condition will be the only action performed.

This means that since the first added piece of paper was at the bottom of the stack, it has the highest priority and will be the action performed since it has overridden all those above it (in the stack) and later (in the event).

I hope this makes sense to everyone. If not, just forget you ever heard about stacks, and remember that the AI instruction you added first will take priority over AI instructions you add afterwards.
[Last edited Jun 15, 2013 19:35:08]
TravisHead said Jun 19, 2013 01:02:32
For anyone using the Mission Editor and working with Neutral AI and Comms orders I found I had to use this to get Neutral ships to refuse AI:
<create type="neutral" x="25500.0" y="0.0" z="90000.0" angle="0.0" name="DS1Defender1" raceKeys="TSN friendly" hullKeys="Destroyer" />
<set_object_property property="willAcceptCommsOrders" value="0" name="DS1Defender1" />
<clear_ai name="DS1Defender1" />

The kicker here is that setting the Object Property (middle line) does not exist in the Editor and will be flagged as Unknown.
The AI option found in the Editor does not seem to work on its own.

Mike_Substelny said Jun 19, 2013 16:24:46
By the time you reach the bottom of the stack, the last read matching condition will be the only action performed.

While your assessment is good, XHawk87, and the above sentence is mostly true, I think I may be able to make it clearer.

As Thom pictures it, every time your mission script adds an AI block to a ship that block goes to the bottom of that ship's stack. When the ship needs to make a decision it starts at the top of the stack and goes down, checking all the conditions of every block. If a block triggers true then that block will be cued to execute. But if another block farther down the stack disagrees with it, then the farther down block will be cued to execute.

After the entire stack is checked, whatever commands are cued will execute. For example:

<add_ai name="Enemy Mine" type ="CHASE_STATION"/>
<add_ai name="Enemy Mine" type ="CHASE_PLAYER" value1="3000" value2="500"/>

If space ship Enemy Mine is in open space and a player ship is within 3,000 units then Enemy Mine will chase the player. Otherwise it will go after a station.

<add_ai name="Bad Guy" type ="CHASE_PLAYER" value1="3000" value2="500"/>
<add_ai name="Bad Guy" type ="CHASE_STATION"/>

Enemy spaceship Bad Guy will only chase the player ship if all stations are destroyed and the player is within 3,000 units.

It *is* possible that more than one command might be executed simultaneously (or nearly simultaneously). To wit:

<add_ai name="Villain" type ="CHASE_STATION"/>
<add_ai name="Villain" type ="CHASE_PLAYER" value1="3000" value2="500"/>
<add_ai name="Villain" type ="LAUNCH_FIGHTERS" value1="3000"/>
<add_ai name="Villain" type ="LEADER_LEADS"/>

For enemy spaceship Villain the chase player, launch fighter, and leader leads blocks can all execute at the same time since they do not conflict with each other.
"Damn the torpedoes! Four bells, Captain Drayton!"

(Likely actual words of Admiral David Farragut, USN, at the battle of Mobile Bay. Four bells was the signal for the engine room to make full steam ahead).
cdm014 said Jul 02, 2013 16:31:30
From a programming point of view, based on the way stacks work, if my script is something like this

<add_ai type="Action_A" when condition_1>
<add_ai type="Action_B" when condition_2>
<add_ai type="Action_C" when condition_3>
<add_ai type="Action_D" when condition_4>

Then the stack is going to look like this to the computer:

<add_ai type="Action_D" when condition_4>
<add_ai type="Action_C" when condition_3>
<add_ai type="Action_B" when condition_2>
<add_ai type="Action_A" when condition_1>

Which means that when it tries to figure out what to do, it's going to check condition_4, then condition_3, then condition_2, then condition_1 and it will execute the action for the FIRST condition that is satisfied. In other words if condition_4 is true, then it executes Action_D and ignores the other actions.

It makes sense if you think of it as do whatever the newest order that you can do is.
JanxJelantru said Jul 10, 2013 17:07:39
For the sake of clarity, a few terms:
Stack = First in, Last Out (FILO is the same thing)
Queue = First In, First out

What Mike describes appears to be a Queue and not a Stack. the first command in the line is the first to execute. The last (most recent) command added to the line is the last to execute.

It may be a bit pedantic, but since we are talking about programming a computer AND using computer programming terms, it is best for the sake of clarity that we use the correct term.

Otherwise every time folks say Stack but mean Queue behavior, they are unintentionally adding confusion to the the conversation.

I suspect everybody on this thread is smart and has a fair level of background on the topic. But this is an area where the terms used, do matter.

Mike_Substelny said Jul 10, 2013 22:48:13
Janx, if you believe that this behaves like a queue then I have explained it poorly. There is no FILO or FIFO behavior. There is no I or O behavior at all because it realy doesn't store anything. Nothing really goes in or out. So the term queue really doesn't apply here.

You can add layers to the brain stack or clear it, but you cannot push anything onto it or pop anything out of it. It is simply the prioritization of how conditions are checked.

But the main reason we call it a "Brain Stack" is because Thom's official documentation uses the that term.
"Damn the torpedoes! Four bells, Captain Drayton!"

(Likely actual words of Admiral David Farragut, USN, at the battle of Mobile Bay. Four bells was the signal for the engine room to make full steam ahead).
Login below to reply: