The World of AI Scripting: Chapter 1

Article written by Leif Ericson
Published on 11-22-2009; updated on 09-22-2010
Tags: ,

Prologue (Purpose)

In my opinion, far too few people know the power and enjoyment of AI scripting. Many of us have had the experience of playing against a powerful AI, but often we don’t even think of making our own. This guide is written to encourage you to throw away your misconceptions about AI and to reveal the true wonders of the world of AI scripting. I invite you to get your feet wet, to explore the wonders that AI can do for you, as a gamer, as a scenario designer, and as an Age of Kings enthusiast, so that your experience of Age of Empires II may be complete and fully enjoyable. The rest of us AI invite you to join us. Welcome to the world of AI scripting.

Introduction

Welcome. You are about to join the thousands of people throughout the years who have experienced the joy of AI scripting. Those of you still out there who are unlucky enough to have not discovered this world, now is the time! The satisfaction of writing your own AI is far greater than designing your own scenarios. Now, let us jump in and I will show you all you need to get started with your first AI!

What are AI’s?

AI stands for Artificial Intelligence. The computer player uses AI files to tell it how to play the game. Now, before you get discouraged, let me dispel one common myth: AI scripting is not hard to understand. For many of us, the words “artificial intelligence” conjures up the image of thousands of lines of complex code that no one except a computer geek understands. AI scripting for The Conquerors is actually quite simple once you learn how. That is why I am here to teach you.

What do I need?

First, we need to create our AI scripting toolbox. Here are the tools you need:

  • The CPSB (Computer Player Strategy Builder Guide) — you can find this by going to My Computer, right-clicking on The Conquerors icon, clicking open on the right-click menu, and opening the DOCS folder. This was the AI scripting guide that came with the game. Use it as a reference if you ever get stuck.
  • Notepad or WordPad – (Microsoft Word or other similar programs that have spell-check will think the codes in your AI are misspelled words and put an annoying squiggly line under your entire code, so I prefer to use Notepad or Wordpad)
  • The SAMPLEAI — you can find this by going to My Computer, right clicking on The Conquerors icon, clicking open on the right-click menu, and opening the Goodies folder. This is a small AI that shows you the real basics, so I don’t encourage you to use it as a base for your AI, although you can look at it to get ideas.

So, now that our toolbox is ready, let’s put our hard hats on and head to work!

Your first rule (finally!)

This guide is organized into sections. From now on, any code in bold print, except for headings, is code that you should put into your AI. Also, at the end of each section I will put a tip or note to wrap up the section. Now, onto AI scripting!

First, let’s talk about rules. Rules form the basis for every AI. The basic logic for rules is as follows: “if this is true, then do this”.

Most rules follow this format:

(defrule ;This starts the rule. Defrule is short for "define rule".
(fact 1) ;This is the "if" part of the rule. The AI checks to see if these facts
(fact 2) ;are true. If all the facts are true then the AI continues onto the
(fact 3) ;actions. Not all rules have 3 facts, but all have at least one.
...
=> ;This is the "then" part of the rule.
(action 1)
(action 2) ;If all the facts are true then these actions occur. Not all rules have
(action 3) ;three actions, but all have at least one.
...
) ;this parenthesis ends the rule
...

Now, let’s write our first rule. First open Notepad or whatever you’re typing up your AI with and type this rule:

(defrule
(unit-type-count villager => 0)
=>
(chat-local-to-self "I just made my first rule!!!!")
)

So, this rule checks to see if the AI has greater than 0 villagers. If it does then it sends a message to itself saying “I just made my first rule!!!!”.

So, now that you know what rules, defrule commands, facts, and actions are, let me tell you a little bit more about rules. First, you can have more than one fact and/or more than one action in a rule, though you must have at least one of each in a rule.

Also, you may have noticed that I used parentheses. In AI’s, almost everything is enclosed in parentheses, including facts, actions, and even the rules themselves. If you forget a parenthesis around one of your facts, actions, or rules you will get an error and the AI will not work. So watch for those parentheses.

Also, many commands will use hyphens between words. I will explain this later.

Testing your AI

Now, you’re probably eager to test out your rule. First, you need to save your AI. When you’ve chosen a name, type in the name and put a .per extension on the end of it. All AI’s are saved in the AI folder (go to My Computer/Local Disk (C)/Program Files/Microsoft Games/Age of Empires II/AI), so make sure you navigate to this folder before you save it.

Next open up a new document and this blank document with the same name as your AI but with an .ai extension instead of a .per extension.

So, the names of your two files could be:

  • My First AI.per
  • My First AI.ai

The .per file includes all the code that the game reads. However, the game needs the .ai file to be able to open the AI file. So, every AI file you create will need two files, one with a .per extension and one with an .ai extension.

Now, to see your AI at work, open up Age of Empires and get ready to start a random map game. To get your AI to play in the random map game, click on the arrow box to the left of your player file, and select the name of your AI.

Screenshot

Then, start the game, and watch the AI yell its message out.

My AI isn’t working!

If your AI has an error in it a window will come up that looks like this. If no window pops up that means your AI is error free (horray!).

The first line says which player has the error. Since player 1 has the error, something is wrong with the AI for player 1.

The second line says what the AI file is that has the error (in this case My First Ai.per).

The third line is the most useful. It will tell you which line the error is on, what type of error it is (more on that later), and it will show the words or symbols that are giving you the error.

In this case, I put pillager in my AI in line 2 instead of villager, so I can edit my AI, save it, and restart the game and see if that fixed it.

If you can’t find your error go through these steps:

  1. Make sure your AI looks exactly like this: (copy it if you need to, but I would rather you typed it)

    (defrule
    (unit-type-count villager > 0)
    =>
    (chat-to-all "I just made my first rule!!!!")
    )

  2. Make sure you saved both a .per and an .ai file under the same name, and make sure they are saved in the AI folder.
  3. When setting up the random map game, choose all the game settings before you select the AI from the list.

You just made your first rule. Congratulations!

The disable-self action

Now, one thing that probably bugged you was that your message kept displaying over and over and over and over and over… To stop this rule from repeating you can add a disable-self action at the end of your rule before the last parenthesis. Whenever you place a disable-self action at the end of a rule, the rule will only run once.

Your rule will look like this with the disable-self command:

;The use of the disable-self action

(defrule
(unit-type-count villager > 0)
=>
(chat-to-all "I just made my first rule!!!!")
(disable-self)
;<~~~the disable-self action
)

Now, you can save your .per file and test your AI, and it will only send the message once. (Hooray!).

Note:

One thing to note is that anything following a semi-colon will not be read by the computer when it runs the AI. This allows scripters to write comments in their AI, for the benefit of the reader. The semi-colon can be placed either at the beginning of a line or in the middle of a line, as shown above.

Tip:

Rules cannot consist of more than 16 lines of code; otherwise you will get an error. Now 16 lines of code in one rule may seem a huge amount right now, but some of the rules in more complex AI’s will have at least 12 lines in each of them!

Also, you can have a maximum of 999 rules in an AI, a number you will not likely reach at this point, but it’s a good thing to know.

Your first AI script

Now the ability for an AI to chat is great, but your AI needs to be able to do more than just chat. These next rules will guide your AI through the Dark Age, the first step to making a great AI. Add these rules to the AI you made in Section 2.

Before this, I want you to think of your own playing style. Your first AI should try to implement your style of play. How many villagers do you make in the Dark Age? Do you rush in the Feudal Age or boom to the Castle Age? What armies do you use? These are some example questions to think about when writing your AI. The rules I will give you will only form the base of your AI. Once you become comfortable with AI scripting feel free to make any changes to your AI or add new rules to it. My playing style will be different from yours, so my AI will not be the same as yours.

First Rule: Building Houses

However, I believe you and I will both agree that the first thing you do is build a house, unless you’re Huns. You could use this rule below to build a house:

(defrule
(can-build house)
=>
(build house)
)

However, this rule would be inefficient because the AI would build a house whenever it could, causing the AI to have an excess of houses and wasting labor and resources. Often in rules you will add more criteria (facts) to make your AI more efficient. Here is a better rule to use: (add this rule to your AI)

(defrule
(can-build house)
(housing-headroom < 4)
   ;the difference between the current population and supportable population (not the
                          ;amount of population houses support)
(population-headroom > 3) ;the difference between the current population and the population limit
=>
(build house)
)

Housing-headroom and population-headroom make the AI more efficient. Checking to see if the housing headroom is less than 4 will make sure that the AI is running out of population room before it builds a house. Checking the population headroom will make sure that the AI won’t keep building houses when the AI is very close to the population limit. You don’t want your AI ending up with 100 houses because you forgot to check the population headroom!

Next Rule: Training Villagers

The next thing you want your AI to do is train villagers. You always want to train villagers constantly in the Dark Age. Here is a good rule to train villagers:

(defrule
(current-age == dark-age)
(unit-type-count-total villager < 30)
(can-train villager)
=>
(train villager)
)

You can change the number of villagers you want to make to any number. However, the best number of Dark Age villagers for AI’s is usually between 25 and 32, depending on its feudal age strategy.

Building the Mill

After you train your villagers, the next step is to build your mill. In AI, there is a nifty fact called “resource-found”, which will detect whether a specified resource is found. This fact is especially useful when building drop-off buildings. Here is a good rule to build mills.

By the way, this rule will not work if the AI is Huns. Why? This is because it tries to make sure a house is built before it builds its mill. Obviously, Huns will never have a house, therefore this rule will not run. As you get more experienced in scripting, you have to think about things like this.

(defrule
(building-type-count-total house > 0) ; We want to build a house before a mill
(building-type-count-total mill == 0) ; Prevents the construction of multiple mills
(resource-found food) ; Builds a mill only if forage bushes or deer is found
(can-build mill)
=>
(build mill)
)

Building the Lumber Camp

The rule for building lumber camps is similar to those for building mills. We use the resource-found rule again, this time for wood. Usually we want our lumber camp built after the mill, so we add a fact to make sure a mill is built first.

(defrule
(building-type-count-total mill > 0)
(building-type-count-total lumber-camp == 0)
(resource-found wood)
(can-build lumber-camp)
=>
(build lumber-camp)
)

Building Farms

Farms are a very important building for AI’s. AI’s cannot hunt boar and they have difficulties hunting deer, so an AI will want to make farms sooner. It will want to have enough farms so that almost all their foragers will be able to transfer to farms when the forage bushes are exhausted. One handy fact for building farms is the “idle-farm-count” fact, which checks how many farms are idle (pretty much self-explanatory). It’s useful to make sure the AI doesn’t build too many farms that don’t have any farmers on them.

(defrule
(current-age == dark-age)
(building-type-count-total lumber-camp > 0) ; We want a lumber camp before farms
(unit-type-count-total villager > 15)
(building-type-count-total farm < 15)
(idle-farm-count < 4) ; Only build farms if there are less than 4 idle farms
=>
(build farm)
)

Advancing to the Feudal Age!

Our first AI is ready to advance to the Feudal Age! We want the AI to advance when it is done training villagers, and we want to make sure it has the buildings it needs.

(defrule
(current-age == dark-age)
(building-type-count-total mill > 0)
(building-type-count-total lumber-camp > 0)
(unit-type-count-total villager >= 30) ; If you changed the number of villagers it trains, modify this number
(can-research feudal-age)
=>
(research feudal-age)
(chat-local-to-self "Feudal Age, here we come!")
)

Strategic Numbers

However, before we test the AI, there is something we have to add to the AI: strategic numbers (sometimes abbreviated SN’s). I’ll explain strategic numbers in more detail later, but for now it will suffice to say that strategic numbers affect the behavior of the AI. For example, without these strategic numbers, some villagers will explore instead of gathering resources or constructing buildings. I’ll explain them briefly for now.

(defrule
(true)
=>
(set-strategic-number sn-percent-civilian-gatherers 50)
(set-strategic-number sn-percent-civilian-explorers 0)
(set-strategic-number sn-percent-civilian-builders 50)
)

These strategic numbers specify what percentage of your villagers are gatherers, explorers, or builders. So, ideally, 50 percent of our villagers will gather resources and 50 percent of our villagers will build buildings. Usually, we don’t want villagers to explore because they wouldn’t be gathering resources. There are times when we want villagers to explore – for example, if the AI can’t find its forage bushes – but we’ll take care of that later.

One thing to note is that while 50 percent of our villagers are specified as builders, there won’t always be half of the villagers constructing buildings. If there aren’t any buildings to be built, the AI is smart enough to tell those builders to gather resources.

However, when the time comes to construct many buildings we want to have a large number of builders, because AI’s are slow at constructing buildings. AI’s only use one villager per building, and they will only build one of each type of building at a time. For example, the AI will only build one farm at a time instead of three, though it can send another villager to build a mining camp while the farm is being built.

Here’s some more useful strategic numbers:

(defrule
(true)
=>
(set-strategic-number sn-minimum-civilian-explorers 0)
(set-strategic-number sn-cap-civilian-explorers 0)
(set-strategic-number sn-total-number-explorers 1)
(set-strategic-number sn-number-explore-groups 1)
(set-strategic-number sn-initial-exploration-required 0)
(disable-self)
)

These strategic numbers tell the AI how to explore. The first strategic number (SN) tells the AI the smallest amount of civilians (villagers, trade carts, etc.) the AI can use for exploring. Right now we want 0 villagers exploring. The second SN gives the cap or the maximum of civilian explorers the AI can use. We’ll set this to 0. The third SN gives the total number of explorers (both civilians and military units) the AI can use We only want one unit – the scout cavalry or eagle warrior – to explore, so we’ll set this to 1.

The third SN gives the number of groups for explorers. This needs to be set to the total number of explorers. Originally, I believe Ensemble Studios intended the AI to be able to have two or more soldiers to be able to explore in a group, but they must have scrapped the idea for practical reasons. So now, AI’s will only use one soldier per exploring group, so matter what value you give this SN.

The last SN tells the percentage of the map that the AI has to explore before it builds buildings. We can set this to zero to allow it to build buildings immediately.

;(Last Rule!!!)

(defrule
(current-age == dark-age)
=>
(set-strategic-number sn-food-gatherer-percentage 60)
(set-strategic-number sn-wood-gatherer-percentage 40)
(set-strategic-number sn-gold-gatherer-percentage 0)
(set-strategic-number sn-stone-gatherer-percentage 0)
)

These strategic numbers set how many villagers are assigned to each resource. So, 60 percent of villagers will gather food and 40 percent will gather wood. We don’t want the AI to gather gold or stone until later. These percentages will usually get an AI through the Dark Age pretty well, but most AI’s will tweak them throughout the Dark Age. I’ll show you how to do this in my next guide.

Dark Age is finished!

Congratulations! You just made your first AI gather resources, construct buildings, and advance to the Feudal Age. You’re well on your way to becoming an AI scripter. In later sections, we will modify this code to make it faster or more efficient.

I encourage you to experiment with different numbers and test out your AI. Add some new rules, change some numbers, add more facts to the rules, and just have fun and experiment. This is a great way to learn how to make your AI more efficient and also it gives your AI more of a personality. If you have time, you can read the CPSB and learn more facts and actions that you can use.

When editing your AI, there is a shortcut so you don’t have to close out of the game to edit your AI. You can press alt-tab or the start menu key to minimize the game, then make changes to your AI, then maximize the game, and restart the random map game you were previously testing your AI on. This is much faster and easier than opening and exiting the game every time!

Extra Challenge

Try creating code to make the AI to build a barracks. Hint: remember the “can-build” fact and the “build” action. Also, to make it more efficient, add facts to check if it has built a lumber camp before it builds the barracks.

Note

In AI scripting, symbols such as > (greater-than), = (greater-or-equal), <= (less-or-equal), or != (not-equal). This will be important when I teach you syntax of facts and actions. However, make sure you use two equals signs (==) when you want to say "equal". Using one equals sign (=) will give you an error)!

Tip

The AI runs the code from top to bottom. So, the first rule it looks at in our AI is the rule that chats “I just made my first rule.” Sometimes, if a rule is deeply buried in an AI, the AI won’t be able get down that far and the rule might not run, or it might run after a delay. In the future, the rules that are the most important should go at the top of your AI. So, try moving the advance to Feudal Age rule to the top of your AI, so that this rule will run quicker.

Do you want to comment on this article? Thank the author? Tribute resources for its improvement? Raze it to the ground?

Come by and visit its thread in the University Forum!