View Full Version : In-Depth Custom Functions

Fair Strides 2
11-19-2012, 11:53 PM
First off, let me get something straight: This IS NOT intended to insult or otherwise "put down" Qui-Gon Glenn's tutorial in any way. I simply couldn't get the hang of it from him, and it took me a good while to learn it from the NWN Lexicon myself.

Now that we have that out of the way, let's get started.

If you want to make a custom function, you need to understand the basics. Rather than repeat all of it here, I'll re-direct you to Qui-Gon Glenn's tutorial (http://www.lucasforums.com/showthread.php?t=208533) first. If you still don't get it or want more info, come back here.


Okay, now let's get more in-depth. For this tutorial, I'll be using a custom function of my own creation to detail the process. I'm not one for using comments, but recently I've been trying to change that, so I'll be adding more comments than usual here. There are 7 different types of data you can use to make a function. A function's prefix
tells you what type of function it is, and incidentally, if it will return anything and what it returns.

A list of data types(Unless otherwise noted, it returns a piece of data of the same type):void Returns nothing. Does what it’s supposed to and stops.
int Short for ‘integer’, any whole number.
float Any number that has a decimal point in it.
object Any physical thing(a chair, person, or equipment).
vector Your 3D position(your x,y, z coordinates on a plane).
location Made up of your vector, and the direction you're facing.
string Anything within quotoation marks(for example, “Go!Go!GO!”).

Note: There is a data type called “struct”, but it is used to reference information, not to make a function.struct Characters
// Here I am declaring 11 NPCs as strings, to represent their names.
// in a struct, you can only declare the variables, not assign data, which in this case is text.
string NPC0;
string NPC1;
string NPC2;
string NPC3;
string NPC4;
string NPC5;
string NPC6;
string NPC7;
string NPC8;
string NPC9;
string NPC10;
string NPC11;

// You can access a single part of a struct with the period( . ) symbol. An example is:

void main()
// declare the struct as a string, to access it
string Characters;

// access the string NPC0 and make it mean “Atton”
Characters.NPC0 = “Atton”;

// Put the newly-named string into a meeage
string message = Character.NPC0;
// send that message to your feedback screen in-game
SendMessageToPC(GetFirstPC(), message);

And a struct must be placed before any functions, so I suggest at the top of the file, after any includes.

An example of what I mean is:

void FindPlayer(string sFindertag, string sPlayer = "<FullName>")

// In this example, the data type, or function prefix if you prefer, is void. Void functions return nothing, so this function
// will do something involving finding the player and then end.

After the datatype, you have the name of the function you're trying to create, which in this case is 'FindPlayer'. A thing to note for future scripting:it is common practice to capitalize the first letter of each word in the name of the function. For one thing, it makes it easier to sift through a hundred or so lines of text and watch out for
'FindPlayer' compared to 'Findplayer' or 'findplayer'.

Now that you have the data type and name of the custom function, you might have noticed the text inside the parentheses and wondered what it was all about. You don’t have to add those, but it makes your scripting much easier and makes it so your script can be used in other scripts without problems arising. There are some cases where you shouldn’t even have to use them, but these are rare.

The text inside the parentheses are called parameters,, though most people call them variables or inputs. You can specify those in your function with the parentheses, and then access them within your script. Here’s an example:

void FindPlayer(string sFindertag, string sPlayer = "<FullName>")
object oFinder = GetObjectByTag(sFindertag);
object oHunted = SWMG_GetObjectByName(sPlayer);

In this example, I have made it possible for the script to find an object with the string ‘sFindertag’ and automatically assign it to the object ‘oFinder’. The same with string ‘sPlayer’, though it might look weird to you and I’ll get to it in a minute. Because I can now make ‘oFinder’ whatever I want by changing ‘sFindertag’, this script can now be used anywhere, with only that small modification.

Now for those still wondering about why ‘string sPlayer’ looks weird or why I pointed that out, I’ll explain. When making a script, you can use “=” symbol, minus the quotes, to assign a default to that piece of data in the script. If you do this, you don’t have to input that data every single time you use the script, just if you want it to be something different. The thing to watch out for is a matter of precedence:

// You can have this just fine
void FindPlayer(string sFindertag, string sPlayer=”<FullName>”)

// and use it in a script
FindPlayer(“c_boma01“); // Notice that I didn't put sPlayer in here!

// this will automatically make the boma attack the user-created player.
//But if the script were wrote like this:
void FindPlayer(string sPlayer=”<FullName>”, string sFindertag)

// you couldn’t use it in a script in the same way, because this:
FindPlayer(, “c_boma01“);

// is not valid syntax. You’d have to define sPlayer every time. Because of this, it is best to put the variables that have defaults at the end of a custom function.

So, after we have all of our parameters declared and know how to use them, we can now detail what we want to happen to our data, which in this case are our objects ‘oFinder’ and ‘oHunted’.

ChangeToStandardFaction(oFinder, 1);

SendMessageToPC(GetFirstPC(), sPlayer);
AssignCommand(oFinder, ActionAttack(oHunted));

The first part, about changing the faction, simply makes oFinder(the guy we declared with ‘string sFindertag’) hostile.

The second part is a common thing when trying to make your own functions.
I use the SendMessageToPC function as a debugging(error-finding) tool when I make my functions. Since the SendMessageToPC function sends a message to your feedback screen in-game, it is a common practice, at least on my part, to set up little “checkpoints” all throughout a custom function so that you can have an overview of what happens, gets skipped, or where things stop in your function. In this case, I was setting up the “checkpoint” so that I would know if I could use a token inside of a function, which I can.

The last part makes oFinder attack oHunted, which by my default, is the character you create at the start of the game.

The entire script, which does work by the way, is:
void FindPlayer(string sFindertag, string sPlayer = "<FullName>")
// Was called "SearchForPlayer" in the Lexicon; I added the parameters.
// Makes an object matching sFindertag visually search for a specific NPC
// and attacks them.
object oFinder = GetObjectByTag(sFindertag);
object oHunted = SWMG_GetObjectByName(sPlayer);

ChangeToStandardFaction(oFinder, 1);

SendMessageToPC(GetFirstPC(), sPlayer);
AssignCommand(oFinder, ActionAttack(oHunted));

You can make any function you want, limited only by your creativity and the ingenuity of all of the members at Holowan Labs here. You can make a function to find the money of you party, add a puppet, or as the above has shown you, make somebody attack a character. In theory, my tutorial has helped you, and if not, then I would have to advise you to look up the custom functions section in the NWN Lexicon.

You can PM me on here, at Deadlystream, or ask me for my email, if you have questions, advice, or you just want to praise me(mind you, that last is low priority; my goal is to help you, not make my ego grow).