Getting Started with IO Scripting

What EXScript Is

EXScript is the scripting language behind entity I/O connections. Anywhere you’d normally wire an output to an input with a static parameter, you can instead attach a short program in which you can run conditionals, loops, logic, etc.

This guide assumes you’re comfortable with the entity I/O system (outputs, inputs, and connections) from the map editor. If you haven’t messed with the standard IO systems before, it’s probably best to get comfortable first. IO scripting is meant for when simple connections arent expressive enough, not as a replacement.

How to Edit Scripts

With an output highlighted in the Rockwall 2 entity inspector’s outputs tab, you will see a small “Is Scripted Output” toggle. Flicking this on will enable the “Open Script” button just below, which will open a new window where you can edit/type your script.

The Five Reserved Names

Every script has access to five special identifiers by default:

_self

The entity that owns this output/script.

_activator

The entity that triggered this chain, if any. Can be null.

chain

An accessor for the PassVariables present, you can add or view values currently in the chain by indexing it with a string. Covered in Advanced IO Scripting.

globals

Persistent key/value storage that survives across level transitions. Indexed by string.

mapglobals

Key/value storage scoped to the current map. This will be saved along with the map state. Indexed by string.

A First Script

Here’s a script on a button’s OnPressed output that only opens a connected door if the activator is actually a player, and logs anything else that tries:

if (_activator != null && _activator.classname == "Player")
{
    door.Open();
    playsound("Door.Open", door.position);
}
else
{
    print("Something that wasn't a player tried the button.");
}

door here is resolved by targetname, exactly like selecting an entity’s name into a normal connection’s target field — any placed entity’s name is a valid identifier in a script. door.Open() and similar calls forward straight to that entity’s registered inputs, the same as a plain connection would.

Note

Statements end with a semicolon, and blocks use curly braces, just like most C style languages. If you’ve written C#/C++/C before, EXScript’s control flow (if/else, while, for) will already feel very familiar.

Declaring Variables

var declares a normal variable, const declares one that can’t be reassigned:

var attempts = 0;
const maxAttempts = 3;

attempts = attempts + 1;
if (attempts >= maxAttempts)
{
    stopchain();
}

stopchain() halts any remaining connections after this one on the same output — useful for guard clauses like the one above.

Waiting

wait(seconds) pauses the script for that long before continuing, without blocking anything else in the engine:

_self.applyimpulse(vec3(0, 400, 0));
wait(0.5);
playsound("Trap.Reset", _self.position);

Where to Go From Here

This covers the basics — variables, calling entities, waiting, and simple branching. For pass variables, functions, vectors, and the standard library of engine-side functions like phystrace and entitiesinradius, see Advanced IO Scripting. For a complete list of every function and entity member available, see the IO Scripting Reference.