A to Z Scripting: More scripting basics: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
No edit summary
No edit summary
Line 1: Line 1:
== More scripting basics ==
== Working tidily ==
=== Working tidily ===
Rule #1 is to keep your scripts tidy and well-commented so they're easy to follow. That includes making liberal use of the 'tab' key, which lets you quickly align your lines.
* Rule #1 is to keep your scripts tidy and well-commented so they're easy to follow. That includes making liberal use of the 'tab' key, which lets you quickly align your lines. Comparison:
//script for reading spawnargs that the mapper has set on a func_mover entity


Comparison 1: script for reading spawnargs that the mapper has set on a func_mover entity
  //bad
  //bad
  vector mover_translate = $wardrobe.getVectorKey("translate");
  vector mover_translate = $wardrobe.getVectorKey("translate");
Line 15: Line 15:




//script for constantly checking if an AI can see the player
Comparison 2: script for constantly checking if an AI can see the player
 
  //bad
  //bad
  void watch_for_player()
  void watch_for_player()
Line 46: Line 45:




=== General tips ===
== General tips ==
* Scripting is case-sensitive.
* Scripting is case-sensitive.
* The scripting engine reads from top to bottom. That makes the order in which scripts and variables are arranged quite important. You can't call a script or use a variable if the engine hasn't seen it defined yet.
* The scripting engine reads from top to bottom. That makes the order in which scripts and variables are arranged quite important. You can't call a script or use a variable if the engine hasn't seen it defined yet.
Line 53: Line 52:




=== Data types ===
== Data types ==
Data type indicates whether something is a text (string), number (float), vector etc. You will always want to be aware of this, since i.e. a script designed to apply a force vector won't work if you give it a string instead of a vector as input.
Data type indicates whether something is a text (string), number (float), vector etc. You will always want to be aware of this, since i.e. a script designed to apply a force vector won't work if you give it a string instead of a vector as input.


Line 74: Line 73:




=== Variables ===
== Variables ==


Variables are an important part of scripting. Each variable stores a piece of data, such as an entity's name or a position, which can then be modified or used by a script event. They allow a single script to have various effects, depending on the values of the variables.
Variables are an important part of scripting. Each variable stores a piece of data, such as an entity's name or a position, which can then be modified or used by a script event. They allow a single script to have various effects, depending on the values of the variables.




==== Creating new variables ====
=== Creating new variables ===


The first time the engine finds a variable in a script it needs to be given a data type. Afterwards you use just the name.  
The first time the engine finds a variable in a script it needs to be given a data type. Afterwards you use just the name.  
Example:
Example:
  vector teleportation_destination; //create a new vector variable called "teleportation_destination"
  vector teleportation_destination; //create a new vector variable called "teleportation_destination"
  ...
  ...
  $player1.setOrigin(teleportation_destination);
  $player1.setOrigin(teleportation_destination);
 


You may also want to assign an initial value. Otherwise, floats will default to 0, strings to "", vectors to '0 0 0' and entities to $null_entity.
You may also want to assign an initial value. Otherwise, floats will default to 0, strings to "", vectors to '0 0 0' and entities to $null_entity.
Line 92: Line 91:
  vector teleportation_destination = '44 68 122';
  vector teleportation_destination = '44 68 122';


Another option is to define a variable using the output of a script event.
Another option is to create a variable using the output of a script event.
3 Examples:
3 Examples:
  vector teleportation_destination = $func_static_1.getOrigin();
  vector teleportation_destination = $func_static_1.getOrigin();
   
   
  float can_see = $guard_westwing_1.canSee($player1);
  float can_see = $guard_westwing_1.canSee($player1);
   
   
  float sound_duration = $entity1.startSound("snd_move", SND_CHANNEL_ANY, false);  //stores the duration of the sound that's been started
  float sound_duration = $entity1.startSound("snd_move", SND_CHANNEL_ANY, false);  //stores the duration of the sound that's been started






==== Where to create variables ====
=== Where to create variables ===
It's important whether you create a variable inside of a script or outside.
It's important whether you create a variable inside of a script or outside.


Line 120: Line 119:
  {
  {
  $func_mover_1.speed(30);
  $func_mover_1.speed(30);
$func_mover_1.moveToPos(target_position);
$func_mover_1.moveToPos(target_position);
  }
  }






==== Simple maths with variables ====
== Basic maths ==
=== Basic maths symbols ===
You can use basic maths symbols, as well as brackets:
{| class="wikitable"
|-
! symbol !! effect !! can be used with
|-
| + || add/combine || floats, vectors, strings
|-
| - || subtract || floats, vectors
|-
| * || multiply || floats
|-
| / || divide || floats
|}
 
=== The = sign ===
An important difference is what the = sign does. In scripting, = means "set", while == means "equals".
teleport_destination = '20 20 20'; //set teleport_destination to '20 20 20'
float1 = float2 + float3; //set float1 to the sum of float2 and float3
if ( float1 == float2 ) //check if float1 is equal to float2
 
=== Combinations ===
You can freely combine script events, variables and numbers in one line like this:
teleport_destination = $player1.getOrigin() + teleportation_offset + '0 0 16';
 
Strings can be cobbled together from strings, floats and vectors with the + sign. This is quite useful for sending helpful messages to the console:
sys.println(entity1 + " is at the location " + position1);
 
 
=== Increasing/decreasing ===
Increasing (incrementing) a variable's value by 1 would work like this:
counter = counter + 1; //set "counter" to: the current value of "counter" + 1
 
An alternative method to increase a variable by 1 is:
counter++; //increase "counter" by 1
counter--; //decrease "counter" by 1
 


=== Vectors ===
You can access individual components of a vector variable by appending _x, _y or _z to the name, i.e. teleport_destination_z. These will be floats.


Vector multiplication requires special script events: DotProduct() and CrossProduct().


More on vectors and what you can do with them in [[A to Z Scripting: Special methods]].




==== Example: puzzle with max 3 attempts ====
== Example: puzzle with max 3 attempts ==


Say you wanted to give a player 3 attempts to solve an optional puzzle, with an option to reset his number of attempts:
Say you wanted to give a player 3 attempts to solve an optional puzzle, with an option to reset his number of attempts:


  float attempts_left = 3; //the starting number of attempts the player can make, defined as a float
  float attempts_left = 3; //the starting number of attempts the player can make, created as a float
   
   
  void attempt_failed() //called every time the player fails an attempt
  void attempt_failed() //called every time the player fails an attempt
Line 154: Line 194:




=== Using the TDM Script Reference ===
== Using the TDM Script Reference ==





Revision as of 15:28, 21 December 2020

Working tidily

Rule #1 is to keep your scripts tidy and well-commented so they're easy to follow. That includes making liberal use of the 'tab' key, which lets you quickly align your lines.


Comparison 1: script for reading spawnargs that the mapper has set on a func_mover entity

//bad
vector mover_translate	= $wardrobe.getVectorKey("translate");
vector mover_rotate = $wardrobe.getVectorKey("rotate");
float mover_time = $wardrobe.getFloatKey("move_time");
//better
vector	mover_translate	= $wardrobe.getVectorKey("translate");
vector	mover_rotate	= $wardrobe.getVectorKey("rotate");
float	mover_time	= $wardrobe.getFloatKey("move_time");	//time taken to move


Comparison 2: script for constantly checking if an AI can see the player

//bad
void watch_for_player()
{
while(1)
{
if($lord_marlow.canSee($player1)
{
$lord_marlow.bark("snd_i_see_you");
return;
}
sys.wait(0.5);
}
}
//better
void watch_for_player()
{
	while($player1.getLocation() == $master_bedroom)	//for as long as the player is in the master bedroom...
	{
		if($lord_marlow.canSee($player1)		//check if Lord Marlow can see the player
		{
			$lord_marlow.bark("snd_i_see_you");	//if yes, make Marlow say something to the player
			return;					//then end this script
		}
		sys.wait(0.5);					//wait 0.5s before checking again
	}
}


General tips

  • Scripting is case-sensitive.
  • The scripting engine reads from top to bottom. That makes the order in which scripts and variables are arranged quite important. You can't call a script or use a variable if the engine hasn't seen it defined yet.
  • The $ sign instructs the engine to look for an entity ingame with that name. If there's no $ sign, the engine will instead look for a variable with that name in the scripts.
  • Commenting can be done either by putting // in front of every line of comment, or by putting /* at the top and */ at the bottom. The latter is useful for multi-line comments or temporarily disabling a section of your script.


Data types

Data type indicates whether something is a text (string), number (float), vector etc. You will always want to be aware of this, since i.e. a script designed to apply a force vector won't work if you give it a string instead of a vector as input.

String A string of letters/numbers, in other words plain text. It must always have double quotation marks. Example: “Text message 123”
Float A float is a single number, decimals are allowed. Example: 15.2
Vector A vector consists of 3 numbers, often used for 3D movements (x y z) or colors (red green blue). It must always have single quotation marks. Example: '0 90 0'
Boolean Can be true or false. Easily replaced by floats (0 or 1). Example: TRUE
Void No type. Commonly used for scripts or script events that have no output.
Entity Indicates an entity, usually using the name as seen in DR. If it's a specific entity, instead of a variable, then a $ sign is required. Example: $player1
Subcategories of “entity” You can be more specific and define an entity as, for example, an ai, light or tdm_elevator. These are names of scriptobjects, and by defining an entity like this you gain access to that scriptobject's internal variables and scripts. For an "ai", useful internal variables are i.e. whether the AI is alerted or knocked out. (see A to Z Scripting: Scripting with... - "AI flags" for more)


Variables

Variables are an important part of scripting. Each variable stores a piece of data, such as an entity's name or a position, which can then be modified or used by a script event. They allow a single script to have various effects, depending on the values of the variables.


Creating new variables

The first time the engine finds a variable in a script it needs to be given a data type. Afterwards you use just the name. Example:

vector teleportation_destination;			//create a new vector variable called "teleportation_destination"
...
$player1.setOrigin(teleportation_destination);


You may also want to assign an initial value. Otherwise, floats will default to 0, strings to "", vectors to '0 0 0' and entities to $null_entity. Example:

vector teleportation_destination = '44 68 122';

Another option is to create a variable using the output of a script event. 3 Examples:

vector teleportation_destination	= $func_static_1.getOrigin();

float can_see				= $guard_westwing_1.canSee($player1);

float sound_duration 			= $entity1.startSound("snd_move", SND_CHANNEL_ANY, false);  //stores the duration of the sound that's been started


Where to create variables

It's important whether you create a variable inside of a script or outside.

If it's created inside of a script, only that script can use it. Also, every time you run the script the variable will reset to the value that you created it with. Example:

void count_targets()		//counts how many targets there are on a relay entity
{
	float number_of_targets = $trigger_relay_1.getNumTargets();
}


If it's created outside of a script, all scripts that come afterwards will be able to use it (remember that the engine reads from top to bottom). Note that you can't run script events outside of scripts. Example:

vector target_position = '48 93 222';

void move_to_position()
{
	$func_mover_1.speed(30);
	$func_mover_1.moveToPos(target_position);
}


Basic maths

Basic maths symbols

You can use basic maths symbols, as well as brackets:

symbol effect can be used with
+ add/combine floats, vectors, strings
- subtract floats, vectors
* multiply floats
/ divide floats

The = sign

An important difference is what the = sign does. In scripting, = means "set", while == means "equals".

teleport_destination	= '20 20 20';		//set teleport_destination to '20 20 20'
float1 			= float2 + float3;	//set float1 to the sum of float2 and float3
if ( float1 == float2 )				//check if float1 is equal to float2

Combinations

You can freely combine script events, variables and numbers in one line like this:

teleport_destination = $player1.getOrigin() + teleportation_offset + '0 0 16';

Strings can be cobbled together from strings, floats and vectors with the + sign. This is quite useful for sending helpful messages to the console:

sys.println(entity1 + " is at the location " + position1);


Increasing/decreasing

Increasing (incrementing) a variable's value by 1 would work like this:

counter = counter + 1;		//set "counter" to: the current value of "counter" + 1

An alternative method to increase a variable by 1 is:

counter++;			//increase "counter" by 1
counter--;			//decrease "counter" by 1


Vectors

You can access individual components of a vector variable by appending _x, _y or _z to the name, i.e. teleport_destination_z. These will be floats.

Vector multiplication requires special script events: DotProduct() and CrossProduct().

More on vectors and what you can do with them in A to Z Scripting: Special methods.


Example: puzzle with max 3 attempts

Say you wanted to give a player 3 attempts to solve an optional puzzle, with an option to reset his number of attempts:

float attempts_left = 3;		//the starting number of attempts the player can make, created as a float

void attempt_failed()			//called every time the player fails an attempt
{
	attempts_left	= attempts_left - 1; 			//reduce the number of attempts left by 1

	if (attempts_left == 0) $puzzle.setFrobable(0);		//if no more attempts, make the puzzle entity unfrobable
}

void reset_attempts()				//calling this resets the player's attempts
{
	attempts_left = 3;

	$puzzle.setFrobable(1);			//also make sure the puzzle entity is frobable
}



Using the TDM Script Reference

The TDM Script Reference is an essential wiki resource for scripting, listing all available script events for the current version of TDM. All script events are listed twice: the first time they're sorted alphabetically, the second time they're grouped based on which kinds of entities they can be called on. By far not all script events have received manual descriptions, so sometimes you may need to experiment with them to properly figure them out.

Here is an example entry:

scriptEvent float canSee(entity ent);

    no description

    Spawnclasses responding to this event: idAI

Interpretation:

  • the script event canSee() is suitable for being called on AIs.
  • an entity must be entered into its input bracket. The event calls this entity "ent", but this name doesn't matter to the scripter
  • the script event returns a float. This means you could for example store the result of this check in a float variable and use that elsewhere in your scripting.


It might take some experimentation to figure out which entity the script event should be called on and which entity should go into the input brackets. In the end it could look something like this:

$guard_westwing_1.canSee($player1);


Alternatively, if you want to store the result as a variable (that we name "guard_sees_player") for later use:

float	guard_sees_player = $guard_westwing_1.canSee($player1);		//if you haven't defined the "guard_sees_player" variable yet


Next / previous article