Compiler Error Messages

From NWN Lexicon
Jump to: navigation, search

This is a list of some reasons why the compiler will produce certain error messages. It does not cover all possible error messages, nor does it identify every possible cause for each of the messages discussed.

When the compiler outputs an error message, it will include the line number in the script where the error was detected. Sometimes the code mistake that is causing the message is actually located on the line preceding the one identified in the message. The location of the mistake is most likely on the identified line or the preceding line. It is rare that the mistake is elsewhere in the script, but it can happen, particularly when the mistake involves the curly braces ({}), which are used to group several code statements into sections called code-blocks. When a code statement spans several lines and the mistake was actually made in the previous code statement, the line displayed in the error message could also be a few lines off. The compiler will never spit out an error identifying some line when the actual mistake is located on a line past the line number shown in the error message. The code mistake will always be either on the identified line or somewhere before it.

Information icon.png Note: this list is incomplete. Some error messages are not covered in this guide.

ARITHMETIC OPERATOR HAS INVALID OPERANDS

Error Message Meaning Example

An operation is being attempted to obtain the result of an arithmetic computation involving two operands. One or both of the operands are not valid for the arithmetic operation being attempted.

Typically the data type of the operand(s) is incorrect for the operator being used, or the data type of the two operands is not the same type.

// Incorrect:
string sMsg = "The number of months in a year is " + 12;

The problem is the arithmetic operator "+" is being used in an attempt to add a string-type value with an int-type value. All arithmetic operators require that both operands have the same data type.

// Correct:
string sMsg = "The number of months in a year is " + IntToString(12);

Resolved by converting the int-type value into a string.

COMPARISON TEST HAS INVALID OPERANDS

Error Message Meaning Example

An operation is being attempted to obtain the result of a comparison involving two operands. One or both of the operands are not valid for the logical operation being attempted.

Typically the data type of the operand(s) is incorrect for the operator being used, or the data type of the two operands is not the same type.

// Incorrect:
if ("Some string" != 12) return;

The problem is the logical comparison operator "!=" is being used in an attempt to test whether a string-type value is not equivalent to an int-type value. All logical operators require that both operands have the same data type.

// Correct:
if ("Some string" != "12") return;

Resolved by converting the int-type value into a string.

CONST KEYWORD CANNOT BE USED ON NON-GLOBAL VARIABLES

Error Message Meaning Example

An attempt is being made to define a constant identifier using the const keyword from within a local function body scope.

All constants must be defined in the script global scope outside of all function body definitions.

// Incorrect:
void MyFunction(object oObject)
{
    const float MY_FLOAT_CONSTANT = 22.0;
    ...
}

void main()
{
    const int MY_INT_CONSTANT = 22;
    ...
}

The problem is that neither of the two constants MY_FLOAT_CONSTANT and MY_INT_CONSTANT is being defined in the script global scope context. MY_FLOAT_CONSTANT is being defined inside a custom function body, and MY_INT_CONSTANT is being defined inside the main function body.

// Correct:
const float MY_FLOAT_CONSTANT = 22.0;
const int   MY_INT_CONSTANT   = 22;

void MyFunction( object oObject )
{ 
    ...
}

void main()
{ 
    ...
}

Resolved by moving the constant definitions outside all function bodies into the script global scope context.

DECLARATION DOES NOT MATCH PARAMETERS

Error Message Meaning Example

The parameters passed in the function call do not match up with the what the function expects (as specified in the function's definition).

Typically the data type of one or more of the parameters being passed does not match the expected data type. Sometimes the number of expected parameters does not match the number being passed in.

// Incorrect:
void MyCustomFunction(object oCreature, location lLocation)
{
    ...
}

void main()
{
    object   oPC       = GetLastUsedBy();
    object   oWaypoint = GetNearestObjectByTag("WaypointTag", oPC);
    location lWaypoint = GetLocation(oWaypoint);

    MyCustomFunction(lWaypoint, oPC);
    MyCustomFunction(oPC, oWaypoint);
}

The problem is that the custom function MyCustomFunction() is defined at the top to expect two parameters. The first one must be an object data type and the second one must be a location data type. But when the function is called from within the main function body, the parameters being passed in do not match datatype-wise. In the first call, they are being passed in backwards. The first one passed is a location and the second one an object. In the second call the data type of the second parameter passed is an object but the function expects a location type there.

// Correct:
void MyCustomFunction(object oCreature, location lLocation)
{
    ...
}

void main()
{
    object   oPC       = GetLastUsedBy();
    object   oWaypoint = GetNearestObjectByTag( "WaypointTag", oPC );
    location lWaypoint = GetLocation( oWaypoint );

    MyCustomFunction(oPC, lWaypoint);
    MyCustomFunction(oPC, GetLocation(oWaypoint));
}

Resolved by passing parameters of the correct data type in the order expected.




// Incorrect:
void MyCustomFunction(object oCreature, location lLocation)
{
    ...
}

void main()
{
    object   oPC       = GetLastUsedBy();
    object   oWaypoint = GetNearestObjectByTag("WaypointTag", oPC);
    location lWaypoint = GetLocation(oWaypoint);

    MyCustomFunction(OBJECT_INVALID);
    MyCustomFunction(oPC, lWaypoint, TRUE);
}

The problem is that the custom function MyCustomFunction() is defined at the top to expect two parameters. But when the function is called from within the main function body, the wrong number of parameters are being passed in. In the first call, only one parameter is being passed. In the second call three are supplied.

// Correct:
void MyCustomFunction(object oCreature, location lLocation)
{
    ...
}

void main()
{
    object   oPC       = GetLastUsedBy();
    object   oWaypoint = GetNearestObjectByTag("WaypointTag", oPC);
    location lWaypoint = GetLocation(oWaypoint);

    MyCustomFunction(OBJECT_INVALID, GetLocation(oPC));
    MyCustomFunction(oPC, lWaypoint);
}

Resolved by passing the correct number of parameters expected by the function.

DUPLICATE FUNCTION IMPLEMENTATION

Error Message Meaning Example

Every event handler script (or script called from an event handler script using the ExecuteScript() statement) must have one and only one main function. This error indicates that the script has defined more than one function named "main".

Typically caused by using the #include directive to include a script that is not a library script but rather a regular event handler script with its own main function defined within. Scripts written to be used as object event handlers must have a main function defined in them. Scripts written to be used as libraries added to a script through the use of the #include directive must not have a main function defined in them.

// Incorrect:

// Some script called "my_script"
void MyCustomFunction()
{
    ...
}

void main()
{
    ...
}

// Some other script used in or called from an object event.
#include "my_script"

void main()
{
    ...
    MyCustomFunction();
    ...
}

The problem is the script "my_script" is being used as an include library by the second script, but "my_script" has a main function defined in it. The compiler includes its contents into the second script when the #include directive is encountered. The resulting script now has two main functions in it, and when the compiler reaches the definition for the main function in the second (master) script, it chokes since it has no idea which version of the main function should be used.

// Correct:

// Some script called "my_script"
void MyCustomFunction()
{
    ...
}

/*
void main()
{
   ...
}
*/

// Some other script used in or called from an object event.
#include "my_script"

void main()
{
    ...
    MyCustomFunction();
    ...
}

Resolved by commenting out the main function in the script being included ("my_script" in this example).

Note that doing this will resolve the compiler error allowing the second script to compile, but if "my_script" is really an event handler instead of a library script, then it might be getting called from somewhere else. So commenting out the main function will make "my_script" invalid in that other context. When you see this, it is usually time to start rethinking what is trying to be accomplished.

DUPLICATE FUNCTION IMPLEMENTATION (<Name>)

Error Message Meaning Example

Every custom function added to a script must be defined once and only once. This error indicates that the custom function designated by the function name <Name> has been defined two or more times in the script.

Typically caused by using the #include directive to include two libraries that each define a function named <Name>, or to include a library that defines a function named <Name> when there is another definition for the <Name> function also defined in the current script.

// Incorrect:

// Some library script called "my_script"
void MyCustomFunction()
{
    ...
}
 

// Some other script.
#include "my_script"

void MyCustomFunction()
{
    ...
}


void main()
{
    ...
    MyCustomFunction();
    ...
}

The problem is the library "my_script" is being included by the second script. Both the library and the master script have a definition for the function MyCustomFunction in them. The compiler includes the "my_script" library's contents into the second script when the #include directive is encountered. The result now has two functions called MyCustomFunction defined in it, and when the compiler reaches the second definition for the function in the master script, it chokes since it has no idea which version of the function should be used.

// Correct:

// Some library script called "my_script"
void MyCustomFunction()
{
    ...
}

 
// Some other script.
#include "my_script"

void MyOtherCustomFunction()
{
    ...
}


void main()
{
    ...
    MyCustomFunction();
    MyOtherCustomFunction();
    ...
}

Resolved by giving one of the two versions of the function a distinct name. Note that when this error is caused by including a library that has a function whose name conflicts with one already defined in the master script, as depicted in this example, it is easiest and safest to rename the one defined in the master script rather than the one in the library which could potentially be used by other scripts elsewhere in the module.

However, when this error is caused due to including two different libraries which each have a function of the same name defined within them (or when one library includes another library and they both have the same function defined), then the resolution is far more complicated. One of them must still be renamed, but since the change will be made inside a library script, all other scripts that are utilizing that library must be reviewed so that calls to the newly renamed function can be taken into account as well. Care must be taken to ensure all function calls will invoke the correct version of the function. Then all scripts will need to be recompiled.

ELLIPSIS IN IDENTIFIER

Error Message Meaning Example

The meaning of this error message is a bit of a mystery. Embedding an ellipsis into an identifier name does not cause this error to appear, you get some other error instead.

At the time this page was authored, the only known way to reproduce the error is in a #include directive when you misspell the keyword as "included". Oddly enough, there is no identifier involved in a #include directive nor does misspelling the keyword in that way have anything to do with the ellipsis.

// Incorrect:

// Some script.
#included "some_library"

void main()
{
    ...
}

The problem is the keyword #include has been misspelled as #included.

// Correct:

// Some script.
#include "some_library"

void main()
{
    ...
}

Resolved by spelling the keyword correctly as #include.

ERROR PARSING VARIABLE LIST

Error Message Meaning Example

The text of this message appears to indicate a problem with a parameter list either in a function definition or call. However it seems to occur more often when an identifier is being defined incorrectly.

It can also indicate there is a function body somewhere that has mismatched curly braces, or that the previous statement was not terminated with a semicolon.

Probably the most common cause for this error is trying to call a function which is defined in some library script and forgetting to add the #include line for the library at the top of the script.

// Incorrect:

// Some script.
void main()
{
    int iMy*Bad*Variable = 0;
    ...
}

The problem is that asterisk characters are not allowed in an identifier name. Only letters, numbers, and the underscore can be used and identifier names are not allowed to start with a number.

// Correct:

// Some script.
void main()
{
    int iMy_Good_Variable = 0;
    ...
}

Resolved by using a variable name that contains only legal characters.




// Incorrect:

// Some script.
int MyFunction( int iX, int iY, int iZ )
{ // MyFunction's function body
    if( iX == 7 )
    {
        iZ = 4;
        iY = iY +1;
        return (iY * iZ);
  
    return ((iY * iZ) + iX);
} // <-- compiler thinks this is the end of the if-statement.


string MyOtherFunction( object oPC ) // <-- not in the global scope
{
    ...
}

The problem is that the first function definition for MyFunction() has mismatched curly braces. There are two opening braces but only one closing brace. This means the compiler cannot determine where the end of the function body is. When the next function definition for MyOtherFunction() is encountered the compiler thinks you are trying to define a new function within the scope of the MyFunction() function body. Functions can only be defined at the global scope level, so it spits out an ERROR PARSING VARIABLE LIST error message.

// Correct:

// Some script.
int MyFunction(int iX, int iY, int iZ)
{ // MyFunction's function body
    if(iX == 7)
    {
        iZ = 4;
        iY = iY + 1;
        return (iY * iZ);
    } // <-- now this curly marks the end of the if-statement.

    return ((iY * iZ) + iX);
} // <-- and this curly marks the end of the function body.


string MyOtherFunction(object oPC) // <-- back in the global scope.
{
    ...
}

Resolved by inserting a closing curly brace at the right spot to end the if-statement.

FUNCTION DEFINITION MISSING NAME

Error Message Meaning Example

This error occurs when an identifier is being defined incorrectly. Although the error message specifically says it's a function name, the error can be produced on variable and constant definitions as well. Apparently the compiler gets confused enough to think you are trying to define a function.

This error is typically related to an attempt to use the same identifier name in a second duplicate definition. Identifier names can only represent one thing at a time in the same scope.

// Incorrect:

// Some script.
...
const int   MyVar;
const float MyVar;
string      MyVar;
float       MyVar;

void main()
{ ...
}

The problem is the identifier name MyVar is being used to represent a constant integer in one line, then a constant float on the next, a variable string on the third, and a variable float on the fourth. The name can only be used to refer to one thing at a time and must be either constant or variable but not both.

// Correct:

// Some script.
...
const int   MY_INT;
const float MY_FLOAT;
string      My_String;
float       My_Float;

void main()
{ ...
}

Resolved by giving different identifier names to each different constant and variable being defined. Notice that identifier names are case-sensitive so the names MY_FLOAT and My_Float are treated as different names.




Interestingly the following script compiles just fine, although it is certainly not clear at all how valid it is.

// Unusual but compiles:

// Some script.
...
int         MyVar1;
const int   MyVar1 = 1; // < compiles but is MyVar1 variable or constant?

string      MyVar2;
const float MyVar2 = 2.0;


void main()
{ float MyVar3 = MyVar2; // < appears to be OK.
// string MyVar4 = MyVar2; // < will generate MISMATCHED_TYPES error
}

This last script also showcases one good reason why it is not always a very good idea to define variables in the global scope. Something like this could produce a stack error at runtime.

FUNCTION IMPLEMENTATION AND DEFINITION DIFFER

Error Message Meaning Example

A function implementation consists of a header line specifying its return type, identifier name, and parameter list, followed by the function body implementation which is a set of statements enclosed by curly braces. All functions must have an implementation defined somewhere in the script in order to be recognized and usable elsewhere in the script.

Functions can only be called after they have been defined or implemented. Sometimes it is desirable to want to call a function from another function implemented earlier in the script. This is accomplished by writing the function's header line by itself and terminating it with a semi-colon. This abbreviated one line form of a function "declares" to the compiler the existence of an implementation for the function elsewhere in the script.

This stand-alone-function-header line is known as a function's definition (also declaration and prototype are terms used for it). Its purpose is to let the compiler know about the function before the compiler sees the implementation of the function in order to make it possible to call the function before its implementation has been encountered. Prototype lines for functions are optional...only the function implementation is required.

Naturally, the function header line in a function's implementation must exactly match up exactly with its prototype definition. When you get this error it is because there is some difference between the two. The compiler encountered the prototype earlier and has been assuming all along that it correctly identified the function's data type specifics, yet now that it has reached the function implementation in the script, it is finding that the header of the implementation is saying the function expects some different parameters and/or returns a different data type.

// Incorrect:

...
   
// Prototype for MyFunction
void MyFunction( int iNum );

... // In here MyFunction is available for use.

// Implementation for MyFunction
void MyFunction( int iNum, object oObject )
{ ...
}

The problem is the prototype line for MyFunction says the function returns nothing, and requires one integer parameter. The implementation on the other hand says it returns nothing, but that it requires two parameters an integer and an object.

// Correct:

...
   
// Prototype for MyFunction
void MyFunction( int iNum, object oObject );

... // In here MyFunction is available for use.

// Implementation for MyFunction
void MyFunction( int iNum, object oObject )
{ ...
}

Resolved by making the prototype match exactly with the function header.




This next sample shows when prototyping a function is a requirement.

// Incorrect:

// Implementation for MyFunctionA
void MyFunctionA( object oPC )
{ ...
  int iB = MyFunctionB( oPC );  // MyFunctionB unknown here.
  ...
}

// Implementation for MyFunctionB
int MyFunctionB( object oPC )
{ ...
  MyFunctionA( oPC );
  ...
}

The problem is that the function MyFunctionA is trying to call the function MyFunctionB before the implementation for MyFunctionB is known. Switching the functions around so MyFunctionB's implementation appears first will not help in this case because MyFunctionB is also calling MyFunctionA and the same error will show up there instead.

// Correct:

// Prototype definition for MyFunctionB
int MyFunctionB( object oPC );

// Implementation for MyFunctionA
void MyFunctionA( object oPC )
{ ...
  int iB = MyFunctionB( oPC );  // this time it's known.
  ...
}

// Implementation for MyFunctionB
int MyFunctionB( object oPC )
{ ...
  MyFunctionA( oPC );
  ...
}

Resolved by adding a prototype definition for MyFunctionB above the implementation for MyFunctionA so that the compiler will know how to compile the line that calls MyFunctionB before its implementation is known.

FUNCTION DEFINITION MISSING PARAMETER LIST

Error Message Meaning Example

All function definitions must include a parameter list enclosed in parentheses immediately following the function's identifier name. This error is saying the compiler has encountered a function definition where no parameter list was specified.

// Incorrect:

// Some script.

void main
{ ...
}

The problem is the definition of the script's main function has no parameter list. The main function of a script can never have any parameters, but the empty parameter list enclosed in parenthesis must still appear in order for the compiler to recognize it as a function definition.

// Correct:

// Some script.

void main()
{ ...
}

Resolved by adding the empty parameter list to the main function definition.




// Incorrect:

// Some script.

void MyFunction
{ ...
}


void main()
{ ...
}

The problem is the definition of the custom function called MyFunction has no parameter list.

// Correct:

// Some script.

void MyFunction(int iMyParameter)
{ ...
}


void main()
{ ...
}

Resolved by adding an appropriate parameter list to the function header.

IDENTIFIER LIST FULL

Error Message Meaning Example

This is a compiler runtime error that can occur when the volume of code being translated overloads the compiler's built-in capacity limits.

Every time a new identifier is defined for a constant or function, its name is saved by the compiler in a list it refers to as it goes along. The compiler uses the list to detect errors as it translates the script. This list has a size limit of 8192 identifiers and when the list becomes full you get this error. It means you are trying to use too many different identifier names in your script and its included libraries.

This error is typically caused when compiling a script that has lots of #include lines in it to access functions defined in script libraries. Often those libraries included will also themselves include even more libraries. All those different function and constant definitions from the libraries add up and the list overflows.

The only way to resolve this error is to reduce the volume of code used by the script. Constants can be converted to variables to help reduce the identifier count. The best way to resolve it, however, is to break up the libraries such that less stuff that is not actually needed by the script is getting included.

INVALID DECLARATION TYPE

Error Message Meaning Example

This error appears to relate to the data type specifications in the parameter list part of a function declaration. It typically occurs when one or more of the parameters in the parameter list of a function definition's header line are missing the required data type keyword, or the keyword is misspelled.

// Incorrect:

// Some script.
void MyFunction( iValue, strign sName )
{ ...
}


void main()
{ ...
}

The problem is the data type specifier for the parameter called iValue in the MyFunction definition is missing. Only the parameter name is present. Also the keyword "string" is misspelled in the declaration of the sName parameter.

// Correct:

// Some script.
void MyFunction( int iValue, string sName )
{ ...
}

void main()
{ ...
}

Resolved by ensuring every parameter in the function's parameter list has an appropriate, correctly spelled, data type specified for it.

MISMATCHED TYPES

Error Message Meaning Example

This error occurs when an operation is being attempted between two incompatible types of data. Operations in NWScript always operate on data items of the exact same datatype. Mixed type operations are not allowed.

// Incorrect:

// Some script.
void main()
{
  int    iA = 0;
  string sB = "1";
  
  if ( iA < sB)
  { ...
    sB = 7;
    ...
  }
}

The problem is that the variable iA is declared as an integer datatype and the variable iB is declared as a string. The if-statement is attempting to perform a less-than comparison operation between the two variables. Since their datatype does not match, the compiler is unable to translate the boolean expression inside the parenthesis.

Also, inside the if-statement's then-part block, an attempt is being made to assign the string type variable sB an integer type value (7). Only a string type value can be assigned to the string variable.

// Correct:

// Some script.
void main()
{
  int    iA = 22;
  string sB = "54";
  
  if ( iA < StringToInt( sB))
  { ...
    sB = IntToString( 7);
    ...
  }
}

Resolved by ensuring all operations are performed only between operands that have matching datatypes. This is typically facilitated using a function that converts one of the operands to the correct type to match the other.

MULTIPLE CASE CONSTANT STATEMENTS WITHIN SWITCH

Error Message Meaning Example

A switch-case statement consists of a switch line containing an integer expression followed by a series of unique case blocks. Each case block starts with a case label line that defines the unique integer value required of the switch expression for the associated case block to execute. It is illegal to define two case blocks in the same switch statement that both refer to the same integer value. This error is what you get when you violate that rule.

Probably the most common cause for this error is the use of constant names to represent integer values in the case labels. If two labels refer to different integer constant names yet the constants have been assigned identical values, a multiple case constant error will occur.

// Incorrect:

// Some script.
void main()
{
  switch (d3())
  {
    case 1: ... break;
    case 3: ... break;
    case 3: ... break;
  }
}

The problem is that the switch statement has two case labels referring to the same value (3).

// Correct:

// Some script.
void main()
{
  switch (d3())
  {
    case 1: ... break;
    case 2: ... break;
    case 3: ... break;
  }
}

Resolved by making sure all the case labels are unique.




// Incorrect:

// Some script.
const int LOW       = 1;
const int MEDIUM    = 2;
const int HIGH      = 3;
const int AFRAID    = 3;
const int CAUTIOUS  = 5;
const int CONFIDENT = 6;

void main()
{
  switch (d6())
  {
    case LOW:       ... break;
    case MEDIUM:    ... break;
    case HIGH:      ... break;
    case AFRAID:    ... break;
    case CAUTIOUS:  ... break;
    case CONFIDENT: ... break;
  }
}

The problem is that the switch statement has two case labels referring to the same value (3) because the constant names HIGH and AFRAID have both been given the value 3.

// Correct:

// Some script.
const int LOW       = 1;
const int MEDIUM    = 2;
const int HIGH      = 3;
const int AFRAID    = 4;  // Assign AFRAID a different value.
const int CAUTIOUS  = 5;
const int CONFIDENT = 6;

void main()
{
  switch (d6())
  {
    case LOW:       ... break;
    case MEDIUM:    ... break;
    case HIGH:      ... break;
    case AFRAID:    ... break;
    case CAUTIOUS:  ... break;
    case CONFIDENT: ... break;
  }
}


  - or -

  
// Some script.
const int LOW       = 1;
const int MEDIUM    = 2;
const int HIGH      = 3;
const int AFRAID    = 3;
const int CAUTIOUS  = 5;
const int CONFIDENT = 6;

void main()
{
  switch (d6())
  {
    case LOW:       ... break;
    case MEDIUM:    ... break;
    case HIGH:      ... break;  // Handles both HIGH and AFRAID.
    case CAUTIOUS:  ... break;
    case CONFIDENT: ... break;
  }
}

Resolved by making sure all constant names used in the case labels of the switch have been given unique values, or by removing all but one of the cases that are being duplicated.

NO COLON AFTER CASE LABEL

Error Message Meaning Example

A switch-case statement consists of a switch line containing an integer expression followed by a series of unique case blocks. Each case block starts with a case label line that defines the unique integer value required of the switch expression for the associated case block to execute.

The case label lines must be formatted starting with the keyword "case" followed by an integer value or integer constant identifier name followed by a colon. If you forget to put in the colon you will get this message. It also appears if you enter some other symbol like a semi-colon there instead of a colon. Most commonly, this error occurs due to a typo where the colon is entered as a semi-colon because the shift-key was not depressed.

// Incorrect:

// Some script.
const int SEVEN = 7;

void main()
{
  int iSpell  = 0;
  int iNumber = 0;
  ...
  switch( iNumber)
  {
    case 1:
      { ...
        iSpell = 720;
        ...
      }
      break;
      
    case 2
      { ...
        iSpell = 546;
        ...
      }
      break;
      
    case SEVEN;
      { ...
        iSpell = 22;
        ...
      }
      break;
  }      
}

The problem is case label 2 has no colon after the 2 and before the {. Also the case label for SEVEN ends with a semicolon instead of a colon.

// Correct:

// Some script.
const int SEVEN = 7;

void main()
{
  int iSpell  = 0;
  int iNumber = 0;
  ...
  switch( iNumber)
  {
    case 1:
      { ...
        iSpell = 720;
        ...
      }
      break;
      
    case 2:
      { ...
        iSpell = 546;
        ...
      }
      break;
      
    case SEVEN:
      { ...
        iSpell = 22;
        ...
      }
      break;
  }      
}

Resolved by following the value or constant identifier name of all case labels with a colon.

NO FUNCTION STARTINGCONDITIONAL() IN SCRIPT

Error Message Meaning Example

This error indicates that the compiler believes the script being compiled is a starting conditional script meant for use in a conversation TextAppearsWhen event, but the main function called StartingConditional, required in all TextAppearsWhen event scripts, was not found anywhere.

There are three types of scripts: libraries, event handlers, and starting conditionals. Of these, libraries (a.k.a. include scripts) cannot be compiled independently. They get compiled when the scripts that include them are compiled. Event handlers, often called just normal scripts, are those that can be entered in object event slots, or executed from within other event handlers. They must have one main function defined in them called "main" which takes no parameters and returns nothing (void). Starting conditional scripts are similar to event handlers except they can only be used in conversation TextAppearsWhen events. Like event handlers they must define one main function. However, unlike event handlers, the main function in a starting conditional script must take no parameters, return an integer data type, and be named StartingConditional.

When an event handler or starting conditional script is compiled, the system usually automatically determines which type of script it is. But sometimes the context used to start the script editor will be the determining factor. For example, if you click the Edit button next to a TextAppearsWhen event slot in a conversation line when using the conversation editor, the script editor opens assuming you will be trying to compile a starting conditional script because event handlers are invalid in a TextAppearsWhen slot. If you then try to compile an event handler, which will not have the required StartingConditional main function defined in it, then you will get this error. Likewise, if you try to compile a library script independently, you will often get this error.

There is a toolset bug related to this error message. It occurs after completing a build when the list of errors is displayed, and you can double click on one of the compile errors listed to open the problem script in the script editor to fix it. When you open the script editor in this way it will, for some odd reason, switch to the mode where it assumes you are going to compile a starting conditional script. This happens even if the script with the errors in it is an event handler. So when you go to compile it after fixing it, you will get this message. To get around this toolset bug you have to use some other means to open the script in the script editor. Either by double-clicking it in the module's script list, or by opening the script editor using the Tool menu and then loading the script, or by finding the event slot where the script is hooked and use the Edit button next to it.

// Incorrect:

// Some TextAppearsWhen script.

...

int StartngCondtionale()
{ ...
  return TRUE;
}

The problem is the name of the main function has been misspelled in the function's header line.

// Correct:

// Some TextAppearsWhen script.

...

int StartingConditional()
{ ...
  return TRUE;
}

Resolved by making sure the script has defined one function called StartingConditional that takes no parameters and returns an integer data type.

NON-INTEGER EXPRESSION WHERE INTEGER REQUIRED

Error Message Meaning Example

Whenever the compiler expects to see an integer expression and instead finds an expression that evaluates to a non-integer value, it generates this error.

Expressions are those parts of scripting statements that compute or represent a specific value at runtime. An expression can be a simple value, a mathematical formula, a call to a function that computes a value, a logical comparison, a reference to some variable or constant name, or any combination. The one thing all expressions have in common is that they can be evaluated at run time to produce a value of some datatype. If the value computed by an expression is an integer datatype, then it is known as an integer expression.

Several scripting statements are structured using an integer expression. For example, when a value is assigned to an integer variable, the assignment statement used is structured using an expression on the right side of an = operator. If-statements, while-statements, and do-statements are all written using an integer expression to compute the condition.

If the compiler expects an integer expression, and you write an expression that returns some non-integer value, expect to see this error. This error can be caused by inadvertently writing the assignment operator "=" in an expression where the logical comparison operator "==" was intended.

// Incorrect:

// Some script.
#include "x0_i0_transport"

void main()
{
  object oWP = GetNearestObject( OBJECT_TYPE_WAYPOINT);
  if (!GetIsObjectValid(oWP)) return;
  
  if (GetDistanceToObject(oWP) > 0.25) return;
  
  string sTAG  = GetTag( oWP);
  object oDest = OBJECT_INVALID;
  
  if (sTAG = "AutoTransport")
    oDest = GetObjectByTag(GetLocalString(oWP, "Destination")));

  else if (sTAG = "HomeTransport")
    oDest = GetObjectByTag(GetLocalString(OBJECT_SELF, "Home")));

  ...
  
  if (GetIsObjectValid(oDest))
    TransportToWaypoint(OBJECT_SELF, oDest);
}

The problem is in the if-statements an integer expression is expected in between the parenthesis "(" & ")" where the condition is written. Here the expression has been written as an assignment statement. Since assignment statements evaluate to a value (i.e. the value being assigned), it is legal to use an assignment statement as an expression. However, in this case since both operands to the assignment operator "=" are strings, the datatype of the expression written is a string type...and the compiler is expecting an integer expression there.

What was intended in this script was a comparison between sTAG and the various specific tag strings but the author has mistakenly used an assignment operator instead of a logical comparison operator "==" in the if-statements' conditional expression. It is valuable to notice that this author is fortunate that he is comparing strings. Had he used integers there, the mistaken use of the assignment operator would have made them integer expressions, and the compiler would not have complained even though the code would not function as intended.

// Correct:

// Some script.
#include "x0_i0_transport"

void main()
{
  object oWP = GetNearestObject(OBJECT_TYPE_WAYPOINT);
  if (!GetIsObjectValid(oWP)) return;
  
  if (GetDistanceToObject(oWP) > 0.25) return;
  
  string sTAG  = GetTag(oWP);
  object oDest = OBJECT_INVALID;
  
  if (sTAG == "AutoTransport")
    oDest = GetObjectByTag GetLocalString(oWP, "Destination")));

  else if (sTAG == "HomeTransport")
    oDest = GetObjectByTag(GetLocalString(OBJECT_SELF, "Home")));

  ...
  
  if (GetIsObjectValid(oDest))
    TransportToWaypoint(OBJECT_SELF, oDest);
}

Resolved by changing the "=" operator to a "==" one so the expressions will be computing a boolean (integer) value instead of a string.

NO LEFT BRACKET ON EXPRESSION

Error Message Meaning Example

Expressions are almost always enclosed in parentheses which are sometimes also called brackets. Often compound expressions are written where sub-expressions appear in nested parentheses which are combined to form a result. Whenever an expression is enclosed in brackets the brackets must pair up. For every ( there must be one and only one matching ) and vice-versa. This error means you have created an expression that has mismatched parenthesis and further identifies the problem as being either one or more missing left or opening brackets, or too many right or closing brackets.

// Incorrect:

// Some script.

void main()
{
  int iA = 3;
  int iB = Random(iA) +1;
  if iA == iB)  // Missing left bracket.
  {
    return;
  }
}

The problem is the expression used in the if-statement is missing a left bracket.

// Correct:

// Some script.

void main()
{
  int iA = 3;
  int iB = Random(iA) +1;
  if (iA == iB) // Expression enclosed by a pair of matching brackets.
  {
    return;
  }
}

Resolved by making sure every one of these ( has a matching one of these ) in the same statement, and every one of these ) has a matching one of these (. Also all the stuff in between them needs to be correct.

NO RIGHT BRACKET ON EXPRESSION

Error Message Meaning Example

Like the previous error message this one indicates a problem with the structure of an expression and the parentheses used to delineate its parts.

You can also get this one if you forget to include a library and then try to call a function defined in that library from within an expression. Or if you misspell a function name when you call it in an expression. So it doesn't always relate to brackets, but it almost always does relate to an expression.

This error also pops up if you try to define an identifier (const, variable, or function name) that starts with a numeric digit. All identifiers must begin with a letter or underscore.

// Incorrect:
// missing library include here

// Some tag-based item script.
void main()
{
  if (GetUserDefinedItemEventNumber() != X2_ITEM_EVENT_ACTIVATE) return;
  ...
}

The problem is the function GetUserDefinedItemEventNumber() is being called but is not defined anywhere. The function definition is in one of the Bioware libraries and the include line for it has been left out.

// Correct:

// Some tag-based item script.
#include "x2_inc_switches"

void main()
{
  if (GetUserDefinedItemEventNumber() != X2_ITEM_EVENT_ACTIVATE) return;
  ...
}

Resolved by including the library that contains the function definition.

NO SEMICOLON AFTER EXPRESSION

Error Message Meaning Example

All code statements must end with a semicolon to separate them from the next statement. The only exception to that rule is statements that end with a closing curly bracket "}" which do not require the ending semicolon.

This error is saying there is a code statement in the script that is not terminated with the required semicolon. Normally the line number identified in the error message points to the line in the script immediately following the problem code statement.

This error can occur if there are too many closing parenthesis ")" at the end of a statement just before the terminating semicolon.

// Incorrect:

// Some script.

...

void main()
{
  object oNPC = GetObjectByTag("Some_NPC_Tag");
  string sNPCName;
  sNPCName = GetName(oNPC)
  
  // Some comment lines.
  // Some comment lines.
  // Some comment lines.
  // Some comment lines.
  if (sNPCName == "Paul Speed")  // <-- Compiler error points to this line.
  {
    PerformIntelligentFeat( oNPC);
    return;
  }
}

The problem is the code statement that assigns the name of the NPC to the variable sNPCName does not end with a semicolon. Note that due to the comment lines which appear between the erroneous statement and the next if-statement, the line number shown in the error message will be several lines past the line that has the missing semicolon. This happens because the compiler doesn't realize the assignment statement should have ended until it encounters the next code statement which is the if-statement (comment lines don't count as code statements).

// Correct:

// Some script.

...

void main()
{
  object oNPC = GetObjectByTag("Some_NPC_Tag");
  string sNPCName;
  sNPCName = GetName(oNPC);
  
  // Some comment lines.
  // Some comment lines.
  // Some comment lines.
  // Some comment lines.
  if (sNPCName == "Paul Speed")
  {
    PerformIntelligentFeat(oNPC);
    return;
  }
}

Resolved by ensuring every code statement ends with a semicolon except those (like the if-statement above) that end with a closing curly brace "}".




// Incorrect:

// Some script.

...

void main()
{
  object oNPC = GetObjectByTag("Some_NPC_Tag");
  string sNPCName;
  sNPCName = GetName(oNPC));
  ...
}

The problem is that there are too many closing parenthesis at the end of the line that assigns the variable sNPCName a value. The compiler thinks the statement ends after the first closing parenthesis so it expects to see a semicolon or maybe a "+" operator. Instead it encounters another closing parenthesis so it spits out "No semicolon after expression".

// Correct:

// Some script.

...

void main()
{
  object oNPC = GetObjectByTag("Some_NPC_Tag");
  string sNPCName;
  sNPCName = GetName(oNPC);
  ...
}

Resolved by removing the extra parenthesis.

NOT ALL CONTROL PATHS RETURN A VALUE

Error Message Meaning Example

This error means a custom definition has been encountered for a function that returns some non-void data type, and one or more of the possible control paths through the function's body ends without returning a value to the caller via a return statement.

Flow of control is a concept referring to the exact sequence of code statements that will execute in any arbitrary block of code, such as a function body block. As the code runs each statement in the block executes producing a particular stream of code statements that have "controlled" the process. The statements that execute represent the flow that the control of the process takes as the code block runs. Sometimes, like when an if-statement is encountered, the sequence can take an alternate "branch" and execute a completely different set of instructions. This creates two possible sequences or "control paths" through the code block that can occur to get to the end.

When a custom function is created that returns some value, it is illegal to have a control path through the function's body block that ends without returning a value of the proper data type to the caller via the use of a return statement. All possible control paths through such a function body must end with a return statement that passes out a value.

This error is saying that there is at least one control path through the function's body block that does not return a value when it ends.

// Incorrect:

// Some script.
string MyIntToString(int iValue)
{
  if (iValue == 0)
  { ...                 // <-- First Control Path.
    return "0";
  }
  else
  { ...                 // <-- Second Control Path.
    return IntToString(iValue +1);
  }
  ...                   // <-- Third Control Path.
}


void main()
{ ...
}

The problem is that the MyIntToString function is defined to return a string value. The function has three possible paths of control that can be followed through the code. Since the third path does not end with a return statement that passes out a string value to the function caller, the compiler generates this error. Note that even though it will be impossible to ever reach the third path due to the way the if-statement condition and its then/else blocks are written, the compiler still sees the third path as an alternative.

// Correct:

// Some script.
string MyIntToString(int iValue)
{
  if(iValue == 0)
  { ...                 // <-- First Control Path.
    return "0";
  }
  else
  { ...                 // <-- Second Control Path.
    return IntToString(iValue +1);
  }
  return "";            // <-- Third Control Path.
}


void main()
{ ...
}

Resolved by making sure that all control paths through the function bodies of all functions defined in the script which return a non-void type of data end with a return statement used to pass out a value of the correct data type to the function caller.




// Incorrect:

// Some script.
string MyValueToString(int iValue)
{
  switch (iValue)
  {
    case 0:  return "The value is zero.";
    case 1:  return "The value is one.";
    default: return "The value is " +IntToString(iValue);
  }
  ...
}


void main()
{ ...
}

The problem is that the MyValueToString function is defined to return a string value. The function has four possible paths of control that can be followed through the code. One for each of the cases in the switch statement, and the (unreachable) code that follows the switch statement. Since the final path beyond the switch statement does not end with a return statement that passes out a string value to the function caller, the compiler generates this error. Note that again, even though it will be impossible to ever reach the code past the switch statement due to the use of the default case block and the fact that all the cases return, the compiler still sees that final path as an alternative so it must end with a return.

// Correct:

// Some script.
string MyValueToString(int iValue)
{
  switch (iValue)
  {
   case 0:  return "The value is zero.";
    case 1:  return "The value is one.";
    default: return "The value is " +IntToString(iValue);
  }
  return "";
}


void main()
{ ...
}

Resolved by making sure that all control paths through the function bodies of all functions defined in the script which return a non-void type of data end with a return statement used to pass out a value of the correct data type to the function caller.

PARSING RETURN STATEMENT

Error Message Meaning Example

This error indicates a problem in a return statement, but it is more common to get it when you have a statement that ends with an expression and is missing the semicolon at the end. Usually if you leave the semicolon off the end of a statement you will get the NO-SEMICOLON AFTER EXPRESSION message. But sometimes if the statement ends with an expression you can get this message instead.

In a return statement, you can get this message when trying to return a value from a void-returning function. Also, when the return statement computes the returned value via an expression entered directly into the return statement, and there is some problem with the syntax of the expression or the semicolon is missing at the very end.

// Incorrect:

// Some script.
...

void MyFunction(int iSelector)
{
  if (iSelector == 0)
  { ...
    return;
  }
  else
  { ...
    return 7
  }
  ...
}

...

The problem is the function MyFunction is defined as void-returning, meaning it does not return a value when called. Yet in the else-part of the if-statement inside the function is a return statement that is attempting to make the function return the integer value 7. In addition, the statement does not have the required terminating semicolon. Making this combination of mistakes will cause ERROR PARSING RETURN STATEMENT to pop up.

// Correct:

// Some script.
...

int MyFunction(int iSelector)
{
  if (iSelector == 0)
  { ...
    return 1;
  }
  else
  { ...
    return 7;
  }
  ...
  return 0;
}

...


  - or -


// Some script.
...

void MyFunction(int iSelector)
{
  if (iSelector == 0)
  { ...
    return;
  }
  else
  { ...
    return;
  }
  ...
}

...

Resolved by either changing the function definition to make it return a value then editing all return statements in the function to make them return a value, or by removing the value from the offending return statement. And by ensuring there is a semicolon at the end of all statements in the script except those that end with a closing curly brace "}".

RETURN TYPE AND FUNCTION TYPE MISMATCHED

Error Message Meaning Example

This error indicates that a return statement is trying to return a value whose data type does not match the type of data the function is designated to compute as specified in the function's header line.

// Incorrect:

int MyCustomFunctionA()
{ ...
  return "";
}

string MyCustomFunctionB()
{ ...
  float fReturnValue = 0.0;
  ...
  return fReturnValue;
}

The problems are that the function called MyCustomFunctionA is defined to compute an integer value but the return statement in the function is trying to return a string. Also the custom function MyCustomFunctionB is defined to compute a string value but the return statement inside the function is trying to pass out a floating point number.

// Correct:

int MyCustomFunctionA()
{ ...
  return 0;
}

float MyCustomFunctionB()
{ ...
  float fReturnValue = 0.0;
  ...
  return fReturnValue;
}

Resolved by either changing the return statement to return a value of the proper type (as in MyCustomFunctionA above), or by changing the data type the function computes in the function header to match what is being returned (as in MyCustomFunctionB above).




// Incorrect:

int MyCustomFunction()
{ ...
  return;
}

The problem is that the function called MyCustomFunction is defined to return an integer value but the return statement in the function is not returning any value at all.

// Correct:

int MyCustomFunction()
{ ...
  return 0;
}

void MyCustomFunction()
{ ...
  return;
}

Resolved by either changing the return statement to pass out a value of the proper type (as in the first fixed version above), or by changing the data type of the function to void (as in the second fixed version above). A void type function returns no value, so any return statements in it must not attempt to return a value either.




// Incorrect:

void MyCustomFunction()
{ ...
  return 0;
}

The problem is that the function called MyCustomFunction is defined as a void returning function (i.e. it does not compute any value at all), but the return statement in the function is trying to pass out a value (in this case an integer, however a value of any data type appearing in the return statement will cause the error).

// Correct:

void MyCustomFunction()
{ ...
  return;
}

int MyCustomFunction()
{ ...
  return 0;
}

Resolved by either eliminating the value from the return statement (as in the first fixed version above), or by changing the data type of the function to match the value being returned by the return statement (as in the second fixed version above).

UNDEFINED IDENTIFIER (<Name>)

Error Message Meaning Example

This error indicates an attempt to use an identifier named <Name> which has not been previously defined. Most often this one occurs when a variable name is misspelled or used before it is declared or without defining it at all, but it will also occur when a prototyped function which has no associated implementation defined is called. Or if the spelling of the name of a custom function is not the same in its prototype and implementation header lines. If you make this latter error and call the function using the spelling in the prototype line, the <Name> part of the error message will be empty and the line number will not appear.

// Incorrect:

// Some script.

void MyFunction()  // Prototype line for the MyFunction function.
void myFunction()  // Implementation with the name 'misspelled'.
{ ...
}

void main()
{
  MyFunction();  // Calling prototyped function with no implementation.
}

The problem is the prototype line and header line for the function MyFunction don't have the same name. The lower-case 'm' makes them different. When the prototyped name is later used to attempt to call the function, the compiler chokes. Doing this produces the error message with no line number and the <Name> missing.

// Correct:

// Some script.

void MyFunction()
void MyFunction()
{ ...
}

void main()
{
  MyFunction();
}

Resolved by making sure all custom functions called in a script have an implementation defined for them somewhere before they are used. And if the function is prototyped (an optional addition), that the prototype line matches up precisely with the header line of the corresponding function implementation.

UNEXPECTED CHARACTER

Error Message Meaning Example

There are many ways to get this error. It is a very generic one that basically means the script author has written something that the compiler can make no sense of at all. The code has so confused the compiler that it cannot provide a more specific error message. Fortunately it is a rare one to encounter and the line number pointed to in the error message is always the line where the mistake actually is.

// Incorrect:

// Some placeable OnUsed script.
void main()
{
  object oPC = GetLastUsedBy();
  ActivatePortal(oPC, 63.127.247.56:5121);
}

The problem is that the URL entered in the call to the ActivatePortal function is not entered as a string. If you look up the prototype for the ActivatePortal function you will see the second parameter is expected to be a string datatype. Here the quotes around the URL are missing. Since they are not there, the compiler is trying to parse thru the URL to determine what type of data it is, but is unable to identify it as an integer or float or any of the other datatypes it knows about. Therefore, as soon as it hits the second decimal point it realizes the constant is invalid for all datatypes since no datatype exists that allows for more than one decimal point to be used. The second decimal point is an unexpected character so the compiler spits out this message.

// Correct:

// Some placeable OnUsed script.
void main()
{
  object oPC = GetLastUsedBy();
  ActivatePortal(oPC, "63.127.247.56:5121");
}

Resolved by passing the URL as a string constant (with quotes around it). It is impossible to show examples for all the various ways this error can be produced, but this is one way it can happen.

UNEXPECTED END COMPOUND STATEMENT

Error Message Meaning Example

A compound statement is one which can include one or more other statements. Like an if-statement which includes one or more statements in its then-part and, optionally, one or more statements in its else-part. Even though there may be many statements being controlled by it, the if-statement as a whole is still considered to be a single giant compound statement.

Usually this error is produced when a compound statement is using the curly braces "{" & "}" to group several statements together into a scoping block. If the script author fails to match up the curly braces that delineate the block by, for example, forgetting to put in the closing one "}" at the end, then the compiler does not recognize that the block has ended and therefore that the compound statement has not ended. As soon as it encounters a statement which does not appear to belong inside the erroneously "unclosed" block, it quits and spits out this error.

// Incorrect:

// Some script.
void main()
{ ...
  switch( iSize)
  {
    case SIZE_SMALL:
      { ...
      }
      break;
      
    case SIZE_MEDIUM:
      { ...
      }
      break;
      
    case SIZE_LARGE:
      { ...
      }
      break;
      
    case SIZE_HUGE:
      { ...
  }
  ...
}

The problem is in the switch statement's SIZE_HUGE case. A scoping block is used to group a bunch of statements there but the closing curly brace that ends the block has been left off. Because the block is not ended, the next curly which is supposed to end the whole switch statement is viewed by the compiler as the end of the case block, and the switch statement (a compound statement) is not complete.

// Correct:

// Some script.
void main()
{ ...
  switch( iSize)
  {
    case SIZE_SMALL:
      { ...
      }
      break;
      
    case SIZE_MEDIUM:
      { ...
      }
      break;
      
    case SIZE_LARGE:
      { ...
      }
      break;
      
    case SIZE_HUGE:
      { ...
      }
  }
  ...
}

Resolved by ensuring your compound statements are correctly structured and that you don't have any unmatched curly braces.

UNKNOWN STATE IN COMPILER

Error Message Meaning Example

This error message seems to be some kind of default general error the compiler spits out when it is confused but cannot figure out what's wrong. There are many ways to get this one and here are a few of them...

Sometimes if you don't match up parentheses in an expression you will get this instead of the missing bracket errors.

Look for extra or missing closing curly braces } and make sure they all match up with an opening brace somewhere. If you leave out an opening curly brace { you will often get this.

If you write a floating point value that is less than 1.0 and you fail to precede the decimal point with a 0 character, the compiler will generate the unknown state error.

Writing an expression such that there is an extra operator with no operand specified for it to operate on will result in an unknown state error.

Attempting to declare a variable inside the condition portion of a loop statement ala the C/C++ style for loop is not valid in NWScript and will put the compiler into an unknown state.

Explicitly specifying parameter datatypes and/or trying to assign values to parameters within the parameter list when calling a function will cause this error to occur. Specifying parameters in this manner is only done when a function is defined or prototyped and must not be done when the function is used (called) from a script.

// Incorrect:

// Some script.
void main()
{ ...
  float  fBadFloat = .55;
  string sMessage  = "Hello I am " +^ GetName( oNPC);
  if ((fBadFloat < 1.0) || (sMessage != "") || )
  { ...
  }
  for (int i = 0; i < 15; i++)
  { ...
  }
  SetLockKeyRequired(object oChest, int nKeyRequired = TRUE);
}

There are several problems in this script all of which will generate an unknown state in compiler error. The first one is on the fBadFloat line. The value .55 must be written with a 0 in front of the decimal. The second error is on the sMessage line. There are two operators next to each other that don't belong together. The third error is in the condition portion of the if-statement where either one of the three sub-conditions making up the entire compound expression is missing, or there is a superfluous operator added at the end of it. Either way it's not legal to use a binary operator and give it only one operand to operate on. The next error is in the conditional portion of the for-statement. This loop is written using C/C++ syntax where it is legal to define a new variable inside the loop condition. In NWScript, you cannot do this. The variable must be defined independently prior to the for-statement in the code. And the last error is with the call to the function SetLockKeyRequired. Specific datatypes and default values are not entered when you call a function, only when you define it.

// Correct:

// Some script.
void main()
{ ...
  float  fBadFloat = 0.55;
  string sMessage  = "Hello I am " + GetName( oNPC);
  if ((fBadFloat < 1.0) || (sMessage != ""))
  { ...
  }
  int i;
  for( i = 0; i < 15; i++)
  { ...
  }
  object oChest       = OBJECT_SELF;
  int    nKeyRequired = TRUE;
  SetLockKeyRequired(oChest, nKeyRequired);  // Use variables.
  SetLockKeyRequired(OBJECT_SELF, TRUE);  // Use values
  SetLockKeyRequired(oChest, TRUE);  // A combination of the two
  SetLockKeyRequired(oChest);  // Rely on default value
}

The fBadFloat line is resolved by adding a 0 to the front of the number. The sMessage line is resolved by using the + operator correctly by itself to combine the two strings together. The third error is fixed by getting rid of the extra || at the end of the expression. The "for" statement problem is fixed by defining the loop variable separately before the for-statement in the code. And the last line can be resolved in a number of ways. You can define variables, give them values, and pass in the variable name only (no datatype keyword) to the function call. Or you can write the values directly into the function call's parameter list. Or you can do some combination of the two. And in this case, since the function SetLockKeyRequired is defined to utilize a default value of TRUE for the second parameter, you can call the function and leave that parameter out to have the function assume the value TRUE for it.

VARIABLE ALREADY USED WITHIN SCOPE

Error Message Meaning Example

This error message is saying that you are trying to define a variable whose name is already in use by another variable, function, or constant defined earlier in the same scope.

Scope is a term used when discussing identifier names to refer to those areas (or sections or lines) of a script where the name is "known" or "defined". Code scoping blocks are identified by the curly braces "{" and "}". All statements appearing between a matching set of curly braces are in the same block or scope. There is also a "script global" scope which is all the areas of the script that are outside of all scoping blocks and function bodies.

Functions and constants can only be defined in the global scope, thus they are known throughout the script beyond the point where they are defined. But variables can be defined inside any scoping block. Therefore their name may only be known in some restricted area of the script...and in fact this is almost always the case with variable names. Also, because they have a more limited scope, it is quite often the case that the same variable name is used in two or more different places (scopes) in the same script to store two entirely different data items. An identifier name can only be used to refer to a single data item in any scope. But the same identifier name can refer to a second different data item as long as it is defined within a different scope in the script.

Variables come into being and exist only within the code block in which they are defined. When the block finishes executing, all variables defined within that block are destroyed and no longer exist. Since scoping blocks can be nested, meaning a block can contain "sub-blocks", all statements appearing inside the sub-blocks are considered to be part of the outer block's scope, but the statements in the outer block are not considered to be part of the inner sub-blocks. This brings about the possibility of having numerous multiply nested scoping levels where a variable name can potentially be defined for use.

A variable defined within an outer block will have a scope that includes all statements that appear after the variable definition line in the entire outer block -- including those statements appearing inside any inner blocks. All statements in the scope of the variable will know about that variable and can therefore legally refer to its name. However, a variable defined inside an inner block will have a scope that only includes the statements within that inner block (and its sub-blocks) which appear after the variable's definition line. Statements in the outer block will not be able to refer to variables defined within the inner blocks because those variables have "gone out of scope" when the inner block finished executing and therefore they no longer exist when the outer block statements run. Only the statements inside the inner block where the variable was defined (i.e. those statements in the variable's scope) can refer to it.

// Incorrect:

// Some script.
int y;
...
string y;

void main()
{
  object y;  // This is allowed but it's a different y. All statements in
             // the main function that use the name "y" will be referring
             // to this object not the integer defined above.
  ...
  int x;
  if (GetIsPC(y)) // if-statements often introduce nested scoping blocks
  {
    float x;  // This is allowed but it's a different x in this scope.
    ...       // x in these statements is the float version
  }           // x "the float" goes out of scope here
  ...         // x in these statements is the int variable
  int x = GetXP(y);
  ...
}             // x "the int" goes out of scope here as does the object y

The problem is that the definition for the string variable y at the top is invalid because the identifier name "y" is already being used to identify an integer type storage location at the global scope level. Also, in the main function body, a variable by the name of "x" is defined and then later an attempt is being made to redefine it within the same scope as the first definition.

// Correct:

// Some script.
int iY;
...
string sY;

void main()
{
  object oY;
  ...
  int x;
  if (GetIsPC(oY)) // if-statements often introduce nested scoping blocks
  {
    float x;  // This is allowed but it's a different x in this scope.
    ...       // x in these statements is the float version
  }           // x "the float" goes out of scope here
  ...         // x in these statements is the int variable
  x = GetXP(oY); // reuse the first x instead of trying to make a second
  int exp = GetXP(oY); // or give the new variable a unique name
  ...
}             // x "the int" goes out of scope here as does the object oY

Resolved by ensuring variable names are all unique within the same scope.

VARIABLE DEFINED WITHOUT TYPE

Error Message Meaning Example

This one means the compiler has encountered an expression that is referencing a variable name which is unrecognized. Presumably because the script author failed to define the variable before trying to use it. The compiler only knows about variable names once they have been defined, and as long as they are in scope. For a definition of scope see the explanation above for the VARIABLE ALREADY USED WITHIN SCOPE error message.

It is common to get this error by misspelling a variable or constant name. Trying to use a variable name before it is defined or after it has gone out of scope will sometimes produce this error message, and sometimes produce the UNDEFINED IDENTIFIER (<Name>) message depending on how the script is written. They are both related to the same mistakes.

// Incorrect:

// Some script.
void main()
{
  object oPC = GetFirstPC();
  int    i;
  for (i = 0; i < iLoops; i++)
  {
    int x = i *2;
    ...
  }
  
  int y = x;
  ...
}

The problem is the variable iLoops is being used in the for-loop but it has never been defined or assigned a value. Also, the variable y is being created and an attempt is being made to assign it an initial value equivalent to the value of the variable x. But the variable x, although previously defined, was defined inside a nested scoping block and no longer exists at the point where y is being defined. Each of these mistakes will get you a VARIABLE DEFINED WITHOUT TYPE error.

// Correct:

// Some script.
void main()
{
  object oPC    = GetFirstPC();
  int    iLoops = (GetHitDice( oPC) /2) +1;
  int    i;
  for (i = 0; i < iLoops; i++)
  { int x = i *2;
    ...
  }
  
  int y = i *2;
  ...
}

Resolved by ensuring all variable names being used have been defined prior to their use, and that no variables are being referenced outside of their scope. In this case, that is accomplished by adding a definition for a variable named iLoops, and by not trying to use the variable x when defining the variable y.




// Incorrect:

// Some script.
void main()
{
  object oPC        = GetFirstPC();
  int    iAlignment = GetAlignmentGoodEvil(oPC);
  int    iTeam      = 0;
  
  if (iAlignment == ALIGNMENT_GOOD)
  {
    iTeam = 1;
    ...
  }                              
  else if (iAlignment == ALIGNMENT_NUTREAL)
  {
    iTeam = 2;
    ...
  }                            
  else if (iAlignment == ALIGNMENT_EVIL)
  {
    iTeam = 3;
    ...
  }
  
  SetLocalInt( oPC, "Team", iTeam);
  ...
}

The problem is the Bioware constant for neutral alignment is being used in the second if-statement but has been misspelled. Since no constant has been defined for the incorrectly spelled name, it is an unknown identifier.

// Correct:

// Some script.
void main()
{
  object oPC        = GetFirstPC();
  int    iAlignment = GetAlignmentGoodEvil(oPC);
  int    iTeam      = 0;
  
  if (iAlignment == ALIGNMENT_GOOD)
  {
    iTeam = 1;
    ...
  }                              
  else if (iAlignment == ALIGNMENT_NEUTRAL)
  {
    iTeam = 2;
    ...
  }                            
  else if (iAlignment == ALIGNMENT_EVIL)
  {
    iTeam = 3;
    ...
  }
  
  SetLocalInt( oPC, "Team", iTeam);
  ...
}

Resolved by making sure all referenced variable and constant names are spelled correctly.


author: Axe Murderer, editors: Proleric, Mistress, contributor: Ken Cotterill