Difference between revisions of "Golem Agent Language"

From Oldunreal-Wiki
Jump to navigation Jump to search
Line 108: Line 108:
  }
  }


The ''action'' sections are similar to the concept of functions in other languages, but, as with inputs, they are also slightly different. In these sections you can set what scripts are to be executed at what time, depending on the conditions defined.
The ''action'' sections are similar to the concept of functions in other languages, but, as with inputs, they are also slightly different. In these sections you can set what scripts are to be executed at what time, depending on the conditions defined. In Golem Studio, you can call individual actions by double-clicking on them in the [[Golem Studio#Actions tab|''Actions'' sub-tab]] of the ''Agent'' tab.


The amount of actions defined depend on the creator of the script, as they are optional. Except for one, called ''Default'' – it is the equivalent of a ''main'' function in C-like languages. That is the action that gets executed on every tick that the entity spends in Agent mode. All other actions are either called from this Default action, or called manually from the game or Golem Studio.
The amount of actions defined depend on the creator of the script, as they are optional. Except for one, called ''Default'' – it is the equivalent of a ''main'' function in C-like languages. That is the action that gets executed on every tick that the entity spends in Agent mode. All other actions are either called from this Default action, or called manually from the game or Golem Studio.
Much like you can (and often should) have utility functions to help keep code clean in other programming languages, you can have "utility actions" in GAL. However, make sure to name them appropriately, because all of the defined actions appear in Golem Studio as-is – you can't set an action to be local, and you don't want users trying to play utility actions by themselves, after all.


Actions contain a set of statements. They are similar to statements in C, as in they are delimited by either a semicolon or between curly braces. The possible statements are explained below.
Actions contain a set of statements. They are similar to statements in C, as in they are delimited by either a semicolon or between curly braces. The possible statements are explained below.
Line 116: Line 118:
=== Channel statements ===
=== Channel statements ===


  '''set'''/'''force''' (<span style="color:darkgreen">optional integer</span>) ''channelname'' ''statement'';
  '''set'''/'''force''' (<span style="color:darkgreen">optional int ''bindinglevel''</span>) ''channelname'' ''statement'';
  '''set'''/'''force''' (<span style="color:darkgreen">optional integer</span>) ''channelname'' { ''statement''; ''statement''; ... }
  '''set'''/'''force''' (<span style="color:darkgreen">optional int ''bindinglevel''</span>) ''channelname'' { ''statement''; ''statement''; ... }
 
The ''set'' and ''force'' statements are one of the main statements used within action sections. They define which channel to apply changes to. You need to have most of the other code within one of these statements in order for them to be functional (otherwise it wouldn't be clear which channel you want the animations to be played or affected). These statements also have an optional integer parameter that defines a binding level. It can be zero or greater, and has to be enclosed in parentheses.
 
Code within these channel statements is not always executed, however. This is where binding levels come into play. A channel can either be bound (executing a script) or unbound (empty). If a channel is bound, then it also has a time for which it will remain bound (typically equal to the script length), and a binding level. If the binding time is zero, it will become unbound on the next tick.
 
When a channel is bound, generally any code within channel statements will not be executed (there is already an animation playing, after all, and you might not want to interrupt it). But GAL does allow interrupting them, if need arises. The ''set'' statement will override bound channels with a binding level lower than its own. The ''force'' command will also override bound channels with a binding level equal to its own (as well as lower ones). Therefore if there are two ''set'' statements with the same binding level one after another, the second one will be ignored; if there are two ''force'' statements with the same binding level one after another, the first one will be ignored.
 
Normally manually setting binding levels should not be necessary. Most animations would use a simple ''set'' command. If there is a more important animation that should discontinue one that is already playing, it should use the ''force'' command. And if there is something even more important that should never be overridden, then binding levels could be used.
 
Example:
 
'''set''' ''AimHead'' '''script''' <span style="color:darkorange">"P_HeadTrack"</span>; <span style="color:darkred">//Plays "P_HeadTrack" on the "AimHead" channel</span>
'''force''' (<span style="color:darkgreen">1</span>) ''AnimAll'' <span style="color:darkred">//Interrupts all current animations in channels "AnimAll" and "AnimUpper" and plays "HatchSequence" in "AnimAll"</span>
{
    '''script''' <span style="color:darkorange">"HatchSequence"</span>;
    '''force''' ''AnimUpper'' {}
}
 
=== Command statements ===


[[Category: Unreal II]] [[Category: Golem]] [[Category:Mods]] [[Category:Scripting]]
[[Category: Unreal II]] [[Category: Golem]] [[Category:Mods]] [[Category:Scripting]]

Revision as of 16:04, 14 July 2012

The Golem Agent Language (GAL) is a fairly simple text-based scripting language that is used by the Agent objects in Golem Studio of Unreal II. It is required in order to create functional Golem Entity Script Agent objects.

Overview

Agent overview

An Entity Script Agent is an object that acts as an intermediary between an entity and its Entity Scripts objects. Note that GAL scripts should not be confused with Entity Scripts (the former controls Entity Script Agent object logic, the latter define a static set of animations). The name "Agent" stems from the fact that Entity Script Agents are a higher level of abstraction than Entity Scripts, and entities normally access scripts through agents, and not directly.

While agents are entirely optional for having a working entity, agents make animating entities a lot easier. They dynamically combine different static scripts to a whole dynamic set of animations. Using Golem Studio you can easily see the difference between using entity scripts directly and using agents by enabling and disabling Agent mode in the Render window.

Agents vs Entity Scripts

There are numerous advantages of using agents as opposed to entity scripts, and especially pure animations, directly. As a comparison, games like Unreal Tournament 2004 use pure animations for all the animation needs. Compared to that system, Entity Scripts are a low more powerful, as they not only play preset animations, but also allow you to combine these pure animations with dynamically generated animations, such as surface walkers, vertex explosion effects, lipsync curves, etc. (see Abilities for a complete list), and combine several of these static or generated animations into one, with specifically set timings and external events, if needed. That alone makes the system a lot more powerful than pure animation-based solutions. However, entity scripts are still inherently static - when replayed, they will look the same every time.

Agents, on the other hand, add even more power to the system by allowing to control several different scripts at the same time with added randomness, conditions, etc. With both pure animation and Entity script systems, making an entity that can walk to all eight sides would require you to create 8 different animations/scripts. If you want to have four weapon carrying poses? You have to make 32 animations/scripts. And making the entity blink naturally during those animations would be outright impossible. Agents, however, allow you to do all of this with relative ease. Plus, agents allow for defining random events - such as playing one of the different idle animations. In pure animation solutions, that functionality was put on the shoulders of UnrealScript coders, while with Agents it can be defined by animators themselves. And that's not all - agents also allow fine control over how different scripts interact with each other under different circumstances, such as blending two animations with each other if the first animation has played over 50% of its animation.

Overall agents allow for a much easier and more precise control over how an entity should animate, without even having to interact with the game logic itself. That in itself allows for more productive separation of work - coders are no longer required to bother with all this animation business, while animators get all the control they need.

Language complexity

While the notion of needing to learn a programming language just to animate an entity can seem daunting, it is not that difficult in terms of GAL scripting. GAL is centred around a single task, instead of being multi-purpose, therefore the overall complexity is reduced. And it sure is a lot less difficult than other artist-centred languages, like 3DS MAX's MAXScript or Blender's Python. As a matter of fact, looking over an example GAL script even without knowing the specifics should make it clear how the language works.

Text vs graphical interfaces

While Golem Studio was generally created as an abstraction that allows for a more intuitive way of handling animations than working with code directly (once again, like it is the case with games that depend on pure animations), it may come as a surprise why GAL was not made into a visual tool and instead kept in text form. As a matter of fact, it was attempted to make it visual, but it was deemed too impractical and subsequently the idea was dropped. The GAL language itself was created specifically for this task. The possible complexity of input with GAL scripts is unlimited, while with a graphical tool the system would get cluttered and confusing very fast, unless it was artificially limited. In the end, this question boils down to the text versus graphical programming debate, and for this purpose a text-based approach proved to work better.

Import process

Importing GAL script files to Entity Script Agent objects is done via the context menu in Golem Studio. See the corresponding page for more information about that.

During the import process, Golem Studio checks whether the GAL script in question are syntactically and semantically valid. You cannot import invalid files. In case of an error, it will be printed in the log window.

Note that these checks do not guard against logical errors, so you should thoroughly check your scripts for any mistakes. The test section can be used to ease this process. The Immediate action box in Golem Studio also allows for quick debugging of small script parts. Testing more inside Golem Studio allows for less time needed for the reimporting routine.

File structure

GAL script files are divided into several different sections - channels, inputs, one or more action, optional transition and optional test. A section is a logical block for doing a specific task.

GAL uses keywords, symbols, identifiers, numbers and "strings". Identifiers (user-defined names) are case-insensitive, but must start with either a letter or an underscore, and the rest of the identifier should be comprised of digits, letters and underscores only.

Whitespace is ignored. The symbols // are used for writing comments - anything on the line after them will be ignored. /* and */ are used to indicate block comments – everything in between them will be ignored.

Numbers can be in different forms - integer numbers (0, 1, 2), floating-point numbers (0.1, 1.6, 2.85) or boolean values (0 or 1). If a float is expected, an integer is accepted as well (it's typecast automatically). If a boolean is expected, only 0 (for false) and 1 (for true) are accepted.

Channels section

channels
{
    channelname;
    channelname;
    ...
}

The first section is called channels. This section identifies the names and the order of the entity script processes used by the agent. Each agent must have at least one defined, and the order is important. Usually channels are used to isolate animations that don't interfere with other animations (so that the entity could blink while walking, for instance). Once defined, the channels can be seen in Golem Studio under the Processes tab, albeit with numbers instead of names.

After defining them, these channel names can then be used in set and force blocks (see below).

Example:

channels
{
    AnimAll;
    AnimUpper;
    AnimLeft;
    AnimRight;
    AnimBlink;
    AnimBrow;
    AnimCheeks;
    AimHead;
    AnimHead;
}

Inputs section

inputs
{
    inputname = inputvalue, inputvalue, ...;
    .localinputname = inputvalue, inputvalue, ...;
    inputname = inputvalue "stringalias", inputvalue "stringalias",  ...;
    .localinputname = inputvalue "stringalias", inputvalue "stringalias",  ...;
    ...
}

The inputs section is in essence the "variables" block of GAL scripts. You can define any number of inputs here. Inputs are in essence arrays of identifiers. Any inputs defined here will be shown in the Inputs subtab in the Agent tab in Golem Studio. Each input must have one name, and can have an unlimited amount of values. The order of the values matters in that the order will be presented as-is in Golem Studio, and the first value will be set by default.

Each value can have an optional string alias. They are defined just after the value (and enclosed in quotes, as it is a string and not an identifier). It is used by str blocks; see below.

As mentioned, inputs act very similarly to variables. Just like variables, they can be global or local. In case of GAL, there is an important distinction – global inputs can be written to only by the user in Golem Studio or the game logic, but not by anything within GAL scripts themselves (except for the test block, see below). Local inputs are the opposite, they cannot be written by the game logic, but can be written by assigning them within GAL scripts. As for reading them, both local and global inputs can be read anywhere at any time.

To define an input as local, you need to prefix its name with a period character (.). If there is no period character before an input name, it is automatically defined as a global input. Note that the period character is not part of the input name, you don't need to enter it if you are checking the value of local inputs.

Example:

inputs
{
    Speed = Walk, Run;                                             //Global (external) input, "Walk" is default
    Mood = Good, Bad, Ugly;                                        //Global (external) input
    .Flavor = Chocolate "Choc", Vanilla "Vanl", Strawberry "Swbr"; //Local (internal) input with string aliases
    .Stooge = Larry, Curly, Moe, Shemp;                            //Local (internal) input, access it by name "Stooge" and not ".Stooge"
}

Action sections

action actionname
{
    statement
    statement
    ...
}

The action sections are similar to the concept of functions in other languages, but, as with inputs, they are also slightly different. In these sections you can set what scripts are to be executed at what time, depending on the conditions defined. In Golem Studio, you can call individual actions by double-clicking on them in the Actions sub-tab of the Agent tab.

The amount of actions defined depend on the creator of the script, as they are optional. Except for one, called Default – it is the equivalent of a main function in C-like languages. That is the action that gets executed on every tick that the entity spends in Agent mode. All other actions are either called from this Default action, or called manually from the game or Golem Studio.

Much like you can (and often should) have utility functions to help keep code clean in other programming languages, you can have "utility actions" in GAL. However, make sure to name them appropriately, because all of the defined actions appear in Golem Studio as-is – you can't set an action to be local, and you don't want users trying to play utility actions by themselves, after all.

Actions contain a set of statements. They are similar to statements in C, as in they are delimited by either a semicolon or between curly braces. The possible statements are explained below.

Channel statements

set/force (optional int bindinglevel) channelname statement;
set/force (optional int bindinglevel) channelname { statement; statement; ... }

The set and force statements are one of the main statements used within action sections. They define which channel to apply changes to. You need to have most of the other code within one of these statements in order for them to be functional (otherwise it wouldn't be clear which channel you want the animations to be played or affected). These statements also have an optional integer parameter that defines a binding level. It can be zero or greater, and has to be enclosed in parentheses.

Code within these channel statements is not always executed, however. This is where binding levels come into play. A channel can either be bound (executing a script) or unbound (empty). If a channel is bound, then it also has a time for which it will remain bound (typically equal to the script length), and a binding level. If the binding time is zero, it will become unbound on the next tick.

When a channel is bound, generally any code within channel statements will not be executed (there is already an animation playing, after all, and you might not want to interrupt it). But GAL does allow interrupting them, if need arises. The set statement will override bound channels with a binding level lower than its own. The force command will also override bound channels with a binding level equal to its own (as well as lower ones). Therefore if there are two set statements with the same binding level one after another, the second one will be ignored; if there are two force statements with the same binding level one after another, the first one will be ignored.

Normally manually setting binding levels should not be necessary. Most animations would use a simple set command. If there is a more important animation that should discontinue one that is already playing, it should use the force command. And if there is something even more important that should never be overridden, then binding levels could be used.

Example:

set AimHead script "P_HeadTrack"; //Plays "P_HeadTrack" on the "AimHead" channel

force (1) AnimAll //Interrupts all current animations in channels "AnimAll" and "AnimUpper" and plays "HatchSequence" in "AnimAll"
{
    script "HatchSequence";
    force AnimUpper {}
}

Command statements