Robert Straughan - Capture Glory: Miscellaneous/Reference

Anything Else?


There are one or two things I haven't done in this tutorial, which I'm quickly going to explain. There are also many nuances in the scripting language, but they really take practice to find. I've made a mention of one here.


Firstly, the important conditional statement that I missed out in this tutorial was the switch/case statement. Consider the script "cave_garbage"


In it, there's a long list of if statements. This entire piece could have been replaced by a switch/case statement. Now that you've got that in mind, let me show you a typical OnUserDefined script.


//Example script
void main()
{
     int nCall = GetUserDefinedEventNumber();
     switch (nCall)
     {
          case 1001: 
               ActionSpeakString("This is my heartbeat event.");
               break;
          case 1002:
               ActionSpeakString ("I have perceived something.");
               break; 
    }
}

Now, this script is the equivalent of two if statements. I get an integer value called nCall, which is based on the number determined by the function. I then put that into the parameter of the switch.


The brackets after the switch are like the brackets after an if statement. In here, we place an integer value (note that we can only use integer values in a switch/case statement. Remember that some integers are represented by string constants, and these are still valid with switch/case).


What the switch effectively does is run down the lines of code, and says if (nParameter == nCase). So it will run down the list of case statements, and look for the one which matchs the parameter.


Also note the use of the break command. This can be used to break out of any loop or conditional statement, without actually ending the script (making it different to return).


It is used in switch/case statements, because although the switch searches down the case statements for the value which matches its parameter, and won't run any script until it finds that value, it will then continue running all script beneath that case line which matches the parameter.


So if I have a large list of case statements, but don't put a break command in, when the switch is run, it will run all the lines below that case, even if some are within other case statements, which you probably don't want it to do.


So in the above example, it gets the calling UserDefinedEventNumber, and then checks to see if it has some script to run according to what number it got. In these examples the numbers are defined by the OnSpawn script for the creature involved.


This is a simple method of keeping long lists of if statements neat and tidy, and also reducing the amount of processing the script has to do, since all those if conditional statements have been reduced to one.


Okay, so I've shown you switch/case, and I've shown you break. I'm also going to show you the other variable type that I haven't used, which is vectors.


A vector is made up of three co-ordinates. They are the x-, y- and z-axis values of any object within an area. Generally, you'll only have to deal with them in one form, that of a vector variable.


You can however split them up if you wish, using the 'dot' operator, as follows:


//Example script
void main()
{
     object oTarget;
     vector vVector = GetPosition(oTarget);
     float fX = vVector.x;
     float fY = vVector.y;
     float fZ = vVector.z;
     vector vNewVector = Vector(fX, fY, fZ);
}

This script gets a vector of an object, pulls it apart, then puts it back together under a new name. That's all there is to a vector really. It's useful if you want to get exact positions, or if you wish to create a new location from scratch.


I'm also going to show you a useful function for conversation files.


//Definition of SetCustomToken function
void SetCustomToken(int nCustomTokenNumber, string sTokenValue)

This function can be used to define a custom token of a given value to a set string. Generally, you determine the number when writing the conversation, and then use the StartingConditional script to run this function (since we need to set it before it appears to the player).


You place the token into the conversation with , where ## is the number of the custom token you have just set. You are not limited to two-digits, but as you are about to read, you must have at least that many.


It's useful if you want to insert information that you don't necessarily know at the time of writing the conversation. The editor already has some predefined tokens, such as , , etc. These get information based on the PC speaking to them.


Why have I included this? Because there's a small nuance that, if you didn't know about it, you could spend forever debugging a script with this function in, and never find a problem. For the custom token number, you cannot use 0-9, as these are reserved numbers.



Common Errors


The compiler is your friend. It will usually tell you if you've made a mistake with your script. The most common error is simply syntax. Misspellings, mistypings, or misuse of variables/functions, or something as simple as missing out a bracket or semi-colon, can all be the problem you're looking for.


Here are a few errors that I got when writing this module:


PARSING VARIABLE LIST - common one, usually meaning you've missed a semi-colon at the end of a line.


IF CANNOT BE FOLLOWED BY NULL STATEMENT - This means you've got an if statement where you've placed a semi-colon immediately after it, instead of having the curly brackets.


VARIABLE DEFINED WITHOUT TYPE - This usually means you forgot to declare a variable before you used it in the script.


ARITHMETIC OPERATION HAS INVALID OPERANDS - This appears when you are trying to do some maths (eg + or -) with variables that are of different variable types, such as trying to add an integer to a float.


NOT ALL CONTROL PATHS RETURN A VALUE - This is found when you are using custom functions, and means you have a conditional statement within your function, where the return command is within the conditional, meaning there's a chance that no return command will be run.


RETURN TYPE AND FUNCTION TYPE MISMATCH - This is also found when using custom functions. It means you've returned the wrong type of variable with the return command, as opposed to what kind of variable you said the function would return.


SKIPPING DECLARATION VIA CASE STATEMENT DISALLOWED - This appears when you use a switch/case statement. You cannot declare any variables within a switch/case statement, they must be declare outside of it (since it's a conditional, so there's a chance it might not get declared).



Tada


Phew. We got there. I may not have explained everything in as great a detail as I could, but to be honest, all that there is to learn about scripting is the basics.


What did I say at the beginning?


"Scripting is like LEGO."


All that I can really teach you is how to put the bricks together. The rest is down to you. Your imagination tells you what you want, and your logical thought tells you how to get there using the basic building techniques.


There is nothing else to it, beyond practice. I could go into lengthy detail about each and every function, and their nuances, but that would take forever.


Just always remember, start with the basics, and build them up to get the complex end result. That's all there ever is to it (any nuances that you run into are not usually a fault of learning, the language or even your logic, more often than not its because of the game engine itself).


If you want a final task, try to build your own module that does everything this one did. Here's the checklist I had when designing this:


  • Must have custom OnDying, OnDeath and OnRespawn rules
  • Must have at least one custom item power
  • Must have at least one henchman
  • Must have at least one scripted sequence of events
  • Must have a multiple creature spawning script
  • Must have at least one puzzle
  • Must have a immersive event which has nothing to do with the player but adds flavour to the current activities (in this one, it was the giant)


For Your Reference


Here are a bunch of useful things you may wish to get hold of when building your Neverwinter Nights Modules.


My Stuff


  • Design Guides (http://www.telarnia.com/index.php?navbar=Telarnia&main=Guides)
  • Downloadable ERFs/Mods (http://www.telarnia.com/erfs.php?navbar=Telarnia)
  • Freebies (http://www.telarnia.com/index.php?navbar=Telarnia&main=Free)

Community Content


  • Celowin's Tutorials (http://nwn.bioware.com/forums/viewtopic.html?topic=81523&forum=47) - These are some excellent little tutorials on how to use scripting. If you've tried this tutorial, you may wish to cover these, as they may explain things a bit better than I have. [Celowin's tutorals also appear in the tutorials section of the Lexicon --Ed.]
  • The Scripter's Guild (http://nwn.bioware.com/guilds_registry/viewguild.html?gid=1110) - The best way to learn scripting is to practice, and this guild allows community members to pull together and share their scripting knowledge, both with asking questions, and answering them.
  • Eligio's Custom Content Guide (http://nwvault.ign.com/Files/other/data/1037585865411.shtml) - Useful guide for building all manner of custom content.
  • Memetic AI (http://www.memeticai.org/) - The AI supplied with the game suffices for simple combat, but is not the best. Many different AI's have been written to replace the default one, but currently this one looks to be the best available. You may wish to experiment based on what you're after, and what level skill of scripting you possess.
  • Custom Scripts courtesy of the NWVault (http://nwvault.ign.com/Files/scripts/) - The Vault has many useful custom scripts written by scripters in the community. If you're having trouble writing a script, try searching the Vault, somebody may have written a script which does what you want.


Writer's Information


If you have questions, email me at jazael@telarnia.com, or send me a PM on the Bioware forum site (username: Jazael). Alternatively, for live scripting help, you can usually find me in the IRC chat room #nwscript found on the server irc.nwconnections.com.


Practice Makes Perfect


Just keep on scripting, and you'll get the hang of it. And remember, always take a break from scripting at least every half an hour, or you'll start seeing the world like Neo does at the end of the Matrix.



Screenshots





 author: Robert Straughan, editor: Charles Feduke