A to Z Scripting: Ways of calling a script
TDM has many methods for calling scripts, some overlap with others but there are always subtle differences. Often you can combine systems such as the objective system with scripting in order to get results that wouldn't easily be possible with either system alone.
Some of the methods allow you to pass on to the script which entities were involved in calling the script as input variables. This allows you to write a single script which chooses to do different things depending on who activated it, i.e. you could have a portal chamber where each portal teleports the player to a different destination even though they all call the same script. You could set custom spawnargs on the entities and use them in the scripts.
From other scripts
To call a script from another script, simply write the name of the script followed by input brackets. The script will wait for the called script to finish.
void script2() { script1(); //call script1, wait for script1 to finish }
Alternatively, you can write "thread" in front. Both scripts will run simultaneously, because each one runs in its own thread.
void script2() { thread script1(); //call script1, don't wait }
You can only call scripts that the engine already knows about, so the called script (script1) needs to be higher up than the calling script (script2). If you're using general .script files (A to Z Scripting: Setting up the .script files), the same applies to the order in which you #include your .script files.
The main advantage of calling one script from another is that you can give as much input as you like - if the called script is designed to use input (see A to Z Scripting: Scripts that use input variables for more). Other methods can usually only provide 1 or 2 pieces of input: the entity that called the script (i.e. a trigger brush) and the entity that triggered the calling entity (i.e. a player or AI stepping into the trigger brush).
target_callscriptfunction
You can create an entity in DR called target_callscriptfunction and give it the spawnarg "call" with the name of the script without brackets, i.e. "call" "script1". Whenever this entity is triggered by something, i.e. a button, the script will be called.
These entities are among the most versatile ways to call a script because, with the spawnarg "foreach" "1", they can pass on 3 entities to the script:
- one target of the callscriptfunction entity. The script will get repeated on each target, one by one (that's where "foreach" comes from)
- the entity that triggered the callscriptfunction entity (aka the activator)(i.e. a button)
- the name of the callscriptfunction itself
Basic example: simply calling a script with no input
void script1() { sys.println("script1 has been called."); }
//spawnarg on the callscriptfunction entity: "call" "script1"
Advanced example: teleportation script to teleport targeted entities in 2 directions
Here's a more complex example of a teleportation script that uses all 3 entities:
void teleport_targets_away(entity ent_target, entity ent_button, entity ent_callscriptfunction) { sys.println("the first entity (the target) is " + ent_target.getName()); sys.println("the second entity (the button) is " + ent_button.getName()); sys.println("the third entity (the callscriptfunction) is " + ent_callscriptfunction.getName()); float teleportation_direction = ent_button.getFloatKey("direction"); //find the teleportation direction, stored on the button vector teleportation_vector = ent_callscriptfunction.getVectorKey("vector"); //find the teleportation vector, stored on the callscriptfunction entity if (teleportation_direction == -1) teleportation_vector = -teleportation_vector; //invert the teleportation vector if the direction is backwards ent_target.setOrigin(ent_target.getOrigin() + teleportation_vector); //teleport the target }
The setup in the map would be 2 buttons (1 per direction) targeting a callscriptfunction entity which targets the entities you want to get teleported. The spawnargs are as follows:
- callscriptfunction entity
- spawnarg: "foreach" "1" (so it repeats for every target and passes on its name and the button that triggered it)
- spawnarg: "call" "teleport_targets_away"
- custom spawnarg: "vector", with whatever teleportation vector you want i.e. "450 0 0"
- 2 buttons targeting the callscriptfunction entity
- one button with custom spawnarg: "direction" "1"
- the other with custom spawnarg: "direction" "-1"
Trigger brushes
Trigger brushes are a simple way to call scripts, activated when the player or an AI enters the volume of the brush. For AIs to work you need to set "anyTouch" "1" on the brush. The brush needs a spawnarg "call" with the name of the script without brackets, i.e. "call" "script1". They also trigger all their targets. See Triggers for details on the creation of trigger brushes and the various types.
Most trigger brushes are quite basic, so they can't pass the name of the entity that stepped into them or their own name to the script. The best you can do is target a callscriptfunction entity (see above) instead of calling the script directly on the brush: this way, the script will know the name of the brush that was activated.
A more advanced type of trigger brush is trigger_touch, which detects all AIs/players/moveables in its volume and calls its script on each of them. More on their use in A to Z Scripting: Special methods.
Potential pitfalls with trigger brushes
- AIs will stop activating trigger_multiple brushes if they become stationary.
Path nodes
Many Path Nodes trigger all of their targets whenever an AI reaches them. They can target a target_callscriptfunction entity in order to call a script.
Stim/Response
The Stim/Response system is very versatile, in particular when augmented with scripting.
Responses, i.e. to frobbing
In most cases, you'll likely be interested in only the "Response" tab of the S/R editor interface. This allows you to make an entity respond to certain stimuli, such as a frob, a trigger or water by executing various effects, such as running a script (no input possible). Many other effects are available from the dropdown list.
One common use is to make an entity frobable and give it a "Response" to frobbing with an effect to run a script. To do so, set the spawnarg "frobable" "1" on the entity to make it frobable. Then open the S/R editor, go to the Response tab, in the left half of the window add a "Frob" entry, in the right half of the window right-click and add an effect to "Run script", naming the script you want to run.
To make this single-use you could add another effect to either:
- disable frobability of this entity, specifying _SELF as the entity
- or deactivate the response to frobbing on _SELF. The ID of the frob stim is 0.
Stim and Response
Working with both the "stim" and "response" tabs of the editor lets you make scripts and other effects happen when two entities come near each other. A common example is a water arrow carrying a water stim being shot at a flame carrying a response to water ("extinguish").
Enabling a "stim" on an entity causes that entity to emit the stim to its surroundings. The settings allow you to finetune this, i.e. how often the stim gets emitted, the radius etc.
Meanwhile, using the "response" tab on another entity allows you to define what effects happen when this entity is reached by a stim of that type.
Creating a custom stim type is recommended, unless you explicitly want to do something with an existing stim like water or fire.
Action scripts
Entities can be given spawnargs that make them run scripts when certain actions are performed on them, such as frobbing or using. The value of the spawnarg is the name of the script. Example: "frob_action_script" "script1".
Like with trigger brushes (see earlier), these entities pass their own name to the script function. This allows you to reuse the same spawnarg & script on many entities.
frob_action_script | Calls the specified script when the entity is frobbed by the player. |
use_action_script | Calls the specified script when the player uses an inventory item on the entity (i.e. uses a key on a door). The inventory item must be named in a "used_by" spawnarg on the entity. More info here: Tool, Key, custom used by inventory actions |
equip_action_script | Calls the specified script when the player is holding the entity and uses it (i.e. eating a held apple by pressing enter). |
Action scripts are able to tell which entity was frobbed/used/equipped.
Example for a frob_action_script that removes the entity when the player frobs it:
void destroy_frobbed(entity ent_frobbed) { ent_frobbed.remove(); }
Spawnarg on each entity that should be destroyable: "frob_action_script" "destroy_frobbed"
Signals
Signals are events which can be setup to call a script. Examples of events are the entity being triggered, touched, removed or damaged (but not: frobbing). Some signals only work for movers i.e. when a mover is blocked or a door is closed/opened. See the Signals wiki article for a full list of available signals.
Note that the signal system is old, so the signal for frobbing is called SIG_TOUCH. The SIG_USE signal refers to a player holding an object and pressing the 'use' key (default enter), as far as I'm aware.
To use the signal system, you need to use a script event to instruct the entity to respond to a certain signal by running a certain script. Example:
sys.onSignal(SIG_TRIGGER, $func_static_1, "script1");
You may later want to disable this again. In that case:
sys.clearSignalThread(SIG_TRIGGER, $func_static_1);
Objective system
The Objectives Editor can be seen as a visual scripting editor. Not unsurprisingly it synergises well with scripting.
The main way to use the objective system for scripting is by specifying completion scripts and failure scripts for when an objective is completed or failed. Note that if the objective is reversible, it might call the scripts multiple times.
The objectives system allows you to do some things much more easily than with regular scripting, such as calling a script when reaching a certain page in a book (i.e. playing an ominous sound). Many maps use a mix of hidden objectives and scripts in order to achieve interesting scripted effects.
Location system
The location system (wiki page: Location Settings allows you to call scripts whenever the player enters or leaves specific locations.
It works by setting spawnargs on the info_location entity, with the value being the script's name:
"call_on_entry" "call_on_exit" "call_once_on_entry" "call_once_on_exit"
On the scripting side of things, your script must specify the location where it's called in its input brackets. Note that this is without a $ sign. Example:
void enter_location_streets(entity info_location_streets) //for an info_location entity with the name "info_location_streets"
To my knowledge, this way of setting up means a script can only be called from one location. If you have multiple locations, you will need multiple scripts even if they do the same thing.
Conversation system
There's no direct way to call a script from a conversation, but you can tell one of the actors to activate a callscriptfunction entity.
From the console
This is only for testing purposes because you will no longer be able to save the game after calling a script from the console. The command is the same as when calling a script from another script, i.e. thread name_of_script();
Next / previous article
- Next article: A to Z Scripting: Getting map information
- Previous article: A to Z Scripting: Setting up the .script files
- Table of contents: A to Z Scripting