In the previous lesson I mentioned that the Player could "interupt" your scripted commands by moving before the jump occurred. I have tested and so far I haven't found this to be an issue in NWN2, so this might only be an issue with NWN1. I will cover how to correct this for those of you following along with NWN1 at the end of this lesson - but first I want to cover the DelayCommand() function and add a few things to our script.

There is absolutely no way to "delay" a script. A script will execute within a split second in it's entirety regardless of how many delays you have in it. All commands within the script are then carried out. However you can delay how fast commands within your script are executed. There are 2 ways to do this, one is with the ActionWait() function and the other is the DelayCommand() function. These 2 functions are not the same. The first one is an action and is loaded into an objects Action queue and executed in order with all other actions. This command is used to make an object "wait". For example, a NPC; you may tell an NPC to "Unlock a door" then "wait 10 seconds" then "Open the Door". You would make them wait by using ActionWait(). The DelayCommand() function instructs the game to delay the execution of a command. For example if you want a chest to explode in a ball of fire, but not until 10 seconds after a PC enters a trigger, you would use DelayCommand(). It is important to note that because the script executes in full, the Delays do not stack. For example, lets assume I want 3 things to happen each 3 seconds apart. Some might think that the script would look like this;

Thinking that SomeCommand(1) would happen 3 seconds after the script executes, then SomeCommand(2) would happen 3 seconds after SomeCommand(1), and someCommand(3) would happen 3 seconds after SomeCommand(2). This is NOT the case. Instead, all three commands would happen at the same time - 3 seconds after the script executes. So the Delays would need to be set up such as this;

It's easy to see that the DelayCommand() function starts it's timer at the end of the script, not after the previous DelayCommand().

 

The syntax for DelayCommand() is simple;

        DelayCommand( float fSeconds, action aActionToDelay);

 

fSeconds is any float value in seconds. A Float is a number that can have a decimal point., ie. 1.0, 3.56, 2.2 are all valid values for fSeconds.

aActionToDelay can be any function that doesn't return a value In other words, you can delay any function that returns a void data type. Note that aActionToDelay is misleading, this parameter does not need to be an action but rather any function that returns void. For example CreateObject() returns a object data type and therefore cannot be delayed using DelayCommand(). Later in an advanced topic, I will show you how to create a wrapper so functions such as CreateObject() can be delayed.

 

I want to point out that there is one function that never need to be delayed. That function is DestroyObject(). If you look at the function discription notes in the script editor, you will see that there is a Delay parameter built into that function. That is; DestroyObject(oObject,fDealy); So using Delaycommand() with DestroyObject() would be redundant.

 

Ok, Open your toolset and load up the "tutorial_3" lesson. Go to "file > Save As" and save it as "tutorial_4". Now lets revise our concept once more,

We will freeze the players "surprise" animation by applying the VFX_DUR_FREEZE_ANIMATION effect, this will allow us to make the PC walk towards the chest without changing animations visually. The PC will appear to be drawn in by the lighting beam effect. To do this, we are going to need to use the DelayCommand() Function.

 

First create another effect variable called eFreeze, for this we will need to construct a visual effect. Typing "visual" in the script assist filter you will see a function called "EffectVisualEffect". This simply creates an effect that is only seen visually. You could create a visual fireball effect this way and no damage would be delt, the players would only see the blast. This effect is good for constructing you own spell and such, using it in combination with other effects.

Now we need to apply this effect, but first we need to figure out the timing. Note: the timings specified here may not match the timings that work for you. The delays will depend a lot on the size of your trigger vs the size of my trigger - that is, the time it takes for the PC to walk to the chest. So don't worry if you need a longer or shorter time to make it work right. Looking at the script, we want to apply this new effect after the PC starts the animation, and we want to make the PC start to walk towards the chest after we apply the effect. So, lets add those lines in now, then we will come back and add in the delays. we will also need to make the beam effect last longer, because now it will take more time before the Player jumps to the inside of the chest. On Line 17, change the eBeam duration to 7.0. Also we will be applying the eFreeze effect the same way we did the eBeam effect. The duration needs to be long enough so the player stays frozen until the jump. I set the duration to 8.0 seconds, depending on your trigger size and how long it will take for the player to reach the chest - you may need to alter these durations.

Now  that we have what we need in the right place, lets go back and add in the delays so it don't all happen at once. On line 18, add DelayCommand(0.8, in front of the ApplyEffectToObject function - don't forget to add a closing parenthesis at the end of the line as well. You can increase or decrease the delay as you like, I picked 8 tenths of a second so the player will freeze in some odd distorted position. We want the player to do the next action (ActionMoveToObject) slightly after the freeze effect is applied. So add this to line 19, DelayCommand(0.9, again don't forget to close the parenthesis at the end of the line. Now, we don't want the player jumping to soon, so we need to also delay the ActionJumpToObject line so it is loaded into the Players Action Queue last. This delay needs to be slightly longer than the previous delay, modify line 21 so it is delayed 1.0 seconds. Our entire script should now look like this;

Compile the script, save your mod, and test it out. What you should see when your PC enters the trigger is this; The PC should be hit by the lighting, then play the animation for a short time and freeze in an obscure position. Then slowly be drawn towards the chest while still froze. once the PC reaches the chest, the transition should happen. You might need to adjust some of the delays to get the timing right so it looks good.

 

For NWN1 users:

         During testing, when your PC gets hit by the lighting and freezes, you would be able to click anywhere and move to that location. this in effect cancels the Jump action and the transition will fail. To prevent this from happening, we will need to add in a SetCommandable() function. This function toggles an objects action queue ON and OFF. When ON, object can carry out commands such as actions but when OFF, objects cannot be affected by actions or any other commands. It can be used to block all commands to an object effectively preventing the player from canceling the characters scripted actions. NWN2 users can do this as well just to sure, but in testing I haven't been able to interrupt the scripted actions. Before I get into the SetCommandable function I need to make it clear that you MUST have a way to set the PC commendable again, otherwise the player will not be able to move or do anything after that. A common way to ensure the PC re-gains control is to load the function, setting them back to commandable as an action with ActionDoCommand(). This function will load another function into the objects action queue, therfore we can make the player object set them self back to commandable. Also, we need to do this backwards as we will need to load the Players action queue first, including the command to set them self back to commandable, then set them to non-commandable.

 

After line 21, we will add another DelayCommand slightly longer than the last action loaded to the queue.

         DelayCommand(1.1,AssignCommand(ActionDoCommand(SetCommandable(TRUE,oEnter))));

This will load itself into the players action queue as the last action to set the player back to commandable thus giving control back to the player. Now on the next line we need to make the Player non-commandable so the player can't interrupt the scripted actions. This too needs to be delayed, we can't set the player to non-commandable before all the actions are loaded into the action queue. So, because the last action was delayed 1.1 seconds, we need to delay this at least 1.2 seconds.

         DelayCommand(1.2,SetCommandable(FALSE,oEnter));

Now it is possible that the player could still cancel things out by clicking within that 1.2 seconds. But by the time the player figures out what is going on and reacts, they will probably be too late. There is also a way around that issue in situations where the delays are even longer, but that is more in the advanced field of scripting.

Thus if you have added these lines, your script should look like this;

NWN2 scripters challenge: An added feature to NWN2 is the ability to scale objects, as we learned in the making of this tutorial. Scaling can be applied threw scripting as well and it also applies to player characters. See if you can create another effect to scale the PC down as they approach the chest adding to the illusion that the player is being shrunk to fit inside the chest. Note that you will not want to shrink the PC smaller than 0.5, as this makes them so small you can't see them. I went no smaller than 0.6. Hint: Use DURATION_TYPE_TEMPORARY so the PC is back to normal size when they enter the chest.

 

Now that we have our completed script, compare it to our concept. try to associate the functions in the script to the sentences in the concept. This is all part of learning to read a script. You should find that the script correlates to the concept. Use this bases of writing out your concept to help you determine what functions you need to write the script. It can make things much easier.

 

Next lesson, we will need a way for the player to get out of the chest, we will do that threw a conversation.