Logical Operator Commands

Logical operator commands are essential commands for AI scripting. If you're not a programmer (or even if you are), you might not know what the term "logical operator" means, but you've probably encountered the commands themselves in AI scripting before, as well as in many other contexts, such as spreadsheet formulas. AoE2 supports seven logical operator commands: and, nand, nor, not, or, xor, and xnor.

Introduction

Logical operator commands give you extra flexibility to control the conditions that must be true before the AI can move on to the actions section of the rule. They evaluate the two facts that follow the logical operator command (or the one following fact for the not command), and check if each fact is true or false. Each logical operator command has different conditions for the facts that must be true for the logical operator command itself will be considered true. For example, in the case of the or command, at least one of the facts within the and command must be true.

Syntax

If you are used to other programming languages, you'll notice that the syntax of logical operator commands in AoE2 is different than other programming languages. Instead of placing the command between the two facts like you would in spoken language or many programming languages, you place the command before the two facts, similar to how you'd use logical operator formulas in spreadsheet software, like Excel. For example, if you're using the or command, the two facts that the or command is evaluating must be enclosed inside of the or command, with the (or preceding the two facts, and a closing parenthesis ) after the second fact.

Unfortunately, the AoE2 scripting language does not allow you to compare more than two facts at a time. To get around this, you can nest logical operator commands, i.e. putting a logical operator command inside of another logical operator command. One or both of the commands within the command can be logical operator commands themselves. Any facts within a nested logical operator command don't count toward the two facts that are within the command. Instead, each entire nested logical operator command would count as a single fact. This is because the nested logical operator commands are evaluated first, becoming either true or false, and then the outer un-nested logical operator command is evaluated (see the example section below to illustrate this). Indenting facts after a logical operator command like the examples below can be a good way to visualize which facts are inside of which command, as well as which logical operator commands will be evaluated first.

Like other commands, logical operator commands count toward the 32 command limit per rule (in UP the limit is 16 commands per rule).

Logical Operator Command List

Here is a list of all seven logical operators and the conditions that must be met for each logical operator to be considered true:

Put another way, here's a logic truth table for 6 of the logical operator commands (not isn't included because it only checks one fact). For example, the and command is only true in the case where Fact A and Fact B are both true.

If Facts A and B are:Then each logical operator command will be:
Fact A ResultFact B Resultandnandornorxorxnor
falsefalsefalsetruefalsetruefalsetrue
truefalsefalsetruetruefalsetruefalse
falsetruefalsetruetruefalsetruefalse
truetruetruefalsetruefalsefalsetrue

Examples

Basic Example

If an enemy has a castle or there is a watch tower inside our town, train up to 3 battering rams.

(defrule
	(or
		(players-building-type-count any-enemy castle > 0)
		(up-building-type-in-town c: watch-tower > 0)
	)
	(unit-type-count-total battering-ram-line < 3)
	(can-train battering-ram-line)
=>
	(train battering-ram-line)
)

Nested Example

This example shows how nested logical operator commands work. In this rule, if the target player isn't Aztecs, Inca, or Maya, the AI will train up to 10 spearmen if it can.

(defrule
	(nor
		(players-civ target-player aztec)
		(or
			(players-civ target-player incan)
			(players-civ target-player mayan)
		)
	)
	(unit-type-count-total spearman-line <= 10)
	(can-train spearman-line)
=>
	(train spearman-line)
)

If the or command from the prior example is false (the target player isn't Inca or Maya), then this is what the code would look like internally after the or command was evaluated. Hopefully it illustrates how nested logical operator commands work. Now, as long as the target player isn't aztec and the AI has <= 10 spearmen, it will train them if it can.

(defrule
	(nor
		(players-civ target-player aztec)
		(false)
	)
	(unit-type-count-total spearman-line <= 10)
	(can-train spearman-line)
=>
	(train spearman-line)
)

Here's how the code would look next if the target player isn't Aztec.

(defrule
	(nor
		(false)
		(false)
	)
	(unit-type-count-total spearman-line <= 10)
	(can-train spearman-line)
=>
	(train spearman-line)
)

Lastly, here's how the code would look after the nor is evaluated.

(defrule
	(true)
	(unit-type-count-total spearman-line <= 10)
	(can-train spearman-line)
=>
	(train spearman-line)
)