Common Tasks

Here are some common scripting tasks.

Ambient Animations

A good place to start with general animations is the switches page here:

http://wendersnaven.com/node/43

The short answer is that you can set the following variables on a creature:

Ambient Animations
X2_L_SPAWN_USE_AMBIENT = 1

Immobile Animations
X2_L_SPAWN_USE_AMBIENT_IMMOBILE

With no waypoints, "X2_L_SPAWN_USE_AMBIENT" includes the familiar wandering around near their spawn point and doing some basic interactions with other NPCs. "X2_L_SPAWN_USE_AMBIENT_IMMOBILE" causes them to do the same interactions (waving, force talking, etc.), but they stay in one place. They will turn to face other NPCs, however.

There are a few waypoints that cause additional behaviors. From x0_i0_amins:

Creatures will move randomly between objects in their
area that have the tag "NW_STOP". (I think there is a % chance of them doing this or the standard wander around.)

UPDATE:  After some testing, it appears the behavior in the next two paragraphs does not work. Generally speaking, waypoints across areas don't work at all in NWN2. They tended to be inconsistent in NWN1, also. Begin incorrect documentation:

 Creatures who are spawned in an area with the "NW_HOME" tag
will mark that area as their home, leave during the day,
and return at night.

Creatures who are spawned in an outdoor area (for instance,
in city streets) will go inside areas that have one of the
interior waypoints (NW_TAVERN, NW_SHOP), if those areas
are connected by an unlocked door. They will come back out
as well.

End incorrect documentation. 

There is a good conversation about ambient animations scripts happening here:

http://nwcitadel.forgottenrealmsweave.org/showthread.php?t=1184

Changing area music with a trigger

qwertyuiop666 asked a question about how one would go about changing the background music in an area when a player walks over a trigger. Here's his question:

I would like to have the music change when the player walks down a path. I am assuming that the best option is to do it from a generic ground trigger to change the music playing when I step on it? I managed to make a trigger that stops the current song. That was easy. I made the ground trigger and then in the "On Enter Script" I just used the "ga_music_stop" script from the drop down.

Shaughn78 and Melirinda were kind enough to give some helpful suggestions. Here is the script that Shaughn78 eventually posted with some minor tweaks for readaiblity:

void main()
{
object oEnter = entering object;
object oArea = GetArea(oEnter);
int nMusic = GetLocalInt (OBJECT_SELF,"music");
int nDefault = GetLocalInt (OBJECT_SELF,"default");
int nCurrent = Get Current Music;
int nOnce = GetLocalInt (OBJECT_SELF,"once");
if(!GetIsPC(oEnter))
{
return;
}
if (nOnce == 0)
{
SetLocalInt (OBJECT_SELF,"once",1);
SetLocalInt (OBJECT_SELF,"default",nCurrent);
}
if(nCurrent != nMusic)
{
MusicBackgroundChangeDay(oArea, nMusic);
}
else
{
MusicBackgroundChangeDay(oArea, nDefault);
}
}

See the full thread here:
http://nwn2forums.bioware.com/forums/viewtopic.html?topic=645938&forum=1...

 

Death and Respawn

There are a number of options out there for dealing with death, but when dealing with respawn, there is one very important thing to know:

The death and respawn event scripts never on Respawn fire when you use the GUI_DEFAULT_DEATH_SCREEN with DisplayGuiScreen. This is the call for nwn_o0_death, the default script for death events.

Both nwn_o0_death and nwn_o0_respawn contain respawn code, but the gui actually uses a callback script named gui_death_respawn. Opening this file through the File > Open script/conversation menu, you'll see that the default death script is:

// gui_death_respawn.nss
/*
Death GUI 'Respawn' callback: wake up groggy
*/
// BMA-OEI 6/29/06


#include "ginc_death"


void main()
{
// Resurrect PC
object oPC = OBJECT_SELF;
WakeUpCreature( oPC );
RemoveDeathScreens( oPC );

// Apply Groggy penalty
effect eGroggy = EffectDazed();
//eGroggy = EffectLinkEffects( EffectSlow(), eGroggy );
ApplyEffectToObject( DURATION_TYPE_TEMPORARY, eGroggy, oPC, RoundsToSeconds( 2 ) );
}

This results in the character standing up right where the died. Generally, it is better to send them to a safe place, such as a standard waypoint with the tag "NW_DEATH_TEMPLE".

For example, here is how Lordniah did his respawn callback script in the FRW base module.

// gui_death_respawn.nss
/*
Death GUI 'Respawn' callback: wake up groggy
*/
// BMA-OEI 6/29/06


#include "ginc_death"


void main()
{
// Resurrect PC
object oPC = OBJECT_SELF;
WakeUpCreature( oPC );
RemoveDeathScreens( oPC );

// Apply Groggy penalty
effect eGroggy = EffectDazed();
//eGroggy = EffectLinkEffects( EffectSlow(), eGroggy );
ApplyEffectToObject( DURATION_TYPE_TEMPORARY, eGroggy, oPC, RoundsToSeconds( 2 ) );


//Jump respawner to temple waypoint if it exists
object oTemple = GetObjectByTag("NW_DEATH_TEMPLE");

if(GetIsObjectValid(oTemple))
{
ClearAllActions(TRUE);
ActionJumpToLocation(GetLocation(oTemple));

}

}

Thanks to Lordniah for putting that comment in his k_module_respawn script that it never fires. Hopefully this info will help someone else out there.

GetGoldPieceValue()

Thanks to cdaulepp and loudent2 for pointing this one out:

When you are using GetGoldPieceValue() on an item to get the value, if the item is not identified the function will return 1.

See the full post here:

GetGoldPieceValue() Does it work correctly?

 

Lugoun's Find and replace a word in a string

Lugoun posted this handy script in the Helpful Scripts thread in the official forums. It allows you to do a find and replace on a string. Just pass in the text you want to perform the find and replace on, the string to find and the string you want to replace it with. His script is below and I've added comments.

// Returns a string based on sStartString where sCurrentWord is replaced by sNewWord 
string FindReplaceSubString(string sStartString, string sCurrentWord, string sNewWord)
{
int nLength = GetStringLength(sStartString);
int nCurrSubLoc = FindSubString(sStartString, sCurrentWord);
string sLeftSide = GetStringLeft(sStartString, nCurrSubLoc);
int nCurrentLength = GetStringLength(sCurrentWord);
int nLeftSideLength = nCurrSubLoc + nCurrentLength;
int nRightSideLength = nLength - nLeftSideLength;
string sRightSide = GetStringRight(sStartString, nRightSideLength);
string sNewString = sLeftSide + sNewWord + sRightSide;
return sNewString;
}

So for instance, you can do a call like this:

string sStartString = "the quick brown fox is quick";
string sNewString = FindReplaceSubString(sStartString, "quick", "slow");

Which would assign sNewString a value of "the slow brown fox is slow".

Making a creature lay down

You can make a creature lay down by placing the following two commands on a dialog node:

ga_play_ca_snd with the sAnim set to "laydownB"
ga_play_custom_animation with the sAnim set to "proneB"

Make them stand up by using:

ga_play_custom_animation with sAnim set to "standupB"

Note that this only work for NPCs you can select via a tag.

Thanks to John B. Gardner's Animation Viewer, where I figured out how to do this.

Making an invisible object cast a spell at the PC

In this thread, puiwaihin was trying to figure out why his invisible creature couldn't cast spells at the PCs. In the end they figured out that anything that is invisible or hidden can't do it.

jackyo123  suggested making the creatures super small instead.

Check it out here:
http://nwn2forums.bioware.com/forums/viewtopic.html?topic=576056&forum=114

NWScript: Giving gold in a conversation

Bemmu over at NWScript.com has created a tutorial that will take you through creating a basic conversation with an attached script to give the PC Speaker some gold.

Tutorial level: very basic

Following along with this tutorial should only take a few minutes. The goal will be to create a new Neverwinter Nights 2 module with one creature in it that you can interact with to receive gold from it.

Click here to view the tutorial:
http://www.nwscript.com/how-to-make-an-npc-give-you-gold.php

NWScript: Levers and doors

Bemmu over at NWScript has created a tutorial for attaching a script to a lever that will open a door.

Tutorial level: very basic

The goal in this tutorial is to create a lever that will cause a door to open when pulled. Following along should be very easy and there will only be about three lines of nwscript (the scripting language in Neverwinter Nights 1 & 2) involved.

Head over to NWScript to check it out:
http://www.nwscript.com/making-a-lever-operated-door.php

NWScript: Object Creation

Bemmu over at NWScript.com has created a tutorial for creating multiple objects in a line using vectors. The object in question happens to be beer!

Tutorial level: basic

A nice feature of virtual worlds is that things can be created out of thin air without cost. In this tutorial we will play a bit with this by creating a sort of beer vending machine, where pulling a lever will add a new beer bottle to the end of an endlessly expanding row of them.

Head over to NWScript to check it out:
http://www.nwscript.com/infinite-beer.php

Scripted Waypoints

A great way to control ambient movement of NPCs is using scripted waypoints. See the sticky thread here:
http://nwn2forums.bioware.com/forums/viewtopic.html?topic=512800&forum=1...

Examples

You can see scripted waypoints at work in the Official Campaign's 1700_Merchant_Quarter.mod and 3000_Neverwinter_A3.mod merchant exterior areas. In module 1700 the road network method is used for ambient commoners (although I could not find the actual script) and in 3000 the dock workers use it.

Here's what Charles Mead (Gameplay Scripter) posted:

Here's some info on a new feature called Scripted Waypoints.

Scripted waypoints builds on the current waypoints system by making the arrival at each waypoint call a script. There are no special requirements for preparing this – it will work with any NPC using the regular default scripts and any new or previously placed set of walkway points.

Quick refresher of the standard waypoint system:
Creatures will automatically walk along a sequence of waypoints that are tagged according to the following convention: “WP_<creature’s tag>_##”. The NPC will begin the journey at waypoint 1 and continue traveling sequentially to waypoint n, and then back again in reverse.

Basic Useage:
In the new “scripted waypoint” system, whenever a creature reaches a waypoint, it calls a script that is named very similarly to the tag used for the waypoints, like this: “wp_<creature’s tag>”. Notice there is just one script for the entire set of waypoints. If the script does not exist, then nothing additional happens and the NPC simply walks back and forth through the set of waypoints.

Below are some examples of “scripted waypoints” scripts:

Example 1.
This script tells the NPC to stop at every waypoint and face in the direction the waypoint is facing and pause 1 second before continuing to the next waypoint.
Notice the inclusion of “ginc_wp” which has a number of helpful functions such as FaceAndPause().

 

#include "ginc_wp"
void main()
{
    int iCurrentWP = GetCurrentWaypoint();
    FaceAndPause(iCurrentWP, 1.0f);
}

Note how we call GetCurrentWaypoint() which returns the waypoint we have just reached. This will typically always be the first thing called in a “scripted waypoints” script.

Example 2.
This is a more complex script that completely overrides the normal waypoint behavior and demonstrates how each waypoint can be individually scripted. It accomplishes the following:
When the NPC reaches waypoint 1, he will sit down for a few seconds, and then randomly travel to one of the other waypoints in the set other than the first.
When the NPC reaches waypoint 2, he will play a “get low” animation, and then proceed to waypoint 1.
When the NPC reaches waypoint 3, he will simply head back to waypoint 1.
If there are more than 3 waypoints in the set, then when the NPC reaches one of those he will behave in the default way.

 
#include "ginc_wp"
 

  
#include "ginc_wp"

void main()
{
int iCurrentWP = GetCurrentWaypoint();
int iNextWP;
switch (iCurrentWP)
{
case 1:
iNextWP = Random(GetNumWaypoints()-1) + 2;
SetNextWaypoint(iNextWP);
ActionPlayAnimation(ANIMATION_LOOPING_SIT_CROSS, 1.0, 7.0);
break;
case 2:
SetNextWaypoint(1);
ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 1.0, 4.0);
break;
case 3:
SetNextWaypoint(1);
break;
}
}

Note in this example the use of SetNextWaypoint(). The “next” waypoint is the one the NPC is enroute to. SetNextWaypoint() allows us to override this and redirect the NPC to an alternate waypoint.

The script template “wp_tag” is available in the script templates directory in source safe. Simply copy and paste it with the proper script name, replacing the word “tag” with the tag of the creature that will be walking waypoints.

*Advanced Usage*
How to have two or more creatures with different tags walk the same set of waypoints:
To override the initial waypoint set a creature uses, simply set a local string variable “WP_TAG” on the creature with the value of the desired waypoint set to use. So, if you have a bear waypoint set for a creature tagged “bear”, you could get a chicken to also walk these waypoints by setting the chicken's local variable WP_TAG to “bear”.
Note that this variable is only checked when the creature is first spawned, so changing this value via script will have no effect.

How to change the set of waypoints a creature walks dynamically:
You can change the set of waypoints a creature walks at any time via script using this function:
object SetWWPController(string sWalkWayPointsTag, object oCreature=OBJECT_SELF);

So from the previous example, we could have our chicken walk the bear’s waypoints by calling this function in script:
SetWWPController(“bear”);

How to pause/restart a creature walking waypoints.
To stop a creature from walking waypoints, use:
SetWalkCondition(NW_WALK_FLAG_PAUSED, TRUE);

You may also want to clear all actions, otherwise, the creature will still complete his pending actions which will take him to whatever the next waypoint is.

To Restart a creature walking waypoints, use:
SetWalkCondition(NW_WALK_FLAG_PAUSED, TRUE);

The creature should get started on his next heartbeat.

How to create a road network:
The basic outline for a script like this is available in the script template “wp_road_walker” and reads as follows:

  
#include "ginc_wp"

const int REDIRECTOR_WP = 1;

void main()
{
int iCurrentWP = GetCurrentWaypoint();// where we are
int iNextWP;
switch (iCurrentWP)
{
case 1:
// Node 1 should be placed off somewhere out of the way. This is where the creatures
// will hang out in between reaching the end of the path and starting on a new path.
// Creatures will change their appearance in between travels.

// 1st param is the list of nodes they may reappear at. Must follow the pattern XX,YY,ZZ...
// 2nd param is the length of time to wait before reappearing.
StandardRedirectorNode("02,03", 5.0f);
break;
case 2:
// Nodes 2 on up define the network the road walkers travel. They will never return to the node
// they just came from. When they reach an end node (typically a door or a route out of the area)
// they will be be "redirector node" - typically node 1.

// 1st param is the list of nodes they may travel to. Must follow the pattern XX,YY,ZZ...
// (end nodes are those with only 1 element in the list)
// 2nd param is the redirector WP
StandardRoadNetworkNode("03", REDIRECTOR_WP);
break;

case 3:
StandardRoadNetworkNode("02", REDIRECTOR_WP);
break;

}
}

Where can I learn more about other thing I can do?
Many useful functions are listed in the prototypes of the include file “ginc_wp”.

 

Sitting

Patcha posted a script to let PCs sit on objects.

I'm providing you the way to let object be "sittable" and the script that allow PC to sit on them!

The file contains:
- the script (in a .erf to import)
- the English tutorial to bring "sittable" objects
- the Italian tutorial (the same)
- a module with many brench and chairs, to test this mothod

Check it out on the vault:
http://nwvault.ign.com/View.php?view=NWN2Scripts.Detail&id=43

Starting a conversation with a placeable

This apparently still uses the old "nw_g0_convplac" from NWN1. Follow these steps:

  1. Start by copying the placeable you want to use. Right click on it and choose "copy blueprint > module". Find it at the bottom of the list and click on it to access its properties.
  2. Change the name, tag, resref as needed in order to keep track of it.
  3. Under the behavior section, set the following:
    • Plot = TRUE (optional, but suggested)
    • Static = FALSE
    • Useable? = TRUE
  4. If you have not already done so, create your conversation file and give it a name. Return to the behaviors section and either paste that name into the "Conversation" field, or use the dropdown to choose it from the list.
  5. Finally, under the Scripts section, set the On Used Script to "nw_g0_convplac"

Test it out and your should get your conversation when you use the placeable.

Treasure

The default treasure generation script seems to be gp_treasure_op_de. It seems to check variables set on the container it is called from. It includes some of the X2 scripts from HotU. I spent some time walking through how this all works.

Note: After playing with this system a bit more, I've found that:
1. The base chance is 50%. This means that unless you set the base chance on an area, you'll get just a few gold just over 50% of the time.
2. The magic treasure type tends to give one or two +1 weapons for a level 1 PC. This may be a bit over-powered for low-level mods.
3. For better customization, consider lordniah's FRW base module's implementation of the NWN1: SoU treasure scripts (For more see http://www.wendersnaven.com/node/98).

gp_treasure_op_de

Here is the header comment, which explains the basics:

// gp_treasure_op_de
/*
    Spawns in general purpose treasure and gold based on variables:

	TreasureClass - one of three values.  Default is low
		const int X2_DTS_CLASS_LOW     = 0;       //Treasure Class Low
		const int X2_DTS_CLASS_MEDIUM  = 1;       //Treasure Clas Medium
		const int X2_DTS_CLASS_HIGH    = 2;       //Treasure Class High

	TreasureType - add desired types together.  For example, gold + disposable = 5
		Defualt is 5 (gold + disp)
		Note that you cannot add the same type more than once (i.e. no gold+gold).
		const int X2_DTS_TYPE_DISP 	= 1;
		const int X2_DTS_TYPE_AMMO	= 2;
		const int X2_DTS_TYPE_GOLD	= 4;       	// actually gold and gems
		(not allowed) const int X2_DTS_TYPE_ITEM	= 8;        // char specific Item (ignores treasure class)
		const int X2_DTS_TYPE_MAGIC	= 16;       // random magic items
		const int X2_DTS_TYPE_MUNDANE = 32;     // random mundane items

	This script should be placed in the container's OnOpen and OnDeath events.
	If bashed, disposeable will be dropped and broken item generated.
	If no treasures are generated, 1d20 gold will be created.
*/

This allows module authors to quickly create random treasure of different types by setting both the "TreasureClass" integer variable and the "TreasureType" integer variable on the container. "TreasureClass" uses a simple 0, 1, or 2. "TreasureType" uses a single number that adds up the type values you want for the container. For example, ammo (2) + gold (4) + magic items (16) would be a value of 22.

An important thing to note is that X2_DTS_TYPE_ITEM (8) is not allowed. Here is the reason given in a comment further down in the script: "these don't scale and are to dangerous for balance reasons to have in the standard treasure generation."

x2_inc_treasure

Our script then calls DTSGenerateTreasureOnContainer(), which is located in "x2_inc_treasure." This script first calls gets a random number of items to create based on the call to DTSGetMaxItems().

Looking at DTSGetMaxItems(), we see that it first looks for the module-level integer variable "X2_DTS_MAXITEMS." If it can't find it, it uses a default of 2. Note that this variable is not set in the switches file or in the default "On Module Load" file, which means the value will be 2 unless you have specifically set it.

Returning to DTSGenerateTreasureOnContainer(), the next step is to call DTSGenerateTreasureItems() for each item we are going to create. This function checks the chances for each of the types of items we told it to create with the variables set on the container. The chance is defined by DTSGetBaseChance(). The default is defined as 50 in the constants at the top of the file, but these can be overridden at the area and module level with the variable "X2_DTS_BASECHANCE." If a class and chance condition is met based on a randomized number, an item is created by DTSGetRandomItemResRef().

Looking at DTSGetRandomItemResRef(), we see that we first have to get the name of the .2da file we want to reference using DTSGet2DANameByType(). This file looks for a module-level string variable, and uses a default if it can't find one.

The variables it looks for are:

  • X2_DTS_TYPE_DISP
  • X2_DTS_TYPE_AMMO
  • X2_DTS_TYPE_ITEM
  • X2_DTS_TYPE_GOLD
  • X2_DTS_TYPE_MAGIC
  • and X2_DTS_TYPE_MUNDANE

(Note that these match the constants uses for the treasure type.)

The default .2da files that will be used are:

  • des_treas_disp
  • des_treas_ammo
  • des_treas_gold
  • des_treas_items
  • des_treas_magic
  • des_treas_mundane

Remember that all these files can be found in Data/2da.zip, in your NWN2 programs files ("C:\Program Files\Atari\Neverwinter Nights 2\Data" by default). Extracting the .zip files to your desktop and opening the .2da files in Microsoft Excel, will reveal how these are laid out. For example, looking at the random magic .2da file (des_treas_magic.2da), will show that the low class items are all +1, the medium class items are +1 and +2, and the high class items are +2, +3 and +4. There is also a very high column, which is probably left over from the epic levels in NWN1: HotU.

Wandering Monsters

Controllore posted a concise answer to using the old HotU "wantering encounter while resting" script.

View the module properties, in the On Module Load event you will see "x2_mod_def_load". Uncomment the line (around 123)

SetModuleSwitch ( MODULE_SWITCH_USE_XP2_RESTSYSTEM, TRUE )

Then where you see

SetWanderingMonster2DAFile( "des_restsystem" )

uncomment it and change "des_restsystem" with any other name you choose.
"des_restsystem" is the name of the 2da file that will be used for the wandering monsters (type, percentage of appearing at daytime/nighttime).
Edit des_restsystem.2da, do your changes and save it with the name you used in x2_mod_def_load.

That should do it.

Edit:
Into your areas, insert a variable named X2_WM_ENCOUNTERTABLE of type string. Its value must be the name used for the TableName in the des_restsystem.2da.

Read the full threat here:
http://nwn2forums.bioware.com/forums/viewtopic.html?topic=535148&forum=1...