A to Z Scripting: Looping a script

From The DarkMod Wiki
Revision as of 18:34, 27 December 2020 by Dragofer (talk | contribs) (→‎Example: fading a shader parameter on an entity)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search


You may want a script to keep repeating until stopped, for as long as a condition stays true, or for a number of times.

The scripting engine allows up to 10,000 events per frame, so if you're doing something a finite number of times (i.e. checking all entities of a certain type) you can usually do it all in a single frame.

However, if the script should keep running continuously (i.e. for a "No harm" objective) you need to build some kind of wait() event into the script. This avoids that the script tries to run an infinite number of times in a single frame (crash with "runaway loop" error).

Looping with thread

The easiest way to loop is by making the script call itself at the end. Unlike other methods, this will always repeat the entire script. It's probably preferrable to call with "thread" to ensure that old script cycles don't hang around waiting for newer cycles to finish.

Example: "No harm" objective

void looping_script()
	if ( $lord_marlow.getHealth() != 100 ) $player1.setObjectiveState(5, OBJ_FAILED);

	thread looping_script();

Looping with while()

while() lets you loop a script for as long as the condition inside the brackets is true. If it should loop permanently, put a 1 into the brackets (true).

Example: timer for a mover

void mover_timer()
	 while( $box.isMoving() )
		float time_moved = time_moved + 0.1;

Repeating with for()

for() lets a script repeat for a number of times that can be either pre-determined or variable. It's well-suited for gradually making a change in many small steps (increments or decrements).

This method would be preferred if you know in advance how often the script needs to repeat i.e. to fade a shader parameter from 0 to 100 in 100 steps. For an unknown number of repeats, i.e. a search for all entities of a certain type, you'd usually use while() or do+while().

Example: fading a shader parameter on an entity

void materialise()
    float i;					//define a float (integer) to keep track of the number of steps
    for (i=0;i<100;i++)			//go from 0 to (one under) 100, one at a time (100 steps)
        fade_entity.setShaderParm(5,i);	//set shaderParm5 to the current number of steps
        sys.waitFrame();			//wait one frame until the next step

To go in the opposite direction ("dematerialise"), you would decrement as follows:

for (i=100; i>0; i--)

Repeating with do + while()

"Do this script for as long as this condition is met". This one is quite similar to just using while(), the difference is it can begin even if the condition is false at first (the conditional is at the end, not at the beginning).

Example: running a script on every entity of a certain type

//Script by Obsttorte
void lamps_toggle()				//finds and triggers all electric lamps in the map
	light lamp;
	do					//do repeat this...
		lamp = sys.getNextEntity("lightType","AIUSE_LIGHTTYPE_ELECTRIC",lamp);	//find the next entity which has this spawnarg value
		if (lamp) sys.trigger(lamp);	//if a valid entity has been found, trigger it

	}	while (lamp);		//repeat for as long as sys.getNextEntity finds valid entities (returns $null_entity if no entity found)

Terminating a running script

A script can only be terminated if it is designed to be terminated, using one of the following methods.

Terminating with killthread()

It's possible to manually terminate a script by giving it a thread name, letting another script terminate it.


void check_health()
	sys.threadname("looping_script");		//assign a name to this script or thread

	if ( $lord_marlow.getHealth() != 100 ) $player1.setObjectiveState(5, OBJ_FAILED);

void terminate_check_health()
	sys.killthread("looping_script");	//terminate the script that was named "looping_script"

Terminating with return

Alternatively you can terminate a script with simply "return". This causes the script to terminate. Its primary purpose is to make the script return a value as output, which comes into play in A to Z Scripting: Utility scripts.


if ( attempts == 3 ) return;

Next / previous article