A to Z Scripting: Special methods: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
This section is devoted to useful applications of various scripting principles and to special cases. | This section is devoted to useful applications of various scripting principles and to special cases. | ||
== Going through all entities of a certain type == | == 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. | 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. | ||
Line 19: | Line 21: | ||
== | === ...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: | numTargets() returns the number of targets that an entity has. This can be combined with "for" to run script events once on every target: | ||
Line 34: | Line 36: | ||
== | === ...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. | 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. | ||
Line 52: | Line 54: | ||
== | === ...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. | 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. | ||
Line 86: | Line 88: | ||
} | } | ||
If you plan to use this event often you may want to create a new entity def that contains most of the desired spawnargs | If you plan to use this event often you may want to create a new entity def that contains most of the desired spawnargs so you no longer need to set them in the script. | ||
Revision as of 19:59, 26 December 2020
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); //repeat for as long as sys.getNextEntity finds electric lights }
...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 } }
...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 } } }
...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'); }
If you plan to use this event often you may want to create a new entity def that contains most of the desired spawnargs so you no longer need to set them in the script.
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
- Next article: A to Z Scripting: Scriptobjects
- Previous article: A to Z Scripting: Scripting with...
- Table of contents: A to Z Scripting