Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




Battle AI documentation

software


Battle AI

Battle AI

Overview



Scripting Language

Basic Syntax

Subject Composition

General Subjects

Specific Subjects

Conditions

Conditional Functions

Comparisons

Multiple Conditions (C 16216c218q lauses)

Using <OR> with Conditions

Actions

Functions

Random Actions

APE Gamevars

Nested Blocks

Special Behavior of Nested Default Blocks

Overview

The Battle AI system uses text scripts to define behavior for monsters in battle. The scripting language is very specific and just powerful enough to do what it needs to do. There are some seemingly reasonable things which can't be done with it, but these things are by no means necessary in creating capable and challenging monster brains. However, in general the language is easily expandable from within the Anachronox source.

Any given monster that exists in the Game Data Base should have a key that specifies which script is used for it:

.

level int 5

xp int 60

aiscript file "battle/ai/scriptname.txt"

.

When battle starts, the game will load the script file for each monster, examine them and report any errors found. When the monster's timer is up, the game will stop time and execute the script. The script then decides what the best action(s) is(are) and makes it(them) happen. When the monster is done doing everything it decided to do, it's turn is over and battle time resumes.

Scripting Language

In an abstract sense, the script files are simply a series of condition-action blocks. (A block is everything between a left bracket and a right bracket; there will be more info on syntax later). Each block begins with one or more conditions to be met, and one or more actions to be performed if all the conditions are true. The game will proceed through the script one block at a time until a true condition is found. Then it will execute all the actions in that block and quit.

Basic Syntax

First, here is an example of a very simple script:

# Test script, just basic

default

Or, in a conceptualized version:

# comment

condition

First of all, everything on a line that comes after a pound sign (#) is a comment and will be ignored by the game. You can use them anywhere you want, but everything after it on that line is a comment.

In the example above, "default" is the only condition. Default is a special conditional which is always true. It's used to tell the AI what the default behavior is in case none of the other conditions are true. In this case, we use default because we want the monster to do the same thing every time.

Notice the brackets. Every condition must be followed by a block of actions, which must exist entirely between an open and a close bracket. To be totally clear: only comments and conditions can be outside the brackets. Only actions can be inside the brackets (with one exception, which we will talk about in a later section). Also, each individual action must be in parentheses.

"Attack nelohp" will make the monster try to attack, in any way possible, it's nearest enemy with the lowest hitpoints. What's that mean?

"In any way possible" means that it will think about each attack it's capable of, starting with the most powerful, until it finds of one that would work. Also, if any of the attack functions can't find an attack to use, it automatically makes the monster move toward the target and/or toward a position where an attack might be possible.

"It's nearest enemy with the lowest hitpoints" is specified by "nelohp." First of all, distances are measured in terms of how many turns it would take to walk there. There will be more information about understanding nelohp in the next section, but for now just understand that "nearest" is more important than "lowest hitpoints." In other words, if the nearest enemy is three steps away then no enemies more than three steps away will be considered.

Subject Composition

The most complex part of writing these scripts is referring to specific entities in battle. After you get the hang of it though, it's very intuitive and fairly easy.

General Subjects

A subject is a short string of characters that refers to a single entity in battle. It may refer to the exact entity, or it may specify a random individual from a group of entities. The basic structure of a subject looks like this:

distance + team [ + stat range + stat type ]

Stat range and stat type are in brackets because they are not required. However, if you specify one you must specify the other as well. Here's a breakdown of what each of those things mean, and what the valid values are:

Distance

N

Nearest

F

Farthest

A

Adjacent

*

Whatever

Team

E

Enemy

A

Ally

*

Whatever

Stat Range

LO

Lowest

HI

Highest

Stat Type

HP

Hitpoints

Special Subjects

SL

Self

All you have to do is put the letters together, and case doesn't matter. Here are some examples to help solidify it for you:

Nahihp

Nearest ally highest hitpoints

sl

Myself

*a

Any ally

n*hihp

The nearest whatever with the highest hitpoints

ae

Any adjacent enemy

Aelohp

Adjacent enemy with the lowest hitpoints

**

Some random lucky bastard

Specific Subjects

You can also specify specific nodes in battle by using a predetermined field created in the editor. For example, say there is a node in your battle that you want everyone to try to attack. You could say:

(attack &targetname=deathnode)

And in BED (the battle editor), you would have to give that node a key/value pair of "targetname=deathnode". Also, if you have an APE gamevar or gamestring that holds the value you want to search for, you can use it as well. However, if you use a numeric variable, you must prefix it with a percent sign ("&uid=%next_uid") or use a dollar sign prefix for a string variable ("&message=$node_message").

Just for completeness' sake, here is the general syntax for it:

&keyname=[%,$]value

Conditions

Conditions control the flow of your script. If there is a prime place for elusive errors and bugs to creep in, this is it. Conditions consist of operations, or functions, which are performed on a subject and result in an integer or boolean value. If the particular function in use results in an integer value, you must provide a comparison (more detail coming up). If the function is boolean, you don't need to compare it to anything. The "default" function, from the example script above, is a boolean function that always results in TRUE.

Conditional Functions

Here is the format for a conditional statement:

subject.function [ operator value[%] ]

or

gamevar:name [ operator value[%] ]

The subject is a string of characters as just specified in the last section. Next, there must be a dot/period. Then comes the function. Here is a list of the possible functions:

These five evaluate to an integer value.

Hp

Hitpoints

Naden

Number of adjacent enemies

Nadal

Number of adjacent allies

Nen

Total number of enemies

Nal

Total number of allies

And these are binary.

Isburn

Is subject burning?

Isnuts

. nuts?

Ispois

. poisoned?

Isfroz

. frozen?

Isslow

. slowed?

Ishast

. hasted?

Iswink

. winky?

Issnoo

. snoozing?

Ispsys

. a psy slave?

Isvuln

is subject vulnerable to attack from any enemy?

Isvis

is subject visible to any enemy?

Canburn

Am I capable of inflicting this status on subject?

Cannuts

Canpois

Canfroz

Canslow

Canhast

Canwink

Cansnoo

Canpsys

Canbeat

Iamon

Isoccupied

Canhurt

Am I capable of using hurt mystech on subject?

Canheal

Am I capable of using heal mystech on subject?

CanFixburn

Am I capable of fixing this status on subject?

CanFixnuts

CanFixpois

CanFixfroz

CanFixwink

CanFixsnoo

CanFixpsys

Comparisons

If you're using a boolean function, then that's it. However, if you're using one of the functions that result in a value, you will need to provide a comparison. For example:

sl.hp < 30%

(Note that the spaces on either side of the operator are currently required. This is a limitation that may or may not be fixed depending on time restraints and demand.) This tests if the current entity's hitpoints are less than 30% of it's maximum. If it's max hitpoints are 200 and it's current hitpoints are 50, this will be TRUE. If it's current hitpoints are 60, it will be false because 60 is 30% of 200, and thus is not less than 30%. If you wanted it to be true, you would need to use the "less than or equal to" operator (see below. that kind of thing shouldn't ever really be a problem or source of stress, but you should be aware of it anyway).

Here is yet another table, this particular one being the list of comarison operators you can use:

<

is less than

(

is less than or equal to

=

is equal to

)

is greater than or equal to

>

is greater than

!

is not equal to

Multiple Conditions (C 16216c218q lauses)

Now we finally get to the point where conditions become a bit more powerful. You can put up to sixteen separate conditions, each of which would be called a clause, on a single line. Just separate each one with a comma, like so:

sl.hp < 30%, sl.canheal

This says "if my hitpoints are less than 30 percent of my max, and I have the ability to heal myself." For the entire line, or statement, to be true, each individual clause must be true.

Using <OR> with Conditions

By default, each clause in a condition has an AND relationship with the other. That is, "A, B" is true only if A and B are both true. By putting

<OR>

as the first thing in a conditional, everything in that conditional will have an OR relationship. "<OR> A, B" is true if either A or B are true.

Actions

If the conditions are the brains of a script, the actions are the brawn. They just get it done. Each individual action must be in parentheses, and there can be only one action on a line. However, you can have up to sixteen individual actions inside a block. When you have multiple actions inside a block, they will be carried out in the order they appear in the block, and each one will not happen until the one before it completes. If you happen to need two separate actions to occur at exactly the same time, too bad. But that functionality could be added with a little effort if it becomes desirable so say something to the programmers if you find yourself needing it.

Functions

Here is the syntax for an action:

(function [parameter 1 [parameter 2] . [parameter N]])

Function is one of the following:

Beat (subject) (gdb item)

Hit target with beat attack, or move closer to target if beat is not possible

Range (subject) (gdb item)

Hit target with ranged attack, or move toward a spot where target is visible from

Attack (subject) (gdb item)

Attack target with anything, or move toward a spot where attack is possible

Invoke (sequence)

Invoke an APE sequence

Gamevar (var)(value)

Assigns a value to an APE gamevar

Sound (name)

Play a sound

Anim (name)

Play an animation

Goto (subject)

Teleport to a specific node

Spawn (GDB classname) (target node) (script name)

Used to call other objects into battle, e.g. Stone Sentinel boulders or Hive Queen drones.

Effect (subject) "effect string"

Used to add hit points, poison, fire, etc to the subject.

Setinvuln (true,false)

Become invulerable or not

Become (script name)

Switch to using a different AI script

Burn (subject)

Set subject on fire

Nuts (subject)

Make subject nuts

Pois (subject)

Poison subject

Froz (subject)

Freeze subject

Wink (subject)

Make subject winky

Snoo (subject)

Make subject snoozin

Psys (subject)

Make subject a psy slave

Slow (subject)

Slow subject

Hast (subject)

Haste subject

Hurt (subject)

Hurt subject

Heal (subject)

Heal subject

Fixburn (subject)

Put out fire on subject

Fixnuts (subject)

Make subject un-nuts

Fixpois (subject)

Un-poison subject

Fixfroz (subject)

Thaw subject

Fixwink (subject)

Unwinkify subject

Fixsnoo (subject)

Wake subject

Fixpsys (subject)

Make subject not a psy slave

Fixany (subject)

Undo any negative status modifiers if possible

Hide

Move to a place where the enemy cannot see

Pass

Skip this turn - do nothing

Moverandom

Just move to wherever

Random Actions

It's hard to create unpredictable behaviour without using some kind of random selection. If you want to have a monster select one action from a list of possible actions, prefix each action to be selected from with a number representing it's probability of being selected, followed by a colon. For example:

5: (attack nelohp)

1: (heal sl)

This will cause the monster to usually attack nelohp, but 1 out of 5 times (randomly, not precisely) it will heal itself.

APE Gamevars

In order to ease interaction between APE and the Battle AI scripts, you can check and set the value of gamevars directly from the AI script. To set it, use the gamevar action, just as any other action, followed by the gamevar name, then a space, then the value to assign to it. You can also add and subtract values for counters. Prefix the number with '+' to add the value, or '-' to subtract.

(gamevar variable [+,-]value)

Nested Blocks

Now we get to the part of writing scripts that takes a little thought. You can put blocks of conditions inside conditions to streamline and simplify your scripts. The only thing that is different inside a nested block is that when the end of a nested block is reached, the script continues at the first condition after the block (with the exception of default block, which is explained below).

To help explain how to use nested blocks, I'm going to use a real example of something you might want to do with a script. Let's say you want a monster to:

Attack, or move toward, it's nearest enemy with the lowest hitpoints

Occasionally attack it's nearest enemy with the highest hitpoints

When it's health gets less than 1/3 of it's max, it will try to get in a place where it can't be attacked

After it gets to a place where it can't be attacked, it will heal itself

You can do this like this:

sl.hp < 33%, sl.isvuln

sl.hp < 33%, sl.canheal

default

Or like this:

sl.hp < 33%

sl.canheal

}

default

In this example, the only advantage you get by nesting the blocks is that it's a bit more comprehendible. In order to read the conditionals like a book, you have to learn to read the comma as the word "and".

The first one is "If my health is low and I can be attacked, get to a place where I can't be attacked. Or if my health is low and I can heal myself, then heal myself."

The second one is "If my health is low, get to a place where I can't be attacked, then heal myself if I can."

But beyond comprehension, if you start writing large complex scripts you'll find that it will be much easier to separate common conditions into a nested block rather than typing the same clause over and over for each block. Also, if you wanted to change the above example to 50% instead of 33%, it's much easier to change at the top of a block than it is on every 5th line.

Special Behavior of Nested Default Blocks

As we learned in section 2.3, the default block will always execute when it's reached. This applies in nested blocks also. Check it out:

sl.naden > 1

sl.hp < 20

}

sl.nadal > 1, nalohp.hp < 50%

default

This says

If I have more than one enemy near me, attack it if my health over 100 or hide if my health is below 20

Or, if I have more than one ally near me and it's hitpoints are less than half, heal it.

Or, pass.

Now, let's say that sl.naden > 1 and sl.nadal > 1, nadal.hp < 50% are true, but that sl.hp is 50. Neither of the blocks under sl.naden > 1 will be true and the script will just go on to sl.nadal > 1, nadal.hp < 50%. But what if we don't want the script to do anything else if there are enemies around? We stick a default in there, and the script will stop at that point:

sl.naden > 1

sl.hp < 20

default

}

sl.nadal > 1, nadal.hp < 50%

default


Document Info


Accesari: 1506
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )