Scripting FAQ

This list of scripting frequently asked questions (and answers) covers some common questions that are not easily categorized elsewhere.

How to apply a visual effect?
The answer to this could be so vast that is actually constitutes its own tutorial. All the effects are applied basically the same way, however. You use either ApplyEffectAtLocation or ApplyEffectToObject.

It is a huge learning curve as some effects will not apply to some objects and some will not apply to locations. Also, some require a DURATION_TYPE of INSTANT while some require a DURATION_TYPE of PERMANENT. It's all a matter of trial and error really. If it will not work one way, try it another.

Here is a simple basic script that can be put into a OnEnter of a trigger to see how the basics of it works.

void main {   object oPC = GetEnteringObject; if(!GetIsPC(oPC))return; effect eDurationEffect = EffectVisualEffect(VFX_DUR_GLOBE_INVULNERABILITY); effect eInstantEffect = EffectVisualEffect(VFX_FNF_METEOR_SWARM); ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDurationEffect,oPC,60.0); ApplyEffectToObject(DURATION_TYPE_INSTANT,eInstantEffect,oPC); }

It applies 2 different effects to the PC that enters the trigger. You will notice one is applied TEMPORAY and one is applied INSTANT. This is because the visual VFX_DUR_* are Duration effects and can be applied TEMPORARY or PERMANENT. The VFX_FNF_* visuals are Fire-and-Forget visuals and can only be applied Instantly.

How to combine multiple scripts in one event?
The frustrating way is to copy and paste all the scripts in to one and pray just before hitting the "compile" button. Chances are, they won't compile for several reasons.

I found it much easier to do it the following way instead. I'll use the OnHartbeat handle for example and lets say I have 3 scripts I want to combine.


 * Save each script with its own name (i.e "hartbeat_01", "hartbeat_02", "hartbeat_03" or whatever you desire)


 * In the Actual OnHartbeat in which you want all of these to run, write a new script like this one.

void main {   ExecuteScript("hartbeat_01",OBJECT_SELF); ExecuteScript("hartbeat_02",OBJECT_SELF); ExecuteScript("hartbeat_03",OBJECT_SELF); }

That's all there is to it! Now they each run in the OnHartbeat of the object, area, or module they are attached to without you having to "re-script" to get them to compile.

How to set a local variable (on a PC)?
There are many ways to set a local variable on a PC. The most common method is setting it from a conversation to keep track of quests or to keep track of where the conversation is leading to, etc.

Actions taken
This is a simple script that would be placed in the "Actions Taken" script node of the PC's response line that the player chooses. For example: PC - "Yes, I accept your Quest".

void main {   object oPC = GetPCSpeaker; SetLocalInt(oPC,"Quest_Taken",1); }

You can set the name of the "Quest_Taken" to anything you want and you can set the number 1, to anything you want. This way you can keep track of what part of the quest the PC is on by using the same "Quest_Taken" name and increment the number by 1 each time. This also sets the variable on the PC object, so he/she carries it with him/her, so to speak.

Text appears When
To check and see if the PC has that variable set from a conversation, you would need a script in the "Text appears When" script node on the line you want displayed in the conversation if the PC has that quest.

int StartingConditional {   object oPC = GetPCSpeaker; if(GetLocalInt(oPC,"Quest_Taken") == 1) return TRUE; return FALSE; }

This will return TRUE and the Text will display if the PC speaking has the Variable "Quest_Taken" set to 1.

How to specify which immobile animations a creature uses?
You can use the ActionPlayAnimation(int, float, float) function.

To follow your example, you could add this to the Performers OnHartbeat script,

ActionPlayAnimation(ANIMATION_FIREFORGET_GREETING); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,1.0); ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,1.0); ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,1.0); ActionPlayAnimation(ANIMATION_FIREFORGET_TAUNT); ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);

This is probably the most you would get into a OnHartbeat, If it loops before the previous OnHartbeat actions are compleat, you will soon see a lot of lag.

Note the ANIMATION_FIREFORGET* types don't need a "duration" time because it is not used for those types. the Looping Animations need one to so the NPC knows how long they should do the animation for.

How to tell if items belong to this module?
Checking the ResRef with  is probably the easiest way, if not the best way to do this. If all items in a given module have a certain code in their ResRef (such as having all ResRefs begin with a certain prefix), then any item whose ResRef does not begin with that prefix is not a custom item for that module. (Standard items' ResRefs begin with "nw_", "x0_", "x1_", or "x2_".) It is also possible to have the code vary based upon some determined criteria, such as a different code for each base item type.

However, there is no real fool-proof way of doing this, particularly if the intent is to find items custom-made by a player (instead of items merely acquired in a previous module). So local vault servers (where this question usually comes up) probably should consider a different approach to whatever problem they are trying to solve.

How to use the SoU projectile traps?
For this example, I'll make a Deadly Dart Trap.


 * On the Right Palett, select "Triggers", then "Traps > Deadly > Projectile Trap Trigger, Dart".
 * Draw the trigger where ever you want it. If you open the trigger propeties, you can make adjustments as you wish.
 * NOTE THE TRIGGER TAG! for this example, it should be "X0_TRAP_DART". Change it if you wish, but remember what the TAG is.
 * Now, you can use one of the Projectile trap object placeables if you whish, but this can really be any placeable you want to use, even an invisable object. Select a placable and place it where you want the projectile to come from.
 * Most important The TAG of the placeable must match the TAG of the Trigger. In this case, my placeable will also have the tag of "X0_TRAP_DART". The placeable should be marked static, but doesn't have to be. If you changed the TAG of the Trigger, be sure to use the same TAG here.

Thats all there is to it really.

What does the question mark mean?
The question mark (?) is called the ternary conditional and is a form of selection, much like an if/else assignment. The Lexicon has a brief but informative article covering the basic syntax.

You are probably familiar with using an if/else statement to check some condition and assign one of two values to a variable depending on the result: the ternary conditional does the same thing using just one line! Therefore if used wisely the ternary conditional can simplify or clarify some scripts. However it is one of the less well-known constructs exercise caution and comment well.

For example, if you wanted check if a number was odd or even you might write the following script: string sResult; // determine if number is odd or even using modulus if(nNumber % 2) {   sResult = "Odd"; } else {   sResult = "Even"; }

and while there is nothing wrong with that you might find it a little less cumbersome to rewrite it using the ternary conditional:

// determine if number is odd or even using modulus string sResult = (nNumber % 2) ? "Odd" : "Even";

You can also nest ternary conditionals: much in the same way as you can with an if/else if/else statement. However I would generally advise against this as it tends to result in greater confusion rather than greater clarity.

For example, if you wanted check if a number was positive, negative or zero you might write the following script:

string sResult; // determine if number is odd or even using modulo if(nNumber > 0) {   sResult = "Positive"; } else if(nNumber < 0) {   sResult = "Negative"; } else {   sResult = " Zero "; }

which again could be rewritten:

// determine if number is positive, negative or zero string sResult = (nNumber > 0) ? "Positive" : (nNumber < 0) ? "Negative" : "Zero";