A to Z Scripting: Ways of calling a script

From The DarkMod Wiki
Revision as of 09:39, 22 December 2020 by Dragofer (talk | contribs)
Jump to navigationJump to search

TDM has many methods for calling scripts. Often you can combine systems such as the objective system with scripting in order to get powerful results that wouldn't easily be possible otherwise. Some methods overlap, but there are subtle differences that justify each method in specific situations. For example a frob_action_script can be applied with a single spawnarg, while a frob response can be deactivated.

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).


Trigger brushes

Trigger brushes are a common 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". See Triggers for details on the creation of trigger brushes and the various types.

Optionally, you can give the script up to 2 pieces of information: the entity which stepped into the brush and the brush itself. This is done by creating entity variables inside the script's input brackets and using them in the script. If you only create 1 entity variable, it'll be the entity that stepped into the brush.

This lets you do things like "teleport every entity stepping into the brush to here", and if multiple brushes call the same script you can put custom spawnargs on each brush that get looked up by the script to customise what happens, i.e. let each brush teleport to a different destination.

Example: multiple trigger brushes teleporting entities, each brush uses a different destination

void teleportation_brush(entity activator, entity trigger_brush)
{
	vector destination = trigger_brush.getVectorKey("teleport_destination");	//get the value of the "teleport_destination spawnarg on the calling brush
	activator.setOrigin(destination);		//teleport the entity that stepped into the brush to that position

	//for testing: send a message to the console about what the script is doing
	sys.println(activator + " has stepped into " + trigger_brush + ", teleporting to " + destination);
}

Spawnargs on the trigger brushes:

"call" "teleportation_brush"
"teleport_destination" "120 43 82"	//this is a custom spawnarg you made up yourself. Each brush would have a different value.


Potential pitfalls with trigger brushes

  • AIs will stop activating trigger_multiple brushes if they become stationary.
  • Trigger_touch brushes can be resource-intensive if continuously active. It's recommended to use a separate script to activate them only for a single frame, then switch them off again.


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. Whenever this entity is triggered, i.e. by a button or if an AI reaches a path_node that targets this, the script will be called. As far as I'm aware, it's not possible to pass any input parameters when calling a script this way.

Example:

The script in the .script file:

void script1()
{
...
}

The spawnarg on the target_callscriptfunction entity in DR:

"call" "script1" 


Path nodes

Many Path Nodes trigger all of their non-path-node 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.

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. 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
  • or deactivate the response to frobbing (the ID of the frob stim is 0).


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).


Signals

Signals are events which can be setup to call a script. Examples of events are the entity being triggered, frobbed, removed or damaged. 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.


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