Eternity Engine Small Usage Documentation v1.1 -- 06/09/05
Return to the Eternity Engine Page
Introduction
This documentation covers how the Small scripting system is implemented in the Eternity
Engine and how it can be used. This is not a general reference or tutorial for the Small
scripting language; see the other documentation on the Eternity Engine webpage for more
information.
Return to Table of Contents
VMs: Gamescript and Levelscript
The Eternity Engine contains two Small virtual machines, known as the Gamescript and
Levelscript. Both of these and the ways in which they can interact are explained in the
subsections below.
Return to Table of Contents
The Gamescript
The Gamescript is an optional set of global scripts which can be invoked at any time during
execution. These scripts are shared between levels, and as such, this VM can act as "glue" to
connect the scripts of individual maps. Levelscripts are not required for a Gamescript to
be loaded.
Return to Table of Contents
Adding a Gamescript
The Gamescript is a normally compiled Small AMX file inserted into the GAMESCR lump in any
wad. Only the last such GAMESCR lump will be loaded, and the functions and variables inside
it will become available. The Gamescript area is initialized at startup, and if it contains
an OnInit() function, that function will be executed once and only once when the
"A_InitGameScript" message appears in the console. The OnInit() function is optional, and
if it does not exist, no error will occur.
Return to Table of Contents
Invoking Gamescripts
Here are the various ways Gamescript public functions (aka scripts) may be invoked:
- Console Commands
The a_execv and a_execi console commands can run public Small functions which
take either no parameters, or any number of integer parameters respectively. By
passing the second parameter ("vm") as the number 0, you will indicate to look
for the named function in the Gamescript VM. If the named function does not exist
in the Gamescript, an error message will be printed. See the
Eternity Engine Console Reference for full
information.
- Cross-VM Execution
Using the Small function _ExecGS, it is
possible to execute Gamescript functions by name from any function in the Levelscript.
If the Gamescript is not loaded or _ExecGS is called from within the Gamescript itself,
the current script will be aborted and an error message will appear in the console.
- Registering Callbacks
Callbacks may be registered from OnInit or from any other Gamescript function which
may then repeatedly call Gamescript functions under the _INVOKE_CALLBACK invocation
model. See the _SetCallback function for
full information. Gamescript callbacks can run at any point during the game, so it
is important to monitor the current game mode if using functions which can only be
used during levels, etc. If a function is called at an inappropriate time, the
callback will be aborted with an "Invalid gamemode for native function" error.
- EDF/BEX Codepointers
The StartScript and PlayerStartScript codepointers may both execute Gamescripts by
number. Only public functions which are named in the fashion "Script#", where # is
any positive integer value, and accept 3 integer parameters can be invoked using these
codepointers. The numeric value used in the function name is passed to the codepointer as
an argument (via the EDF/BEX args frame values). Use the number 0 as the second parameter
to either of these codepointers to indicate the Gamescript as the target VM. If the
Gamescript is not loaded in this case, the codepointer will perform no action. See the
Eternity Engine Definitive Codepointer Reference for full
information.
Warning: If StartScript or PlayerStartScript are called from frames into which an
object is set by other scripts, or they call a script which may change the object's
state, any new script started will be executed recursively. This means that the second
script will be executing before the first has finished. Be sure to carefully account for
this in your scripting logic, and do not erroneously assume that any other script must
have finished executing before the one that is currently running, or that other scripts
will not execute before the current script has finished.
Return to Table of Contents
Using Gamescript Variables
Like any compiled Small program, the Gamescript may contain scalar global variables
declared as "public." These variables, aside from being normally accessable from any
function within the Gamescript, can also be accessed from outside by using the
_GetGameVar and
_SetGameVar functions. Using these functions
in your Levelscripts can allow maps to affect each other, by having one map set a variable
in the Gamescript, and then having another one check it. This is analogous to game and
hub variables in ACS and FraggleScript.
Return to Table of Contents
The Levelscript
The Levelscript is an optional set of map-local scripts which can be invoked only while the
map which owns those scripts is being played. A Gamescript is not required for Levelscripts
to be loaded. Levelscripts cannot access the scripts of other levels, but they can access
public functions and variables of the Gamescript, and the Gamescript can access public
functions and variables of the currently loaded Levelscript.
Return to Table of Contents
Adding a Levelscript
The Levelscript is a normally compiled Small AMX file inserted into any lump. The lump must
be attached to the map using MapInfo. The "levelscript"
value for the map must be set to the name of the lump containing the compiled scripts for
that level. The Levelscript area is initialized during level setup, and if the currently
loaded Levelscript contains an OnInit() function, that function will be executed once and only
once, provided a save game is not being loaded. The OnInit() function is optional, and if it
does not exist, no error will occur.
Return to Table of Contents
Invoking Levelscripts
Here are the various ways Levelscript public functions (aka scripts) may be invoked:
- Console Commands
The a_execv and a_execi console commands can run public Small functions which
take either no parameters, or any number of integer parameters respectively. By
passing the second parameter ("vm") as the number 1, you will indicate to look
for the named function in the Levelscript VM. If the named function does not exist
in the Levelscript, an error message will be printed. See the
Eternity Engine Console Reference for full
information.
- Cross-VM Execution
Using the Small function _ExecLS, it is
possible to execute Levelscript functions by name from any function in the Gamescript.
If the Levelscript is not loaded or ExecLS is called from within the Levelscript, the
current script will be aborted and an error message will appear in the console. Note
that ExecLS can only call functions in the current level's Levelscript. State may be
transferred between levels using public Gamescript global variables.
- Registering Callbacks
Callbacks may be registered from OnInit or from any other Levelscript function which
may then repeatedly call Levelscript functions under the _INVOKE_CALLBACK invocation
model. See the _SetCallback function for
full information. Levelscript callbacks can only run during gameplay on that map, and
any scheduled Levelscript callbacks will be killed immediately any time a level is exited
in any manner.
- EDF/BEX Codepointers
The StartScript and PlayerStartScript codepointers may both execute Levelscripts by
number. Only public functions which are named in the fashion "Script#", where # is
any positive integer value, and accept 3 integer parameters can be invoked using these
codepointers. The numeric value used in the function name is passed to the codepointer as
an argument (via the EDF/BEX args frame values). Use the number 1 as the second parameter
to either of these codepointers to indicate the Levelscript as the target VM. If the
Levelscript is not loaded in this case, the codepointer will perform no action. See the
Eternity Engine Definitive Codepointer Reference for full
information.
Warning: If StartScript or PlayerStartScript are called from frames into which an
object is set by other scripts, or they call a script which may change the object's
state, any new script started will be executed recursively. This means that the second
script will be executing before the first has finished. Be sure to carefully account for
this in your scripting logic, and do not erroneously assume that any other script must
have finished executing before the one that is currently running, or that other scripts
will not execute before the current script has finished.
- Script Linedefs
Levelscripts may also be executed by number using the same naming convention for
the StartScript codepointers, but accepting zero parameters and using the tag of the
line as the script number, with one of the following specials:
- 280: WR Start Script From Tag Number
- 273: WR Start Script From Tag Number 1-Way (activates from first side only)
- 274: W1 Start Script From Tag Number
- 275: W1 Start Script From Tag Number 1-Way (activates from first side only)
- 276: SR Start Script From Tag Number
- 277: S1 Start Script From Tag Number
- 278: GR Start Script From Tag Number
- 279: G1 Start Script From Tag Number
Return to Table of Contents
Using Levelscript Variables
Like any compiled Small program, the Levelscript may contain scalar global variables
declared as "public." These variables, aside from being normally accessable from any
function within the Levelscript, can also be accessed from outside by using the
_GetLevelVar and
_SetLevelVar functions. Using these functions
in your Gamescripts can allow the Gamescript to perform similar actions on many
levels. Note that if a variable is not defined in a particular Levelscript, the Gamescript
executing _GetLevelVar or _SetLevelVar will abort with an error message. The variable must be
defined in each Levelscript in which the Gamescript may attempt to access it.
Return to Table of Contents
Savegame Semantics
The following subsections contain information on how the Small system behaves when the
game is saved or loaded.
Return to Table of Contents
The OnInit Function
In the Gamescript, the OnInit function is executed only once at program startup, and therefore
this is not affected by saving or loading games. When a game is loaded, it can be assumed that
the Gamescript OnInit function has already been executed.
In the Levelscript, the OnInit function is executed each time the level is loaded from scratch.
However, if the level is being initialized during savegame loading, the OnInit function will
NOT be executed, as it is expected that the program state created by it was preserved in the
savegame. Executing it again in that case could create duplicate objects, show unnecessary
messages, etc. Be sure that your OnInit function's changes to the map are saveable or are not
necessary to be repeated after loading a saved game.
Return to Table of Contents
Global Variables
Global variables declared in both VMs, public or private, will have their values saved in
save games. This means that when a normal game loading action takes place, the values of
global variables in both VMs will instantly change to reflect the state that was in place at
the time of the save.
Return to Table of Contents
Static Local Variables
Static local variables are variables declared inside functions using the static keyword
as opposed to the new keyword. As mentioned in the Small language documentation, static
local variables, unlike normal local variables, retain their values between calls to the
function in which they are declared. Because static locals are really just limited-scope
globals, they are treated the same way, and their values will be saved in savegames. When a
normal game loading action takes place, the values of all static local variables in both VMs
will instantly change to reflect the state that was in place at the time of the save.
Normal local variables are the only storage class of variable that is not archived in save
games. In addition, the status of the Small stack and heap are also not currently saved, since
Eternity does not allow script execution to be interrupted by a save game under any circumstance.
Return to Table of Contents
Callbacks
Callbacks currently scheduled for either VM will be saved in save games. At the time of a normal
load action, any existing callbacks in either VM will be instantly destroyed and will be replaced
with the callbacks which were scheduled at the time of the save.
Return to Table of Contents
Load Errors
The following fatal errors may occur while loading a savegame which contains script data under
the given circumstances. Eternity will currently exit if these errors occur.
- "P_UnArchiveScripts: vm presence inconsistency"
The presence of the Gamescript and/or Levelscript has changed since the time of
the savegame. If a Gamescript or Levelscript is removed from a WAD, but a savegame
containing its archived image is subsequently loaded, this error will occur. This
error will also occur if a Gamescript or Levelscript has been added to a WAD and
there is no archived image of it in the savegame.
- "P_UnArchiveSmallAMX: data segment consistency error"
The size of one or both Small AMX data segments has changed since the time of the
savegame. This can only occur if a Small script has been recompiled. You cannot
reload savegames if any of the involved scripts have been recompiled.
Return to Table of Contents
System-Defined Event Handlers
Complete documentation of all system-defined event handlers is below. System-defined event
handlers are optional functions that you can provide in your script that will be started as
callback scripts by the game engine in response to internal events. If the functions do not
exist, no calls will be issued.
Return to Table of Contents
OnInit
Required Prototype: public OnInit();
Can Be Defined In: Gamescript, Levelscript
The OnInit function is called when its corresponding virtual machine is initialized. For the
Gamescript, the OnInit function is executed only once at program startup. In the Levelscript,
the OnInit function is executed each time the level is loaded from scratch, NOT including when
a savegame is being loaded.
Return to Table of Contents
OnHUDStart
Required Prototype: public OnHUDStart();
Can Be Defined In: Gamescript, Levelscript
OnHUDStart will be called first in the Gamescript and then in the Levelscript, if defined in
either or both. It is called whenever a new level is started, or when the player being
displayed by the game engine changes. Because text widgets are cleared by default, you may
want to set new values to them in this function. You may also use it to maintain the internal
state of your scripts with respect to the HUD.
Return to Table of Contents
OnHUDPreDraw
Required Prototype: public OnHUDPreDraw();
Can Be Defined In: Gamescript, Levelscript
OnHUDPreDraw will be called first in the Gamescript and then in the Levelscript, if defined in
either or both. It is called once per frame after HUD widgets from the previous frame have
been erased, but before drawing of widgets for the current frame has begun. This is the safest
time to alter the properties of HUD widgets. Altering properties such as location or graphic
being shown at any other time may result in visual artifacts. Call functions such as
_MoveWidget from this event handler.
Return to Table of Contents
Eternity Small Headers
This section lists the standard headers provided with the Eternity Small compiler
distribution. These headers will be automatically included by the compiler, and so it
is not necessary (although not an error) to include them explicitly.
- default.inc : This header includes core.inc and common.inc, and is automatically
included by the Small compiler when running with the default parameters.
- core.inc : This header is provided by the Small AMX library. It includes prototypes
for all of the suggested core Small functions, but be aware that many of these are
not currently supported for use under the Eternity Engine. Only those functions listed
in the Eternity Small Function Reference may be used
safely and compatibly.
- common.inc : This header includes all of the standard Eternity Engine headers below.
- cameras.inc : Contains function prototypes and constants dealing with game cameras.
- fixed.inc : Contains function prototypes, stock functions, overloaded operators, and
constants dealing with fixed-point math.
- game.inc : Contains function prototypes and constants for manipulating game play.
- hud.inc : Contains function prototypes and constants for manipulating the heads-up
display system.
- invoke.inc : Contains function prototypes and constants related to invocation models,
starting scripts, scheduling callbacks, and external access to public variables.
- io.inc : Contains function prototypes and constants for player input and output.
- random.inc : Contains function prototypes for the DOOM RNG interface.
- sound.inc : Contains function prototypes and constants for sound and music functions.
- specials.inc : Contains function prototypes and constants for manipulating all aspects
of a map, including lines and sectors.
- things.inc : Contains function prototypes and constants for manipulating all aspects of
moving objects, including monsters, decorations, and player avatars.
Return to Table of Contents
Reserved Identifiers
The following function, definition, and constant names are explicitly reserved by the Eternity
Engine and should not be used by user script functions or constants. Doing so may cause
your scripts to not compile with future versions of the engine.
Note: The syntax [<character class>]* means zero or more of the characters within the
class indicated inside the brackets. Programmers should recognize this syntax as a regular
expression.
- On[A-Za-z0-9_]* : Reserved for system-defined event handlers.
- _[A-Za-z0-9_]* : Reserved for system-defined identifiers (ie., native functions).
Return to Table of Contents