GAME CONCEPT AND DESIGN
COSC 320.101_SU09
SUMMER 2009
Some Useful Scripts
This page may be pretty long. I'll try to put sub-links here so you can skip to the places you want to be. I'll think up some useful scripts, explain what they do, then post them for you to copy. During class I'll walk through them as well to kinda get your minds thinking down those lines.
Of course, I'll show the solution to a particular problem, but you might need to alter the solution somewhat to address a concern of your particular game. So...welcome to programming!

Making Changes to the Avatar When It Enters the Game
This is something that we frequently want to do. The default characters come with gold, armor, weapons, and trinkets that we might not want them to have. So we want to catch them when they enter the game and take everything away.
However, as I mentioned earlier (or you may have found out on your own) we cannot use the module's onClientEnter event to do this because even though it will fire when the client logs in to your game...the avatar has not yet landed on your map. So you can't make changes to it during onClientEnter.
One workaround is to put a generic trigger around the starting point. Then, when the avatar actually enters the game and lands on the start point, he will trip the trigger. So, the first thing to have that trigger script do is check to see if the value of a local variable (like "nBeenStripped") is 1. It won't be, because the person just entered the game. So you make your changes to the avatar then set the local variable to 1. If the player enters the trigger again, it'll look for "nBeenStripped," see that it's a 1, and not do anything. Here's a code snippet for that:
object oPlayer = GetEnteringObject( );
int nBeenStripped;
if(GetIsPC(oPlayer) == TRUE)
{
nBeenStripped = GetLocalInt(oPlayer,"BeenStripped");
if(nBeenStripped != 1)
{
//make all your changes
SetLocalInt(oPlayer,"BeenStripped",1);
}
}

Fiddling with the Avatar's Inventory
It's often handy to sort through the player's inventory looking for something...or taking it all away. However, this can be tricky to understand. So let me walk you through the thinking and the process.
- First the player can re-organize his inventory. How would we know what is where?
- He can drop things, he can pick up things.
- There's several slots per page and there's 5 or 6 inventory pages. And if they have bags, those bags have slots. So it's next to impossible for us to know how many items he has.
- Fortunately, NWN does keep track of these things and does have a way of numbering. We don't know what that system is, and we don't really need to.
- So we'll just set up a loop. We'll tell the engine to look at the "first thing" in the inventory. Then we process it. Then we tell the engine to look at the "next thing" in the inventory, and we process that. And we keep looking at the "next thing" until there isn't a next thing.
- When you try to tell NWN to find an object or item and it can't, it often returns the constant variable OBJECT_INVALID. So in our loop above, we keep looking at the "next item" until the next item is OBJECT_INVALID. Once we see that, we exit the loop.
With all that in mind, here's a code example that steps through the player's inventory. Notice it doesn't do anything (that's for you to add), but it does step through it.
object oPlayer; //and you figure out who he is...
object oItem;
oItem = GetFirstItemInInventory(oPlayer);
while(oItem != OBJECT_INVALID)
{
//process the item
oItem = GetNextItemInInventory(oPlayer);
}

Destroying the Inventory Items
Here's the same script but with a line that lets you destroy the items you found.
object oPlayer; //and you figure out who he is...
object oItem;
oItem = GetFirstItemInInventory(oPlayer);
while(oItem != OBJECT_INVALID)
{
DestroyObject(oItem);
oItem = GetNextItemInInventory(oPlayer);
}

Destroying "Non-Destroyable" Items
Sometimes you'll do this and you'll find that upon testing...he's still got some of then junk you are trying to destroy! What gives?
The answer could be either or both of two issues. (There may be more, but these are the two I know.)
- If an item is set to "plot," it can't be destroyed. So we'll using scripting to un-set the "plot" flag. Then we can delete it.
- If an item is equipped, you probably can't destroy it. You'll have to use script to un-equip it first. This has another little trap of figuring out how to step through the "equipment" slots.
The first item is easy. Once you've identified the object use this command:
SetPlotFlag(oItem,FALSE);
It's no longer plot, use DestroyObject(oItem) to kill it.
The second requires a bit more. There are, fortunately, a known number of slots for "equipping" items. And there's a few handy ways of getting that data.
NUM_INVENTORY_SLOTS is a constant for the number of slots that exist. So, theoretically, we just start at slot 1 and work our way to "slot-the-last."
Each of these inventory slots have constant values, such as:
INVENTORY_SLOT_CHEST
INVENTORY_SLOT_HEAD
INVENTORY_SLOT_RIGHTHAND
...and so on. So we could step through each of those.
But there is an easier, niftier way. Each of those slots is a constant and handily, they are integers. Numbers! That means we can use a more-or-less regular loop and look at each slot number to find out what's there. Handily, there's a command that lets us look in numbered slots! And finally, there's a command that lets us force the player/creature to unequip an item.
So we'll set up a loop that looks at each slot. If it finds an item it'll unequip it, then destroy it. Hhere's the code bit:
object oPlayer = <whatever process you used to find the player>;
int nSlot;
object oItem;
for(nSlot = 0;nSlot<NUM_INVENTORY_SLOTS;nSlot++)
{
//look at each slot and see if there's something there
oItem = GetItemInSlot(nSlot,oPlayer);
//if there is, unequip it, then destroy it
if(GetIsObjectValid(oItem) == TRUE)
{
AssignCommand(oPlayer,ActionUnequipItem(oItem));
DestroyObject(oItem);
}
}

Taking Gold From the Player
If you want to do this, we first use a command to find out how much he has, then we destroy it. When we destroy the gold we actually get to decide if the gold goes to the object/NPC that's running the script (FALSE) or if we just make the gold vanish from the game (TRUE).
object oPlayer = <whatever process you used to find the player>;
int nGold = GetGold(oPlayer);
TakeGoldFromCreature(nCoins, oPlayer,TRUE);

Giving Gold To the Player
We've been so mean to the poor player. Let's give him some stuff.
GiveGoldToCreature(oPlayer, 500);

Giving General Inventory Items to the Player
Just as we looked at creating objects to put on the map, now we're going to create inventory items. As you are hopefully guessing, you'll have to know the oCreature (player or NPC) that you're giving the item to, and the resref of the item you're creating.
The template for the command is:
CreateItemOnObject(<resref>,<target>,<stack size>,<new tag>);

Giving Equipable Items and Forcing an Equip Action
In this case we're going to give the item to the player, then force him to equip it. So we need a way to refer to the item after it has been created. Fortunately, the CreateItemOnObject command returns a reference to the new object...if we set ourselves up to "catch" the reference. Once we do that, we use one of the INVENTORY_SLOT_<something> constants to force the equip.
Let's assume we're giving him armor that has the resref of "thorn_armor" and it goes in the chest slot.
object oPlayer = <however you find him>;
object oItem;
oItem = CreateItemOnObject("thorn_armor",oPlayer,,"thorn_armor");
AssignCommand(oPlayer,ActionEquipItem(oItem,INVENTORY_SLOT_CHEST));
Notice the empty commas. The space between them is where the <stack size> goes. We're not stacking (and can't) the armor but we did want to give the new armor a custom tag. So we had to use the reserved space for stacking, even though we left it blank.

Random Walk
Suppose you don't want your creature to just stand at his spawn point, but you don't want to have him walk any waypoints. And you don't want him to get far from where-ever he spawns. You can use ActionRandomWalk( ); to have him wander around where he happens to be at the moment.
object oCreature = <however you find the creature>
AssignCommand(oCreature,ActionRandomWalk( ));
When you issue this command to a creature, it's as if a stake was driven into the map at his location and a leash is put on him. He will wander off in a random direction, but he won't get very far from the stake. Then he'll stop and pause, then wander again...but he'll still stay close to that invisible stake.
AssignCommand( ) is worthy of a look, actually. There are a number of clearly defined "actions" you might want to make a creature carry out. So, you have to "assign" that action to that creature. First is AssignCommand( ) which takes two arguments: the creature you're giving the assignment to, then the actual command. So here, we have two commands...one nested inside the other.

|