Difference between revisions of "A to Z Scripting: Looping a script"

From The DarkMod Wiki
Jump to navigationJump to search
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Looping a script ==
== Basics ==
You may want a script to keep repeating until stopped, for as long as a condition stays true, or for a number of times.
You may want a script to keep repeating until stopped, for as long as a condition stays true, or for a number of times.


Line 7: Line 7:




=== Looping with thread ===
== Looping with thread ==
The easiest way to loop is by making the script call itself at the end with "thread". Unlike other methods, this will always repeat the whole script.
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 ====
=== Example: "No harm" objective ===
  void looping_script()
  void looping_script()
  {
  {
Line 20: Line 20:




=== Looping with while() ===
== 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).
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 ====
=== Example: timer for a mover ===
  void mover_timer()
  void mover_timer()
  {
  {
Line 34: Line 34:




=== Repeating with for() ===
== 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).
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).


==== Example: fading a shader parameter on an entity ====
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()
  void materialise()
  {
  {
     float i; //define a float (integer) to keep track of the number of steps
     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
     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
         fade_entity.setShaderParm(5,i); //set shaderParm5 to the current number of steps
Line 51: Line 54:




=== Repeating with do + while() ===
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).
"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 ====
=== Example: running a script on every entity of a certain type ===
  //Script by Obsttorte
  //Script by Obsttorte
  void lamps_toggle() //finds and triggers all electric lamps in the map
  void lamps_toggle() //finds and triggers all electric lamps in the map
Line 62: Line 68:
  {
  {
  lamp = sys.getNextEntity("lightType","AIUSE_LIGHTTYPE_ELECTRIC",lamp); //find the next entity which has this spawnarg value
  lamp = sys.getNextEntity("lightType","AIUSE_LIGHTTYPE_ELECTRIC",lamp); //find the next entity which has this spawnarg value
  if (lamp != $null_entity) sys.trigger(lamp);
  if (lamp) sys.trigger(lamp); //if a valid entity has been found, trigger it
  } while (lamp != $null_entity); //repeat for as long as sys.getNextEntity finds electric lights
  } while (lamp); //repeat for as long as sys.getNextEntity finds valid entities (returns $null_entity if no entity found)
  }
  }




=== Terminating a running script ===
== Terminating a running script ==
==== Terminating with killthread() ====
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 any script by giving it a (thread) name, and letting another script terminate it.
It's possible to manually terminate a script by giving it a thread name, letting another script terminate it.


Example:
Example:
Line 86: Line 95:
  }
  }


==== Terminating with return ====
=== 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]].


Alternatively you can terminate a script with simply "return". This causes the script to terminate.
Example:
Example:
  if ( attempts == 3 ) return;
  if ( attempts == 3 ) return;


== Next / previous article ==
== Next / previous article ==
Line 98: Line 107:
*Previous article: [[A to Z Scripting: Conditionals]]
*Previous article: [[A to Z Scripting: Conditionals]]
*Table of contents: [[A to Z Scripting]]
*Table of contents: [[A to Z Scripting]]
[[Category:Scripting]]

Latest revision as of 18:34, 27 December 2020

Basics

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

	sys.wait(0.5);
	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() )
	 {
 		sys.wait(0.1);
		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.

Example:

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);
	sys.wait(0.5);
}

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.

Example:

if ( attempts == 3 ) return;

Next / previous article