Scripting overview

From Dragon Age Toolset Wiki

Jump to: navigation, search
Scripting

Scripting is used whenever the designers need control over the game's behaviour. The syntax for DA scripts is very similar to the C programming language.

Detailed documentation for the scripting language can be found in the "dascript.chm" file, available in your "Dragon Age\packages\core" directory.

The main uses for it are to:

DA also has a client-side scripting language whose primary responsibility is automated testing of the game. See client scripts for more details.

AI Scripts are event based. Objects will have only one event-handling script assigned to them that will be run whenever they receive a game event. This script will receive the event type as a parameter and will need to determine the appropriate response for itself.

There are several file extensions associated with scripts:

Contents

Script editor

Scripts are created in the Designer Toolset using the Script Editor. Once created, scripts must be assigned to such things as Creatures before they can be used. Once assigned, both the referencing object and the script must be exported in order to be viewed in the game. Exporting happens automatically or can be done manually by the designer during testing.

The script editor supports the following features:

To the right of the script editor is a sidebar with a browser that can display all currently-defined functions, variables, or constants, or a set of 'template' scripts that can serve as a starting point when writing a script from scratch. The browser also has a filter field where you can type in a partial string and have the list automatically exclude everything that doesn't include it in the name.

This is the constant browser:

Scripting constant browser.png

Here it is with "team" typed into the filter field, displaying only constants with names that contain the substring "team" (not case sensitive):

Scripting constant browser filtered.png

The templates that come with Dragon Age include frameworks for the most common event scripts found in the game. You can add your own templates quite easily, just create a text file with the template code in it and place it in the Dragon Age\Toolset\scripttemplates directory with the others.

Scripting template browser.png

Dragon Age's toolset supports Doxygen-style comments. If you double-click on a function name a help window will pop open to display its documentation. You can also jump to a function's definition (provided it isn't an engine-defined function in script.ldf) by right-clicking on it and selecting "go to definition".

Scripting help window.png

Writing scripts

For a script to compile, it needs a body:

void main()
{
}

The parameters on this can't be changed or the script won't compile.

Scripts associated with a dialog node take this alternate form:

int StartingConditional()
{
    return 1;
}

Including files

Other script files can be included by using the #include directive.

#include "rules_h"
 
void main()
{
    DoSomethingOrOther();
}

The included file is inserted into the main file before the script is compiled. Any number of files can be included. Important: this means that whenever you change an "include file" you must export all script that include it before they will use the new version!

Operators

The scripting language supports the following operators:

Arithmetic Operators

Operator Name Example
Prefix Increment
while ( ++a < 10) { }
Postfix Increment
 for (i = 0; i < 10; i++) { } 
Assignment by addition
a += b;
Subtraction (difference)
x = a - b;
Addition (sum)
x = a + b;
Prefix decrement
while (--a > 10) { }
Postfix decrement
while (a-- > 10) { }
Assignment by subtraction
a -= b;
Multiplication (product)
x = a * b;
Division (quotient)
x = a / b;
Modulo (remainder)
if (a % b == 1) { }

Comparison Operators

Operator Name Example
Less than
if (a < b) { }
Less than or equal to
if (a <= b) { }
Greater than
if (a > b) { }
Greater than or equal to
if (a >= b) { }
Not Equal to
if (a != b) { }
Equal to
if (a == b) { }

Logical Operators

Operator Name Example
Logical negation (NOT)
if (!a) { }
Logical AND
if (a && b) { }
Logical OR
if (a || b) { }

Other Operators

Operator Name Example
Basic assignment
a = b;
Function call
a();
Array subscript
array[0] = 1;
Member (on structures)
structure.member = 0;
Ternary conditional
return a < b ? c : d;

Types & Variable

The scripting language natively supports:

The server language has been expanded to support these engine defined structures:

All of these types are always passed by value, which means a new copy is made whenever they are passed into a function or copied to another variable.

This means that most functions that are supposed to modify a structure in some way need to return the modified one:

void main()
{
    effect e1 = Effect(100);
    effect e2 = SetEffectType(e1, 101); // e1 != e2
}

Structures

Users can define their own structures using the struct keyword:

// user-defined type
struct quaternion
{
    float w, x, y, z;
};
 
// constructor
struct quaternion Quaternion(float fW, float fX, float fY, float fZ)
{
    struct quaternion q;
 
    q.w = fW;
    q.x = fX;
    q.y = fY;
    q.z = fZ;
 
    return q;
}
 
void main()
{
    struct quaternion q = Quaternion(0.0, 0.0, 0.0, 0.0);
}

Arrays

Variables can be declared as arrays for any type except user-defined structs. Designers can create their own arrays of any major data type (int, string, object). Many functions will also return arrays (for example, creatures in an area will be returned as an array, and the action queue will be returned as an array).

These are different from C-style arrays in that they can be resized like STL vectors, and their notation is slightly different.

Arrays also behave differently from other objects in the scripting language because they are passed by reference. If an array is passed into a function and modified:

void main()
{
    int[] i;                 // new array of integers with a size of zero 
    i[0] = 5;                // value of array position 0 is now 5
    i[1] = -1;               // value of array position 1 is now -1
 
    int[] j = i;             // i and j point to the same array
    j[1] = 12;               // value of array position 1 for both i and j is now 12!
 
    SortArrayDescending(i);  // i and j are both sorted now, this function has no return value
}

GetArraySize returns the size of an array.

Local Variables

In Neverwinter Nights, variables for various objects could be created and set with functions such as SetLocalInt(). Dragon Age does not have analogous functions. Instead, all of the variables that a given object is able to have values assigned to must be defined ahead of time in a 2DA. This more restrictive approach is intended to improve performance and reduce the opportunity for errors (for example, making a typo in the name of a variable and losing track of it as a result).

Functions

There are two ways to discover a function and what it does.

If you type in the name of a function that's been defined and then an opening bracket, a tooltip will pop up showing the function's parameter types and return type.

Alternately, if you have the help window open (View -> Other Windows -> Help Window), then whenever you select a function in the function browser a help page describing the function will be displayed.

Passing parameters to scripts

To pass parameters to scripts they must be called with the 'runscript' command. This can be useful for writing debug scripts or changing actions based on input. To accept parameters simply add this line to your script:

string sParams = GetLocalString(GetModule(),"RUNSCRIPT_VAR");

You can then type 'runscript scriptname parameter1 parameter2 ... paramaterN' to pass parameters.

Some examples:

// Debug script: heals the object with the given tag. If tag is invalid, nothing happens
void main()
{
 
    string sTag = GetLocalString(GetModule(),"RUNSCRIPT_VAR");    
    object oCreature = GetObjectByTag(sTag);
    effect   eHeal = EffectHeal(25.0f)
    //ApplyEffect...
}
// Debug script: applies the visual effect passed in as parameter to the player
void main()
{
 
    string sEffect = GetLocalString(GetModule(),"RUNSCRIPT_VAR");    
    int    nEffect = StringToInt(sEffect);
    effect eVfx = EffectVisualEffect(nEffect);
    //ApplyEffect...
}

Error messages and logging

See Script error for details of how to correct errors in scripts.

To enable script logging, edit or create <DragonAgeInstallDirectory>\bin_ship\ECLog.ini and set Script=1 in the [LogTypes] section.

The PrintToLog function prints messages to the log file once logging is enabled.

Timing

Commands, delayed events and object destruction all take place after the current script is finished running. Plot flags set in script are set in-line but the triggered plot script runs before the flag is actually set (this is clarified a bit in the plot script template).

Given that ExecuteScript is deprecated, HandleEvent should be used when you want the script to run in-line and DelayEvent should be used when you want to delay execution.

To delay execution when dealing with creatures, custom AI and (safe) command complete are nice tools. DelayEvent should be used whenever you know how long you want to wait before the event fires. (It can also be used in quite small time increments to give the illusion of smoothly sliding placeables with SetPosition or interpolate between two different atmosphere/lighting settings, but the overhead of this is noticeable if overused).

Searching Scripts

To find examples of how Bioware does things, or simply to discover where a function or variable is used, it's useful to be able to search all the scripts in the data base for a string.

You'll need Microsoft SQL Server Management Studio Express - see Preparing a dialog for recording .

Enter the following query:

  SELECT DISTINCT Module.Name, Resource.Name 
    FROM   [bw_dragonage_content].[dbo].[t_Module] Module, 
           [bw_dragonage_content].[dbo].[t_ModuleResRefVersion] Resource, 
           [bw_dragonage_content].[dbo].[t_Script] Script 
    WHERE  Module.ID   = Resource.ModuleID
    AND    Resource.ID = Script.ModuleResRefVersionID
    AND    Script.Text LIKE '%######%'
    ORDER BY 1, 2; 

where ###### is the string you want to find.

This will list the name of every script that contains the string ######.

Language: English  • Русский
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox