A to Z Scripting: Special methods

From The DarkMod Wiki
Revision as of 11:06, 21 December 2020 by Dragofer (talk | contribs) (Created page with "== Special methods == This section is devoted to useful applications of various scripting principles and to special cases. === Going through all entities of a certain type ==...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

Special methods

This section is devoted to useful applications of various scripting principles and to special cases.

Going through all entities of a certain type

The getNextEntity() function allows you to find every entity in the map that has a certain spawnarg. It finds one entity at a time, so you'll need to run it many times. Each time it runs you'll have an opportunity to run script events on the entity that was found.

As shown in "Looping scripts", the combination of do + while() is well suited for this application:

//Example script by Obsttorte
void lamps_toggle()				//finds and triggers all electric lamps in the map. They're identified based on the value of the "lightType" spawnarg
{
	light lamp;
	do					//do repeat this...
	{
		lamp = sys.getNextEntity("lightType","AIUSE_LIGHTTYPE_ELECTRIC",lamp);	//find the next entity with this spawnarg; continue the search from the previously discovered lamp entity
		if (lamp != $null_entity) sys.trigger(lamp);
	}	while (lamp != $null_entity);		//repeat for as long as sys.getNextEntity finds electric lights
}


Going through all targets of an entity

numTargets() returns the number of targets that an entity has. This can be combined with "for" to run script events once on every target:

void hide_targets()						//finds all targets of an entity and runs a script event on them (in this case: hide)
{
	float i;						//define a float (i for integer) to keep track of how many targets have been identified

	for(i = 0; i < $func_static_1.numTargets(); i++)	//for every target of func_static_1...
	{
		entity m_target = $func_static_1.getTarget(i);	//store target #i as a variable so we can call an event on it. Will get overwritten by the next target
		m_target.hide();				//call hide() on this target
	}
}


Going through all entities bound to an entity

This is almost identical to going through all targets of an entity. Important is the distinction between bindChildren and bindMasters: bindChildren are lower in the bind hierarchy, bindMasters are higher in the bind hierarchy relative to the entity in question.

void identify_handle()					//goes through all entities bound to a door in order to identify a handle
{
	float i;

	for(i = 0; i < $mover_door_1.numBindChildren(); i++)			
	{
		entity m_bind_child = $mover_door_1.getBindChild(i);		//find the nth bound entity
		if(m_bind_child.getKey("spawnclass") == "CFrobDoorHandle")	//check if this bound entity is a handle. If yes...
		{
			entity m_handle = m_bind_child;				//...store it for later
		}
	}
}

Going through all spawnargs with the same prefix

This works quite similar to going through all entities of a certain type. The difference is that there's a 2nd step: first find the name of the spawnarg, then find the value of that spawnarg.

Example: finding all frob_peers of a door and making sure they're all frobable

void find_peers()
{
	string key;			//name of the spawnarg
	entity frob_peer;		//value of the spawnarg; in this case, it'll be a frob_peer entity

	do
	{
		key 		= $mover_door_1.getNextKey("frob_peer", key);	//find the exact name of the next spawnarg that begins with "frob_peer", starting from the previous result
		frob_peer	= $mover_door_1.getEntityKey(key);		//find the value of this spawnarg, which should be an entity

		if(frob_peer) frob_peer.setFrobable(1);				//if a valid entity has been found, set it to frobable 
	}	while(key);							//keep repeating until this script stops finding valid spawnarg names
}

Note:

  • Alternatively, you could pass getNextKey() an empty string, "". That should make the script find all spawnargs of this entity.


Spawning entities

You can spawn an entity of a specified classname while the map is running. In the same frame, you should also set any custom values that you need for spawnargs. Example:

void spawn_stagecoach()
{
	entity spawned_entity 	= sys.spawn("func_static");		//spawn a "func_static" entity
	spawned_entity.setName("stagecoach");
	spawned_entity.setModel("models/darkmod/misc/carriages/stagecoach.lwo");
	spawned_entity.setOrigin('483 723 41');
}


Doing more with vector variables

Accessing individual components as floats

It's possible to access individual components of a vector by appending _x, _z or _y to the end of the vector variable's name. These will get treated as floats.

Example: teleporting the player up by 16 units from wherever he is now

void teleport_player_up()
{
	vector player_position	= $player1.getOrigin();		//where is the player now? Store as a variable named "player_position"
	player_position_z	= player_position_z + 16;	//increase the z-component (height) of "player_position" by 16

	$player1.setOrigin(player_position);			//set the new origin of the player to the modified "player_position"
}


Getting the magnitude of a vector

Another option is to get the magnitude, or length, of a vector with sys.vecLength(), which turns the vector into a float. This is useful for example in calculating distances or expressing the progress of a mover as a percentage.

Example: checking the progress of a func_mover

void check_progress()
{
	vector start_position 	= '0 0 0';
	vector target_position	= '200 0 0';
	vector current_position	= $func_mover_1.getOrigin();

	float distance_moved 	= sys.vecLength(current_position - start_position);			//how far the mover has moved so far in units
	float percent_progress	= distance_moved / sys.vecLength(target_position - start_position);	//how far the mover has moved so far in percent 
}


Spline movers

A spline is a curved line which is stored on a spline mover entity (misleading name). A regular mover (func_mover) can be scripted to move along this spline. Usually the spline mover is invisible, while the func_mover is visible or has visible entities bound to it.

To create a spline in DarkRadiant, click on the button "Create a NURBS curve" along the left edge of the window. Next to this button there are several other buttons which allow you to append, insert or remove control points from this curve, or convert it into a curve which uses the CatmullRom algorithm instead of NURBS. The control points can be moved around to change the shape of the curve, quite similar to how the control vertices of patches work.

When your spline is finished, create a small ca. 8x8x8 brush textured with textures/common/nodraw around the origin of the curve (make sure you look at it in all 3 axis). Select the brush and right-click > create entity > func_splinemover.

Copy the "curve_Nurbs" or "curve_CatmullRomSpline" spawnarg from the curve, paste it onto the nodraw brush and delete the original curve. You now have a spline. Next you need to create a func_mover with the same origin as the spline. This func_mover can be a visible model, or it can be another nodraw brush to which you can bind a func_smoke particle, which would leave a trail like the wisps in Thief.


You'll now need a script to make the func_mover move along the spline:

void start_spline()
{
	entity spline		= $func_splinemover_2;		//the name of the nodraw splinemover brush carrying the curve data in your map
	entity func_mover	= $func_mover_1;		//the name of the func_mover in your map

	func_mover.time(10);					//let the mover take 10s per lap. Alternatively set speed(), in units per second
	func_mover.disableSplineAngles();			//optional: use this to stop the mover from rotating wildly depending on how the curve is angled
 	sys.threadname("spline_1");				//optional: give this thread a name so the spline mover can be stopped by another script with sys.killthread("spline_1");

	while(1)						//loop the following indefinitely
	{
		func_mover.startSpline(spline);			//start the mover along the spline
	 	sys.waitFor(func_mover);			//wait for the mover to finish its movement
	}
}


Setting up Stim/Response via script

It's possible to apply Stim/Response settings to an entity at run time, rather than doing so manually in DR. This is especially useful for setting up a spawned entity to respond to triggers or frobs. The below example is for setting up an entity to respond to triggering by running "script1":

$func_static_1.ResponseAdd(STIM_TRIGGER);
$func_static_1.ResponseSetAction(STIM_TRIGGER,"script1");
$func_static_1.ResponseEnable(STIM_TRIGGER,1);


Next / previous article