Main Menu

Site Home Page

Glossary of Terms

Current Class Mod Package

Divider

Help! My mod is corrupted!

Divider

Week of June 15th, 2009

Topics:

  • Getting Help
    • The "Assistance" windows
    • The Lexicon
    • The Forums
  • Variables
    • Type-casting and the types
    • Conventions
    • Constants
  • Who Dun' It?
    • Who Spoke?
    • Who Used the Placeable?
    • Who Activated the Item?
    • Who Crossed the Trigger? Who Entered the Area?
    • Was it a Player? a DM?
  • Creating Objects
    • Preparing the Object
      • The Resref
      • The Object Type
    • At a Waypoint
      • Find the Waypoint
      • Find the Location
    • Where the player is
      • Find the Location
    • Create the Object
      • Deciding on a Tag
      • Spawning in the Object
      • Doing Things to the Object after Creation
  • Tracking Variables
    • Local Variables
    • Persistent Variables
  • Some Useful Scripts
    • Making Changes to the Avatar When It Enters the Game
    • Fiddling with the Avatar's Inventory
    • Destroying the Inventory Items
    • Destroying "Non-Destroyable" Items
    • Taking Gold From the Player
    • Giving Gold To the Player
    • Giving General Inventory Items to the Player
    • Giving Equipable Items and Forcing an Equip Action
    • Random Walk

Homework: Dungeon and Quest

Divider

Week of June 7th, 2009

Topics:

  • Items
    • Properties
    • Building your own items
    • How to make an item have a conversation.
  • Creatures
    • Properties
    • Building your own
  • Triggers
    • Choosing the right one
    • Drawing a trigger
    • Trigger Properties
    • Trigger Events and Scripting Preview
    • Examples of Trigger Use
  • Waypoints
    • Waypoint Properties
    • Waypoint Directions
    • Uses for Waypoints
    • Scripting Preview
    • How to Set Up a Patrol Route
  • Conversations
    • How they're used
    • The basic tree.
    • Branching
    • Links (or "Loop backs")
    • Tokens: Built-in and Custom
    • Colorizing the Text
    • Including Other Speakers
    • "Actions Taken" and other events
    • Conditional Nodes
  • The Journal
    • Categories
    • Entries
    • Updating the Journal through Conversations
    • Updating the Journal through Scripting
  • How to Test Your Mod
    • The Build Module Option.
    • The Real Way
    • The Test Module Option

Homework:


Divider

Week of June 1st, 2009

Topics:

  • Areas
    • Area Properties
    • Module Properties
  • Tiles
    • Tile Properties
  • Names
    • Blueprint / Resref
    • Tag
    • Display Name
  • Doors
    • Door Properties
    • Transitions between doors
    • How to make a door close itself
    • How to have a transition without a door
  • Placeables
    • Placeable properties
    • Spawning placeables.
    • How to stack placeables
    • How to have a placeable hold a conversation

Homework:

Divider

May 27, 2009

Topics

Homework

 

 

GAME CONCEPT AND DESIGN
COSC 320.101_SU09
SUMMER 2009


Tracking Variables

One of the things you'll find that you need to do is track variables. Has the player talked to a particular NPC? Has he read a book that he needs to read before he can claim to have "learned" the recipe? ...and so forth. The only real way to do that is by setting variables and flags so that you can check them later.

This can be problematical because, as I mentioned last time, all the scripts are local scripts and have no real knowledge of any other scripts. And in a multiplayer game, you could have different players doing different things--all at the same time--causing scripts to fire in all sorts of orders. So, let's look at a way to deal with variables in order to allow yourself the ability to keep track of what the players have done.

Local Variables

What we're going to do is "attach" a variable to a player. Once it's attached, it stays attached even after the script that set it stops running. So you can set the variable in one script and then--a long time later--another script can check that variable and allow you to decide what to do depending on the result that you find. Do note, however, that if the player logs off or goes link-dead then all your custom variable attachments are lost. (There are ways and there are ways to get around this...and I'll touch on them...but basically consider them lost.)

So, the two commands we're going to look at to do this is SetLocal<type> and GetLocal<type>.

By the way, when I'm teaching programming, you'll often see me put words in angle-brackets like that. That means "something goes here, but it'll be whatever you determine." For instance, if we're creating an object I'll say: CreateObject(OBJECT_TYPE_PLACEABLE, "<your resref>" .....); Clearly, you wouldn't actually type in <your resref>...instead you would substitute your data in that place.

Ok..back to the commands. Remember when I talked about variables and how they're data-typed as int, float, and so forth? Well, when you attach a variable to an object, you have to tell NWN what type of variable you're attaching. So the actual commands are:

  • SetLocalInt to attach an integer.
  • SetLocalFloat to attach a float.
  • SetLocalLocation to attach a location variable
  • SetLocalObject to attach a reference to an object
  • SetLocalString to attach a string.

Makes sense, eh? To fully use the command you have to then specify the object you're attaching the variable to, the "name" of the variable, and the value you want to set it to.

So let's assume that you've got a quest that has 5 steps that the player must complete in order. You'd then want to keep track of which step she's on. So let's say she's just talked to an NPC that sets up the quest. One of the lines in the conversation fires a script and we're going to use that script to track that she's done step number one. Your conversation script might look like this:

void main( )
{
   object oPlayer = GetPCSpeaker( );

   SetLocalInt(oPlayer,"CurrentStep",1);
}

That's all there is to it. Now a variable named "CurrentStep" has been set equal to 1 and has been attached to oPlayer.

Now, later on, she's got to talk to a second NPC. If she has not talked to the first NPC, the second one will just say "Hello" and basically ignore her. However, if she has talked to the first one then the second will give her more information. The thought-sequence for you, the programmer, is:

  • Check the status of CurrentStep
  • If CurrentStep = 0, just say "hello"
  • If CurrentStep = 1, give new data and set CurrentStep = 2

We'll use GetLocalInt( ) to recover the value of "CurrentStep". Therefore, the code snippet (pseudo-code warning!) is:

object oPlayer = <GetPlayerIdentity>;
int nCurrentStep = GetLocalInt(oPlayer,"CurrentStep");

if(nCurrentStep != 1)
{
   //NPC just says Hello
}
else
{
   //it is 1, so we'll do our other stuff
   //NPC gives more data
   SetLocalInt(oPlayer,"CurrentStep",2);
}

So you can see that your various scripts can check the value of "CurrentStep," do whatever you need to do, then set the variable to a new number.

Persistent Variables

When NWN was first released, we world builders were upset to learn that there was no way to have a persistant world. Local variables were lost when the player left the game or the server went down. So each time a player entered the game--as far as NWN was concerned--it was the first time!

We came up with a few ways to work around the issue, but none were very pretty. Let me share them with you!

1: First we have the issue of players losing the local data when they leave the game. This can be worked around by attaching the variables to a placeable rather than the player character. So we'd create an invisible object placeable somewhere and call it...MasterData...or something similar, and we'd attach the variables to that. So if "Jessica" advanced the "ChickenQuest" to step 3, we'd get her name then use string manipulation to add her name to the quest name and that would become our variable. Then we'd attach that variable to MasterData and set the value. Something like:

string sPlayerName = GetName(oPlayer); //assuming you can get it somewhere
string sVariable = sPlayerName + "_ChickenQuest";
object oMasterData = GetObjectByTag("MasterData");

SetLocalString(oMasterData,sVariable,3);

And we've done it. Now the variable isn't stored on the avatar, it's stored on MasterData.

So when it came time to check the status of the quest, of course, we didn't check her. Instead we built the reference to the variable as above and we'd use GetLocalInt( ) off of MasterData.

This worked pretty good except---as you well know--computers crash including the server! And if that happened, or if the server was brought down to do an update, then all those variables on MasterData were lost too.

2: So then we dreamed up making small inventory items and giving them to the player as "markers" of their progress. So I'd make an item with the tag "ChickenQuest_1" and another with "ChickenQuest_2"...and so on. Then I could

  • Check the player's inventory and find out which item number he had.
  • Take that item away.
  • Give him the next in line.

The nice part was that this gave us a form of persistance because inventory items were kept between sessions (as long as we made it so the player couldn't sell / drop / destroy the marker). The bad parts were:

  • If I had lots of quests and each quest had lots of steps, my Custom Items palette grew to unwieldy proportions.
  • Even if I used "inventory small" items (only 1 square), each marker still used up a square. And if I had lots of quests that the player could work on simultaneously, I could rapidly eat up a lot of inventory space with 1-square markers.

3: Bioware eventually gave in and added primitive database support and commands that would allow the server to write and read data to/from a database. These variables were called "Campaign" variables and worked more-or-less like SetLocal<var> and GetLocal<var>. The thing was slow and cumbersome, but at long last we had persistence.

4: Some intrepid "hackers" created an add-on to NWN that gave us some new commands and the ability to use a slicker, faster, MySQL-type database. You can find that at http://www.nwnx.org/