Intensity Engine Scripting API Documentation. (C) 2009 Alon Zakai. License: CC-BY-SA-NC.

Intensity Engine Scripting

# Introduction

Scripts in the Intensity Engine are written in JavaScript, while using a custom Intensity Engine API. The custom API consists of

- A set of calls into the main C++ engine code, to affect it in various ways (e.g., to show a particle effect, or to move an object from one position to another).
- A framework, written in JavaScript, for writing Intensity Engine applications and entities. This includes a 'standard library' as well as a class framework.

In general, you should only use the latter: Calling directly into C++ should be handled for you by the JavaScript part of the API. However, we mention the former here because you may see it used in actual code, and at times it may be the best way to do something (until the JavaScript part of the API improves). In this document we will therefore talk only about the JavaScript part of the API.

## Terminology

- Activity: Typically a game. An activity is a combination of a map, scripts, models, etc. As an activity has a single map, the term activity and map can sometimes be used interchangeably.

## Types of Scripts

- Map scripts are executed when a map/activity starts. They set up the entity classes and pretty much all the logic for the map/activity. This document deals almost entirely with such scripts. Map scripts are always called map.js and they reside in the map directory (along with the other map files like map.ogz). Map scripts can run code from other scripts, see Library.include.
- Model scripts are executed when a model (mesh) is loaded. Such scripts usually just call the relevant cubescript commands to set up the model (through the JavaScript API, see the Map namespace mentioned below). Model scripts have the name md5.js, obj.js, md3.js or md2.js (for md5, obj, md3 and md2 models, respectively). The engine runs model scripts when it starts to load the model; you don't need to run them directly from your map script.
- Texture scripts are executed in order to define textures in the game. By convention they reside in the same directory as the textures they define. Like model scripts, they usually just call the relevant cubescript commands. Unlike model scripts, they must be run from the map script.

## The Standard Library

The standard library is implemented as 'namespaces', using JavaScript objects. So, for example you would write Map.someFunction() to access someFunction in the 'namespace' Map.

The standard library has two parts: The core, and the optional.

- The core is what is present in src/javascript/intensity. This is code that is run by default when your map is started (but, given that this is JavaScript, you can still override and replace things - so even this is optional in a sense).
- The optional libraries appear in packages/library. All of the components in these libraries are optional - you load them from your maps if you want them. These extra libraries have versions, 1_1, 1_2, etc., which allows older maps to continue to work with older library versions.

The main namespaces of the standard library are as follows. For now we just give an overview, details will appear later on. A full index of the standard library appears in the Appendix.

- Map: Deals with changing map definitions, like map textures, visual settings like fog, etc. Much of this is a reflection of the Cube 2 mapping commands.
- World: Deals with physical aspects of the environment, like checking collisions, gravity, etc.
- Library: Deals with loading other libraries.
- Model: Deals with setting up models (meshes). Much of this is a reflection of the Cube 2 model commands.
- UserInterface: Deals with showing messages, dialogs, etc.
- Global: A few settings about the scripting environment in general.

# Tutorial

The best way to learn is to go over a working example script. Here is a 'hello world' (minimal working example):

// Default materials, etc.
Library.include('library/MapDefaults');
// Textures
Library.include('yo_frankie/');
// Map settings
Map.fogColor(0, 0, 0);
Map.fog(9999);
Map.loadSky("skyboxes/philo/sky3");
Map.skylight(100, 100, 100);
Map.ambient(20);
Map.shadowmapAmbient("0x505050");
Map.shadowmapAngle(300);
//// Player class
registerEntityClass(Player.extend({
_class: "GamePlayer",
}));
//// Application
ApplicationManager.setApplicationClass(Application.extend({
_class: "GameApplication",
getPcClass: function() {
return "GamePlayer";
},
clientOnEntityOffMap: function(entity) {
entity.position = [600,600,600];
}
}));
//// Load permanent entities
if (Global.SERVER) {
var entities = CAPI.readFile("./entities.json");
loadEntities(entities);
}

Let us go over it piece by piece:

- Library.include('library/MapDefaults');
  This includes a library (Library.include is sort of like #include in C/C++ or import in Python). Includes are always relative to packages/, the directory containing content (of which there are two directories - one in the installation of the engine, and one in your home directory. The latter contains downloaded content, etc.). In this case Library.include will run a .js (JavaScript) file called packages/library/MapDefaults.js. This basic script is included in most activities, it sets up general stuff like textures for water.
- Library.include('yo_frankie/');
  When given a directory (as you can see by the trailing slash), Library.include will look for a Package.js file in that directory (this is a naming convention). In this case, yo_frankie/ contains some content from the open game Yo Frankie!, a nice project by the Blender Foundation. By including this file, we can use some textures from there in our map.
- Map.fogColor(0, 0, 0);
  etc.
  These commands define visual settings for the map, like the fog color and distance, shadow color and angle, and so forth.
- registerEntityClass(Player.extend({
  _class: "GamePlayer",
  }));
  This is where things start getting more involved.
  registerEntityClass takes a class and 'registers' it in the system. Registration allows you to find the class in the engine, using its name, which is given in _class (note the initial underscore - this is because 'class' is a reserved word in JavaScript). You need to register any class that will need to be accessed by its name. But wait, does JavaScript even have classes?
  In the core language it of course does not. But it is a very flexible language, and many libraries can provide class-like functionality in JavaScript. The Intensity Engine uses a simple system based on some code by John Resig (in src/javascript/SimpleInheritance.js). This allows expressions like Player.extend({ _class: "GamePlayer" }), which takes an existing class - Player - and extends it, basically producing a subclass. In the code above, the subclass only has one new attribute, _class, but you can add any number of attributes as well as functions (more on that later).
  So basically, in this bit of code we create a GamePlayer class, which is simply a subclass of Player but with a new name, and we register it in the system.
- ApplicationManager.setApplicationClass(Application.extend({
  _class: "GameApplication",
  Every activity has an 'Application', an object that handles some high-level functionality. ApplicationManager.setApplicationClass sets the class from which the Application instance will be created. In this case, again, we subclass an existing class, here 'Application', which is the base class for all applications. As a first step, we give the subclass an attribute _class, as before; this is actually not strictly necessary, but it is convenient sometimes for debugging, so we do it anyhow.
- getPcClass: function() {
  return "GamePlayer";
  },
  Here we provide our subclass of Application with a getPcClass function. This by convention returns the name of the class from which players will be created. In other words, when someone logs into this activity, the entity representing them will be an instance of that class. Here we return "GamePlayer", the name of our class from before.
- clientOnEntityOffMap: function(entity) {
  entity.position = [600,600,600];
  }
  clientOnEntityOffMap is called by the system when an entity falls off of the map - that is, falls so far that it is completely out of the world. The behavior we define here is pretty simple: We set the position of the entity to [600,600,600], which is somewhere in the middle of a typical map (which has coordinates in the range 0-1024,0-1024,0-1024; bigger maps can have large coordinates).
  Note the standard JavaScript syntax: entity.position is the position of the entity (where it is in the world), and [600,600,600] is a JavaScript array. Behind the scenes, though, a lot more has to occur for this to be useful: The engine 'catches' the assignment into the position attribute, and makes the actual change in the main engine, in C++. This happens because position is not a typical JavaScript attribute, but really a 'state variable'. We will say a lot more about state variables later, as they are fundamental to the Intensity Engine API. But the point to notice here is that, even though complex things might occur in the background, the code you write is quite clean.
  (Note that in most games you would generally 'kill' the entity at this point, instead of just moving it back up into the map. But of course, you can do whatever is suitable for your activity.)
- if (Global.SERVER) {
  var entities = CAPI.readFile("./entities.json");
  loadEntities(entities);
  }
  Here we must explain another fundamental aspect of Intensity Engine scripting: You write a single script that runs on both the client and the server. In general this saves a lot of work, as normally you want them both to do the same things. So, in the code we saw so far, both client and server will have a GamePlayer class, the same fog and texture settings, and so forth. But, sometimes you want to do something only on the client or only on the server. One way to do this (we will see another later) is simply to check Global.CLIENT and Global.SERVER; only one of them will be true, depending on where the script is running. In this case, we want the two lines appearing after Global.SERVER to only run on the server. The clients connected to that server will simply not run those lines.
  On the server, the script first loads some data from a file, using CAPI.readFile. The file is entities.json, and './' means it should be in the same directory as the current script. entities.json is a file containing some serialized entities in JSON format. loadEntities then loads those entities into the running activity.
  This bit of code is very standard - it simply loads the 'map entities', things like props, lights, and so forth. These are stored separately from the map geometry (the map.ogz) file. By convention they are stored in entities.json.
  The reason we do this only on the server is that entities are synchronized automatically. You only need to create an entity once on the server, and it will be streamed to the clients. In fact, it isn't valid for clients to create entities; they must send requests to the server to do so.

That concludes the code for this simple script. If you run an activity with this script, it will be fairly boring, as there is nothing in the world (well, unless exciting things are in the entities.json file). But this is the general framework for a map script.
Summary of main points in this Chapter:

- The API uses a class-based inheritance system for convenience (which is implemented using JavaScript's prototype-based inheritance)
- Every activity has an Application Class, from which the ApplicationManager creates a single instance. This instance is used to manage activity-specific callbacks from the engine (like when an entity falls off the map).
- The API tries to use as normal-looking JavaScript code as possible, while doing all the hard work transparently behind the scenes.
- A single map script is run for each activity, on both the clients and the server (but there are ways to set it so particular pieces of code run only on one side or another).

# Main Concepts

## Logic Entities and State Variables

Logic entities, or just 'entities', are the important things in an activity, for example, the characters, props, and so forth ('logic' refers to the terms 'game logic', 'business logic', and so forth). Each actual entity is an instance of a particular entity class. You can use inheritance to create such classes, or the component-based system described later.
Logic entities are synchronized between the client and server: When you create a new entity on the server, without your needing to do anything, the engine will tell the clients to 'reflect' that entity, so they are aware of it. Furthermore, the engine will also synchronize some of the entity's attributes in a transparent manner, such attributes are called state variables. Attributes of an entity that are not state variables are not synchronized; a common mistake is to assume that they are by writing to one on the server and trying to read it on the clients. The reason that not all attributes are synchronized is that this would take a significant amount of bandwidth and CPU power, whereas sometimes you need just a 'local' attribute, on just the server or just the client; such attributes can be worked with very fast (V8, the engine running JavaScript in the Intensity Engine, optimizes such variables very significantly).
Here is a simple example of a state variable in an entity class:
var Door = Mapmodel.extend({
_class: "Door",
open: new StateBoolean(),
});
(Mapmodel is a class of 'prop' entities. More on them later.) As you can see, state variables are defined as members of the entity class. In this case we define 'open' as a state boolean, which is a state variable that is a boolean, i.e., true or false. (The reason you need to declare the type of the variable - as opposed to normal JavaScript variables - is that the type affects how the variable is transmitted over the network when it is synchronized.) In this example, a door instance can be either open or closed.
With this declaration, we can create an instance of the class as follows:
registerEntityClass(Door);
var someDoor = newEntity("Door");
Note that we need to register the class on both the client and the server, but the creation (using newEntity) can only be done on the server. Note also that newEntity takes the name of a class, not the class itself. It looks up the class among the registered classes, which is why we needed to register our class beforehand (this is necessary because requests to create a class can arrive from the clients in string form).
After calling newEntity in this way, the entity is put into play, and it will be reflected automatically on all the connected clients. You can then do someDoor.open = True; on the server, and that value will be synchronized between the server and all the clients. More specifically,

- If you assign to 'open' on the server, it will send notifications to all the clients. It will also update its own copy of the value immediately, so that if you were to do var isOpen = someDoor.open; then you will get the expected value. This happens because the server is the 'final arbiter' of the value (more on that in the next paragraph).
- If you assign to 'open' on a client, it does not update its own copy of the value. Instead, if will send a message to the server requesting to change it. If the server agrees (which it does by default), the server will set the value, and update all the clients, including the one that made the request.

The logic behind this is that the server is the 'final arbiter' of the value. There must be some arbiter, or otherwise each client (and the server) could set the value independently, and synchronizing the values might lead to unpredictable results, depending on network speeds and so forth. So, by default the server is the arbiter of state variables (but this can be changed; more on that later).
In particular, this leads to the following peculiarity on the client:
// Assume someDoor.open is equal to False beforehand
someDoor.open = True;
var isOpen = someDoor.open; // Still False!
The reason is that it takes time for the request to be sent to the server, and for the server to respond. Until that time, the client still shows the old value. This can be confusing, but really there is no way to get around this aspect of writing distributed applications - it is confusing sometimes.
Let us now add some functionality to our class. To do so in a convenient matter, we will use the component-based entity system, which is generally more convenient than using class inheritance. Instead of inheriting classes, we will build classes out of 'building blocks', or components, also known as 'plugins'. Here is an example of such code:
Library.include('library/Plugins');
var Door = bakePlugins(
Mapmodel,
[
{
_class: "Door",
open: new StateBoolean(),
activate: function() {
this.open = false;
this.locked = true;
this.connect(
'onModify_open',
this.checkLock
);
},
checkLock: function(value) {
if (value === true && this.locked) {
throw "CancelStateDataUpdate";
}
},
}
]
);
bakePlugins takes two parameters: A base class, and an array of 'plugins'/'components'. It returns a new class which is a subclass of the base and has the functionality of all the components. In this example, we provided a single plugin, which as before gives the class a name of "Door" and has a single state variable, "open". There are then two new pieces of code here, the activate and checkLock functions, which we will now describe:

- activate is a function present in all entity classes; by writing code in an activate function in a plugin, we are defining code to be called when activate is called, which is when an instance of that class is 'activated'. 'Activated' means set into action. It is called when creating a new entity, or when deserializing an old one. It occurs only on the server.
  In this example, we set open to be 'false'. This means that all instances of the class Door will start out closed.
  We then set 'locked' to true. Note that locked is not a state variable! It is a normal JavaScript variable. There is no reason to make it a state variable because we don't want to synchronize it with the clients - in this example, they don't need to know if the door is locked or not, as we will see when we explain 'checkLock', below. So 'locked' will only exist on the server.
  Finally, the last line of activate connects a signal. The signal is onModify_open, which means the signal that is emitted when the state variable 'open' is modified on the server. Whenever that happens, the callback that we connect to the signal will be called with that value. Here we connect this.checkLock, which we will now explain.
- checkLock is a normal JavaScript function. When defined in a plugin in this manner, it will simply become a function of the new class returned by bakePlugins.
  As just explained, checkLock will be called when the 'open' state variable is modified on the server. The parameter passed to it contains the new value attempting to be set. In the code above, we check whether it is in fact valid to make the modification: If an attempt is made to open the door (value === true), but the door is locked (this.locked), then we don't allow that - locked doors can't be opened. So we throw the "CancelStateDataUpdate" exception, which will prevent the update from going through - the old value will remain. (Note about terminology: "State data" is a name for all of the state variables of an entity.)

In summary, this example shows how we can use state variables to maintain important information about an entity. Let's think for a minute about how this would work in the bigger picture, and why it makes sense to do it as we did. Assume that 'locked' was in fact a state variable, and therefore accessible on the client, and that when a player clicks to open a door, then that would run a piece of code that look this:
if (!this.locked) this.open = True;
That is, if the door isn't locked, open it (otherwise, perhaps play a sound, or show a message "the door is locked", etc.). This seems like it would work, and that we don't need to check validity on the server at all - the client will only notify the server to open the door if it's unlocked. But the issue is that, with distributed applications, all sorts of things might happen. For example, the door might get locked between the time the player clicks on the door and before that request arrives at the server. In that case, our code above on the server would handle the situation correctly - keep the door closed. (Note that the failure here is silent - the player will simply see the door not open, but not get any other feedback. Typically you would handle this so that the player gets the same feedback they would get for a normal locked door that they try to open.) Similar problems can occur, for example, in capture-the-flag type games, if two players try to grab the flag at almost the same instant - both will send requests to the server to pick up the flag, but it should only let one of them (the first) do so.

## Main Functions of Logic Entities

Aside from activate, which we saw above, there are several other important functions that you can use in plugins:

- init: Called once on the server, when an entity instance is first created. This is not called if you later serialize and deserialize it.
- activate: As described above, this is called whenever the entity is 'put into play', either when first created, or when deserialized. This runs only on the server.
- clientActivate: This is called on the client when the entity is activated. This follows a standard convention of X being the server-side version (the default, most-used one), and clientX being the client-side version. Note that clientActivate is called on each client connected to the server, unlike activate which is called just once (as there is a single server).
- act: This is called once each frame on the server, and receives a single parameter, which is the amount of seconds that the frame lasts. You can write code here to control the entity's behavior, with the amount of seconds telling you how much time it has to do so.
- clientAct: This is called once each frame on each of the clients, and like act it receives the amount of seconds that the frame lasts as a parameter. Note that while on the server frame rates are usually 1/30 of a second, and generally consistent, on the client the frame rate depends on the power of the CPU, GPU, and so forth, so different clients may see very different values here.

As we saw earlier, you can also define new functions in a plugin, and those will become functions of the class they are baked into.

## Frame-Based Coding

As just mentioned, act() and clientAct() are called on each frame. This is different from some scripting APIs that simply let you write long scripts that run continuously (in most such cases, each in a separate thread, or queued after each other), or APIs that let you write event handlers (although, you can see act and clientAct as event handlers, in a way). The main difference is responsiveness vs. throughput.
If each script runs in its own thread, or multiple threads handle events in parallel, that can definitely help throughput, if multiple CPU cores are available. (It can also lead to simpler code in some cases, but not others.) But the price is less predictability and responsiveness, in the sense that we can't time script code to occur exactly in sync with our frames (unless we handle events that occur once per frame - which is exactly what act and clientAct do). In fast-paced games, we do need such predictability and responsiveness: If a player clicks, the effects of that click should occur in the very next frame; likewise, if some event is occurring (say, the player is under a spell), we may want to be able to have a visual effect signal the end of the event on the exact same frame that happens. In both cases, frame-based coding can work, but a complicated multithreaded system that schedules scripts might not.
One consequence of frame-based coding is that we need to be careful what we run in each frame - if we spend too much time in act or clientAct for a particular entity, the entire frame will take too long, which may be noticeable to the player. One way to be careful about this is to schedule code to only occur every so often, for example, a bot might look for new targets only once per second. This can be done in a simple way using a RepeatingTimer, which we will see examples of below.

## Types of State Variables

We already saw boolean state variables mentioned. Here is a list of all the important kinds (note that you can also define your own, see src/javascript/intensity/Variables.js):

- StateString: A single string value, of arbitrary length.
- StateInteger: A single integer value.
- StateBoolean: A single boolean value.
- StateFloat: A single float value (actually a double, since all JavaScript floating-point values are doubles).
- StateArray: An array of string values. Note that when you access such a property (by something like var x = this.myStateArray;), you do not get a normal JavaScript array. Instead, you get an object with get(index) and set(index, value) functions, allowing you to change the individual values. It also has an asArray() function that returns a normal JavaScript array, but note that it is a copy, so if you modify it the actual value will not change (whereas changes due to set() do take hold). Note that you can set the entire variable normally, for example, with this.myStateArray = ["some", "data"];(Note: StateArray should be renamed to StateArrayString, but is kept as it is for backwards compatibility. However, in your own code you can easily alias it, by StateArrayString = StateArray;)
- StateArrayFloat: An array of floating point values. Behaves similarly to StateArray otherwise.
- StateJSON: Meant for synchronization of large amounts of data. When you read this you get the normal JavaScript value (i.e., already unserialized from JSON), and you can write normal JavaScript data to it. It is transmitted over the network using JSON. Note that when you read it you receive what is effectively a copy, so modifying it will not change the actual value. To do so, read it, modify what you want, and write the entire thing back.

## Properties of State Variables

When you define a state variable, you can define some properties for it, using syntax of the following form:
door: new StateBoolean({ clientWrite: false });
(Note the curly brackets - an object is used here.) In the example here we set the property 'clientWrite' to false. This property, and the other important ones, are explained below:

- clientSet (default: false): If true, this means that the clients are the 'final arbiters' of this value. That means that if a client (any client) sets the value, it will be applied immediately on that client, and an update sent to the server, which will update the value and notify all the other clients (but not the originator, which already set the value). This is a very important property, that allows nicely responsive activites to be written, as the client will receive immediate feedback without needing to wait for the server to respond. For example, if a game has a health value that has clientSet: true, then if you run code on the client that lowers the health (say, because the player stepped in acid), and you show some visual effect or play a sound when health is lowered, then the feedback to the player will be immediate, as if the entire game was being played locally. (Note that this assumes the health is lowered on the client. If a server event lowers the health, there will still be a delay as the update reaches the client over the network.)
- clientWrite (default: true): Whether clients are allowed to set this value. If false, then they can only read it. Useful for data you want to synchronize with the clients, but never want them to send requests to change.
- reliable (default: true): By default, state variables are reliable - when they change, synchronization of that change must succeed, so that (after network delays, if any) everyone will see the same value. But some types of data can be sent in unreliable mode, which means that if the update is dropped by the network, or arrives much too late, it will simply be ignored. This makes sense if you send a lot of updates for a variable, and don't care too much about each particular one. For example, this would be useful if you update the orientation of an object 10 times per second; if one update is lost, the next one will be good enough. The reason that reliable updates would be a problem here is that all updates - reliable and unreliable - arrive in the right order. If a reliable update is late, all other updates will wait for it. So if you send 10 updates a second, it is likely this will lead to lag at some point. On the other hand, unreliable updates can never lead to such lag, as if they arrive late, or never arrive at all, that doesn't matter as other updates are processed normally.
- hasHistory (default: true): By default, state variables care about their history, in the sense that when serialized the value is saved, and if a value changes, and much later a new player logs in, that player will receive the current value of that variable. However, if you set hasHistory to false, then history is ignored, and changes to the state variable are in effect 'events' - they matter when they occur, but not afterwards. For example, you can have a state variable indicate that a shot is being fired right now, so that each time the value changes you show a shot being fired. With history, if a client logs in, they will see a shot fired, even if it actually occurred far in the past. On the other hand, if you set hasHistory to false, this will work as desired.
- clientPrivate (default: false): By default state variables are sychronized between all clients - changes to data are reflected everywhere. However, some information should only be sent to some clients, like say the inventory in an RPG game. A clientPrivate state variable can achieve that, since it is only sent to the client whose avatar that is. In other words, clientPrivate variables on a player entity are only updated to that player - other clients will not see a value for that variable on that entity. (Note that clientPrivate has no effect on non-player entities.)
- guiName: If defined, this name will be shown in the in-game editor when editing the entity's state data (i.e., the state variables), which is done by rightclicking on an entity in edit mode.
- customSynch (default: false): If true, then synchronization for this variable is done using some non-standard way, like a special protocol, and the normal synchronization will not do anything regarding sending and updating values. You probably won't need to use this unless you write some C++ code to handle the custom protocol (which you really should not need to do).

## Main Logic Entity Classes

The following are the main entity classes in the API:

- AnimatableLogicEntity: An internal class with a 3D animatable model, attachments, etc. You should not subclass this yourself.
- StaticEntity: The basis for all 'static' entities, which are entities that do not move, or hardly move - like static props, lights, particle effects, etc. You should not subclass this yourself.
- Light: A static light, which affects lightmaps.
- ParticleEffect: A particle effect. See the Cube 2 documentation for details.
- Mapmodel: A static prop, that is, a mesh that is placed in a particular position in the map.
- AreaTrigger: A space which can let you know when (dynamic) entities (like players) enter it (via onCollision, clientOnCollision).
- ResettableAreaTrigger: An AreaTrigger that 'fires' once when entered, and will not signal additional collisions until it is 'reset'.
- WorldMarker: A marker of a position in the map. The typical use is to give it some tag, then find it using that tag in a script, and use its position to do something (like place respawning characters there, etc.).
- Character: The basis for all dynamic (fast-moving) entities. Subclass this for NPC classes (bots).
- Player: A Character representing a player.

## The Action System

Every entity has an action queue. You can add actions to the action queue, and they will be performed in order. This is useful for controlling the 'state' of an entity, for example, if a game has a 'death state', we can implement that as follows:
DeathAction = Action.extend({
_name: 'DeathAction',
canMultiplyQueue: false,
canBeCancelled: false,
secondsLeft: 5.5,
doStart: function() {
this.actor.emit('fragged');
this.actor.canMove = false;
this.actor.animation = ANIM_DYING|ANIM_RAGDOLL;
},
doFinish: function() {
this.actor.respawn();
}
});
(This is taken from packages/library/Health.js.)
As you can see, action classes are subclasses of Action. Here we give the action a _name, and set some properties:

- canMultiplyQueue (default: true): When set to false, only one action of this type can be queued (the 'type' is defined as having the same _name). This makes sense for a death action, as you can't kill someone that is already dead.
- canBeCancelled (default: true): When set to false, the player that the entity represents can't easily cancel the action. When set to true, moving the character or pressing the escape key will cancel all current actions. For example, if the player is performing a 'cast spell' action, it makes sense for escape to cancel it, but for our death action here it doesn't.
- secondsLeft: How long the action will last. In this example we set it so players will stay dead for 5.5 seconds.

Aside from the properties mentioned above (canMultiplyQueue, canBeCancelled, secondsLeft), subclasses of Action can have a few other properties,

- animation: If defined, while the action runs the value given here will be used for the animation of the entity performing the action.
- parallelTo: If defined, this should be an action instance. This action will then finish exactly when that action does.

In the example above we then overload two functions:

- doStart: Called when the action is first started (not queued - but when it actually begins to run). In this example, we emit a signal, 'fragged', which other components can connect to if they want (for example, in a capture the flag game, you might connect to this so that players drop flags they hold when they die). Note that we access the player through this.actor - this is the action, and this.actor is the entity that is performing the action. We then set canMove to false, so the player can't move (canMove is a state variable, so it is automatically synchronized between the server and clients; when equal to false, the player cannot move). Finally, we set an animation, a combination of a dying animation and a ragdoll animation (which means that a ragdoll death sequence will be shown if available, or if not, a dying animation; animation is a state variable, so like canMove it is automatically synchronized between the server and clients - everyone will see the same animation for a character).
- doFinish: Called when the action finishes (or is cancelled). We call respawn() on the character, which should implement something appropriate. In particular it should set canMove to true, change the animation, and probably move the character to a start position (we could do the first two here, which would let us clean up nicely after doStart, but often respawn procedures need more control over things (for example, first making the player vanish, then moving them, then making them appear - perhaps using some visual effect - and only then letting them move).

Another useful function to override (which we didn't need in the example above) is the following:

- doExecute: This is called each frame while the action is running, with the number of seconds the current frame lasts as a parameter. In that respect doExecute is very much like act() and clientAct() (note that whether it occurs on the client or the server depends on where you queued the action - actions are not synchronized).

After defining the DeathAction class from before, we can use it as follows:
player.queueAction(new DeathAction());
This will queue a new death action on player. Note that in this example, we would probably do player.clearActions(); before it, to cancel any current actions and make the death action start immediately.
In summary, note that you don't need to use actions - you can accomplish the same results by coding behavior into the act() and clientAct() functions. But you'd probably end up with a lot of conditions and 'spaghetti code'. The action system can make writing clear, extensible code easier.

## Other Useful Things

- src/javascript/Utilities.js contains some useful classes, like Vector3, RepeatingTimer, and functions like normalizeAngle, yawTo, etc.
- src/javascript/Effect.js contains access to the engine's particle effect system and other visual effects.
- src/javascript/MessageSystem.js contains access to the engine's network protocol system (which you probably won't need to use directly - except perhaps for showClientMessage).
- src/javascript/Sound.js contains access to the engine's sound and music system.
- packages/library contains several useful components, like Health, GameManager, Projectiles, etc.

# Plugin Example: Stunball Gun

In this chapter we will look over an example of plugin, specifically a 'stunball gun' - a weapon that shoots projectiles that explode and stun their targets, making them move more slowly for a short time. Here is the code, taken from packages/library/guns/Stunball.js:
Library.include('library/Firing');
Library.include('library/Projectiles');
Stunball = Projectiles.Projectile.extend({
radius: 4,
color: 0xABCDFF,
explosionPower: 50.0,
speed: 90.0,
timeLeft: 1.0,
customDamageFunc: function(entity, damage) {
if (damage > 25) {
entity.sufferStun(damage);
}
},
});
StunballGun = Gun.extend({
delay: 0.5,
repeating: false,
originTag: '',
handleClientEffect: function(shooter, originPosition, targetPosition, targetEntity) {
shooter.projectileManager.add( new Stunball(
originPosition,
targetPosition.subNew(originPosition).normalize(),
shooter
));
Sound.play("olpc/AdamKeshen/CAN_1.L.wav", originPosition);
},
});
StunballVictimPlugin = {
sufferingStun: new StateBoolean({ clientSet: true }),
activate: function() {
this.sufferingStun = false;
},
sufferStun: function(stun) {
if (!this.sufferingStun) {
this.oldMovementSpeed = this.movementSpeed;
this.movementSpeed /= 4;
this.sufferingStun = true;
}
this.sufferingStunLeft = stun/10; // seconds
},
clientAct: function(seconds) {
if (this.sufferingStun) {
var ox = (Math.random() - 0.5)*2*2;
var oy = (Math.random() - 0.5)*2*2;
var oz = (Math.random() - 0.5)*2;
var speed = 150;
var density = 2;
Effect.flame(PARTICLE.SMOKE, this.getCenter().add(new Vector3(ox,oy,oz)), 0.5, 1.5, 0x000000, density, 2.0, speed, 0.6, -15);
if (this === getPlayerEntity()) {
this.sufferingStunLeft -= seconds;
if (this.sufferingStunLeft <= 0) {
this.movementSpeed = this.oldMovementSpeed;
this.sufferingStun = false;
}
}
}
},
};
Map.preloadSound('olpc/AdamKeshen/CAN_1.L.wav');
Comments and points of interest:

- We rely on two other components, Firing and Projectiles. Firing handles guns, shooting, etc., and Projectiles handles moving projectiles. Note that Library.include is smart enough not to include something twice, so if you include something already imported, no problem will occur.
- Stunball is a subclass of Projectiles.Projectile.

- We define some attributes for it:

- radius: The size of the projectile (in 'cube coordinates' - a player is about 15 units)
- color: The color of the projectile (note that we specify the color in 0xRRGGBB format)
- explosionPower: How much damage it will cause when it explodes (see below)
- speed: How fast it moves, in cube coordinates/second
- timeLeft: How long it will last, if it doesn't hit something beforehand, in seconds

- We implement customDamageFunc(), because we want our stunballs to do something other than just reduce health: We want them to stun their targets. In the code for that function, we call sufferStun if the damage is high enough (that is, we want to stun only on direct hits or close to direct hits - as the explosionPower is 50, damage of 25 or more means a very close hit). Note that customDamageFunc, and damage in general, is by default done on each client only for that client's entity. That is, each player manages their own damage, not anybody else's. This is important for a responsive game. Therefore, when inside customDamageFunc, you know that entity is the player entity for this client (again, unless you changed the default behavior).

- StunballGun is a subclass of Gun, the base class for all weapons.

- We define some attributes for it:

- delay: How long the gun will be inactive after each shot, in seconds
- repeating: If the gun allows keeping the trigger button down for repeated firing
- originTag: The tag of the attachment from where the shot will appear. In this example we don't specify one, subclasses of SunballGun would do so (or originTag could be set manually for an instance of StunballGun)

- We implement handleClientEffect(), which is called on each client when a shot is fired. Typically the visual effect of the shot is done here. Here we create a new projectile and set it in motion:

- projectileManager will exist in the shooting entity if they have the Projectile plugin baked in with bakePlugins. This manages projectiles for that entity.
- We create a new Stunball instance, passing it where it starts, its direction (note how we calculate the direction, and normalize the vector), and who fired it).
- We play a sound, whose location is where the shot originates (so people far away won't hear it).

- StunballVictimPlugin is a plugin for characters that manages their suffering the stun effect. This component should be added to the character class using bakePlugins.

- sufferingStun, a state variable, says whether this character is currently suffering the stun effect. We need this to be a state variable so that it will be synchronized between the clients: Every client needs to know who is currently stunned in order to show an appropriate visual effect for that entity, as we will see below. Note that sufferingStun has clientSet: true, which means that when a client-side script sets stun, the value is set immediately, without waiting for a server response. This is important because we simulate projectiles on the clients, and when a client gets hit by one, we want them to immediately see that they are stunned. Waiting for a server response would make the game feel 'laggy'.
- activate sets the initial value for sufferingStun, which is of course false.
- sufferStun, which we saw called earlier from Stunball, starts the stun effect:

- If this entity is not already stunned, save its original speed (in a normal JavaScript variable), and slow it down by a factor of 4. Note that movementSpeed is a state variable, specifying how fast the entity can move, jump, etc.
- Set sufferingStun to true.
- Set sufferingStunLeft (a normal JavaScript variable, not a state variable) to the seconds remaining for the stun effect. As stun is a value in the range 25-50, as we saw earlier, this means somewhere between 2.5 and 5 seconds.

- clientAct is called for each entity on each frame; here we render a visual effect for being stunned.

- First we check that the entity is indeed stunned. Note that while sufferingStun was only set to true on the client to whom the player belongs, we can read that value on any of the other clients, because it is a state variable.
- We show a flame-type effect, specifically smoke, at a random location around the center of the entity. Stunned entities will appear to give off smoke, like a faulty robot.
- If this entity is in fact the player entity - that is, represents the player on this machine, not some other player - then we also manage the stun effect, deducing time from the time the stun effect has left. In other words, each player manages their own stun state. After deducting the time, if no time is left we restore the original movement speed and reset sufferingStun - the stun effect is over.

- The final line of the script preloads a sound, the same sound used when firing the gun. Preloading is useful as otherwise the sound will be loaded only when first played, which will cause a small (but perhaps noticeable) delay on that first fire.

# Complete Working Activity: Sketch World

In this chapter we will look over a complete working example activity: Sketch World. If you haven't seen it in action, it can be summarized as an activity where every player can 'write' on the scenery, in a different color, in streaks of light (but you should really see it in action before reading this!). Here is the code:
Library.include('library/Plugins');
Library.include('library/PlayerList');
Library.include('library/MapDefaults');
Library.include('yo_frankie/');
Map.fogColor(0, 0, 0);
Map.fog(9999);
Map.loadSky("skyboxes/philo/sky3");
Map.skylight(100, 100, 100);
Map.ambient(20);
Map.shadowmapAmbient("0x101010");
Map.shadowmapAngle(300);
//// Player class
registerEntityClass(
bakePlugins(
Player,
[
PlayerList.plugin,
{
_class: "GamePlayer",
markColor: new StateInteger({ clientSet: true }),
newMark: new StateArrayFloat({ clientSet: true, hasHistory: false }), //, reliable: false }),
clearMarks: new StateBoolean({ clientSet: true, hasHistory: false }),
init: function() {
this.modelName = 'frankie';
},
activate: function() {
this.movementSpeed = 75;
this.clearMarks = true;
},
clientActivate: function() {
this.marks = [];
this.connect('client_onModify_newMark', this.onNewMark);
this.connect('client_onModify_clearMarks', this.resetMarks);
},
resetMarks: function() {
this.marks = [];
if (this === getPlayerEntity()) {
function randomChannel() { return integer(Math.random()*256); }
this.markColor = randomChannel() + (randomChannel() << 8) + (randomChannel() << 16);
Effect.splash(PARTICLE.SPARK, 15, 1.0, this.position.addNew(new Vector3(0,0,20)), this.markColor, 1.0, 70, 1);
}
},
clientAct: function(seconds) {
// Show marks
var color = this.markColor;
var last;
forEach(this.marks, function(mark) {
if (last && mark) {
Effect.flare(PARTICLE.STREAK, last, mark, 0, color, 1.0);
Effect.flare(PARTICLE.STREAK, mark, last, 0, color, 1.0);
}
last = mark;
});
// Create new mark, possibly
if (this === getPlayerEntity()) {
var newBatch = this.marks.length === 0 || !this.marks[this.marks.length-1];
var continuingBatch = this.marks.length > 0 && this.marks[this.marks.length-1];
if (continuingBatch) {
Effect.splash(PARTICLE.SPARK, 10, 0.15, this.marks[this.marks.length-1], color, 1.0, 25, 1);
}
if (this.pressing) {
var newPosition = CAPI.getTargetPosition();
var toPlayer = this.position.subNew(newPosition);
newPosition.add(toPlayer.normalize().mul(1.0)); // Bring a little out of the scenery
// Add if a new batch, or otherwise only if not too close
if (newBatch || !this.marks[this.marks.length-1].isCloseTo(newPosition, 5.0)) {
this.newMark = newPosition.asArray();
}
}
}
},
onNewMark: function(mark) {
if (mark.length === 3) {
mark = new Vector3(mark);
} else {
mark = null;
}
this.marks.push(mark);
// TODO: Expire old marks beyond a certain number of total marks
},
}
]
)
);
//// Application
ApplicationManager.setApplicationClass(Application.extend({
_class: "SketchWorldApp",
getPcClass: function() {
return "GamePlayer";
},
getScoreboardText: PlayerList.getScoreboardText,
clientOnEntityOffMap: function(entity) {
entity.position = [600,600,600];
},
clientClick: function(button, down, position, entity) {
var player = getPlayerEntity();
if (!entity) {
if (button === 1) {
player.pressing = down;
} else if (button === 2 && down) {
player.newMark = []; // Separator
}
} else {
// There are much better ways to code this sort of thing, but as a hack it will work
if (down && entity._class === 'Mapmodel') {
player.clearMarks = true;
}
}
return true; // Handled
},
}));
//// Load permanent entities
if (Global.SERVER) { // Run this only on the server - not the clients
var entities = CAPI.readFile("./entities.json");
loadEntities(entities);
}
Comments and points of interest:

- PlayerList is a small but useful plugin that shows a list of players when the player presses TAB. Games would typically extend it to also show separate teams, scores, etc.
- Aside from PlayerList, we bake in one plugin to handle the sketch world functionality, with the following properties:

- markColor is the color the player uses to draw with. Notice that it is clientSet: true, so that when the player changes his or her color, the change is effective for them immediately.
- newMark and clearMarks are 'events', so they have hasHistory: false. We send them only to signal that a new mark is added, or all marks should be cleared, for a particular entity.
- this.marks, which is stored only clientside, is a normal JavaScript variable. We send the marks in the state variable newMark as they appear, and store them here, as Vector3 instances.
- clientAct: Here we show the player's marks. This works because each client has an entity for each player, not just themselves. Each frame, clientAct is called for every entity, so in this way we let every entity draw its own marks.

- In a related matter, getPlayerEntity() returns the entity representing the player (whose machine the script is running on). This is used in clientAct to make sure each player only adds marks for themselves, as clientAct is called on each client for all the players, as just mentioned.
- The actual drawing is done using Effect.flare.
- A simple 'batch' system is used for the marks: if an element of this.marks is equal to null, it separates batches. Within a batch, we connect each mark to the previous, creating a single connected chain. Rightclicking adds a separator, while normal clicks add new marks within the same batch.
- Clicking and dragging adds new marks, but not if they are too close to the previous (so we don't end up with ridiculous amounts). For this we use some vector math with the Vector3 instances: add, sub, etc. (note that addNew and subNew add and subtract, respectively, while returning a new Vector3, as opposed to add and sub which alter the existing one).
- CAPI.getTargetPosition() returns a Vector3 of the current mouse target position.

- We also modify the Application class as follows:

- clientClick: We implememt this to capture mouse clicks. We decide what to do with them depending on the mouse button, and whether the click is a downclick or an upclick (i.e., the button was pressed or released).

- If the player clicks on a Mapmodel then we clear their marks (which also picks a new color for them). In the map, a Mapmodel exists with a mesh of a tree, so clicking the tree clears the player's marks. Note that checking if the click is on a Mapmodel in the way it is done here (reading the _class) is quite hackish. Usually you would tag the entity and check that.

# Appendix: Standard Library Reference

Comments appear inside the source code files. For now, they are the best documentation of individual classes, functions, parameters, etc. This section gives an overview of the files, so you know where to look for things.
The core standard library (src/javascript/intensity) includes:

- Actions: Things that entities can do, last for certain amounts of time, can be queued, etc.
- Animatable: The core entity class, which is 'visual': can be animated, has attachments, etc.
- Application: The interface to handling basic features of your activity.
- Character: The classes for players and bots.
- Effects: Visual effects.
- LogicEntity: The core entity class, the basis for everything else.
- LogicEntityClasses: Management of entity classes - their registration, etc.
- LogicEntityStore: Handles the active entites in memory, serializing them, filtering them, etc.
- MessageSystem: Sending network messages.
- ModelAttachments: Attachments for models.
- Platform: Basic settings are stored in the Global object, including whether this is the client or the server, etc.
- Projectiles: Moving objects (not entities) that are typically transient.
- Sound: Playing sounds and music.
- StaticEntity: The main 'static' entity classes - entities that do not move a lot, and persist with the map, like Lights, Mapmodels, WorldMarkers, AreaTriggers, etc.
- Steering: Movement planning and control for bots.
- Utilities: Various useful classes, like Vector3
- Variables: State Variables of all kinds

The optional standard library (packages/library) includes (as of version 1.2 of the extra standard library):

- AutoTargeting: Lets entities target other entities, for example, automatic cannons that shoot at players.
- Chat: Additional chat functionality beyond the basics already present in the engine.
- CustomEffect: More complex, composite effects than those in Effects in the core standard library, for example, fireworks. These are built using those simpler core ones.
- CutScenes: Allows the camera to be controlled, letting you create cutscenes.
- EntityQueries: Improved querying of active entities, over that already existing in LogicEntityStore in the core library.
- Events: More complex actions and action systems, including parallel actions, adding action systems to arbitrary objects (not just entities), etc.
- Firing: Generic system for guns - registering them, using them to fire shots, etc.
- GameManager: A singleton entity that handles the current game. Has optional plugins for game modes and things like intermissions, team balancing, etc.
- Health: Defines health for entities, spawning based on that health, and so forth.
- MapDefaults: The latest version of the 'standard' setup for maps (materials and textures, etc.).
- MultipartRendering: Makes it easier to render multiple models for a single entity (e.g., used for cannons which have a base and a barrel).
- Platforms: Moving platforms that players can jump on and be carried by.
- PlayerList: Manages a list of players for the builtin scoreboard (shown when tab is pressed).
- Plugins: The basis for many of the extra libraries - a system for building new entity classes using plugins, in a flexible way.
- Projectiles: A better version of the Projectiles in the core library (replaces it entirely).
- Roles: A system for 'classes' in a game, like tank, defensive, sniper, etc. (called 'roles' in the code, so as not to confuse with the term 'classes').
- Vehicles: Lets entities move like vehicles instead of like walking characters (the default).
- World: Querying information about the world (like normal vectors), and physics related to that (like reflecting vectors, bouncing physics, etc.)
- WorldSignals: A signal system that lets you connect to and emit signals that are relevant to certain areas in the 3D space.
- ZeroG: Lets you create games without gravity, or control gravity entirely in scripts in a custom manner.
- ai/Steering: A better version of Steering from the core library.
- guns/*: Various example guns, for use with Firing.
- mapelements/Cannons: Static cannons that shoot at players.
- mapelements/JumpPads: Send players in the air when stepped on.
- mapelements/Portals: Show a scene in another world, and teleport players to other game servers.
- mapelements/Teleporters: Teleport within the same world.
- mapelements/WorldAreas: Let you define custom behavior in particular areas of the world, like mouse clicks behaving differently, etc.
- mapelements/WorldNotices: Show some text when players are in some area.
- mapelements/WorldSequences: Let you define sequences that track the player's progress, if the player goes through the areas in the right order
- mapelements/specific/ModelForge: Helps with creating models by letting you test a model easily, as you modify it in an external tool.
- modes/CTF: Capture-the-flag game mode.
- modes/Time: Lets a team get points for time passing.