Libraries allow the builder to encapsulate many scripts into one, dramatically reducing the script count in the module. In a library, each script is a function bound to a unique name and/or number. When the library is called, the name is routed to the proper function.
Since each script defined by a library has a unique name to identify it, the builder can execute a library script without having to know the file it is located in. This makes it easy to create script systems to override behavior of another system; you don't have to edit the other system's code, you just implement your own function to override it.
util_i_libraries.nss
holds functions for interacting with libraries. This
script requires util_i_debug.nss
, util_i_csvlists.nss
, util_i_sqlite.nss
,
and util_i_nss.nss
.
This is an example of a simple library:
#include "util_i_libraries"
void MyFunction()
{
// ...
}
void MyOtherFunction()
{
// ...
}
void OnLibraryLoad()
{
RegisterLibraryScript("MyFunction");
RegisterLibraryScript("MyOtherFunction");
}
This script contains custom functions (MyFunction()
and MyOtherFunction()
) as
well as an OnLibraryLoad()
function. OnLibraryLoad()
is executed whenever
the library is loaded by LoadLibrary()
; it calls RegisterLibraryScript()
to
expose the names of the custom functions as library scripts. When a library
script is called with RunLibraryScript()
, the custom functions are called.
If you want to do something more complicated that can't be handled by a single
function call, you can pass a unique number to RegisterLibraryScript()
as its
second parameter, which will cause RunLibraryScript()
to call a special
customizable dispatching function called OnLibraryScript()
. This function
takes the name and number of the desired function and executes the desired code.
For example:
#include "util_i_libraries"
void OnLibraryLoad()
{
RegisterLibraryScript("Give50GP", 1);
RegisterLibraryScript("Give100GP", 2);
}
void OnLibraryScript(string sScript, int nEntry)
{
switch (nEntry)
{
case 1: GiveGoldToCreature(OBJECT_SELF, 50); break;
case 2: GiveGoldToCreature(OBJECT_SELF, 100); break;
}
}
Note: A library does not need to have a main()
function, because this will
be automatically generated by the LoadLibrary()
and RunLibraryScript()
functions.
util_i_libraries.nss
is needed to load or run library scripts.
To use a library, you must first load it. This will activate the library's
OnLibraryLoad()
function and register each desired function.
// Loads a single library
LoadLibrary("my_l_library");
// Loads a CSV list of library scripts
LoadLibraries("pw_l_plugin, dlg_l_example, prr_l_main");
// Loads all libraries matching a glob pattern
LoadLibrariesByPattern("*_l_*");
// Loads all libraries matching a prefix
LoadLibrariesByPrefix("pw_l_");
If a library implements a script that has already been implemented in another library, a warning will be issued and the newer script will take precedence.
Calling a library script is done using RunLibraryScript()
. The name supplied
should be the name bound to the function in the library's OnLibraryLoad()
. If
the name supplied is implemented by a library, the library will be JIT compiled
and the desired function will be called with ExecuteScriptChunk()
. Otherwise,
the name will be assumed to match a normal script, which will be executed with
ExecuteScript()
.
// Executes a single library script on OBJECT_SELF
RunLibraryScript("MyFunction");
// Executes a CSV list of library scripts, for which oPC will be OBJECT_SELF
object oPC = GetFirstPC();
RunLibraryScripts("MyFunction, MyOtherFunction", oPC);
By default, libraries are run using ExecuteScriptChunk()
, which JIT compiles
the script and runs it each time the library script is called. If you wish to
have your script pre-compiled, you can include the script util_i_library.nss
in your file in place of util_i_libraries.nss
. This script contains a main()
function that will call either your OnLibraryLoad()
or OnLibraryScript()
function as appropriate; thus, if you use this method, you must provide an
OnLibraryScript()
dispatch function.
Note: util_i_library.nss
uses the nwnsc default_function
pragma to
prevent compilation errors and will not compile with the toolset compiler. If
this is not desired, you can either comment those lines out or implement the
main()
function yourself.
For longer libraries, string comparison in a large if/else tree may be tedious
and slow. Using nEntry
to identify the script to run can help, and it enables
more complicated routing. For example, in this long library, we use a
switch/case statement to limit the number of comparisons we have to make. The
hex formatting and bitwise operations make it a little easier to visually
distinguish related scripts, but it's not really necessary:
void OnLibraryLoad()
{
// Event functions
RegisterLibraryScript("prr_OnComponentActivate", 0x0100+0x01);
RegisterLibraryScript("prr_OnClientEnter", 0x0100+0x02);
// Dialog utility functions
RegisterLibraryScript("prr_SetDatabaseInt", 0x0200+0x01);
RegisterLibraryScript("prr_GetDatabaseInt", 0x0200+0x02);
RegisterLibraryScript("prr_SetHasMetNPC", 0x0200+0x03);
RegisterLibraryScript("prr_GetHasMetNPC", 0x0200+0x04);
RegisterLibraryScript("prr_GetReactionHate", 0x0200+0x05);
RegisterLibraryScript("prr_GetReactionNeutral", 0x0200+0x06);
RegisterLibraryScript("prr_GetReactionLike", 0x0200+0x07);
RegisterLibraryScript("prr_SkillCheckHigh", 0x0200+0x08);
RegisterLibraryScript("prr_SkillCheckMid", 0x0200+0x09);
RegisterLibraryScript("prr_SkillCheckLow", 0x0200+0x0A);
RegisterLibraryScript("prr_SkillCheckCustom", 0x0200+0x0B);
// Dialog reputation functions
RegisterLibraryScript("prr_ReputationIncreaseHigh", 0x0300+0x01);
RegisterLibraryScript("prr_ReputationIncreaseMid", 0x0300+0x02);
RegisterLibraryScript("prr_ReputationIncreaseLow", 0x0300+0x03);
RegisterLibraryScript("prr_ReputationDecreaseHigh", 0x0300+0x04);
RegisterLibraryScript("prr_ReputationDecreaseMid", 0x0300+0x05);
RegisterLibraryScript("prr_ReputationDecreaseLow", 0x0300+0x06);
RegisterLibraryScript("prr_ReputationChangeCustom", 0x0300+0x07);
RegisterLibraryScript("prr_ReputationIncreaseHigh_Party", 0x0300+0x08);
RegisterLibraryScript("prr_ReputationIncreaseMid_Party", 0x0300+0x09);
RegisterLibraryScript("prr_ReputationIncreaseLow_Party", 0x0300+0x0A);
RegisterLibraryScript("prr_ReputationDecreaseHigh_Party", 0x0300+0x0B);
RegisterLibraryScript("prr_ReputationDecreaseMid_Party", 0x0300+0x0C);
RegisterLibraryScript("prr_ReputationDecreaseLow_Party", 0x0300+0x0D);
RegisterLibraryScript("prr_ReputationChangeCustom_Party", 0x0300+0x0E);
// Dialog faction reputation functions
RegisterLibraryScript("prr_FactionReputationIncreaseHigh", 0x0400+0x01);
RegisterLibraryScript("prr_FactionReputationIncreaseMid", 0x0400+0x02);
RegisterLibraryScript("prr_FactionReputationIncreaseLow", 0x0400+0x03);
RegisterLibraryScript("prr_FactionReputationDecreaseHigh", 0x0400+0x04);
RegisterLibraryScript("prr_FactionReputationDecreaseMid", 0x0400+0x05);
RegisterLibraryScript("prr_FactionReputationDecreaseLow", 0x0400+0x06);
RegisterLibraryScript("prr_FactionReputationChangeCustom", 0x0400+0x07);
RegisterLibraryScript("prr_FactionReputationIncreaseHigh_Party", 0x0400+0x08);
RegisterLibraryScript("prr_FactionReputationIncreaseMid_Party", 0x0400+0x09);
RegisterLibraryScript("prr_FactionReputationIncreaseLow_Party", 0x0400+0x0A);
RegisterLibraryScript("prr_FactionReputationDecreaseHigh_Party", 0x0400+0x0B);
RegisterLibraryScript("prr_FactionReputationDecreaseMid_Party", 0x0400+0x0C);
RegisterLibraryScript("prr_FactionReputationDecreaseLow_Party", 0x0400+0x0D);
RegisterLibraryScript("prr_FactionReputationChangeCustom_Party", 0x0400+0x0E);
// General Utility functions
RegisterLibraryScript("prr_CaptureChatText", 0x0500+0x01);
}
void OnLibraryScript(string sScript, int nEntry)
{
switch (nEntry & 0xff00)
{
case 0x0100:
switch (nEntry & 0x00ff)
{
case 0x01: prr_OnComponentActivate(); break;
case 0x02: prr_OnClientEnter(); break;
} break;
case 0x0200:
switch (nEntry & 0x00ff)
{
case 0x01: prr_SetDatabaseInt(); break;
case 0x02: prr_GetDatabaseInt(); break;
case 0x03: prr_SetHasMetNPC(); break;
case 0x04: prr_GetHasMetNPC(); break;
case 0x05: prr_GetReactionHate(); break;
case 0x06: prr_GetReactionNeutral(); break;
case 0x07: prr_GetReactionLike(); break;
case 0x08: prr_SkillCheckHigh(); break;
case 0x09: prr_SkillCheckMid(); break;
case 0x0A: prr_SkillCheckLow(); break;
case 0x0B: prr_SkillCheckCustom(); break;
} break;
case 0x0300:
switch (nEntry & 0x00ff)
{
case 0x01: prr_ReputationIncreaseHigh(); break;
case 0x02: prr_ReputationIncreaseMid(); break;
case 0x03: prr_ReputationIncreaseLow(); break;
case 0x04: prr_ReputationDecreaseHigh(); break;
case 0x05: prr_ReputationDecreaseMid(); break;
case 0x06: prr_ReputationDecreaseLow(); break;
case 0x07: prr_ReputationChangeCustom(); break;
case 0x08: prr_ReputationIncreaseHigh_Party(); break;
case 0x09: prr_ReputationIncreaseMid_Party(); break;
case 0x0A: prr_ReputationIncreaseLow_Party(); break;
case 0x0B: prr_ReputationDecreaseHigh_Party(); break;
case 0x0C: prr_ReputationDecreaseMid_Party(); break;
case 0x0D: prr_ReputationDecreaseLow_Party(); break;
case 0x0E: prr_ReputationChangeCustom_Party(); break;
} break;
case 0x0400:
switch (nEntry & 0x00ff)
{
case 0x01: prr_FactionReputationIncreaseHigh(); break;
case 0x02: prr_FactionReputationIncreaseMid(); break;
case 0x03: prr_FactionReputationIncreaseLow(); break;
case 0x04: prr_FactionReputationDecreaseHigh(); break;
case 0x05: prr_FactionReputationDecreaseMid(); break;
case 0x06: prr_FactionReputationDecreaseLow(); break;
case 0x07: prr_FactionReputationChangeCustom(); break;
case 0x08: prr_FactionReputationIncreaseHigh_Party(); break;
case 0x09: prr_FactionReputationIncreaseMid_Party(); break;
case 0x0A: prr_FactionReputationIncreaseLow_Party(); break;
case 0x0B: prr_FactionReputationDecreaseHigh_Party(); break;
case 0x0C: prr_FactionReputationDecreaseMid_Party(); break;
case 0x0D: prr_FactionReputationDecreaseLow_Party(); break;
case 0x0E: prr_FactionReputationChangeCustom_Party(); break;
} break;
case 0x0500:
switch (nEntry & 0x00ff)
{
case 0x01: prr_CaptureChatText(); break;
} break;
}
}
If maintaining the function reference (nEntry
) numbers proves challenging due
to the size of the library, you can use variable incrementation to assign and
access function reference numbers. This technique will require less time to
build a library, however, order is exceptionally important.
Warning If a function is no longer registered by RegisterLibraryScript
in
OnLibraryLoad()
, it must be removed from OnLibraryScript()
or this
technique may route the request to an undesired function. Additionally, the
functions routed in OnLibraryScript()
must be inserted in the same order they
are registered in OnLibraryLoad()
.
The following is the same library definition as above, but uses variable
incrementation to define the function entry numbers. The various subsections are
defined by modifying the value of, in this case, n
, but any variable may be
used.
Note Dividing functions into sections is a technique, not a requirement.
This example uses an increment of 100 numbers between sections. If another
increment is used, that number should be reflected in the value of n
and the
case
values in OnLibraryScript()
.
void OnLibraryLoad()
{
// Event functions
int n = 100;
RegisterLibraryScript("prr_OnComponentActivate", n++);
RegisterLibraryScript("prr_OnClientEnter", n++);
// Dialog utility functions
n = 200;
RegisterLibraryScript("prr_SetDatabaseInt", n++);
RegisterLibraryScript("prr_GetDatabaseInt", n++);
RegisterLibraryScript("prr_SetHasMetNPC", n++);
RegisterLibraryScript("prr_GetHasMetNPC", n++);
RegisterLibraryScript("prr_GetReactionHate", n++);
RegisterLibraryScript("prr_GetReactionNeutral", n++);
RegisterLibraryScript("prr_GetReactionLike", n++);
RegisterLibraryScript("prr_SkillCheckHigh", n++);
RegisterLibraryScript("prr_SkillCheckMid", n++);
RegisterLibraryScript("prr_SkillCheckLow", n++);
RegisterLibraryScript("prr_SkillCheckCustom", n++);
// Dialog reputation functions
n = 300;
RegisterLibraryScript("prr_ReputationIncreaseHigh", n++);
RegisterLibraryScript("prr_ReputationIncreaseMid", n++);
RegisterLibraryScript("prr_ReputationIncreaseLow", n++);
RegisterLibraryScript("prr_ReputationDecreaseHigh", n++);
RegisterLibraryScript("prr_ReputationDecreaseMid", n++);
RegisterLibraryScript("prr_ReputationDecreaseLow", n++);
RegisterLibraryScript("prr_ReputationChangeCustom", n++);
RegisterLibraryScript("prr_ReputationIncreaseHigh_Party", n++);
RegisterLibraryScript("prr_ReputationIncreaseMid_Party", n++);
RegisterLibraryScript("prr_ReputationIncreaseLow_Party", n++);
RegisterLibraryScript("prr_ReputationDecreaseHigh_Party", n++);
RegisterLibraryScript("prr_ReputationDecreaseMid_Party", n++);
RegisterLibraryScript("prr_ReputationDecreaseLow_Party", n++);
RegisterLibraryScript("prr_ReputationChangeCustom_Party", n++);
// Dialog faction reputation functions
n = 400;
RegisterLibraryScript("prr_FactionReputationIncreaseHigh", n++);
RegisterLibraryScript("prr_FactionReputationIncreaseMid", n++);
RegisterLibraryScript("prr_FactionReputationIncreaseLow", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseHigh", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseMid", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseLow", n++);
RegisterLibraryScript("prr_FactionReputationChangeCustom", n++);
RegisterLibraryScript("prr_FactionReputationIncreaseHigh_Party", n++);
RegisterLibraryScript("prr_FactionReputationIncreaseMid_Party", n++);
RegisterLibraryScript("prr_FactionReputationIncreaseLow_Party", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseHigh_Party", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseMid_Party", n++);
RegisterLibraryScript("prr_FactionReputationDecreaseLow_Party", n++);
RegisterLibraryScript("prr_FactionReputationChangeCustom_Party", n++);
// General Utility functions
n = 500;
RegisterLibraryScript("prr_CaptureChatText", n++);
}
void OnLibraryScript(string sScript, int nEntry)
{
int n = nEntry / 100 * 100;
switch (n)
{
case 100:
{
if (nEntry == n++) prr_OnComponentActivate();
else if (nEntry == n++) prr_OnClientEnter();
} break;
case 200:
{
if (nEntry == n++) prr_SetDatabaseInt();
else if (nEntry == n++) prr_GetDatabaseInt();
else if (nEntry == n++) prr_SetHasMetNPC();
else if (nEntry == n++) prr_GetDatabaseInt();
else if (nEntry == n++) prr_GetReactionHate();
else if (nEntry == n++) prr_GetReactionNeutral();
else if (nEntry == n++) prr_GetReactionLike();
else if (nEntry == n++) prr_SkillCheckHigh();
else if (nEntry == n++) prr_SkillCheckMid();
else if (nEntry == n++) prr_SkillCheckLow();
else if (nEntry == n++) prr_SkillCheckCustom();
} break;
case 300:
{
if (nEntry == n++) prr_ReputationIncreaseHigh();
else if (nEntry == n++) prr_ReputationIncreaseMid();
else if (nEntry == n++) prr_ReputationIncreaseLow();
else if (nEntry == n++) prr_ReputationDecreaseHigh();
else if (nEntry == n++) prr_ReputationDecreaseMid();
else if (nEntry == n++) prr_ReputationDecreaseLow();
else if (nEntry == n++) prr_ReputationChangeCustom();
else if (nEntry == n++) prr_ReputationIncreaseHigh_Party();
else if (nEntry == n++) prr_ReputationIncreaseMid_Party();
else if (nEntry == n++) prr_ReputationIncreaseLow_Party();
else if (nEntry == n++) prr_ReputationDecreaseHigh_Party();
else if (nEntry == n++) prr_ReputationDecreaseMid_Party();
else if (nEntry == n++) prr_ReputationDecreaseLow_Party();
else if (nEntry == n++) prr_ReputationChangeCustom_Party();
} break;
case 400:
{
if (nEntry == n++) prr_FactionReputationIncreaseHigh();
else if (nEntry == n++) prr_FactionReputationIncreaseMid();
else if (nEntry == n++) prr_FactionReputationIncreaseLow();
else if (nEntry == n++) prr_FactionReputationDecreaseHigh();
else if (nEntry == n++) prr_FactionReputationDecreaseMid();
else if (nEntry == n++) prr_FactionReputationDecreaseLow();
else if (nEntry == n++) prr_FactionReputationChangeCustom();
else if (nEntry == n++) prr_FactionReputationIncreaseHigh_Party();
else if (nEntry == n++) prr_FactionReputationIncreaseMid_Party();
else if (nEntry == n++) prr_FactionReputationIncreaseLow_Party();
else if (nEntry == n++) prr_FactionReputationDecreaseHigh_Party();
else if (nEntry == n++) prr_FactionReputationDecreaseMid_Party();
else if (nEntry == n++) prr_FactionReputationDecreaseLow_Party();
else if (nEntry == n++) prr_FactionReputationChangeCustom_Party();
} break;
case 500:
{
if (nEntry == n++) prr_CaptureChatText();
} break;
default: CriticalError("Library function " + sScript + " not found");
}
}