Added persistent player storage
Added persistent player storage. Fixed store items. Full compile. Updated release archive.
This commit is contained in:
44
_module/nss/at_ent_dbi_room.nss
Normal file
44
_module/nss/at_ent_dbi_room.nss
Normal file
@@ -0,0 +1,44 @@
|
||||
void main()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
object oBaseArea = GetObjectByTag("DBI_PC_ROOMS");
|
||||
|
||||
string sPCName = GetName(oPC);
|
||||
string sBaseResRef = GetResRef(oBaseArea);
|
||||
string sBaseName = GetName(oBaseArea);
|
||||
string sNewTag = sPCName+sBaseResRef;
|
||||
string sNewName = sPCName+"'s Room at the Dragonback Inn";
|
||||
|
||||
//:: Create instanced area from player's information
|
||||
CreateArea(sBaseResRef, sNewTag, sNewName);
|
||||
|
||||
//:: Get information about new area instance
|
||||
object oNewRoom = GetObjectByTag(sNewTag);
|
||||
string sNewResRef = GetResRef(oNewRoom);
|
||||
|
||||
|
||||
location lEntry = GetLocation(GetObjectByTag("DBI_ROOM_MAT"));
|
||||
|
||||
|
||||
//:: Create entry waypoint in new area instance
|
||||
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", lEntry, FALSE, "WP_"+sNewTag);
|
||||
|
||||
//:: Make sure the area is valid
|
||||
object oTarget;
|
||||
location lTarget;
|
||||
oTarget = GetWaypointByTag("WP_"+sNewTag);
|
||||
|
||||
lTarget = GetLocation(oTarget);
|
||||
|
||||
if (GetAreaFromLocation(lTarget)==OBJECT_INVALID)
|
||||
{
|
||||
SendMessageToPC(oPC, "Warning: Area does not exist!");
|
||||
return;
|
||||
}
|
||||
//:: Move PC to instanced area.
|
||||
AssignCommand(oPC, ClearAllActions());
|
||||
|
||||
AssignCommand(oPC, ActionJumpToLocation(lTarget));
|
||||
|
||||
}
|
44
_module/nss/at_enter_pc_room.nss
Normal file
44
_module/nss/at_enter_pc_room.nss
Normal file
@@ -0,0 +1,44 @@
|
||||
void main()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
object oBaseArea = GetObjectByTag("IFM_PC_ROOMS");
|
||||
|
||||
string sPCName = GetName(oPC);
|
||||
string sBaseResRef = GetResRef(oBaseArea);
|
||||
string sBaseName = GetName(oBaseArea);
|
||||
string sNewTag = sPCName+sBaseResRef;
|
||||
string sNewName = sPCName+"'s Room at the Flying Monkey";
|
||||
|
||||
//:: Create instanced area from player's information
|
||||
CreateArea(sBaseResRef, sNewTag, sNewName);
|
||||
|
||||
//:: Get information about new area instance
|
||||
object oNewRoom = GetObjectByTag(sNewTag);
|
||||
string sNewResRef = GetResRef(oNewRoom);
|
||||
|
||||
|
||||
location lEntry = GetLocation(GetObjectByTag("PC_ROOM_MAT"));
|
||||
|
||||
|
||||
//:: Create entry waypoint in new area instance
|
||||
CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", lEntry, FALSE, "WP_"+sNewTag);
|
||||
|
||||
//:: Make sure the area is valid
|
||||
object oTarget;
|
||||
location lTarget;
|
||||
oTarget = GetWaypointByTag("WP_"+sNewTag);
|
||||
|
||||
lTarget = GetLocation(oTarget);
|
||||
|
||||
if (GetAreaFromLocation(lTarget)==OBJECT_INVALID)
|
||||
{
|
||||
SendMessageToPC(oPC, "Warning: Area does not exist!");
|
||||
return;
|
||||
}
|
||||
//:: Move PC to instanced area.
|
||||
AssignCommand(oPC, ClearAllActions());
|
||||
|
||||
AssignCommand(oPC, ActionJumpToLocation(lTarget));
|
||||
|
||||
}
|
10
_module/nss/cv_inn_door.nss
Normal file
10
_module/nss/cv_inn_door.nss
Normal file
@@ -0,0 +1,10 @@
|
||||
void main()
|
||||
{
|
||||
|
||||
object oPC = GetClickingObject();
|
||||
|
||||
if (!GetIsPC(oPC)) return;
|
||||
|
||||
ActionStartConversation(oPC, "");
|
||||
|
||||
}
|
@@ -5,9 +5,16 @@
|
||||
// multiple handlers for the onmoduleload event.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
#include "nui_i_main"
|
||||
|
||||
void main()
|
||||
{
|
||||
ExecuteScript("prc_onmodload", OBJECT_SELF);
|
||||
SetEventScript(GetModule(), EVENT_SCRIPT_MODULE_ON_NUI_EVENT, "mod_events");
|
||||
SetEventScript(GetModule(), EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET, "mod_events");
|
||||
|
||||
NUI_Initialize();
|
||||
NUI_HandleEvents();
|
||||
|
||||
ExecuteScript("prc_onmodload", OBJECT_SELF);
|
||||
ExecuteScript("trin_modload", OBJECT_SELF);
|
||||
}
|
||||
|
23
_module/nss/mod_events.nss
Normal file
23
_module/nss/mod_events.nss
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "nui_i_main"
|
||||
|
||||
void main()
|
||||
{
|
||||
int nEvent = GetCurrentlyRunningEvent();
|
||||
|
||||
if (nEvent == EVENT_SCRIPT_MODULE_ON_MODULE_LOAD)
|
||||
{
|
||||
SetEventScript(GetModule(), EVENT_SCRIPT_MODULE_ON_NUI_EVENT, "mod_events");
|
||||
SetEventScript(GetModule(), EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET, "mod_events");
|
||||
|
||||
NUI_Initialize();
|
||||
NUI_HandleEvents();
|
||||
}
|
||||
else if (nEvent == EVENT_SCRIPT_MODULE_ON_NUI_EVENT)
|
||||
{
|
||||
NUI_HandleEvents();
|
||||
}
|
||||
else if (nEvent == EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET)
|
||||
{
|
||||
NUI_HandleEvents(GetLastPlayerToSelectTarget());
|
||||
}
|
||||
}
|
6
_module/nss/mod_nuievent.nss
Normal file
6
_module/nss/mod_nuievent.nss
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "nui_i_main"
|
||||
|
||||
void main()
|
||||
{
|
||||
NUI_HandleEvents();
|
||||
}
|
8
_module/nss/mod_onplaytarget.nss
Normal file
8
_module/nss/mod_onplaytarget.nss
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "nui_i_main"
|
||||
|
||||
void main()
|
||||
{
|
||||
ExecuteScript("prc_onplaytarget");
|
||||
|
||||
NUI_HandleEvents(GetLastPlayerToSelectTarget());
|
||||
}
|
50
_module/nss/nui_c_config.nss
Normal file
50
_module/nss/nui_c_config.nss
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file nui_c_config.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief NUI Form Creation and Management System Configuration
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// FORM INSPECTOR
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// The form inspection capability allows you to record data about a form's status,
|
||||
// including bind values and how various events affect them. To use the inspection
|
||||
// capability, you must include the `nui_f_inspector` formfile in your module and
|
||||
// set NUI_FI_RECORD_DATA to the desired value.
|
||||
|
||||
// *** WARNING *** Form inspection is very expensive. Is it recommended that
|
||||
// you only use the form inspection capability during debug or set this
|
||||
// value to NUI_FI_WHEN_OPEN to prevent unnecessary traffic.
|
||||
const int NUI_FI_NEVER = 0;
|
||||
const int NUI_FI_ALWAYS = 1;
|
||||
const int NUI_FI_WHEN_OPEN = 2;
|
||||
|
||||
const int NUI_FI_RECORD_DATA = NUI_FI_WHEN_OPEN;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Custom Functions
|
||||
// MODIFY THESE TO ENSURE COMPATIBILTY WITH YOUR MODULE'S SYSTEMS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// This system has some basic debugging functionality. In order to make this system work
|
||||
// under multiple modules without collision, the following function is provided to
|
||||
// allow you to call whatever debugging system you'd like to call. If you use
|
||||
// squattingmonk's debug utility, no changes need to be made. The primary system does
|
||||
// not provide any organic debug calls, but this function is available to all formfiles
|
||||
// for debugging purposes.
|
||||
//
|
||||
const int NUI_DEBUG_SEVERITY_NONE = 0;
|
||||
const int NUI_DEBUG_SEVERITY_CRITICAL = 1;
|
||||
const int NUI_DEBUG_SEVERITY_ERROR = 2;
|
||||
const int NUI_DEBUG_SEVERITY_WARNING = 3;
|
||||
const int NUI_DEBUG_SEVERITY_NOTICE = 4;
|
||||
const int NUI_DEBUG_SEVERITY_DEBUG = 5;
|
||||
|
||||
//#include "util_i_debug"
|
||||
|
||||
void NUI_Debug(string sMessage, int nSeverity = 4)
|
||||
{
|
||||
//Debug(sMessage, nSeverity);
|
||||
}
|
225
_module/nss/nui_c_storage.nss
Normal file
225
_module/nss/nui_c_storage.nss
Normal file
@@ -0,0 +1,225 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file nui_c_storage.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Persistent Storage formfile configuration settings
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
/// @note Most of the following global/default settings can be overriden on a
|
||||
/// per-container basis by setting a local variable on the container
|
||||
/// object as noted in the setting descriptions below. Constants, such as
|
||||
/// PS_TRUE, PS_NONE, etc. should be used in this configuration file, however,
|
||||
/// actual values must be used when setting local overrides. Those values
|
||||
/// are provided below.
|
||||
|
||||
/// @warning This system uses player character UUIDs. This can cause issues in
|
||||
/// single-player modules if the player-character is not exported and the
|
||||
/// UUID is not saved to the .bic file.
|
||||
|
||||
/// @brief By default, containers will be saved to a database table referenced
|
||||
/// by the container object's tag. The saved item data includes the UUID
|
||||
/// and CD Key of the PC that deposited the item so the same container can
|
||||
/// be used for multiple PCs. To set a specific (unique) name to use as the
|
||||
/// table name instead, set a local string called `PS_UNIQUE_ID` on the
|
||||
/// container object and set it to any unique string.
|
||||
|
||||
/// @brief Determines usage of the `Search` button.
|
||||
/// Configuration File:
|
||||
/// PS_TRUE to force players to click the `Search` button
|
||||
/// before an inventory search will commence. This is a good idea
|
||||
/// for containers that you expect will have large inventories.
|
||||
/// PS_FALSE to allow real-time searching as the player types
|
||||
/// characters into the `Search` textbox.
|
||||
/// Local Override (int): PS_FORCE_SEARCH_BUTTON
|
||||
/// 1 = PS_TRUE
|
||||
/// -1 = PS_FALSE
|
||||
const int PS_FORCE_SEARCH_BUTTON_DEFAULT = PS_FALSE;
|
||||
|
||||
/// @brief Determines whether item object state is saved to the database. The
|
||||
/// object state includes variables and effects.
|
||||
/// Configuration File:
|
||||
/// PS_TRUE saves the object state
|
||||
/// PS_FALSE does not save the object state
|
||||
/// Local Override (int): PS_FORCE_OBJECT_STATE
|
||||
/// 1 = PS_TRUE
|
||||
/// -1 = PS_FALSE
|
||||
const int PS_FORCE_OBJECT_STATE_DEFAULT = PS_TRUE;
|
||||
|
||||
/// @brief Sets the item storage limit.
|
||||
/// Configuration File:
|
||||
/// PS_UNLIMITED to allow unlimited item storage.
|
||||
/// Set to any positive integer to limit item storage to that amount.
|
||||
/// Local Override (int): PS_STORAGE_LIMIT
|
||||
/// -1 = PS_UNLIMITED
|
||||
/// Set to any positive integer to limit item storage to that amount.
|
||||
const int PS_STORAGE_LIMIT_DEFAULT = 500;
|
||||
|
||||
/// @brief Set the maximum distance (meters) a PC can travel from the container
|
||||
/// before the form will auto-close.
|
||||
/// Configuration File:
|
||||
/// PS_UNLIMITED_DISTANCE to never auto-close the form
|
||||
/// Set to any positive float to limit distance to that amount.
|
||||
/// Local Override (float): PS_DISTANCE
|
||||
/// -1.0 = PS_UNLIMITED_DISTANCE
|
||||
/// Set to any positive float to limit distance to that amount.
|
||||
const float PS_DISTANCE_DEFAULT = 2.0;
|
||||
|
||||
/// @brief Set the container access type. Container inventories can be accessed
|
||||
/// by two methods: exclusive and contentious.
|
||||
/// - Exclusive: Multiple players may open the same container, but each
|
||||
/// player will only see items they've previously deposited. Players
|
||||
/// may only withdraw items they've previously deposited.
|
||||
/// - Contentious: Multiple players may open the same container. All
|
||||
/// players will see all items deposited by any player. Any player
|
||||
/// can remove any item, regardless of who originally deposited the
|
||||
/// item.
|
||||
///
|
||||
/// Configuration File:
|
||||
/// PS_ACCESS_EXCLUSIVE for exclusive access
|
||||
/// PS_ACCESS_CONTENTIOUS for contentious access
|
||||
/// Local Override (int): PS_ACCESS_TYPE
|
||||
/// 1 = PS_ACCESS_EXCLUSIVE
|
||||
/// 2 = PS_ACCESS_CONTENTIOUS
|
||||
const int PS_ACCESS_TYPE_DEFAULT = PS_ACCESS_EXCLUSIVE;
|
||||
|
||||
/// @brief Set the container type. Containers can be of multiple types:
|
||||
/// - Public: Any player can open, deposit and withdraw items from this
|
||||
/// container. Whether they are limited to specific items is dependant
|
||||
/// on the container's access setting.
|
||||
/// - Character: Creates a 'portable' storage container for any player
|
||||
/// character. Any container of this type will hold the same inventory
|
||||
/// for any specific player.
|
||||
/// - CD Key: Creates a 'portable' storage container for any characters
|
||||
/// owned by cd-key associated with the player character. Any container
|
||||
/// of this type will hold the inventory desposited by any character
|
||||
/// sharing the player's cd key.
|
||||
///
|
||||
/// Configuration File:
|
||||
/// PS_CONTAINER_PUBLIC for public.
|
||||
/// PS_CONTAINER_CHARACTER for per-character.
|
||||
/// PS_CONTAINER_CD_KEY for per-cdkey.
|
||||
/// Local Override (int): PS_CONTAINER_TYPE
|
||||
/// 1 = PS_CONTAINER_PUBLIC
|
||||
/// 2 = PS_CONTAINER_CHARACTER
|
||||
/// 3 = PS_CONTAINER_CDKEY
|
||||
const int PS_CONTAINER_TYPE_DEFAULT = PS_CONTAINER_CDKEY;
|
||||
|
||||
/// @brief Set the default container type, if the container is an item. Containers
|
||||
/// can be of multiple types:
|
||||
/// - Public: Any player can open, deposit and withdraw items from this
|
||||
/// container. Whether they are limited to specific items is dependant
|
||||
/// on the container's access setting.
|
||||
/// - Character: Creates a 'portable' storage container for any player
|
||||
/// character. Any container of this type will hold the same inventory
|
||||
/// for any specific player.
|
||||
/// - CD Key: Creates a 'portable' storage container for any characters
|
||||
/// owned by cd-key associated with the player character. Any container
|
||||
/// of this type will hold the inventory desposited by any character
|
||||
/// sharing the player's cd key.
|
||||
///
|
||||
/// Configuration File:
|
||||
/// PS_CONTAINER_PUBLIC for public.
|
||||
/// PS_CONTAINER_CHARACTER for per-character.
|
||||
/// PS_CONTAINER_CD_KEY for per-cdkey.
|
||||
/// Local Override (int): PS_CONTAINER_TYPE
|
||||
/// 1 = PS_CONTAINER_PUBLIC
|
||||
/// 2 = PS_CONTAINER_CHARACTER
|
||||
/// 3 = PS_CONTAINER_CDKEY
|
||||
const int PS_CONTAINER_ITEM_TYPE_DEFAULT = PS_CONTAINER_CDKEY;
|
||||
|
||||
/// @brief Determines whether the player's inventory window will be opened
|
||||
/// when a container is opened.
|
||||
/// Configuration File:
|
||||
/// PS_TRUE to open the inventory window.
|
||||
/// PS_FALSE to prevent the window from opening. If the inventory
|
||||
/// window is already open, this will not close it.
|
||||
/// Local Override (int): PS_OPEN_INVENTORY
|
||||
/// 1 = PS_TRUE
|
||||
/// -1 = PS_FALSE
|
||||
const int PS_OPEN_INVENTORY_DEFAULT = PS_TRUE;
|
||||
|
||||
/// @brief Determines the maximum amount of gold a container can store.
|
||||
/// If the container is set to store no gold, the form controls that
|
||||
/// manipulate gold storage will not be visible on the form.
|
||||
/// Configuration File:
|
||||
/// PS_UNLIMITED to allow unlimited gold storage.
|
||||
/// PS_NONE to prevent gold storage.
|
||||
/// Set to any positive integer to limit gold to that amount.
|
||||
/// Local Override (int): PS_MAX_GOLD
|
||||
/// -1 = PS_UNLIMITED
|
||||
/// -2 = PS_NONE
|
||||
/// Set to any positive integer to limit gold to that amount.
|
||||
const int PS_MAX_GOLD_DEFAULT = 2000000000;
|
||||
|
||||
/// @note Reference these terms for the following option:
|
||||
/// Container: A persistent storage object in the game, such as a chest.
|
||||
/// Container Item: An item which:
|
||||
/// Can have its own inventory
|
||||
/// Can be carried in a player's inventory
|
||||
|
||||
/// @brief Determines handling for container objects. Containers can optionally
|
||||
/// store container items.
|
||||
/// Configuration File:
|
||||
/// PS_UNLIMITED to allow storage of an unlimited number of container items.
|
||||
/// PS_NONE to prevent storage of any container items.
|
||||
/// Set to any positive integer to limit storage to that number of container
|
||||
/// items.
|
||||
/// Local Override (int): PS_MAX_CONTAINER_TIMES
|
||||
/// -1 = PS_UNLIMITED
|
||||
/// -2 = PS_NONE
|
||||
/// Set to any positive integer to limit storage to that number of container
|
||||
/// items.
|
||||
const int PS_MAX_CONTAINER_ITEMS_DEFAULT = 10;
|
||||
|
||||
/// @brief Determines how many items can be stored in stored container items.
|
||||
/// Configuration File:
|
||||
/// PS_UNLIMITED to allow storage of any number of items within a container
|
||||
/// item's inventory. This will be naturally limited by the size of
|
||||
/// the container item's inventory.
|
||||
/// PS_NONE to prevent any items from being stored in a container item. If
|
||||
/// container item storage is allow and PS_NONE is used, only empty
|
||||
/// container items can be stored.
|
||||
/// Set to any positive integer to limit the number of items stored in
|
||||
/// the inventory of a container item.
|
||||
/// Local Override (int): PS_MAX_CONTAINER_ITEMS_INVENTORY
|
||||
/// -1 = PS_UNLIMITED
|
||||
/// -2 = PS_NONE
|
||||
/// Set to any positive integer to limit the number of items stored in
|
||||
/// the inventory of a container item.
|
||||
///
|
||||
/// @note This configuration option has no effect if PS_MAX_CONTAINER_ITEMS_DEFAULT
|
||||
/// is set to PS_NONE or its local override is set to -1.
|
||||
/// @warning Items that fail check involved with container item limitations do
|
||||
/// not have default messages reported to the player. The item will simply fail
|
||||
/// to be stored.
|
||||
const int PS_MAX_CONTAINER_ITEMS_INVENTORY_DEFAULT = 100;
|
||||
|
||||
/// @brief Creates the form's title.
|
||||
/// @param oContainer The container object being used.
|
||||
/// @param oPC The player using oContainer.
|
||||
/// @note A local string called `PS_TITLE` may be set on the object for easy
|
||||
/// reference in this function. The function below is an example and may
|
||||
/// be modified in any way. The returned value will be displayed as the
|
||||
/// form's title.
|
||||
string ps_GetFormTitle(object oContainer, object oPC, int nAccess, int nType)
|
||||
{
|
||||
string sTitle;
|
||||
if ((sTitle = GetLocalString(oContainer, PS_TITLE)) != "")
|
||||
return sTitle;
|
||||
else
|
||||
{
|
||||
switch (nType)
|
||||
{
|
||||
case PS_CONTAINER_PUBLIC:
|
||||
return GetTag(oContainer);
|
||||
case PS_CONTAINER_CDKEY:
|
||||
return GetName(oPC) + "'s Player-Specific Storage";
|
||||
case PS_CONTAINER_CHARACTER:
|
||||
return GetName(oPC) + "'s Character-Specific Storage";
|
||||
}
|
||||
|
||||
if (GetIsPC(OBJECT_SELF))
|
||||
return GetName(OBJECT_SELF) + "'s Storage";
|
||||
}
|
||||
|
||||
return "Persistent Storage";
|
||||
}
|
1147
_module/nss/nui_f_storage.nss
Normal file
1147
_module/nss/nui_f_storage.nss
Normal file
File diff suppressed because it is too large
Load Diff
43
_module/nss/nui_i_library.nss
Normal file
43
_module/nss/nui_i_library.nss
Normal file
@@ -0,0 +1,43 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file nui_i_library.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Boilerplate code for creating a library dispatcher. Should only be
|
||||
/// included in library scripts as it implements main().
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "nui_i_main"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Protoypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void DefineForm();
|
||||
void BindForm();
|
||||
void HandleNUIEvents();
|
||||
void HandleModuleEvents();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// These are dummy implementations to prevent nwnsc from complaining that they
|
||||
// do not exist. If you want to compile in the toolset rather than using nwnsc,
|
||||
// comment these lines out.
|
||||
//#pragma default_function(DefineForm)
|
||||
//#pragma default_function(BindForm)
|
||||
//#pragma default_function(HandleNUIEvents)
|
||||
//#pragma default_function(HandleModuleEvents)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Library Dispatch
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
string sOperation = GetScriptParam("NUI_FUNCTION");
|
||||
|
||||
if (sOperation == NUI_DEFINE) DefineForm();
|
||||
else if (sOperation == NUI_BIND) BindForm();
|
||||
else if (sOperation == NUI_EVENT_NUI) HandleNUIEvents();
|
||||
else HandleModuleEvents();
|
||||
}
|
2697
_module/nss/nui_i_main.nss
Normal file
2697
_module/nss/nui_i_main.nss
Normal file
File diff suppressed because it is too large
Load Diff
15
_module/nss/pc_room_onexit.nss
Normal file
15
_module/nss/pc_room_onexit.nss
Normal file
@@ -0,0 +1,15 @@
|
||||
void main()
|
||||
{
|
||||
object oPlayer = GetExitingObject();
|
||||
|
||||
/* int nToken = NuiFindWindow(oPlayer, PC_NUI_WINDOW_ID);
|
||||
|
||||
//:: Murder the poor window
|
||||
|
||||
NuiDestroy(oPlayer, nToken);
|
||||
|
||||
nToken = NuiFindWindow(oPlayer, PC_NUI_GOLD_WINDOW_ID);
|
||||
if (nToken)
|
||||
NuiDestroy(oPlayer, nToken); */
|
||||
|
||||
}
|
6
_module/nss/ra_close_door.nss
Normal file
6
_module/nss/ra_close_door.nss
Normal file
@@ -0,0 +1,6 @@
|
||||
//Closes door if it is open
|
||||
void main()
|
||||
{
|
||||
DelayCommand(13.0f,ActionCloseDoor(OBJECT_SELF));
|
||||
}
|
||||
|
86
_module/nss/se_door_death.nss
Normal file
86
_module/nss/se_door_death.nss
Normal file
@@ -0,0 +1,86 @@
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
//:: Name Respawn Door/s v1.1
|
||||
//:: FileName se_door_death
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
Respawn a door after a set delay
|
||||
Set a float on the door ie. RESPAWN_TIMER = xx else the default is used
|
||||
Thanks to Craig Welburn for the insight
|
||||
Cheers to Zarathustra217
|
||||
*/
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
//:: Created By: Sir Elric
|
||||
//:: Created On: 8th May, 2006
|
||||
//:: Modified On: 16th August, 2007
|
||||
//:: Event Used: OnDeath event of a door
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "x2_inc_compon"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CONSTANTS - Settings below
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const float RESPAWN_TIMER_DEFAULT = 600.0; // Default respawn delay
|
||||
const int DO_CRAFT_DROP = TRUE; // Drop default Bioware crafting item?
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PROTOTYPES
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Respawn a door after a set delay
|
||||
// If no float is set on the door ie. RESPAWN_TIMER = xx
|
||||
// The default delay will be used ie. RESPAWN_TIMER_DEFAULT = xx
|
||||
// oSelf: - Object calling the script
|
||||
void SE_RespawnDoor(object oSelf);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void SE_RespawnDoor(object oSelf)
|
||||
{
|
||||
PlayAnimation(ANIMATION_DOOR_CLOSE);
|
||||
int nHealAmount = GetMaxHitPoints(oSelf) - GetCurrentHitPoints(oSelf);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nHealAmount), oSelf);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MAIN
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
object oSelf = OBJECT_SELF;
|
||||
object oKiller = GetLastKiller();
|
||||
|
||||
SetIsDestroyable(FALSE);
|
||||
|
||||
float fDelay = GetLocalFloat(oSelf, "RESPAWN_TIMER");
|
||||
if(fDelay == 0.0)
|
||||
fDelay = RESPAWN_TIMER_DEFAULT;
|
||||
|
||||
DelayCommand(fDelay, SE_RespawnDoor(oSelf));
|
||||
|
||||
if (!GetIsPC(oKiller))
|
||||
return;
|
||||
|
||||
while (GetIsObjectValid(GetMaster(oKiller)))
|
||||
{
|
||||
oKiller=GetMaster(oKiller);
|
||||
}
|
||||
|
||||
if(GetIsObjectValid(oKiller))
|
||||
{
|
||||
AdjustReputation(oKiller, OBJECT_SELF, -35);
|
||||
AdjustAlignment (oKiller, ALIGNMENT_CHAOTIC, 10);
|
||||
}
|
||||
|
||||
if(DO_CRAFT_DROP)
|
||||
craft_drop_placeable();
|
||||
}
|
34
_module/nss/sei_sit.nss
Normal file
34
_module/nss/sei_sit.nss
Normal file
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// NWSit
|
||||
//
|
||||
// Script to make the PC using the object sit on it.
|
||||
//
|
||||
// (c) Shir'le E. Illios, 2002 (shirle@drowwanderer.com)
|
||||
//
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
// Get the character using the object.
|
||||
object oPlayer = GetLastUsedBy();
|
||||
|
||||
// Make certain that the character is a PC.
|
||||
if( GetIsPC( oPlayer ) )
|
||||
{
|
||||
|
||||
// Get the object being sat on.
|
||||
object oChair = OBJECT_SELF;
|
||||
|
||||
// If the object is valid and nobody else is currently sitting on it.
|
||||
if( GetIsObjectValid( oChair ) &&
|
||||
!GetIsObjectValid( GetSittingCreature( oChair ) ) )
|
||||
{
|
||||
// Let the player sit on the object.
|
||||
AssignCommand( oPlayer, ActionSit( oChair ) );
|
||||
}
|
||||
|
||||
} // End if
|
||||
|
||||
} // End main
|
||||
|
7
_module/nss/sob_examine002.nss
Normal file
7
_module/nss/sob_examine002.nss
Normal file
@@ -0,0 +1,7 @@
|
||||
//Allow PC to see his description.
|
||||
void main()
|
||||
{
|
||||
object oPC=GetLastUsedBy();
|
||||
|
||||
AssignCommand(oPC,ActionExamine(OBJECT_SELF));
|
||||
}
|
225
_module/nss/util_c_color.nss
Normal file
225
_module/nss/util_c_color.nss
Normal file
@@ -0,0 +1,225 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_color.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Configuration file for util_i_color.nss.
|
||||
/// @details
|
||||
/// These color codes are used with the functions from util_i_color.nss. These
|
||||
/// are hex color codes, the same as you'd use in web design and may other
|
||||
/// areas, so they are easy to look up and to copy-paste into other programs.
|
||||
///
|
||||
/// You can change the values of any of constants below, but do not change the
|
||||
/// names of the constants themselves. You can also add your own constants for
|
||||
/// use in your module.
|
||||
///
|
||||
/// ## Acknowledgement
|
||||
/// - Function colors copied from https://nwn.wiki/display/NWN1/Colour+Tokens.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// X11 Color Palette
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ----- Whites ----------------------------------------------------------------
|
||||
const int COLOR_AZURE = 0xf0ffff;
|
||||
const int COLOR_BEIGE = 0xf5f5dc;
|
||||
const int COLOR_BLUE_ALICE = 0xf0f8ff;
|
||||
const int COLOR_HONEYDEW = 0xf0fff0;
|
||||
const int COLOR_IVORY = 0xfffff0;
|
||||
const int COLOR_LAVENDERBLUSH = 0xfff0f5;
|
||||
const int COLOR_LINEN = 0xfaf0e6;
|
||||
const int COLOR_MINTCREAM = 0xf5fffa;
|
||||
const int COLOR_MISTYROSE = 0xffe4e1;
|
||||
const int COLOR_OLDLACE = 0xfdf5e6;
|
||||
const int COLOR_SEASHELL = 0xfff5ee;
|
||||
const int COLOR_SNOW = 0xfffafa;
|
||||
const int COLOR_WHITE = 0xffffff;
|
||||
const int COLOR_WHITE_ANTIQUE = 0xfaebd7;
|
||||
const int COLOR_WHITE_FLORAL = 0xfffaf0;
|
||||
const int COLOR_WHITE_GHOST = 0xf8f8ff;
|
||||
const int COLOR_WHITE_SMOKE = 0xf5f5f5;
|
||||
|
||||
// ----- Blues -----------------------------------------------------------------
|
||||
const int COLOR_AQUA = 0x00ffff;
|
||||
const int COLOR_AQUAMARINE = 0x7fffd4;
|
||||
const int COLOR_BLUE = 0x0000ff;
|
||||
const int COLOR_BLUE_CORNFLOWER = 0x6495ed;
|
||||
const int COLOR_BLUE_DARK = 0x00008b;
|
||||
const int COLOR_BLUE_DODGER = 0x1e90ff;
|
||||
const int COLOR_BLUE_LIGHT = 0xadd8e6;
|
||||
const int COLOR_BLUE_MEDIUM = 0x0000cd;
|
||||
const int COLOR_BLUE_MIDNIGHT = 0x191970;
|
||||
const int COLOR_BLUE_POWDER = 0xb0e0e6;
|
||||
const int COLOR_BLUE_ROYAL = 0x4169e1;
|
||||
const int COLOR_BLUE_SKY = 0x87ceeb;
|
||||
const int COLOR_BLUE_SKY_DEEP = 0x00bfff;
|
||||
const int COLOR_BLUE_SKY_LIGHT = 0x87cefa;
|
||||
const int COLOR_BLUE_SLATE = 0x6a5acd;
|
||||
const int COLOR_BLUE_SLATE_MEDIUM = 0x7b68ee;
|
||||
const int COLOR_BLUE_STEEL = 0x4682b4;
|
||||
const int COLOR_BLUE_STEEL_LIGHT = 0xb0c4de;
|
||||
const int COLOR_CYAN = 0x00ffff;
|
||||
const int COLOR_CYAN_LIGHT = 0xe0ffff;
|
||||
const int COLOR_NAVY = 0x000080;
|
||||
const int COLOR_TURQUOISE = 0x40e0d0;
|
||||
const int COLOR_TURQUOISE_DARK = 0x00ced1;
|
||||
const int COLOR_TURQUOISE_MEDIUM = 0x48d1cc;
|
||||
const int COLOR_TURQUOISE_PALE = 0xafeeee;
|
||||
|
||||
// ----- Browns ----------------------------------------------------------------
|
||||
const int COLOR_BISQUE = 0xffe4c4;
|
||||
const int COLOR_BLANCHED_ALMOND = 0xffebcd;
|
||||
const int COLOR_BROWN = 0xa52a2a;
|
||||
const int COLOR_BROWN_LIGHT = 0xd0814b;
|
||||
const int COLOR_BROWN_ROSY = 0xbc8f8f;
|
||||
const int COLOR_BROWN_SADDLE = 0x8b4513;
|
||||
const int COLOR_BROWN_SANDY = 0xf4a460;
|
||||
const int COLOR_BURLYWOOD = 0xdeb887;
|
||||
const int COLOR_CHOCOLATE = 0xd2691e;
|
||||
const int COLOR_CORNSILK = 0xfff8dc;
|
||||
const int COLOR_GOLDENROD = 0xdaa520;
|
||||
const int COLOR_GOLDENROD_DARK = 0xb8860b;
|
||||
const int COLOR_MAROON = 0x800000;
|
||||
const int COLOR_PERU = 0xcd853f;
|
||||
const int COLOR_SIENNA = 0xa0522d;
|
||||
const int COLOR_TAN = 0xd2b48c;
|
||||
const int COLOR_WHEAT = 0xf5deb3;
|
||||
const int COLOR_WHITE_NAVAJO = 0xffdead;
|
||||
|
||||
// ----- Purples ---------------------------------------------------------------
|
||||
const int COLOR_BLUE_SLATE_DARK = 0x483d8b;
|
||||
const int COLOR_BLUE_VIOLET = 0x8a2be2;
|
||||
const int COLOR_FUCHSIA = 0xff00ff;
|
||||
const int COLOR_INDIGO = 0x4b0082;
|
||||
const int COLOR_LAVENDER = 0xe6e6fa;
|
||||
const int COLOR_MAGENTA = 0xff00ff;
|
||||
const int COLOR_MAGENTA_DARK = 0x8b008b;
|
||||
const int COLOR_ORCHID = 0xda70d6;
|
||||
const int COLOR_ORCHID_DARK = 0x9932cc;
|
||||
const int COLOR_ORCHID_MEDIUM = 0xba55d3;
|
||||
const int COLOR_PLUM = 0xdda0dd;
|
||||
const int COLOR_PURPLE = 0x800080;
|
||||
const int COLOR_PURPLE_MEDIUM = 0x9370d8;
|
||||
const int COLOR_THISTLE = 0xd8bfd8;
|
||||
const int COLOR_VIOLET = 0xee82ee;
|
||||
const int COLOR_VIOLET_DARK = 0x9400d3;
|
||||
const int COLOR_VIOLET_LIGHT = 0xf397f8;
|
||||
|
||||
// ----- Oranges ---------------------------------------------------------------
|
||||
const int COLOR_CORAL = 0xff7f50;
|
||||
const int COLOR_ORANGE = 0xffa500;
|
||||
const int COLOR_ORANGE_DARK = 0xff8c00;
|
||||
const int COLOR_ORANGE_LIGHT = 0xf3b800;
|
||||
const int COLOR_ORANGE_RED = 0xff4500;
|
||||
const int COLOR_SALMON_LIGHT = 0xffa07a;
|
||||
const int COLOR_TOMATO = 0xff6347;
|
||||
|
||||
// ----- Reds ------------------------------------------------------------------
|
||||
const int COLOR_CORAL_LIGHT = 0xf08080;
|
||||
const int COLOR_CRIMSON = 0xdc143c;
|
||||
const int COLOR_FIREBRICK = 0xb22222;
|
||||
const int COLOR_RED = 0xff0000;
|
||||
const int COLOR_RED_DARK = 0x8b0000;
|
||||
const int COLOR_RED_INDIAN = 0xcd5c4c;
|
||||
const int COLOR_RED_LIGHT = 0xfa6155;
|
||||
const int COLOR_SALMON = 0xfa8072;
|
||||
const int COLOR_SALMON_DARK = 0xe9967a;
|
||||
|
||||
// ----- Pinks -----------------------------------------------------------------
|
||||
const int COLOR_PINK = 0xffc0cb;
|
||||
const int COLOR_PINK_DEEP = 0xff1493;
|
||||
const int COLOR_PINK_HOT = 0xff69b4;
|
||||
const int COLOR_PINK_LIGHT = 0xffb6c1;
|
||||
const int COLOR_VIOLET_RED_MEDIUM = 0xc71585;
|
||||
const int COLOR_VIOLET_RED_PALE = 0xdb7093;
|
||||
|
||||
// ----- Grays -----------------------------------------------------------------
|
||||
const int COLOR_BLACK = 0x000000;
|
||||
const int COLOR_GAINSBORO = 0xdcdcdc;
|
||||
const int COLOR_GRAY = 0x808080;
|
||||
const int COLOR_GRAY_DARK = 0xa9a9a9;
|
||||
const int COLOR_GRAY_DIM = 0x696969;
|
||||
const int COLOR_GRAY_LIGHT = 0xd3d3d3;
|
||||
const int COLOR_GRAY_SLATE = 0x708090;
|
||||
const int COLOR_GRAY_SLATE_DARK = 0x2f4f4f;
|
||||
const int COLOR_GRAY_SLATE_LIGHT = 0x778899;
|
||||
const int COLOR_SILVER = 0xc0c0c0;
|
||||
|
||||
// ----- Greens ----------------------------------------------------------------
|
||||
const int COLOR_AQUAMARINE_MEDIUM = 0x66cdaa;
|
||||
const int COLOR_CHARTREUSE = 0x7fff00;
|
||||
const int COLOR_CYAN_DARK = 0x008b8b;
|
||||
const int COLOR_GREEN = 0x008000;
|
||||
const int COLOR_GREEN_DARK = 0x006400;
|
||||
const int COLOR_GREEN_FOREST = 0x228b22;
|
||||
const int COLOR_GREEN_LAWN = 0x7cfc00;
|
||||
const int COLOR_GREEN_LIGHT = 0x90ee90;
|
||||
const int COLOR_GREEN_LIME = 0x32cd32;
|
||||
const int COLOR_GREEN_OLIVE_DARK = 0x556b2f;
|
||||
const int COLOR_GREEN_PALE = 0x98fb98;
|
||||
const int COLOR_GREEN_SEA = 0x2e8b57;
|
||||
const int COLOR_GREEN_SEA_DARK = 0x8fbc8f;
|
||||
const int COLOR_GREEN_SEA_LIGHT = 0x20b2aa;
|
||||
const int COLOR_GREEN_SEA_MEDIUM = 0x3cb371;
|
||||
const int COLOR_GREEN_SPRING = 0x00ff7f;
|
||||
const int COLOR_GREEN_SPRING_MEDIUM = 0x00fa9a;
|
||||
const int COLOR_GREEN_YELLOW = 0xadff2f;
|
||||
const int COLOR_LIME = 0x00ff00;
|
||||
const int COLOR_OLIVE = 0x808000;
|
||||
const int COLOR_OLIVE_DRAB = 0x6b8e23;
|
||||
const int COLOR_TEAL = 0x008080;
|
||||
const int COLOR_YELLOW_GREEN = 0x9acd32;
|
||||
|
||||
// ----- Yellows ---------------------------------------------------------------
|
||||
const int COLOR_GOLD = 0xffd700;
|
||||
const int COLOR_GOLDENROD_LIGHT = 0xfafad2;
|
||||
const int COLOR_GOLDENROD_PALE = 0xeee8aa;
|
||||
const int COLOR_KHAKI = 0xf0e68c;
|
||||
const int COLOR_KHAKI_DARK = 0xbdb76b;
|
||||
const int COLOR_LEMON_CHIFFON = 0xfffacd;
|
||||
const int COLOR_MOCCASIN = 0xffe4b5;
|
||||
const int COLOR_PAPAYA_WHIP = 0xffefd5;
|
||||
const int COLOR_PEACH_PUFF = 0xffdab9;
|
||||
const int COLOR_YELLOW = 0xffff00;
|
||||
const int COLOR_YELLOW_DARK = 0xd0ce00;
|
||||
const int COLOR_YELLOW_LIGHT = 0xffffe0;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Colors By Function
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const int COLOR_DEFAULT = 0xfefefe;
|
||||
const int COLOR_ATTENTION = 0xfea400;
|
||||
const int COLOR_BUG = 0x660000;
|
||||
const int COLOR_FAIL = 0xff0000;
|
||||
const int COLOR_SUCCESS = 0x3dc93d;
|
||||
const int COLOR_DEBUG = 0xb4b4b4;
|
||||
const int COLOR_INFO = 0xd0814b;
|
||||
|
||||
// ----- Damage Types ----------------------------------------------------------
|
||||
const int COLOR_DAMAGE_MAGICAL = 0xcc77ff;
|
||||
const int COLOR_DAMAGE_ACID = 0x01ff01;
|
||||
const int COLOR_DAMAGE_COLD = 0x99ffff;
|
||||
const int COLOR_DAMAGE_DIVINE = 0xffff01;
|
||||
const int COLOR_DAMAGE_ELECTRICAL = 0x0166ff;
|
||||
const int COLOR_DAMAGE_FIRE = 0xff0101;
|
||||
const int COLOR_DAMAGE_NEGATIVE = 0x999999;
|
||||
const int COLOR_DAMAGE_POSITIVE = 0xffffff;
|
||||
const int COLOR_DAMAGE_SONIC = 0xff9901;
|
||||
|
||||
// ----- Chat Log Messages -----------------------------------------------------
|
||||
const int COLOR_MESSAGE_FEEDBACK = 0xffff01;
|
||||
const int COLOR_MESSAGE_COMBAT = 0xff6601;
|
||||
const int COLOR_MESSAGE_MAGIC = 0xcc77ff;
|
||||
const int COLOR_MESSAGE_SKILLS = 0x0166ff;
|
||||
const int COLOR_MESSAGE_SAVING = 0x66ccff;
|
||||
const int COLOR_SAVE_STATUS = 0x20ff20;
|
||||
const int COLOR_PAUSE_STATE = 0xff0101;
|
||||
const int COLOR_NAME_CLIENT = 0x99ffff;
|
||||
const int COLOR_NAME_OTHER = 0xcc99cc;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Custom Colors
|
||||
// -----------------------------------------------------------------------------
|
||||
// You can add any custom colors you need for your functions below this line.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
77
_module/nss/util_c_debug.nss
Normal file
77
_module/nss/util_c_debug.nss
Normal file
@@ -0,0 +1,77 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_debug.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Configuration file for util_i_debug.nss.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helper Constants and Functions
|
||||
// -----------------------------------------------------------------------------
|
||||
// If you need custom constants, functions, or #includes, you may add them here.
|
||||
// Since this file is included by util_i_debug.nss, you do not need to #include
|
||||
// it to use its constants.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
// These constants are used by the example code below. Uncomment if you want to
|
||||
// use them.
|
||||
|
||||
/// @brief This is the minimum debug level required to trigger custom handling.
|
||||
/// @details Setting this to DEBUG_LEVEL_ERROR means OnDebug() will handle only
|
||||
/// messages marked as DEBUG_LEVEL_ERROR and DEBUG_LEVEL_CRITICAL. If set to
|
||||
/// DEBUG_LEVEL_NONE, the user-defined event will never be triggered.
|
||||
/// @warning It is not recommended to set this level to DEBUG_LEVEL_NOTICE or
|
||||
/// DEBUG_LEVEL_DEBUG as this could create high message traffic rates.
|
||||
const int DEBUG_EVENT_TRIGGER_LEVEL = DEBUG_LEVEL_ERROR;
|
||||
|
||||
// These are varnames for script parameters
|
||||
const string DEBUG_PARAM_PREFIX = "DEBUG_PARAM_PREFIX";
|
||||
const string DEBUG_PARAM_MESSAGE = "DEBUG_PARAM_MESSAGE";
|
||||
const string DEBUG_PARAM_LEVEL = "DEBUG_PARAM_LEVEL";
|
||||
const string DEBUG_PARAM_TARGET = "DEBUG_PARAM_TARGET";
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Debug Handler
|
||||
// -----------------------------------------------------------------------------
|
||||
// You may alter the contents of this function, but do not alter its signature.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Custom debug event handler
|
||||
/// @details This is a customizable function that runs before a message is shown
|
||||
/// using Debug(). This function provides a user-definable hook into the
|
||||
/// debug notification system. For example, a module can use this hook to
|
||||
/// execute a script that may be able to handle module-specific error
|
||||
/// handling or messaging.
|
||||
/// @param sPrefix the debug message source provided by GetDebugPrefix()
|
||||
/// @param sMessage the debug message provided to Debug()
|
||||
/// @param nLevel the debug level of the message provided to Debug()
|
||||
/// @param oTarget the game object being debugged as provided to Debug()
|
||||
/// @returns TRUE if the message should be sent as normal; FALSE if no message
|
||||
/// should be sent.
|
||||
/// @note This function will never fire if oTarget is not debugging messages of
|
||||
/// nLevel.
|
||||
/// @warning Do not call Debug() or its aliases Notice(), Warning(), Error(), or
|
||||
/// CriticalError() from this function; that would cause an infinite loop.
|
||||
int HandleDebug(string sPrefix, string sMessage, int nLevel, object oTarget)
|
||||
{
|
||||
/*
|
||||
// The following example code allows an external script to handle the event
|
||||
// with access to the appropriate script parameters. Optionally, all event
|
||||
// handling can be accomplished directly in this function.
|
||||
|
||||
// Only do custom handling if the debug level is error or critical error.
|
||||
if (!nLevel || nLevel > DEBUG_EVENT_TRIGGER_LEVEL)
|
||||
return TRUE;
|
||||
|
||||
SetScriptParam(DEBUG_PARAM_PREFIX, sPrefix);
|
||||
SetScriptParam(DEBUG_PARAM_MESSAGE, sMessage);
|
||||
SetScriptParam(DEBUG_PARAM_LEVEL, IntToString(nLevel));
|
||||
SetScriptParam(DEBUG_PARAM_TARGET, ObjectToString(oTarget));
|
||||
ExecuteScript("mydebugscript", oTarget);
|
||||
return FALSE;
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
97
_module/nss/util_c_strftime.nss
Normal file
97
_module/nss/util_c_strftime.nss
Normal file
@@ -0,0 +1,97 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_strftime.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Configuration settings for util_i_strftime.nss.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Locale
|
||||
// -----------------------------------------------------------------------------
|
||||
// A locale is a group of localization settings stored as key-value pairs on a
|
||||
// json object which is then stored on the module and accessed by a name. Some
|
||||
// functions can take a locale name as an optional parameter so they can access
|
||||
// those settings. If no name is provided, those functions will use the default
|
||||
// locale instead.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// This is the name for the default locale. All settings below will apply to
|
||||
/// this locale.
|
||||
const string DEFAULT_LOCALE = "EN_US";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Translations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// This is a 12-element comma-separated list of month names. `%B` evaluates to
|
||||
/// the item at index `(month - 1) % 12`.
|
||||
const string DEFAULT_MONTHS = "January, February, March, April, May, June, July, August, September, October, November, December";
|
||||
|
||||
/// This is a 12-element comma-separated list of abbreviated month names. `%b`
|
||||
/// evaluates to the item at index `(month - 1) % 12`.
|
||||
const string DEFAULT_MONTHS_ABBR = "Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec";
|
||||
|
||||
/// This is a 7-element comma-separated list of weekday names. `%A` evaluates to
|
||||
/// the item at index `(day - 1) % 7`.
|
||||
const string DEFAULT_DAYS = "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday";
|
||||
|
||||
/// This is a 7-element comma-separated list of abbreviated day names. `%a`
|
||||
/// evaluates to the item at index `(day - 1) % 7`.
|
||||
const string DEFAULT_DAYS_ABBR = "Mon, Tue, Wed, Thu, Fri, Sat, Sun";
|
||||
|
||||
/// This is a 2-element comma-separated list with the preferred representation
|
||||
/// of AM/PM. Noon is treated as PM and midnight is treated as AM. Evaluated by
|
||||
/// `%p` (uppercase) and `%P` (lowercase).
|
||||
const string DEFAULT_AMPM = "AM, PM";
|
||||
|
||||
/// This is a comma-separated list of suffixes for ordinal numbers. The list
|
||||
/// should start with the suffix for 0. When formatting using the ordinal flag
|
||||
/// (e.g., "Today is the %Od day of %B"), the number being formatted is used as
|
||||
/// an index into this list. If the last two digits of the number are greater
|
||||
/// than or equal to the length of the list, only the last digit of the number
|
||||
/// is used. The default value will handle all integers in English.
|
||||
const string DEFAULT_ORDINAL_SUFFIXES = "th, st, nd, rd, th, th, th, th, th, th, th, th, th, th";
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Formatting
|
||||
// -----------------------------------------------------------------------------
|
||||
// These are strings that are used to format dates and times. Refer to the
|
||||
// comments in `util_i_strftime.nss` for the meaning of format codes. Some codes
|
||||
// are aliases for these values, so take care to avoid using those codes in
|
||||
// these values to prevent an infinite loop.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// This is a string used to format a date and time. Aliased by `%c`.
|
||||
const string DEFAULT_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S:%f";
|
||||
|
||||
/// This is a string used to format a date without the time. Aliased by `%x`.
|
||||
const string DEFAULT_DATE_FORMAT = "%Y-%m-%d";
|
||||
|
||||
/// This is a string used to format a time without the date. Aliased by `%X`.
|
||||
const string DEFAULT_TIME_FORMAT = "%H:%M:%S";
|
||||
|
||||
/// This is a string used to format a time using AM/PM. Aliased by `%r`.
|
||||
const string DEFAULT_AMPM_FORMAT = "%I:%M:%S %p";
|
||||
|
||||
/// This is a string used to format a date and time when era-based formatting is
|
||||
/// used. If "", will fall back to DEFAULT_DATETIME_FORMAT. Aliased by `%Ec`.
|
||||
const string DEFAULT_ERA_DATETIME_FORMAT = "";
|
||||
|
||||
/// This is a string used to format a date without the time when era-based
|
||||
/// formatting is used. If "", will fall back to DEFAULT_DATE_FORMAT. Aliased by
|
||||
/// `%Ex`.
|
||||
const string DEFAULT_ERA_DATE_FORMAT = "";
|
||||
|
||||
/// This is a string used to format a time without the date when era-based
|
||||
/// formatting is used. If "", will fall back to DEFAULT_TIME_FORMAT. Aliased by
|
||||
/// `%EX`.
|
||||
const string DEFAULT_ERA_TIME_FORMAT = "";
|
||||
|
||||
/// This is a string used to format years when era-based formatting is used. If
|
||||
/// "", will always use the current year. Aliased by `%EY`.
|
||||
const string DEFAULT_ERA_YEAR_FORMAT = "%Ey %EC";
|
||||
|
||||
/// This is a string used to format the era name when era-based formatting is
|
||||
/// used. Normally, each era has its own name, but setting this can allow you
|
||||
/// to display an era name even if you don't set up any eras for your locale.
|
||||
const string DEFAULT_ERA_NAME = "";
|
23
_module/nss/util_c_targeting.nss
Normal file
23
_module/nss/util_c_targeting.nss
Normal file
@@ -0,0 +1,23 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_targeting.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Configuration settings for util_i_targeting.nss.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Targeting Mode Script Handler
|
||||
// -----------------------------------------------------------------------------
|
||||
// You may alter the contents of this function, but do not alter its signature.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Custom handler to run scripts associated with targeting hooks.
|
||||
/// @param sScript The script assigned to the current targeting hook.
|
||||
/// @param oSelf The PC object assigned to the current targeting event.
|
||||
void RunTargetingHookScript(string sScript, object oSelf = OBJECT_SELF)
|
||||
{
|
||||
/* Use this function to implement your module's methodology for
|
||||
running scripts.
|
||||
|
||||
ExecuteScript(sScript, oSelf);
|
||||
*/
|
||||
}
|
105
_module/nss/util_c_unittest.nss
Normal file
105
_module/nss/util_c_unittest.nss
Normal file
@@ -0,0 +1,105 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_unittest.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Configuration file for util_i_unittest.nss.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_debug"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unit Test Configuration Settings
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Set this value to the color the test title text will be colored to. The value
|
||||
// can be a value from util_c_color or any other hex value representing a
|
||||
// color.
|
||||
// Example Output: Test My Variable Test
|
||||
// ^^^^ This portion of the text will be affected
|
||||
const int UNITTEST_TITLE_COLOR = COLOR_CYAN;
|
||||
|
||||
// Set this value to the color the test name text will be colored to. The value
|
||||
// can be a value from util_c_color or any other hex value representing a
|
||||
// color.
|
||||
// Example Output: Test My Variable Test | PASS
|
||||
// ^^^^^^^^^^^^^^^^ This portion of the text will be affected
|
||||
const int UNITTEST_NAME_COLOR = COLOR_ORANGE_LIGHT;
|
||||
|
||||
// Set this value to the color the test parameter text will be colored to. The
|
||||
// value can be a value from util_c_color or any other hex value representing a
|
||||
// color.
|
||||
// Example Output: Input: my_input
|
||||
// Expected: my_assertion
|
||||
// Received: my_output
|
||||
// ^^^^^^^^^ This portion of the text will be affected
|
||||
const int UNITTEST_PARAMETER_COLOR = COLOR_WHITE;
|
||||
|
||||
// Set this value to the color the test parameter text will be colored to. The
|
||||
// value can be a value from util_c_color or any other hex value representing a
|
||||
// color.
|
||||
// Example Output: Input: my_input
|
||||
// Expected: my_assertion
|
||||
// ^^^^^^^^^^^^ This portion of the text will be affected
|
||||
const int UNITTEST_PARAMETER_INPUT = COLOR_GREEN_SEA;
|
||||
|
||||
// Set this value to the color the test parameter text will be colored to. The
|
||||
// value can be a value from util_c_color or any other hex value representing a
|
||||
// color.
|
||||
// Example Output: Received: my_output
|
||||
// ^^^^^^^^^ This portion of the text will be affected
|
||||
const int UNITTEST_PARAMETER_RECEIVED = COLOR_PINK;
|
||||
|
||||
// Set this value to the name of the script or event to run in case of a unit
|
||||
// test failure.
|
||||
const string UNITTEST_FAILURE_SCRIPT = "";
|
||||
|
||||
// This value determines whether test results are expanded. Set to TRUE to force
|
||||
// all test results to show expanded data. Set to FALSE to show expanded data
|
||||
// only on test failures.
|
||||
const int UNITTEST_ALWAYS_EXPAND = FALSE;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helper Constants and Functions
|
||||
// -----------------------------------------------------------------------------
|
||||
// If you need custom constants, functions, or #includes, you may add them here.
|
||||
// Since this file is included by util_i_unittest.nss, you do not need to
|
||||
// #include it to use its constants.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unit Test Output Handler
|
||||
// -----------------------------------------------------------------------------
|
||||
// You may alter the contents of this function, but do not alter its signature.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Custom handler to handle reporting unit test results.
|
||||
/// @param sOutput The formatted and colored output results of a unit test.
|
||||
void HandleUnitTestOutput(string sOutput)
|
||||
{
|
||||
// This handler can be used to report the unit test output using any module
|
||||
// debugging or other reporting system.
|
||||
/*
|
||||
SendMessageToPC(GetFirstPC(), sOutput);
|
||||
*/
|
||||
|
||||
Notice(sOutput);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unit Test Failure Reporting Handler
|
||||
// -----------------------------------------------------------------------------
|
||||
// You may alter the contents of this function, but do not alter its signature.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Custom handler to report unit testing failures.
|
||||
/// @param sOutput The formatted and colored output results of a unit test.
|
||||
void HandleUnitTestFailure(string sOutput)
|
||||
{
|
||||
// This handler can be used to report unit test failures to module systems
|
||||
// or take specific action based on a failure. This function will
|
||||
// generally not be used in a test environment, but may be useful for
|
||||
// reporting failures in a production environment if unit tests are run
|
||||
// during module startup.
|
||||
|
||||
if (UNITTEST_FAILURE_SCRIPT != "")
|
||||
ExecuteScript(UNITTEST_FAILURE_SCRIPT, GetModule());
|
||||
}
|
91
_module/nss/util_c_variables.nss
Normal file
91
_module/nss/util_c_variables.nss
Normal file
@@ -0,0 +1,91 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_c_variables.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Configuration file for util_i_variables.nss.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Configuration
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// This volatile table will be created on the GetModule() object the first time
|
||||
// a module variable is set.
|
||||
const string VARIABLE_TABLE_MODULE = "module_variables";
|
||||
|
||||
// This persitent table will be created on the PC object the first time a player
|
||||
// variable is set. This table will be stored in the player's .bic file.
|
||||
const string VARIABLE_TABLE_PC = "player_variables";
|
||||
|
||||
// A persistent table will be created in a campaign database with the following
|
||||
// name. The table name will be VARIABLE_TABLE_MODULE above.
|
||||
const string VARIABLE_CAMPAIGN_DATABASE = "module_variables";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Local VarName Constructor
|
||||
// -----------------------------------------------------------------------------
|
||||
// This function is called when attempting to copy variables from a database
|
||||
// to a game object. Since game objects do not accept additonal fields, such
|
||||
// as a tag or timestamp, this function is provided to allow construction of
|
||||
// a unique varname, if desired, from the fields in the database record. You
|
||||
// may alter the contents of this function, but do not alter its signature.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Constructs a varname for a local variable copied from a database.
|
||||
/// @param oDatabase The database object the variable is sourced from. Will
|
||||
/// be either a player object, DB_MODULE or DM_CAMPAIGN.
|
||||
/// @param oTarget The game object the variable will be copied to.
|
||||
/// @param sVarName VarName field retrieved from database.
|
||||
/// @param sTag Tag field retrieved from database.
|
||||
/// @param nType Type field retrieved from database. VARIABLE_TYPE_*, but
|
||||
/// limited to VARIABLE_TYPE_INT|FLOAT|STRING|OBJECT|LOCATION|JSON.
|
||||
/// @returns The constructed string that will be used as the varname once
|
||||
/// copied to the target game object.
|
||||
string DatabaseToObjectVarName(object oDatabase, object oTarget, string sVarName,
|
||||
string sTag, int nType)
|
||||
{
|
||||
return sVarName;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Database VarName and Tag Constructors
|
||||
// -----------------------------------------------------------------------------
|
||||
// These functions are called when attempting to copy variables from a game
|
||||
// object to a database. These functions are provided to allow construction
|
||||
// of unique varnames and tag from local variables varnames. If the function
|
||||
// `DatabaseToObjectVarName()` above is used to copy database variables to a
|
||||
// local object, these functions can be used to reverse the process if
|
||||
// previously copied variables are returned to a database. You may alter the
|
||||
// contents of these functions, but do not alter their signatures.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Constructs a varname for a local variable copied to a database.
|
||||
/// @param oSource The game object the variable will be copied from.
|
||||
/// @param oDatabase The database object the variable will be copied to. Will
|
||||
/// be either a player object, DB_MODULE or DM_CAMPAIGN.
|
||||
/// @param sVarName VarName field retrieved from the local variable.
|
||||
/// @param nType Type field retrieved from database. VARIABLE_TYPE_*, but
|
||||
/// limited to VARIABLE_TYPE_INT|FLOAT|STRING|OBJECT|LOCATION|JSON.
|
||||
/// @param sTag sTag as passed to `CopyLocalVariablesToDatabase()`.
|
||||
/// @returns The constructed string that will be used as the varname once
|
||||
/// copied to the target game object.
|
||||
string ObjectToDatabaseVarName(object oSource, object oDatabase, string sVarName,
|
||||
int nType, string sTag)
|
||||
{
|
||||
return sVarName;
|
||||
}
|
||||
|
||||
/// @brief Constructs a varname for a local variable copied to a database.
|
||||
/// @param oSource The game object the variable will be copied from.
|
||||
/// @param oDatabase The database object the variable will be copied to. Will
|
||||
/// be either a player object, DB_MODULE or DM_CAMPAIGN.
|
||||
/// @param sVarName VarName field retrieved from the local variable.
|
||||
/// @param nType Type field retrieved from database. VARIABLE_TYPE_*, but
|
||||
/// limited to VARIABLE_TYPE_INT|FLOAT|STRING|OBJECT|LOCATION|JSON.
|
||||
/// @param sTag sTag as passed to `CopyLocalVariablesToDatabase()`.
|
||||
/// @returns The constructed string that will be used as the varname once
|
||||
/// copied to the target game object.
|
||||
string ObjectToDatabaseTag(object oSource, object oDatabase, string sVarName,
|
||||
int nType, string sTag)
|
||||
{
|
||||
return sTag;
|
||||
}
|
385
_module/nss/util_i_argstack.nss
Normal file
385
_module/nss/util_i_argstack.nss
Normal file
@@ -0,0 +1,385 @@
|
||||
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_argstack.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for manipulating an argument stack.
|
||||
/// @details
|
||||
/// An argument stack provides a method for library functions to send values
|
||||
/// to other functions without being able to call them directly. This allows
|
||||
/// library functions to abstract away the connection layer and frees the
|
||||
/// builder to design plug-and-play systems that don't break when unrelated
|
||||
/// systems are removed or replaced.
|
||||
///
|
||||
/// Stacks work on a last in - first out basis and are split by variable type.
|
||||
/// Popping a value will delete and return the last entered value of the
|
||||
/// specified type stack. Other variable types will not be affected.
|
||||
///
|
||||
/// ```nwscript
|
||||
/// PushInt(30);
|
||||
/// PushInt(40);
|
||||
/// PushInt(50);
|
||||
/// PushString("test");
|
||||
///
|
||||
/// int nPop = PopInt(); // nPop = 50
|
||||
/// string sPop = PopString(); // sPop = "test";
|
||||
/// ```nwscript
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_varlists"
|
||||
|
||||
const string ARGS_DEFAULT_STACK = "ARGS_DEFAULT_STACK";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param nValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushInt(int nValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
int PopInt(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
int PeekInt(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountIntStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param sValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushString(string sValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
string PopString(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
string PeekString(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountStringStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param fValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushFloat(float fValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
float PopFloat(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
float PeekFloat(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountFloatStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param oValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushObject(object oValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
object PopObject(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
object PeekObject(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountObjectStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param lValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.getlistfloat
|
||||
/// @returns Count of values on the stack.
|
||||
int PushLocation(location lValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
location PopLocation(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
location PeekLocation(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountLocationStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param vValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushVector(vector vValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
vector PopVector(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
vector PeekVector(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountVectorStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Push as value onto the stack.
|
||||
/// @param jValue Value to add to stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Count of values on the stack.
|
||||
int PushJson(json jValue, string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Pop a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
json PopJson(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Peek a value from the stack.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns Most recent value pushed on the stack.
|
||||
json PeekJson(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieve the stack size.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @returns The number of values in the stack.
|
||||
int CountJsonStack(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
/// @brief Clear all stack values.
|
||||
/// @param sListName [Optional] Name of stack.
|
||||
/// @param oTarget [Optional] Object stack will be saved to.
|
||||
/// @note Use this function to ensure all stack values are cleared.
|
||||
void ClearStacks(string sListName = "", object oTarget = OBJECT_INVALID);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string _GetListName(string s)
|
||||
{
|
||||
return s == "" ? ARGS_DEFAULT_STACK : s;
|
||||
}
|
||||
|
||||
object _GetTarget(object o)
|
||||
{
|
||||
if (o == OBJECT_INVALID || GetIsObjectValid(o) == FALSE)
|
||||
return GetModule();
|
||||
return o;
|
||||
}
|
||||
|
||||
int PushInt(int nValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListInt(_GetTarget(oTarget), 0, nValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PopInt(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListInt(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PeekInt(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListInt(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountIntStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountIntList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushString(string sValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListString(_GetTarget(oTarget), 0, sValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
string PopString(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListString(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
string PeekString(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListString(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountStringStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountStringList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushFloat(float fValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListFloat(_GetTarget(oTarget), 0, fValue, _GetListName(sListName), FALSE);
|
||||
}
|
||||
|
||||
float PopFloat(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListFloat(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
float PeekFloat(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListFloat(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountFloatStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountFloatList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushObject(object oValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListObject(_GetTarget(oTarget), 0, oValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
object PopObject(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListObject(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
object PeekObject(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListObject(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountObjectStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountObjectList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushLocation(location lValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListLocation(_GetTarget(oTarget), 0, lValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
location PopLocation(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListLocation(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
location PeekLocation(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListLocation(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountLocationStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountLocationList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushVector(vector vValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListVector(_GetTarget(oTarget), 0, vValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
vector PopVector(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListVector(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
vector PeekVector(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListVector(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountVectorStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountVectorList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
int PushJson(json jValue, string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return InsertListJson(_GetTarget(oTarget), 0, jValue, _GetListName(sListName));
|
||||
}
|
||||
|
||||
json PopJson(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return PopListJson(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
json PeekJson(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return GetListJson(_GetTarget(oTarget), 0, _GetListName(sListName));
|
||||
}
|
||||
|
||||
int CountJsonStack(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
return CountJsonList(_GetTarget(oTarget), _GetListName(sListName));
|
||||
}
|
||||
|
||||
void ClearStacks(string sListName = "", object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
sListName = _GetListName(sListName);
|
||||
oTarget = _GetTarget(oTarget);
|
||||
|
||||
DeleteIntList(oTarget, sListName);
|
||||
DeleteStringList(oTarget, sListName);
|
||||
DeleteFloatList(oTarget, sListName);
|
||||
DeleteObjectList(oTarget, sListName);
|
||||
DeleteLocationList(oTarget, sListName);
|
||||
DeleteVectorList(oTarget, sListName);
|
||||
DeleteJsonList(oTarget, sListName);
|
||||
}
|
348
_module/nss/util_i_color.nss
Normal file
348
_module/nss/util_i_color.nss
Normal file
@@ -0,0 +1,348 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_color.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Functions to handle colors.
|
||||
/// @details
|
||||
/// NWN normally uses color codes to color strings. These codes take the format
|
||||
/// `<cRGB>`, where RGB are ALT codes (0-0255) for colors.
|
||||
///
|
||||
/// Because color codes are arcane and can't be easily looked up, the functions
|
||||
/// in this file prefer to use hex color codes. These codes are the same as
|
||||
/// you'd use in web design and many other areas, so they are easy to look up
|
||||
/// and can be copied and pasted into other programs. util_c_color.nss provides
|
||||
/// some hex codes for common uses.
|
||||
///
|
||||
/// This file also contains functions to represent colors as RGB or HSV
|
||||
/// triplets. HSV (Hue, Saturation, Value) may be particularly useful if you
|
||||
/// want to play around with shifting colors.
|
||||
///
|
||||
/// ## Acknowledgements
|
||||
/// - `GetColorCode()` function by rdjparadis.
|
||||
/// - RGB <-> HSV colors adapted from NWShacker's Named Color Token System.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "x3_inc_string"
|
||||
#include "util_i_math"
|
||||
#include "util_c_color"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// Used to generate colors from RGB values. NEVER modify this string.
|
||||
/// @see https://nwn.wiki/display/NWN1/Colour+Tokens
|
||||
/// @note First character is "nearest to 00" since we can't use `\x00` itself
|
||||
/// @note COLOR_TOKEN originally by rdjparadis. Converted to NWN:EE escaped
|
||||
/// characters by Jasperre.
|
||||
const string COLOR_TOKEN = "\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct RGB
|
||||
{
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct HSV
|
||||
{
|
||||
float h;
|
||||
float s;
|
||||
float v;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ----- Type Creation ---------------------------------------------------------
|
||||
|
||||
/// @brief Create an RBG color struct.
|
||||
/// @param nRed The value of the red channel (0..255).
|
||||
/// @param nGreen The value of the green channel (0..255).
|
||||
/// @param nBlue The value of the blue channel (0..255).
|
||||
struct RGB GetRGB(int nRed, int nGreen, int nBlue);
|
||||
|
||||
/// @brief Create an HSV color struct.
|
||||
/// @details The ranges are as follows:
|
||||
/// 0.0 <= H < 360.0
|
||||
/// 0.0 <= S <= 1.0
|
||||
/// 0.0 <= V <= 1.0
|
||||
/// @param fHue The hue (i.e. location on color wheel).
|
||||
/// @param fSaturation The saturation (i.e., distance from white/black).
|
||||
/// @param fValue The value (i.e., brightness of color).
|
||||
struct HSV GetHSV(float fHue, float fSaturation, float fValue);
|
||||
|
||||
// ----- Type Conversion -------------------------------------------------------
|
||||
|
||||
/// @brief Convert a hexadecimal color to an RGB struct.
|
||||
/// @param nColor Hexadecimal to convert to RGB.
|
||||
struct RGB HexToRGB(int nColor);
|
||||
|
||||
/// @brief Convert an RGB struct to a hexadecimal color.
|
||||
/// @param rgb RGB to convert to hexadecimal.
|
||||
int RGBToHex(struct RGB rgb);
|
||||
|
||||
/// @brief Convert an RGB struct to an HSV struct.
|
||||
/// @param rgb RGB to convert to HSV.
|
||||
struct HSV RGBToHSV(struct RGB rgb);
|
||||
|
||||
/// @brief Convert an HSV struct to an RGB struct.
|
||||
/// @param hsv HSV to convert to RGB.
|
||||
struct RGB HSVToRGB(struct HSV hsv);
|
||||
|
||||
/// @brief Converts a hexadecimal color to an HSV struct.
|
||||
/// @param nColor Hexadecimal to convert to HSV.
|
||||
struct HSV HexToHSV(int nColor);
|
||||
|
||||
/// @brief Converts an HSV struct to a hexadecial color.
|
||||
/// @param hsv HSV to convert to hexadecimal.
|
||||
int HSVToHex(struct HSV hsv);
|
||||
|
||||
// ----- Coloring Functions ----------------------------------------------------
|
||||
|
||||
/// @brief Construct a color code that can be used to color a string.
|
||||
/// @param nRed The intensity of the red channel (0..255).
|
||||
/// @param nGreen The intensity of the green channel (0..255).
|
||||
/// @param nBlue The intensity of the blue channel (0..255).
|
||||
/// @returns A string color code in `<cRBG>` form.
|
||||
string GetColorCode(int nRed, int nGreen, int nBlue);
|
||||
|
||||
/// @brief Convert a hexadecimal color to a color code.
|
||||
/// @param nColor Hexadecimal representation of an RGB color.
|
||||
/// @returns A string color code in `<cRBG>` form.
|
||||
string HexToColor(int nColor);
|
||||
|
||||
/// @brief Convert a color code prefix to a hexadecimal
|
||||
/// @param sColor A string color code in `<cRBG>` form.
|
||||
int ColorToHex(string sColor);
|
||||
|
||||
/// @brief Color a string with a color code.
|
||||
/// @param sString The string to color.
|
||||
/// @param sColor A string color code in `<cRBG>` form.
|
||||
string ColorString(string sString, string sColor);
|
||||
|
||||
/// @brief Color a string with a hexadecimal color.
|
||||
/// @param sString The string to color.
|
||||
/// @param nColor A hexadecimal color.
|
||||
string HexColorString(string sString, int nColor);
|
||||
|
||||
/// @brief Color a string with an RGB color.
|
||||
/// @param sString The string to color.
|
||||
/// @param rgb The RGB color struct.
|
||||
string RGBColorString(string sString, struct RGB rgb);
|
||||
|
||||
/// @brief Color a string with a struct HSV color
|
||||
/// @param sString The string to color.
|
||||
/// @param hsv The HSV color struct.
|
||||
string HSVColorString(string sString, struct HSV hsv);
|
||||
|
||||
/// @brief Remove color codes from a string.
|
||||
/// @param sString The string to uncolor.
|
||||
/// @returns sString with color codes removed.
|
||||
string UnColorString(string sString);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ----- Type Creation ---------------------------------------------------------
|
||||
|
||||
struct RGB GetRGB(int nRed, int nGreen, int nBlue)
|
||||
{
|
||||
struct RGB rgb;
|
||||
|
||||
rgb.r = clamp(nRed, 0, 255);
|
||||
rgb.g = clamp(nGreen, 0, 255);
|
||||
rgb.b = clamp(nBlue, 0, 255);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
struct HSV GetHSV(float fHue, float fSat, float fVal)
|
||||
{
|
||||
struct HSV hsv;
|
||||
|
||||
hsv.h = fclamp(fHue, 0.0, 360.0);
|
||||
hsv.s = fclamp(fSat, 0.0, 1.0);
|
||||
hsv.v = fclamp(fVal, 0.0, 1.0);
|
||||
|
||||
if (hsv.h == 360.0)
|
||||
hsv.h = 0.0;
|
||||
|
||||
return hsv;
|
||||
}
|
||||
|
||||
// ----- Type Conversion -------------------------------------------------------
|
||||
|
||||
struct RGB HexToRGB(int nColor)
|
||||
{
|
||||
int nRed = (nColor & 0xff0000) >> 16;
|
||||
int nGreen = (nColor & 0x00ff00) >> 8;
|
||||
int nBlue = (nColor & 0x0000ff);
|
||||
return GetRGB(nRed, nGreen, nBlue);
|
||||
}
|
||||
|
||||
int RGBToHex(struct RGB rgb)
|
||||
{
|
||||
int nRed = (clamp(rgb.r, 0, 255) << 16);
|
||||
int nGreen = (clamp(rgb.g, 0, 255) << 8);
|
||||
int nBlue = clamp(rgb.b, 0, 255);
|
||||
return nRed + nGreen + nBlue;
|
||||
}
|
||||
|
||||
struct HSV RGBToHSV(struct RGB rgb)
|
||||
{
|
||||
// Ensure the RGB values are within defined limits
|
||||
rgb = GetRGB(rgb.r, rgb.g, rgb.b);
|
||||
|
||||
struct HSV hsv;
|
||||
|
||||
// Convert RGB to a range from 0 - 1
|
||||
float fRed = IntToFloat(rgb.r) / 255.0;
|
||||
float fGreen = IntToFloat(rgb.g) / 255.0;
|
||||
float fBlue = IntToFloat(rgb.b) / 255.0;
|
||||
|
||||
float fMax = fmax(fRed, fmax(fGreen, fBlue));
|
||||
float fMin = fmin(fRed, fmin(fGreen, fBlue));
|
||||
float fChroma = fMax - fMin;
|
||||
|
||||
if (fMax > fMin)
|
||||
{
|
||||
if (fMax == fRed)
|
||||
hsv.h = 60.0 * ((fGreen - fBlue) / fChroma);
|
||||
else if (fMax == fGreen)
|
||||
hsv.h = 60.0 * ((fBlue - fRed) / fChroma + 2.0);
|
||||
else
|
||||
hsv.h = 60.0 * ((fRed - fGreen) / fChroma + 4.0);
|
||||
|
||||
if (hsv.h < 0.0)
|
||||
hsv.h += 360.0;
|
||||
}
|
||||
|
||||
if (fMax > 0.0)
|
||||
hsv.s = fChroma / fMax;
|
||||
|
||||
hsv.v = fMax;
|
||||
return hsv;
|
||||
}
|
||||
|
||||
struct RGB HSVToRGB(struct HSV hsv)
|
||||
{
|
||||
// Ensure the HSV values are within defined limits
|
||||
hsv = GetHSV(hsv.h, hsv.s, hsv.v);
|
||||
|
||||
struct RGB rgb;
|
||||
|
||||
// If value is 0, the resulting color will always be black
|
||||
if (hsv.v == 0.0)
|
||||
return rgb;
|
||||
|
||||
// If the saturation is 0, the resulting color will be a shade of grey
|
||||
if (hsv.s == 0.0)
|
||||
{
|
||||
// Scale from white to black based on value
|
||||
int nValue = FloatToInt(hsv.v * 255.0);
|
||||
return GetRGB(nValue, nValue, nValue);
|
||||
}
|
||||
|
||||
float h = hsv.h / 60.0;
|
||||
float f = frac(h);
|
||||
int v = FloatToInt(hsv.v * 255.0);
|
||||
int p = FloatToInt(v * (1.0 - hsv.s));
|
||||
int q = FloatToInt(v * (1.0 - hsv.s * f));
|
||||
int t = FloatToInt(v * (1.0 - hsv.s * (1.0 - f)));
|
||||
int i = FloatToInt(h);
|
||||
|
||||
switch (i % 6)
|
||||
{
|
||||
case 0: rgb = GetRGB(v, t, p); break;
|
||||
case 1: rgb = GetRGB(q, v, p); break;
|
||||
case 2: rgb = GetRGB(p, v, t); break;
|
||||
case 3: rgb = GetRGB(p, q, v); break;
|
||||
case 4: rgb = GetRGB(t, p, v); break;
|
||||
case 5: rgb = GetRGB(v, p, q); break;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
struct HSV HexToHSV(int nColor)
|
||||
{
|
||||
return RGBToHSV(HexToRGB(nColor));
|
||||
}
|
||||
|
||||
int HSVToHex(struct HSV hsv)
|
||||
{
|
||||
return RGBToHex(HSVToRGB(hsv));
|
||||
}
|
||||
|
||||
// ----- Coloring Functions ----------------------------------------------------
|
||||
|
||||
string GetColorCode(int nRed, int nGreen, int nBlue)
|
||||
{
|
||||
return "<c" + GetSubString(COLOR_TOKEN, nRed, 1) +
|
||||
GetSubString(COLOR_TOKEN, nGreen, 1) +
|
||||
GetSubString(COLOR_TOKEN, nBlue, 1) + ">";
|
||||
}
|
||||
|
||||
string HexToColor(int nColor)
|
||||
{
|
||||
if (nColor < 0 || nColor > 0xffffff)
|
||||
return "";
|
||||
|
||||
int nRed = (nColor & 0xff0000) >> 16;
|
||||
int nGreen = (nColor & 0x00ff00) >> 8;
|
||||
int nBlue = (nColor & 0x0000ff);
|
||||
return GetColorCode(nRed, nGreen, nBlue);
|
||||
}
|
||||
|
||||
int ColorToHex(string sColor)
|
||||
{
|
||||
if (sColor == "")
|
||||
return -1;
|
||||
|
||||
string sRed = GetSubString(sColor, 2, 1);
|
||||
string sGreen = GetSubString(sColor, 3, 1);
|
||||
string sBlue = GetSubString(sColor, 4, 1);
|
||||
|
||||
int nRed = FindSubString(COLOR_TOKEN, sRed) << 16;
|
||||
int nGreen = FindSubString(COLOR_TOKEN, sGreen) << 8;
|
||||
int nBlue = FindSubString(COLOR_TOKEN, sBlue);
|
||||
|
||||
return nRed + nGreen + nBlue;
|
||||
}
|
||||
|
||||
string ColorString(string sString, string sColor)
|
||||
{
|
||||
if (sColor != "")
|
||||
sString = sColor + sString + "</c>";
|
||||
|
||||
return sString;
|
||||
}
|
||||
|
||||
string HexColorString(string sString, int nColor)
|
||||
{
|
||||
string sColor = HexToColor(nColor);
|
||||
return ColorString(sString, sColor);
|
||||
}
|
||||
|
||||
string RGBColorString(string sString, struct RGB rgb)
|
||||
{
|
||||
string sColor = GetColorCode(rgb.r, rgb.g, rgb.b);
|
||||
return ColorString(sString, sColor);
|
||||
}
|
||||
|
||||
string HSVColorString(string sString, struct HSV hsv)
|
||||
{
|
||||
struct RGB rgb = HSVToRGB(hsv);
|
||||
return RGBColorString(sString, rgb);
|
||||
}
|
||||
|
||||
string UnColorString(string sString)
|
||||
{
|
||||
return RegExpReplace("<c[\\S\\s]{3}>|<\\/c>", sString, "");
|
||||
}
|
209
_module/nss/util_i_constants.nss
Normal file
209
_module/nss/util_i_constants.nss
Normal file
@@ -0,0 +1,209 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_constants.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions to retrieve the value of a constant from a script file.
|
||||
/// @details
|
||||
///
|
||||
/// ## Example Usage
|
||||
///
|
||||
/// To retrieve the value of string constant `MODULE_EVENT_ON_NUI` from the Core
|
||||
/// Framework file `core_i_constants`:
|
||||
/// ```nwscript
|
||||
/// struct CONSTANT c = GetConstantString("MODULE_EVENT_ON_NUI", "core_i_constants");
|
||||
/// string sSetting = c.sValue;
|
||||
/// ```
|
||||
/// If successful, `sSetting` will contain the string value "OnNUI". If not
|
||||
/// successful, `c.bError` will be TRUE, `c.sError` will contain the reason for
|
||||
/// the error, and `c.sValue` will be set to an empty string ("").
|
||||
///
|
||||
/// To retrieve the value of integer constant `EVENT_STATE_OK`from the Core
|
||||
/// Framework file `core_i_constants`:
|
||||
/// ```nwscript
|
||||
/// struct CONSTANT c = GetConstantInt("EVENT_STATE_OK", "core_i_constants");
|
||||
/// int nState = c.bError ? -1 : c.nValue;
|
||||
///
|
||||
/// // or...
|
||||
/// if (!c.bError)
|
||||
/// {
|
||||
/// int nState = c.nValue;
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
/// If successful, `nState` will contain the integer value 0. Since an error
|
||||
/// value will also return 0, scripts should check `[struct].bError` before
|
||||
/// using any constant that could return 0 as a valid value.
|
||||
///
|
||||
/// @note These functions require uncompiled `.nss` files, otherwise only base
|
||||
/// nwscript constants will be retrievable. If you use a tool such as nasher
|
||||
/// to build your module, ensure you do not filter out the `.nss` files when
|
||||
/// building.
|
||||
///
|
||||
/// @note Based on clippy's code at
|
||||
/// https://github.com/Finaldeath/nwscript_utility_scripts
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_debug"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const string CONSTANTS_RESULT = "CONSTANTS_RESULT";
|
||||
const string CONSTANTS_ERROR_FILE_NOT_FOUND = "FILE NOT FOUND";
|
||||
const string CONSTANTS_ERROR_CONSTANT_NOT_FOUND = "VARIABLE DEFINED WITHOUT TYPE";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct CONSTANT
|
||||
{
|
||||
int bError;
|
||||
string sError;
|
||||
|
||||
string sValue;
|
||||
int nValue;
|
||||
float fValue;
|
||||
|
||||
string sFile;
|
||||
string sConstant;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Retrieves a constant string value from a script file
|
||||
/// @param sConstant Name of the constant, must match case
|
||||
/// @param sFile Optional: file to retrieve value from; if omitted, nwscript
|
||||
/// is assumed
|
||||
/// @returns a CONSTANT structure containing the following:
|
||||
/// bError - TRUE if the constant could not be found
|
||||
/// sError - The reason for the error, if any
|
||||
/// sValue - The value of the constant retrieved, if successful, or ""
|
||||
struct CONSTANT GetConstantString(string sConstant, string sFile = "");
|
||||
|
||||
/// @brief Retrieves a constant integer value from a script file
|
||||
/// @param sConstant Name of the constant, must match case
|
||||
/// @param sFile Optional: file to retrieve value from; if omitted, nwscript
|
||||
/// is assumed
|
||||
/// @returns a CONSTANT structure containing the following:
|
||||
/// bError - TRUE if the constant could not be found
|
||||
/// sError - The reason for the error, if any
|
||||
/// nValue - The value of the constant retrieved, if successful, or 0
|
||||
struct CONSTANT GetConstantInt(string sConstant, string sFile = "");
|
||||
|
||||
/// @brief Retrieves a constant float value from a script file
|
||||
/// @param sConstant Name of the constant, must match case
|
||||
/// @param sFile Optional: file to retrieve value from; if omitted, nwscript
|
||||
/// is assumed
|
||||
/// @returns a CONSTANT structure containing the following:
|
||||
/// bError - TRUE if the constant could not be found
|
||||
/// sError - The reason for the error, if any
|
||||
/// fValue - The value of the constant retrieved, if successful, or 0.0
|
||||
struct CONSTANT GetConstantFloat(string sConstant, string sFile = "");
|
||||
|
||||
/// @brief Find an constant name given the constant value.
|
||||
/// @param sPrefix The prefix portion of the constant name being sought.
|
||||
/// @param jValue The value of the sPrefix_* constant being sought. This must be
|
||||
/// a json value to simplify argument passage. Create via a Json* function,
|
||||
/// such as JsonInt(n), JsonString(s) or JsonFloat(f).
|
||||
/// @param bSuffixOnly If TRUE, will only return the portion of the constant name
|
||||
/// found after sPrefix, not including an intervening underscore.
|
||||
/// @param sFile If passed, sFile will be searched for the appropriate constant name.
|
||||
/// If not passed, `nwscript.nss` will be searched.
|
||||
/// @note Does not work with nwscript TRUE/FALSE. Floats that are affected by
|
||||
/// floating point error, such as 1.67, will also fail to find the correct
|
||||
/// constant name. Floats that end in .0, such as for DIRECTION_, work correctly.
|
||||
/// @warning This function is primarily designed for debugging messages. Using it
|
||||
/// regularly can result in degraded performance.
|
||||
string GetConstantName(string sPrefix, json jValue, int bSuffixOnly = FALSE, string sFile = "");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Attempts to retrieve the value of sConstant from sFile. If found, the
|
||||
// appropriate fields in struct CONSTANT are populated. If not, [struct].bError is
|
||||
// set to TRUE and the reason for failure is populated into [struct].sError. If the
|
||||
// error cannot be determined, the error returned by ExecuteScriptChunk is
|
||||
// populated directly into [struct].sError.
|
||||
struct CONSTANT constants_RetrieveConstant(string sConstant, string sFile, string sType)
|
||||
{
|
||||
int COLOR_KEY = COLOR_BLUE_LIGHT;
|
||||
int COLOR_VALUE = COLOR_SALMON;
|
||||
int COLOR_FAILED = COLOR_MESSAGE_FEEDBACK;
|
||||
|
||||
struct CONSTANT c;
|
||||
string sError, sChunk = "SetLocal" + sType + "(GetModule(), \"" +
|
||||
CONSTANTS_RESULT + "\", " + sConstant + ");";
|
||||
|
||||
c.sConstant = sConstant;
|
||||
c.sFile = sFile == "" ? "nwscript" : sFile;
|
||||
|
||||
if (sFile != "")
|
||||
sChunk = "#include \"" + sFile + "\" void main() {" + sChunk + "}";
|
||||
|
||||
if ((sError = ExecuteScriptChunk(sChunk, GetModule(), sFile == "")) != "")
|
||||
{
|
||||
c.bError = TRUE;
|
||||
|
||||
if (FindSubString(sError, CONSTANTS_ERROR_FILE_NOT_FOUND) != -1)
|
||||
c.sError = "Unable to find file `" + c.sFile + ".nss`";
|
||||
else if (FindSubString(sError, CONSTANTS_ERROR_CONSTANT_NOT_FOUND) != -1)
|
||||
c.sError = "Constant `" + c.sConstant + "` not found in `" + c.sFile + ".nss`";
|
||||
else
|
||||
c.sError = sError;
|
||||
|
||||
string sMessage = "[CONSTANTS] " + HexColorString("Failed", COLOR_FAILED) + " to retrieve constant value" +
|
||||
"\n " + HexColorString("sConstant", COLOR_KEY) + " " + HexColorString(sConstant, COLOR_VALUE) +
|
||||
"\n " + HexColorString("sFile", COLOR_KEY) + " " + HexColorString(c.sFile, COLOR_VALUE) +
|
||||
"\n " + HexColorString("Reason", COLOR_KEY) + " " + HexColorString(c.sError, COLOR_VALUE);
|
||||
Warning(sMessage);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct CONSTANT GetConstantString(string sConstant, string sFile = "")
|
||||
{
|
||||
struct CONSTANT c = constants_RetrieveConstant(sConstant, sFile, "String");
|
||||
if (!c.bError)
|
||||
c.sValue = GetLocalString(GetModule(), CONSTANTS_RESULT);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct CONSTANT GetConstantInt(string sConstant, string sFile = "")
|
||||
{
|
||||
struct CONSTANT c = constants_RetrieveConstant(sConstant, sFile, "Int");
|
||||
if (!c.bError)
|
||||
c.nValue = GetLocalInt(GetModule(), CONSTANTS_RESULT);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
struct CONSTANT GetConstantFloat(string sConstant, string sFile = "")
|
||||
{
|
||||
struct CONSTANT c = constants_RetrieveConstant(sConstant, sFile, "Float");
|
||||
if (!c.bError)
|
||||
c.fValue = GetLocalFloat(GetModule(), CONSTANTS_RESULT);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
string GetConstantName(string sPrefix, json jValue, int bSuffixOnly = FALSE, string sFile = "")
|
||||
{
|
||||
if (sFile == "") sFile = "nwscript";
|
||||
|
||||
sPrefix = GetStringUpperCase(bSuffixOnly ? sPrefix + "_?(" : "(" + sPrefix);
|
||||
json jMatch = RegExpMatch(sPrefix + ".*?)(?: |=).*?=\\s*(" +
|
||||
JsonDump(jValue) + ")\\s*;", ResManGetFileContents(sFile, RESTYPE_NSS));
|
||||
|
||||
return jMatch != JsonArray() ? JsonGetString(JsonArrayGet(jMatch, 1)) : "";
|
||||
}
|
353
_module/nss/util_i_csvlists.nss
Normal file
353
_module/nss/util_i_csvlists.nss
Normal file
@@ -0,0 +1,353 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_csvlists.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for manipulating comma-separated value (CSV) lists.
|
||||
/// @details
|
||||
///
|
||||
/// ## Usage:
|
||||
///
|
||||
/// ```nwscript
|
||||
/// string sKnight, sKnights = "Lancelot, Galahad, Robin";
|
||||
/// int i, nCount = CountList(sKnights);
|
||||
/// for (i = 0; i < nCount; i++)
|
||||
/// {
|
||||
/// sKnight = GetListItem(sKnights, i);
|
||||
/// SpeakString("Sir " + sKnight);
|
||||
/// }
|
||||
///
|
||||
/// int bBedivere = HasListItem(sKnights, "Bedivere");
|
||||
/// SpeakString("Bedivere " + (bBedivere ? "is" : "is not") + " in the party.");
|
||||
///
|
||||
/// sKnights = AddListItem(sKnights, "Bedivere");
|
||||
/// bBedivere = HasListItem(sKnights, "Bedivere");
|
||||
/// SpeakString("Bedivere " + (bBedivere ? "is" : "is not") + " in the party.");
|
||||
///
|
||||
/// int nRobin = FindListItem(sKnights, "Robin");
|
||||
/// SpeakString("Robin is knight " + IntToString(nRobin) + " in the party.");
|
||||
/// ```
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "x3_inc_string"
|
||||
#include "util_i_math"
|
||||
#include "util_i_strings"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Trim excess space around commas and, optionally, remove excess commas/
|
||||
/// empty list items.
|
||||
/// @param sList The CSV list to normalize.
|
||||
/// @param bRemoveEmpty TRUE to remove empty items.
|
||||
string NormalizeList(string sList, int bRemoveEmpty = TRUE);
|
||||
|
||||
/// @brief Return the number of items in a CSV list.
|
||||
/// @param sList The CSV list to count.
|
||||
int CountList(string sList);
|
||||
|
||||
/// @brief Add an item to a CSV list.
|
||||
/// @param sList The CSV list to add the item to.
|
||||
/// @param sListItem The item to add to sList.
|
||||
/// @param bAddUnique If TRUE, will only add the item to the list if it is not
|
||||
/// already there.
|
||||
/// @returns A modified copy of sList with sListItem added.
|
||||
string AddListItem(string sList, string sListItem, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Insert an item into a CSV list.
|
||||
/// @param sList The CSV list to insert the item into.
|
||||
/// @param sListItem The item to insert into sList.
|
||||
/// @param nIndex The index of the item to insert (0-based).
|
||||
/// @param bAddUnique If TRUE, will only insert the item to the list if it is not
|
||||
/// already there.
|
||||
/// @returns A modified copy of sList with sListItem inserted.
|
||||
string InsertListItem(string sList, string sListItem, int nIndex = -1, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Modify an existing item in a CSV list.
|
||||
/// @param sList The CSV list to modify.
|
||||
/// @param sListItem The item to insert at nIndex.
|
||||
/// @param nIndex The index of the item to modify (0-based).
|
||||
/// @param bAddUnique If TRUE, will only modify the item to the list if it is not
|
||||
/// already there.
|
||||
/// @returns A modified copy of sList with item at nIndex modified.
|
||||
/// @note If nIndex is out of bounds for sList, no values will be modified.
|
||||
/// @warning If bAddUnique is TRUE and a non-unique value is set, the value with a lower
|
||||
/// list index will be kept and values with higher list indices removed.
|
||||
string SetListItem(string sList, string sListItem, int nIndex = -1, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Return the item at an index in a CSV list.
|
||||
/// @param sList The CSV list to get the item from.
|
||||
/// @param nIndex The index of the item to get (0-based).
|
||||
string GetListItem(string sList, int nIndex = 0);
|
||||
|
||||
/// @brief Return the index of a value in a CSV list.
|
||||
/// @param sList The CSV list to search.
|
||||
/// @param sListItem The value to search for.
|
||||
/// @param nNth The nth repetition of sListItem.
|
||||
/// @returns -1 if the item was not found in the list.
|
||||
int FindListItem(string sList, string sListItem, int nNth = 0);
|
||||
|
||||
/// @brief Return whether a CSV list contains a value.
|
||||
/// @param sList The CSV list to search.
|
||||
/// @param sListItem The value to search for.
|
||||
/// @returns TRUE if the item is in the list, otherwise FALSE.
|
||||
int HasListItem(string sList, string sListItem);
|
||||
|
||||
/// @brief Delete the item at an index in a CSV list.
|
||||
/// @param sList The CSV list to delete the item from.
|
||||
/// @param nIndex The index of the item to delete (0-based).
|
||||
/// @returns A modified copy of sList with the item deleted.
|
||||
string DeleteListItem(string sList, int nIndex = 0);
|
||||
|
||||
/// @brief Delete the first occurrence of an item in a CSV list.
|
||||
/// @param sList The CSV list to remove the item from.
|
||||
/// @param sListItem The value to remove from the list.
|
||||
/// @param nNth The nth repetition of sListItem.
|
||||
/// @returns A modified copy of sList with the item removed.
|
||||
string RemoveListItem(string sList, string sListItem, int nNth = 0);
|
||||
|
||||
/// @brief Copy items from one CSV list to another.
|
||||
/// @param sSource The CSV list to copy items from.
|
||||
/// @param sTarget The CSV list to copy items to.
|
||||
/// @param nIndex The index to begin copying from.
|
||||
/// @param nRange The number of items to copy.
|
||||
/// @param bAddUnique If TRUE, will only copy items to sTarget if they are not
|
||||
/// already there.
|
||||
/// @returns A modified copy of sTarget with the items added to the end.
|
||||
string CopyListItem(string sSource, string sTarget, int nIndex, int nRange = 1, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Merge the contents of two CSV lists.
|
||||
/// @param sList1 The first CSV list.
|
||||
/// @param sList2 The second CSV list.
|
||||
/// @param bAddUnique If TRUE, will only put items in the returned list if they
|
||||
/// are not already there.
|
||||
/// @returns A CSV list containing the items from each list.
|
||||
string MergeLists(string sList1, string sList2, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Add an item to a CSV list saved as a local variable on an object.
|
||||
/// @param oObject The object on which the local variable is saved.
|
||||
/// @param sListName The varname for the local variable.
|
||||
/// @param sListItem The item to add to the list.
|
||||
/// @param bAddUnique If TRUE, will only add the item to the list if it is not
|
||||
/// already there.
|
||||
/// @returns The updated copy of the list with sListItem added.
|
||||
string AddLocalListItem(object oObject, string sListName, string sListItem, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Delete an item in a CSV list saved as a local variable on an object.
|
||||
/// @param oObject The object on which the local variable is saved.
|
||||
/// @param sListName The varname for the local variable.
|
||||
/// @param nIndex The index of the item to delete (0-based).
|
||||
/// @returns The updated copy of the list with the item at nIndex deleted.
|
||||
string DeleteLocalListItem(object oObject, string sListName, int nIndex = 0);
|
||||
|
||||
/// @brief Remove an item in a CSV list saved as a local variable on an object.
|
||||
/// @param oObject The object on which the local variable is saved.
|
||||
/// @param sListName The varname for the local variable.
|
||||
/// @param sListItem The value to remove from the list.
|
||||
/// @param nNth The nth repetition of sListItem.
|
||||
/// @returns The updated copy of the list with the first instance of sListItem
|
||||
/// removed.
|
||||
string RemoveLocalListItem(object oObject, string sListName, string sListItem, int nNth = 0);
|
||||
|
||||
/// @brief Merge the contents of a CSV list with those of a CSV list stored as a
|
||||
/// local variable on an object.
|
||||
/// @param oObject The object on which the local variable is saved.
|
||||
/// @param sListName The varname for the local variable.
|
||||
/// @param sListToMerge The CSV list to merge into the saved list.
|
||||
/// @param bAddUnique If TRUE, will only put items in the returned list if they
|
||||
/// are not already there.
|
||||
/// @returns The updated copy of the list with all items from sListToMerge
|
||||
/// added.
|
||||
string MergeLocalList(object oObject, string sListName, string sListToMerge, int bAddUnique = FALSE);
|
||||
|
||||
/// @brief Convert a comma-separated value list to a JSON array.
|
||||
/// @param sList Source CSV list.
|
||||
/// @param bNormalize TRUE to remove excess spaces and values. See NormalizeList().
|
||||
/// @returns JSON array representation of CSV list.
|
||||
json ListToJson(string sList, int bNormalize = TRUE);
|
||||
|
||||
/// @brief Convert a JSON array to a comma-separate value list.
|
||||
/// @param jList JSON array list.
|
||||
/// @param bNormalize TRUE to remove excess spaces and values. See NormalizeList().
|
||||
/// @returns CSV list of JSON array values.
|
||||
string JsonToList(json jList, int bNormalize = TRUE);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string NormalizeList(string sList, int bRemoveEmpty = TRUE)
|
||||
{
|
||||
string sRegex = "(?:[\\s]*,[\\s]*)" + (bRemoveEmpty ? "+" : "");
|
||||
sList = RegExpReplace(sRegex, sList, ",");
|
||||
return TrimString(bRemoveEmpty ? RegExpReplace("^[\\s]*,|,[\\s]*$", sList, "") : sList);
|
||||
}
|
||||
|
||||
int CountList(string sList)
|
||||
{
|
||||
if (sList == "")
|
||||
return 0;
|
||||
|
||||
return GetSubStringCount(sList, ",") + 1;
|
||||
}
|
||||
|
||||
string AddListItem(string sList, string sListItem, int bAddUnique = FALSE)
|
||||
{
|
||||
sList = NormalizeList(sList);
|
||||
sListItem = TrimString(sListItem);
|
||||
|
||||
if (bAddUnique && HasListItem(sList, sListItem))
|
||||
return sList;
|
||||
|
||||
if (sList != "")
|
||||
return sList + "," + sListItem;
|
||||
|
||||
return sListItem;
|
||||
}
|
||||
|
||||
string InsertListItem(string sList, string sListItem, int nIndex = -1, int bAddUnique = FALSE)
|
||||
{
|
||||
if (nIndex == -1 || sList == "" || nIndex > CountList(sList) - 1)
|
||||
return AddListItem(sList, sListItem, bAddUnique);
|
||||
|
||||
if (nIndex < 0) nIndex = 0;
|
||||
json jList = JsonArrayInsert(ListToJson(sList), JsonString(sListItem), nIndex);
|
||||
|
||||
if (bAddUnique == TRUE)
|
||||
jList = JsonArrayTransform(jList, JSON_ARRAY_UNIQUE);
|
||||
|
||||
return JsonToList(jList);
|
||||
}
|
||||
|
||||
string SetListItem(string sList, string sListItem, int nIndex = -1, int bAddUnique = FALSE)
|
||||
{
|
||||
if (nIndex < 0 || nIndex > (CountList(sList) - 1))
|
||||
return sList;
|
||||
|
||||
json jList = JsonArraySet(ListToJson(sList), nIndex, JsonString(sListItem));
|
||||
|
||||
if (bAddUnique == TRUE)
|
||||
jList = JsonArrayTransform(jList, JSON_ARRAY_UNIQUE);
|
||||
|
||||
return JsonToList(jList);
|
||||
}
|
||||
|
||||
string GetListItem(string sList, int nIndex = 0)
|
||||
{
|
||||
if (nIndex < 0 || sList == "" || nIndex > (CountList(sList) - 1))
|
||||
return "";
|
||||
|
||||
return JsonGetString(JsonArrayGet(ListToJson(sList), nIndex));
|
||||
}
|
||||
|
||||
int FindListItem(string sList, string sListItem, int nNth = 0)
|
||||
{
|
||||
json jIndex = JsonFind(ListToJson(sList), JsonString(TrimString(sListItem)), nNth);
|
||||
return jIndex == JSON_NULL ? -1 : JsonGetInt(jIndex);
|
||||
}
|
||||
|
||||
int HasListItem(string sList, string sListItem)
|
||||
{
|
||||
return (FindListItem(sList, sListItem) > -1);
|
||||
}
|
||||
|
||||
string DeleteListItem(string sList, int nIndex = 0)
|
||||
{
|
||||
if (nIndex < 0 || sList == "" || nIndex > (CountList(sList) - 1))
|
||||
return sList;
|
||||
|
||||
return JsonToList(JsonArrayDel(ListToJson(sList), nIndex));
|
||||
}
|
||||
|
||||
string RemoveListItem(string sList, string sListItem, int nNth = 0)
|
||||
{
|
||||
return DeleteListItem(sList, FindListItem(sList, sListItem, nNth));
|
||||
}
|
||||
|
||||
string CopyListItem(string sSource, string sTarget, int nIndex, int nRange = 1, int bAddUnique = FALSE)
|
||||
{
|
||||
int i, nCount = CountList(sSource);
|
||||
|
||||
if (nIndex < 0 || nIndex >= nCount || !nCount)
|
||||
return sSource;
|
||||
|
||||
nRange = clamp(nRange, 1, nCount - nIndex);
|
||||
|
||||
for (i = 0; i < nRange; i++)
|
||||
sTarget = AddListItem(sTarget, GetListItem(sSource, nIndex + i), bAddUnique);
|
||||
|
||||
return sTarget;
|
||||
}
|
||||
|
||||
string MergeLists(string sList1, string sList2, int bAddUnique = FALSE)
|
||||
{
|
||||
if (sList1 != "" && sList2 == "")
|
||||
return sList1;
|
||||
else if (sList1 == "" && sList2 != "")
|
||||
return sList2;
|
||||
else if (sList1 == "" && sList2 == "")
|
||||
return "";
|
||||
|
||||
string sList = sList1 + "," + sList2;
|
||||
|
||||
if (bAddUnique)
|
||||
sList = JsonToList(JsonArrayTransform(ListToJson(sList), JSON_ARRAY_UNIQUE));
|
||||
|
||||
return bAddUnique ? sList : NormalizeList(sList);
|
||||
}
|
||||
|
||||
string AddLocalListItem(object oObject, string sListName, string sListItem, int bAddUnique = FALSE)
|
||||
{
|
||||
string sList = GetLocalString(oObject, sListName);
|
||||
sList = AddListItem(sList, sListItem, bAddUnique);
|
||||
SetLocalString(oObject, sListName, sList);
|
||||
return sList;
|
||||
}
|
||||
|
||||
string DeleteLocalListItem(object oObject, string sListName, int nIndex = 0)
|
||||
{
|
||||
string sList = GetLocalString(oObject, sListName);
|
||||
sList = DeleteListItem(sList, nIndex);
|
||||
SetLocalString(oObject, sListName, sList);
|
||||
return sList;
|
||||
}
|
||||
|
||||
string RemoveLocalListItem(object oObject, string sListName, string sListItem, int nNth = 0)
|
||||
{
|
||||
string sList = GetLocalString(oObject, sListName);
|
||||
sList = RemoveListItem(sList, sListItem, nNth);
|
||||
SetLocalString(oObject, sListName, sList);
|
||||
return sList;
|
||||
}
|
||||
|
||||
string MergeLocalList(object oObject, string sListName, string sListToMerge, int bAddUnique = FALSE)
|
||||
{
|
||||
string sList = GetLocalString(oObject, sListName);
|
||||
sList = MergeLists(sList, sListToMerge, bAddUnique);
|
||||
SetLocalString(oObject, sListName, sList);
|
||||
return sList;
|
||||
}
|
||||
|
||||
json ListToJson(string sList, int bNormalize = TRUE)
|
||||
{
|
||||
if (sList == "")
|
||||
return JSON_ARRAY;
|
||||
|
||||
if (bNormalize)
|
||||
sList = NormalizeList(sList);
|
||||
|
||||
sList = RegExpReplace("\"", sList, "\\\"");
|
||||
return JsonParse("[\"" + RegExpReplace(",", sList, "\",\"") + "\"]");
|
||||
}
|
||||
|
||||
string JsonToList(json jList, int bNormalize = TRUE)
|
||||
{
|
||||
if (JsonGetType(jList) != JSON_TYPE_ARRAY)
|
||||
return "";
|
||||
|
||||
string sList;
|
||||
int n; for (n; n < JsonGetLength(jList); n++)
|
||||
sList += (sList == "" ? "" : ",") + JsonGetString(JsonArrayGet(jList, n));
|
||||
|
||||
return bNormalize ? NormalizeList(sList) : sList;
|
||||
}
|
132
_module/nss/util_i_datapoint.nss
Normal file
132
_module/nss/util_i_datapoint.nss
Normal file
@@ -0,0 +1,132 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_datapoint.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for creating and interacting with datapoints, which are
|
||||
/// invisible objects used to hold variables specific to a system.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const string DATA_PREFIX = "Datapoint: ";
|
||||
const string DATA_POINT = "x1_hen_inv"; ///< Resref for data points
|
||||
const string DATA_ITEM = "nw_it_msmlmisc22"; ///< Resref for data items
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Creates a datapoint (placeable) that stores variables for a
|
||||
/// specified system
|
||||
/// @param sSystem Name of system associated with this datapoint
|
||||
/// @param oOwner (optional) Parent object of this datapoint; if omitted,
|
||||
/// defaults to GetModule();
|
||||
/// @note A datapoint is created at oOwner's location; if oOwner is invalid or
|
||||
/// is an area object, the datapoint is created at the module starting
|
||||
/// location.
|
||||
/// @returns sSystem's datapoint object
|
||||
object CreateDatapoint(string sSystem, object oOwner = OBJECT_INVALID);
|
||||
|
||||
/// @brief Retrieves a datapoint (placeable) that stores variables for a
|
||||
/// specified system
|
||||
/// @param sSystem Name of system associated with this datapoint
|
||||
/// @param oOwner (optional) Parent object of this datapoint; if omitted,
|
||||
/// defaults to GetModule()
|
||||
/// @param bCreate If TRUE and the datapoint cannot be found, a new datapoint
|
||||
/// will be created at oOwner's location; if oOwner is invalid or is an
|
||||
/// area object, the datapoint is created at the module starting location
|
||||
/// @returns sSystem's datapoint object
|
||||
object GetDatapoint(string sSystem, object oOwner = OBJECT_INVALID, int bCreate = TRUE);
|
||||
|
||||
/// @brief Sets a datapoint (game object) as the object that stores variables
|
||||
/// for a specified system
|
||||
/// @param sSystem Name of system associated with this datapoint
|
||||
/// @param oTarget Object to be used as a datapoint
|
||||
/// @param oOwner (optional) Parent object of this datapoint; if omitted,
|
||||
/// default to GetModule()
|
||||
/// @note Allows any valid game object to be used as a datapoint
|
||||
void SetDatapoint(string sSystem, object oTarget, object oOwner = OBJECT_INVALID);
|
||||
|
||||
/// @brief Creates a data item (item) that stores variables for a specified
|
||||
/// sub-system
|
||||
/// @param oDatapoint Datapoint object on which to place the data item
|
||||
/// @param sSubSystem Name of sub-system associated with this data item
|
||||
/// @returns sSubSystem's data item object
|
||||
object CreateDataItem(object oDatapoint, string sSubSystem);
|
||||
|
||||
/// @brief Retrieves a data item (item) that stores variables for a specified
|
||||
/// sub-system
|
||||
/// @param oDatapoint Datapoint object from which to retrieve the data item
|
||||
/// @param sSubSystem Name of sub-system associated with the data item
|
||||
/// @returns sSubSystem's data item object
|
||||
object GetDataItem(object oDatapoint, string sSubSystem);
|
||||
|
||||
/// @brief Sets a data item (item) as the object that stores variables for a
|
||||
/// specified sub-system
|
||||
/// @param oDatapoint Datapoint object on which to place the data item
|
||||
/// @param sSubSystem Name of sub-system assocaited with the data item
|
||||
/// @param oItem Item to be used as a data item
|
||||
/// @note oItem must a valid game item that can be placed into an object's
|
||||
/// inventory
|
||||
void SetDataItem(object oDatapoint, string sSubSystem, object oItem);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
object CreateDatapoint(string sSystem, object oOwner = OBJECT_INVALID)
|
||||
{
|
||||
if (oOwner == OBJECT_INVALID)
|
||||
oOwner = GetModule();
|
||||
|
||||
location lLoc = GetLocation(oOwner);
|
||||
if (!GetObjectType(oOwner))
|
||||
lLoc = GetStartingLocation();
|
||||
|
||||
object oData = CreateObject(OBJECT_TYPE_PLACEABLE, DATA_POINT, lLoc);
|
||||
SetName(oData, DATA_PREFIX + sSystem);
|
||||
SetUseableFlag(oData, FALSE);
|
||||
SetDatapoint(sSystem, oData, oOwner);
|
||||
return oData;
|
||||
}
|
||||
|
||||
object GetDatapoint(string sSystem, object oOwner = OBJECT_INVALID, int bCreate = TRUE)
|
||||
{
|
||||
if (oOwner == OBJECT_INVALID)
|
||||
oOwner = GetModule();
|
||||
|
||||
object oData = GetLocalObject(oOwner, DATA_PREFIX + sSystem);
|
||||
|
||||
if (!GetIsObjectValid(oData) && bCreate)
|
||||
oData = CreateDatapoint(sSystem, oOwner);
|
||||
|
||||
return oData;
|
||||
}
|
||||
|
||||
void SetDatapoint(string sSystem, object oTarget, object oOwner = OBJECT_INVALID)
|
||||
{
|
||||
if (oOwner == OBJECT_INVALID)
|
||||
oOwner = GetModule();
|
||||
|
||||
SetLocalObject(oOwner, DATA_PREFIX + sSystem, oTarget);
|
||||
}
|
||||
|
||||
object CreateDataItem(object oDatapoint, string sSubSystem)
|
||||
{
|
||||
object oItem = CreateItemOnObject(DATA_ITEM, oDatapoint);
|
||||
SetLocalObject(oDatapoint, sSubSystem, oItem);
|
||||
SetName(oItem, sSubSystem);
|
||||
return oItem;
|
||||
}
|
||||
|
||||
object GetDataItem(object oDatapoint, string sSubSystem)
|
||||
{
|
||||
return GetLocalObject(oDatapoint, sSubSystem);
|
||||
}
|
||||
|
||||
void SetDataItem(object oDatapoint, string sSubSystem, object oItem)
|
||||
{
|
||||
SetLocalObject(oDatapoint, sSubSystem, oItem);
|
||||
}
|
324
_module/nss/util_i_debug.nss
Normal file
324
_module/nss/util_i_debug.nss
Normal file
@@ -0,0 +1,324 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_debug.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for generating debug messages.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// VarNames
|
||||
const string DEBUG_COLOR = "DEBUG_COLOR";
|
||||
const string DEBUG_LEVEL = "DEBUG_LEVEL";
|
||||
const string DEBUG_LOG = "DEBUG_LOG";
|
||||
const string DEBUG_OVERRIDE = "DEBUG_OVERRIDE";
|
||||
const string DEBUG_PREFIX = "DEBUG_PREFIX";
|
||||
const string DEBUG_DISPATCH = "DEBUG_DISPATCH";
|
||||
|
||||
// Debug levels
|
||||
const int DEBUG_LEVEL_NONE = 0; ///< No debug level set
|
||||
const int DEBUG_LEVEL_CRITICAL = 1; ///< Errors severe enough to stop the script
|
||||
const int DEBUG_LEVEL_ERROR = 2; ///< Indicates the script malfunctioned in some way
|
||||
const int DEBUG_LEVEL_WARNING = 3; ///< Indicates that unexpected behavior may occur
|
||||
const int DEBUG_LEVEL_NOTICE = 4; ///< Information to track the flow of the function
|
||||
const int DEBUG_LEVEL_DEBUG = 5; ///< Data dumps used for debugging
|
||||
|
||||
// Debug logging
|
||||
const int DEBUG_LOG_NONE = 0x0; ///< Do not log debug messages
|
||||
const int DEBUG_LOG_FILE = 0x1; ///< Send debug messages to the log file
|
||||
const int DEBUG_LOG_DM = 0x2; ///< Send debug messages to online DMs
|
||||
const int DEBUG_LOG_PC = 0x4; ///< Send debug messages to the first PC
|
||||
const int DEBUG_LOG_LIST = 0x8; ///< Send debug messages to the dispatch list
|
||||
const int DEBUG_LOG_ALL = 0xf; ///< Send messages to the log file, DMs, and first PC or dispatch list
|
||||
|
||||
#include "util_c_debug"
|
||||
#include "util_i_color"
|
||||
#include "util_i_varlists"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Temporarily override the debug level for all objects.
|
||||
/// @param nLevel The maximum verbosity of messages to show. Use FALSE to stop
|
||||
/// overriding the debug level.
|
||||
void OverrideDebugLevel(int nLevel);
|
||||
|
||||
/// @brief Return the verbosity of debug messages displayed for an object.
|
||||
/// @param oTarget The object to check the debug level of. If no debug level has
|
||||
/// been set on oTarget, will use the module instead.
|
||||
/// @returns A `DEBUG_LEVEL_*` constant representing the maximum verbosity of
|
||||
/// messages that will be displayed when debugging oTarget.
|
||||
int GetDebugLevel(object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Set the verbosity of debug messages displayed for an object.
|
||||
/// @param nLevel A `DEBUG_LEVEL_*` constant representing the maximum verbosity
|
||||
/// of messages that will be displayed when debugging oTarget. If set to
|
||||
/// `DEBUG_LEVEL_NONE`, oTarget will use the module's debug level instead.
|
||||
/// @param oTarget The object to set the debug level of. If no debug level has
|
||||
/// been set on oTarget, will use the module instead.
|
||||
void SetDebugLevel(int nLevel, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Return the color of debug messages of a given level.
|
||||
/// @param nLevel A `DEBUG_LEVEL_*` constant representing the verbosity of debug
|
||||
/// messsages to get the color for.
|
||||
/// @returns A color code (in <cRGB> form).
|
||||
string GetDebugColor(int nLevel);
|
||||
|
||||
/// @brief Set the color of debug messages of a given level.
|
||||
/// @param nLevel A `DEBUG_LEVEL_*` constant representing the verbosity of debug
|
||||
/// messsages to get the color for.
|
||||
/// @param sColor A color core (in <cRBG> form) for the debug messages. If "",
|
||||
/// will use the default color code for the level.
|
||||
void SetDebugColor(int nLevel, string sColor = "");
|
||||
|
||||
/// @brief Return the prefix an object uses before its debug messages.
|
||||
/// @param oTarget The target to check for a prefix.
|
||||
/// @returns The user-defined prefix if one has been set. If it has not, will
|
||||
/// return the object's tag (or name, if the object has no tag) in square
|
||||
/// brackets.
|
||||
string GetDebugPrefix(object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Set the prefix an object uses before its debug messages.
|
||||
/// @param sPrefix The prefix to set. You can include color codes in the prefix,
|
||||
/// but you can also set thedefault color code for all prefixes using
|
||||
/// `SetDebugColor(DEBUG_COLOR_NONE, sColor);`.
|
||||
/// @param oTarget The target to set the prefix for.
|
||||
void SetDebugPrefix(string sPrefix, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Return the enabled debug logging destinations.
|
||||
/// @returns A bitmask of `DEBUG_LOG_*` values.
|
||||
int GetDebugLogging();
|
||||
|
||||
/// @brief Set the enabled debug logging destinations.
|
||||
/// @param nEnabled A bitmask of `DEBUG_LOG_*` destinations to enable.
|
||||
void SetDebugLogging(int nEnabled);
|
||||
|
||||
/// @brief Add a player object to the debug message dispatch list. Player
|
||||
/// objects on the dispatch list will receive debug messages if the
|
||||
/// module's DEBUG_LOG_LEVEL includes DEBUG_LOG_LIST.
|
||||
/// @param oPC Player object to add.
|
||||
void AddDebugLoggingPC(object oPC);
|
||||
|
||||
/// @brief Remove a player object from the debug dispatch list.
|
||||
/// @param oPC Player object to remove.
|
||||
void RemoveDebugLoggingPC(object oPC);
|
||||
|
||||
/// @brief Return whether debug messages of a given level will be logged on a
|
||||
/// target. Useful for avoiding spending cycles computing extra debug
|
||||
/// information if it will not be shown.
|
||||
/// @param nLevel A `DEBUG_LEVEL_*` constant representing the message verbosity.
|
||||
/// @param oTarget The object that would be debugged.
|
||||
/// @returns TRUE if messages of nLevel would be logged on oTarget; FALSE
|
||||
/// otherwise.
|
||||
int IsDebugging(int nLevel, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// If oTarget has a debug level of nLevel or higher, logs sMessages to all
|
||||
/// destinations set with SetDebugLogging(). If no debug level is set on
|
||||
/// oTarget,
|
||||
/// will debug using the module's debug level instead.
|
||||
/// @brief Display a debug message.
|
||||
/// @details If the target has a debug level of nLevel or higher, sMessage will
|
||||
/// be sent to all destinations enabled by SetDebugLogging(). If no debug
|
||||
/// level is set on oTarget, will debug using the module's debug level
|
||||
/// instead.
|
||||
/// @param sMessage The message to display.
|
||||
/// @param nLevel A `DEBUG_LEVEL_*` constant representing the message verbosity.
|
||||
/// @param oTarget The object originating the message.
|
||||
void Debug(string sMessage, int nLevel = DEBUG_LEVEL_DEBUG, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Display a general notice message. Alias for Debug().
|
||||
/// @param sMessage The message to display.
|
||||
/// @param oTarget The object originating the message.
|
||||
void Notice(string sMessage, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Display a warning message. Alias for Debug().
|
||||
/// @param sMessage The message to display.
|
||||
/// @param oTarget The object originating the message.
|
||||
void Warning(string sMessage, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Display an error message. Alias for Debug().
|
||||
/// @param sMessage The message to display.
|
||||
/// @param oTarget The object originating the message.
|
||||
void Error(string sMessage, object oTarget = OBJECT_SELF);
|
||||
|
||||
/// @brief Display a critical error message. Alias for Debug().
|
||||
/// @param sMessage The message to display.
|
||||
/// @param oTarget The object originating the message.
|
||||
void CriticalError(string sMessage, object oTarget = OBJECT_SELF);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void OverrideDebugLevel(int nLevel)
|
||||
{
|
||||
nLevel = clamp(nLevel, DEBUG_LEVEL_NONE, DEBUG_LEVEL_DEBUG);
|
||||
SetLocalInt(GetModule(), DEBUG_OVERRIDE, nLevel);
|
||||
}
|
||||
|
||||
int GetDebugLevel(object oTarget = OBJECT_SELF)
|
||||
{
|
||||
object oModule = GetModule();
|
||||
int nOverride = GetLocalInt(oModule, DEBUG_OVERRIDE);
|
||||
if (nOverride)
|
||||
return nOverride;
|
||||
|
||||
int nModule = GetLocalInt(oModule, DEBUG_LEVEL);
|
||||
if (oTarget == oModule || !GetIsObjectValid(oTarget))
|
||||
return nModule;
|
||||
|
||||
int nLevel = GetLocalInt(oTarget, DEBUG_LEVEL);
|
||||
return (nLevel ? nLevel : nModule ? nModule : DEBUG_LEVEL_CRITICAL);
|
||||
}
|
||||
|
||||
void SetDebugLevel(int nLevel, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
SetLocalInt(oTarget, DEBUG_LEVEL, nLevel);
|
||||
}
|
||||
|
||||
string GetDebugColor(int nLevel)
|
||||
{
|
||||
string sColor = GetLocalString(GetModule(), DEBUG_COLOR + IntToString(nLevel));
|
||||
|
||||
if (sColor == "")
|
||||
{
|
||||
int nColor;
|
||||
switch (nLevel)
|
||||
{
|
||||
case DEBUG_LEVEL_CRITICAL: nColor = COLOR_RED; break;
|
||||
case DEBUG_LEVEL_ERROR: nColor = COLOR_ORANGE_DARK; break;
|
||||
case DEBUG_LEVEL_WARNING: nColor = COLOR_ORANGE_LIGHT; break;
|
||||
case DEBUG_LEVEL_NOTICE: nColor = COLOR_YELLOW; break;
|
||||
case DEBUG_LEVEL_NONE: nColor = COLOR_GREEN_LIGHT; break;
|
||||
default: nColor = COLOR_GRAY_LIGHT; break;
|
||||
}
|
||||
|
||||
sColor = HexToColor(nColor);
|
||||
SetDebugColor(nLevel, sColor);
|
||||
}
|
||||
|
||||
return sColor;
|
||||
}
|
||||
|
||||
void SetDebugColor(int nLevel, string sColor = "")
|
||||
{
|
||||
SetLocalString(GetModule(), DEBUG_COLOR + IntToString(nLevel), sColor);
|
||||
}
|
||||
|
||||
string GetDebugPrefix(object oTarget = OBJECT_SELF)
|
||||
{
|
||||
string sColor = GetDebugColor(DEBUG_LEVEL_NONE);
|
||||
string sPrefix = GetLocalString(oTarget, DEBUG_PREFIX);
|
||||
if (sPrefix == "")
|
||||
{
|
||||
if (!GetIsObjectValid(oTarget))
|
||||
{
|
||||
sColor = GetDebugColor(DEBUG_LEVEL_WARNING);
|
||||
sPrefix = "Invalid Object: #" + ObjectToString(oTarget);
|
||||
}
|
||||
else
|
||||
sPrefix = (sPrefix = GetTag(oTarget)) == "" ? GetName(oTarget) : sPrefix;
|
||||
|
||||
sPrefix = "[" + sPrefix + "]";
|
||||
}
|
||||
|
||||
return ColorString(sPrefix, sColor);
|
||||
}
|
||||
|
||||
void SetDebugPrefix(string sPrefix, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
SetLocalString(oTarget, DEBUG_PREFIX, sPrefix);
|
||||
}
|
||||
|
||||
int GetDebugLogging()
|
||||
{
|
||||
return GetLocalInt(GetModule(), DEBUG_LOG);
|
||||
}
|
||||
|
||||
void SetDebugLogging(int nEnabled)
|
||||
{
|
||||
SetLocalInt(GetModule(), DEBUG_LOG, nEnabled);
|
||||
}
|
||||
|
||||
void AddDebugLoggingPC(object oPC)
|
||||
{
|
||||
if (GetIsPC(oPC))
|
||||
AddListObject(GetModule(), oPC, DEBUG_DISPATCH, TRUE);
|
||||
}
|
||||
|
||||
void RemoveDebugLoggingPC(object oPC)
|
||||
{
|
||||
RemoveListObject(GetModule(), oPC, DEBUG_DISPATCH);
|
||||
}
|
||||
|
||||
int IsDebugging(int nLevel, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
return (nLevel <= GetDebugLevel(oTarget));
|
||||
}
|
||||
|
||||
void Debug(string sMessage, int nLevel = DEBUG_LEVEL_DEBUG, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
if (IsDebugging(nLevel, oTarget))
|
||||
{
|
||||
string sColor = GetDebugColor(nLevel);
|
||||
string sPrefix = GetDebugPrefix(oTarget) + " ";
|
||||
|
||||
switch (nLevel)
|
||||
{
|
||||
case DEBUG_LEVEL_CRITICAL: sPrefix += "[Critical Error] "; break;
|
||||
case DEBUG_LEVEL_ERROR: sPrefix += "[Error] "; break;
|
||||
case DEBUG_LEVEL_WARNING: sPrefix += "[Warning] "; break;
|
||||
}
|
||||
|
||||
if (!HandleDebug(sPrefix, sMessage, nLevel, oTarget))
|
||||
return;
|
||||
|
||||
sMessage = sPrefix + sMessage;
|
||||
int nLogging = GetLocalInt(GetModule(), DEBUG_LOG);
|
||||
|
||||
if (nLogging & DEBUG_LOG_FILE)
|
||||
WriteTimestampedLogEntry(UnColorString(sMessage));
|
||||
|
||||
sMessage = ColorString(sMessage, sColor);
|
||||
|
||||
if (nLogging & DEBUG_LOG_DM)
|
||||
SendMessageToAllDMs(sMessage);
|
||||
|
||||
if (nLogging & DEBUG_LOG_PC)
|
||||
SendMessageToPC(GetFirstPC(), sMessage);
|
||||
|
||||
if (nLogging & DEBUG_LOG_LIST)
|
||||
{
|
||||
json jDispatchList = GetObjectList(GetModule(), DEBUG_DISPATCH);
|
||||
int n; for (n; n < JsonGetLength(jDispatchList); n++)
|
||||
{
|
||||
object oPC = GetListObject(GetModule(), n, DEBUG_DISPATCH);
|
||||
if (GetIsPC(oPC) && !((nLogging & DEBUG_LOG_PC) && oPC == GetFirstPC()))
|
||||
SendMessageToPC(oPC, sMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Notice(string sMessage, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
Debug(sMessage, DEBUG_LEVEL_NOTICE, oTarget);
|
||||
}
|
||||
|
||||
void Warning(string sMessage, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
Debug(sMessage, DEBUG_LEVEL_WARNING, oTarget);
|
||||
}
|
||||
|
||||
void Error(string sMessage, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
Debug(sMessage, DEBUG_LEVEL_ERROR, oTarget);
|
||||
}
|
||||
|
||||
void CriticalError(string sMessage, object oTarget = OBJECT_SELF)
|
||||
{
|
||||
Debug(sMessage, DEBUG_LEVEL_CRITICAL, oTarget);
|
||||
}
|
481
_module/nss/util_i_libraries.nss
Normal file
481
_module/nss/util_i_libraries.nss
Normal file
@@ -0,0 +1,481 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_libraries.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief This file holds functions for packing scripts into libraries. This
|
||||
/// allows the builder to dramatically reduce the module script count by
|
||||
/// keeping related scripts in the same file.
|
||||
/// @details
|
||||
/// 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.
|
||||
///
|
||||
/// ## Anatomy of a Library
|
||||
/// This is an example of a simple library:
|
||||
///
|
||||
/// ``` nwscript
|
||||
/// #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:
|
||||
///
|
||||
/// ``` nwscript
|
||||
/// #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.
|
||||
///
|
||||
/// ## Using a Library
|
||||
/// `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.
|
||||
///
|
||||
/// ``` nwscript
|
||||
/// // 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()`.
|
||||
///
|
||||
/// ``` nwscript
|
||||
/// // 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);
|
||||
/// ```
|
||||
///
|
||||
/// ## Pre-Compiled Libraries
|
||||
/// 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.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_debug"
|
||||
#include "util_i_csvlists"
|
||||
#include "util_i_sqlite"
|
||||
#include "util_i_nss"
|
||||
#include "util_i_matching"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const string LIB_RETURN = "LIB_RETURN"; ///< The return value of the library
|
||||
const string LIB_LIBRARY = "LIB_LIBRARY"; ///< The library being processed
|
||||
const string LIB_SCRIPT = "LIB_SCRIPT"; ///< The library script name
|
||||
const string LIB_ENTRY = "LIB_ENTRY"; ///< The library script entry number
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Create a library table in the module's volatile sqlite database.
|
||||
/// @param bReset if TRUE, the table will be dropped if already present.
|
||||
/// @note This is called automatically by the library functions.
|
||||
void CreateLibraryTable(int bReset = FALSE);
|
||||
|
||||
/// @brief Add a database record associating a script with a library.
|
||||
/// @param sLibrary The script to source from.
|
||||
/// @param sScript The name to associate with the library script.
|
||||
/// @param nEntry A number unique to sLibrary to identify this script. If this
|
||||
/// is 0 and the library has not been pre-compiled, RunLibraryScript() will
|
||||
/// call sScript directly. Otherwise, RunLibraryScript() will run a dispatch
|
||||
/// function that can use this number to execute the correct code. Thus,
|
||||
/// nEntry must be set if sScript does not exactly match the desired
|
||||
/// function name or the function requires parameters.
|
||||
void AddLibraryScript(string sLibrary, string sScript, int nEntry = 0);
|
||||
|
||||
/// @brief Return the name of the library containing a script from the database.
|
||||
/// @param sScript The name of the library script.
|
||||
string GetScriptLibrary(string sScript);
|
||||
|
||||
/// @brief Return the entry number associated with a library script.
|
||||
/// @param sScript The name of the library script.
|
||||
int GetScriptEntry(string sScript);
|
||||
|
||||
/// @brief Return a prepared query with the with the library and entry data
|
||||
/// associated with a library script.
|
||||
/// @param sScript The name of the library script.
|
||||
/// @note This allows users to retrive the same data returned by
|
||||
/// GetScriptLibrary() and GetScriptEntry() with one function.
|
||||
sqlquery GetScriptData(string sScript);
|
||||
|
||||
/// @brief Return whether a script library has been loaded.
|
||||
/// @param sLibrary The name of the script library file.
|
||||
int GetIsLibraryLoaded(string sLibrary);
|
||||
|
||||
/// @brief Load a script library by executing its OnLibraryLoad() function.
|
||||
/// @param sLibrary The name of the script library file.
|
||||
/// @param bForce If TRUE, will re-load the library if it was already loaded.
|
||||
void LoadLibrary(string sLibrary, int bForce = FALSE);
|
||||
|
||||
/// @brief Load a list of script libraries in sequence.
|
||||
/// @param sLibraries A CSV list of libraries to load.
|
||||
/// @param bForce If TRUE, will re-load the library if it was already loaded.
|
||||
void LoadLibraries(string sLibraries, int bForce = FALSE);
|
||||
|
||||
/// @brief Return a json array of script names with a prefix.
|
||||
/// @param sPrefix The prefix matching the scripts to find.
|
||||
/// @returns A sorted json array of script names, minus the extensions.
|
||||
/// @note The search includes both nss and ncs files, with duplicates removed.
|
||||
json GetScriptsByPrefix(string sPrefix);
|
||||
|
||||
/// @brief Load all scripts matching the given glob pattern(s).
|
||||
/// @param sPattern A CSV list of glob patterns to match with. Supported syntax:
|
||||
/// - `*`: match zero or more characters
|
||||
/// - `?`: match a single character
|
||||
/// - `[abc]`: match any of a, b, or c
|
||||
/// - `[a-z]`: match any character from a-z
|
||||
/// - other text is matched literally
|
||||
/// @param bForce If TRUE, will-reload the library if it was already loaded.
|
||||
void LoadLibrariesByPattern(string sPattern, int bForce = FALSE);
|
||||
|
||||
/// @brief Load all scripts with a given prefix as script libraries.
|
||||
/// @param sPrefix A prefix for the desired script libraries.
|
||||
/// @param bForce If TRUE, will re-load the library if it was already loaded.
|
||||
/// @see GetMatchesPattern() for the rules on glob syntax.
|
||||
void LoadLibrariesByPrefix(string sPrefix, int bForce = FALSE);
|
||||
|
||||
/// @brief Execute a registered library script.
|
||||
/// @param sScript The unique name of the library script.
|
||||
/// @param oSelf The object that should execute the script as OBJECT_SELF.
|
||||
/// @returns The integer value set with LibraryReturn() by sScript.
|
||||
/// @note If sScript is not registered as a library script, it will be executed
|
||||
/// as a regular script instead.
|
||||
int RunLibraryScript(string sScript, object oSelf = OBJECT_SELF);
|
||||
|
||||
/// @brief Execute a list of registered library scripts in sequence.
|
||||
/// @param sScripts A CSV list of library script names.
|
||||
/// @param oSelf The object that should execute the scripts as OBJECT_SELF.
|
||||
/// @note If any script in sScripts is not registered as a library script, it
|
||||
/// will be executed as a regular script instead.
|
||||
void RunLibraryScripts(string sScripts, object oSelf = OBJECT_SELF);
|
||||
|
||||
/// @brief Register a script to a library. The script can later be called using
|
||||
/// RunLibraryScript().
|
||||
/// @param sScript A name for the script. Must be unique in the module. If a
|
||||
/// second script with the same name is registered, it will overwrite the
|
||||
/// first one. This value does not have to match the function or script name.
|
||||
/// @param nEntry A number unique to this library to identify this script. If
|
||||
/// this is 0 and the library has not been pre-compiled, RunLibraryScript()
|
||||
/// will call sScript directly. Otherwise, RunLibraryScript() will run a
|
||||
/// dispatch function that can use this number to execute the correct code.
|
||||
/// Thus, nEntry must be set if sScript does not exactly match the desired
|
||||
/// function name or the function requires parameters.
|
||||
/// @note Must be called within a script library's OnLibraryLoad() function. For
|
||||
/// uses in other places, use AddLibraryScript().
|
||||
void RegisterLibraryScript(string sScript, int nEntry = 0);
|
||||
|
||||
/// @brief Set the return value of the currently executing library script.
|
||||
/// @param nValue The value to return to the calling script.
|
||||
void LibraryReturn(int nValue);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void CreateLibraryTable(int bReset = FALSE)
|
||||
{
|
||||
SqlCreateTableModule("library_scripts",
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"sLibrary TEXT NOT NULL, " +
|
||||
"sScript TEXT NOT NULL UNIQUE ON CONFLICT REPLACE, " +
|
||||
"nEntry INTEGER NOT NULL);",
|
||||
bReset);
|
||||
}
|
||||
|
||||
void AddLibraryScript(string sLibrary, string sScript, int nEntry = 0)
|
||||
{
|
||||
CreateLibraryTable();
|
||||
|
||||
string sQuery = "INSERT INTO library_scripts (sLibrary, sScript, nEntry) " +
|
||||
"VALUES (@sLibrary, @sScript, @nEntry);";
|
||||
sqlquery sql = SqlPrepareQueryModule(sQuery);
|
||||
SqlBindString(sql, "@sLibrary", sLibrary);
|
||||
SqlBindString(sql, "@sScript", sScript);
|
||||
SqlBindInt(sql, "@nEntry", nEntry);
|
||||
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
string GetScriptFieldData(string sField, string sScript)
|
||||
{
|
||||
CreateLibraryTable();
|
||||
|
||||
string sQuery = "SELECT " + sField + " FROM library_scripts " +
|
||||
"WHERE sScript = @sScript;";
|
||||
sqlquery sql = SqlPrepareQueryModule(sQuery);
|
||||
SqlBindString(sql, "@sScript", sScript);
|
||||
|
||||
return SqlStep(sql) ? SqlGetString(sql, 0) : "";
|
||||
}
|
||||
|
||||
string GetScriptLibrary(string sScript)
|
||||
{
|
||||
return GetScriptFieldData("sLibrary", sScript);
|
||||
}
|
||||
|
||||
int GetScriptEntry(string sScript)
|
||||
{
|
||||
return StringToInt(GetScriptFieldData("nEntry", sScript));
|
||||
}
|
||||
|
||||
sqlquery GetScriptData(string sScript)
|
||||
{
|
||||
CreateLibraryTable();
|
||||
|
||||
string sQuery = "SELECT sLibrary, nEntry FROM library_scripts " +
|
||||
"WHERE sScript = @sScript;";
|
||||
sqlquery sql = SqlPrepareQueryModule(sQuery);
|
||||
SqlBindString(sql, "@sScript", sScript);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
int GetIsLibraryLoaded(string sLibrary)
|
||||
{
|
||||
CreateLibraryTable();
|
||||
|
||||
string sQuery = "SELECT COUNT(sLibrary) FROM library_scripts " +
|
||||
"WHERE sLibrary = @sLibrary LIMIT 1;";
|
||||
sqlquery sql = SqlPrepareQueryModule(sQuery);
|
||||
SqlBindString(sql, "@sLibrary", sLibrary);
|
||||
|
||||
return SqlStep(sql) ? SqlGetInt(sql, 0) : FALSE;
|
||||
}
|
||||
|
||||
void LoadLibrary(string sLibrary, int bForce = FALSE)
|
||||
{
|
||||
Debug("Attempting to " + (bForce ? "force " : "") + "load library " + sLibrary);
|
||||
|
||||
if (bForce || !GetIsLibraryLoaded(sLibrary))
|
||||
{
|
||||
SetScriptParam(LIB_LIBRARY, sLibrary);
|
||||
if (ResManGetAliasFor(sLibrary, RESTYPE_NCS) == "")
|
||||
{
|
||||
Debug(sLibrary + ".ncs not present; loading library as chunk");
|
||||
string sChunk = NssInclude(sLibrary) + NssVoidMain(NssFunction("OnLibraryLoad"));
|
||||
string sError = ExecuteScriptChunk(sChunk, GetModule(), FALSE);
|
||||
if (sError != "")
|
||||
CriticalError("Could not load " + sLibrary + ": " + sError);
|
||||
}
|
||||
else
|
||||
ExecuteScript(sLibrary, GetModule());
|
||||
|
||||
}
|
||||
else
|
||||
Error("Library " + sLibrary + " already loaded!");
|
||||
}
|
||||
|
||||
void LoadLibraries(string sLibraries, int bForce = FALSE)
|
||||
{
|
||||
Debug("Attempting to " + (bForce ? "force " : "") + "load libraries " + sLibraries);
|
||||
|
||||
int i, nCount = CountList(sLibraries);
|
||||
for (i = 0; i < nCount; i++)
|
||||
LoadLibrary(GetListItem(sLibraries, i), bForce);
|
||||
}
|
||||
|
||||
// Private function for GetScriptsByPrefix*(). Adds all scripts of nResType
|
||||
// matching a prefix to a json array and returns it.
|
||||
json _GetScriptsByPrefix(json jArray, string sPrefix, int nResType)
|
||||
{
|
||||
int i;
|
||||
string sScript;
|
||||
while ((sScript = ResManFindPrefix(sPrefix, nResType, ++i)) != "")
|
||||
jArray = JsonArrayInsert(jArray, JsonString(sScript));
|
||||
|
||||
return jArray;
|
||||
}
|
||||
|
||||
json GetScriptsByPrefix(string sPrefix)
|
||||
{
|
||||
json jScripts = _GetScriptsByPrefix(JsonArray(), sPrefix, RESTYPE_NCS);
|
||||
jScripts = _GetScriptsByPrefix(jScripts, sPrefix, RESTYPE_NSS);
|
||||
jScripts = JsonArrayTransform(jScripts, JSON_ARRAY_UNIQUE);
|
||||
jScripts = JsonArrayTransform(jScripts, JSON_ARRAY_SORT_ASCENDING);
|
||||
return jScripts;
|
||||
}
|
||||
|
||||
void LoadLibrariesByPattern(string sPatterns, int bForce = FALSE)
|
||||
{
|
||||
if (sPatterns == "")
|
||||
return;
|
||||
|
||||
Debug("Finding libraries matching \"" + sPatterns + "\"");
|
||||
json jPatterns = ListToJson(sPatterns);
|
||||
json jLibraries = FilterByPatterns(GetScriptsByPrefix(""), jPatterns, TRUE);
|
||||
LoadLibraries(JsonToList(jLibraries), bForce);
|
||||
}
|
||||
|
||||
void LoadLibrariesByPrefix(string sPrefix, int bForce = FALSE)
|
||||
{
|
||||
Debug("Finding libraries with prefix \"" + sPrefix + "\"");
|
||||
json jLibraries = GetScriptsByPrefix(sPrefix);
|
||||
LoadLibraries(JsonToList(jLibraries), bForce);
|
||||
}
|
||||
|
||||
void LoadPrefixLibraries(string sPrefix, int bForce = FALSE)
|
||||
{
|
||||
Debug("LoadPrefixLibraries() is deprecated; use LoadLibrariesByPrefix()");
|
||||
LoadLibrariesByPrefix(sPrefix, bForce);
|
||||
}
|
||||
|
||||
int RunLibraryScript(string sScript, object oSelf = OBJECT_SELF)
|
||||
{
|
||||
if (sScript == "") return -1;
|
||||
|
||||
string sLibrary;
|
||||
int nEntry;
|
||||
|
||||
sqlquery sqlScriptData = GetScriptData(sScript);
|
||||
if (SqlStep(sqlScriptData))
|
||||
{
|
||||
sLibrary = SqlGetString(sqlScriptData, 0);
|
||||
nEntry = SqlGetInt(sqlScriptData, 1);
|
||||
}
|
||||
|
||||
DeleteLocalInt(oSelf, LIB_RETURN);
|
||||
|
||||
if (sLibrary != "")
|
||||
{
|
||||
Debug("Library script " + sScript + " found in " + sLibrary +
|
||||
(nEntry != 0 ? " at entry " + IntToString(nEntry) : ""));
|
||||
|
||||
SetScriptParam(LIB_LIBRARY, sLibrary);
|
||||
SetScriptParam(LIB_SCRIPT, sScript);
|
||||
SetScriptParam(LIB_ENTRY, IntToString(nEntry));
|
||||
|
||||
if (ResManGetAliasFor(sLibrary, RESTYPE_NCS) == "")
|
||||
{
|
||||
Debug(sLibrary + ".ncs not present; running library script as chunk");
|
||||
string sChunk = NssInclude(sLibrary) + NssVoidMain(nEntry ?
|
||||
NssFunction("OnLibraryScript", NssQuote(sScript) + ", " + IntToString(nEntry)) :
|
||||
NssFunction(sScript));
|
||||
string sError = ExecuteScriptChunk(sChunk, oSelf, FALSE);
|
||||
if (sError != "")
|
||||
CriticalError("RunLibraryScript(" + sScript +") failed: " + sError);
|
||||
}
|
||||
else
|
||||
ExecuteScript(sLibrary, oSelf);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(sScript + " is not a library script; executing directly");
|
||||
ExecuteScript(sScript, oSelf);
|
||||
}
|
||||
|
||||
return GetLocalInt(oSelf, LIB_RETURN);
|
||||
}
|
||||
|
||||
void RunLibraryScripts(string sScripts, object oSelf = OBJECT_SELF)
|
||||
{
|
||||
int i, nCount = CountList(sScripts);
|
||||
for (i = 0; i < nCount; i++)
|
||||
RunLibraryScript(GetListItem(sScripts, i), oSelf);
|
||||
}
|
||||
|
||||
void RegisterLibraryScript(string sScript, int nEntry = 0)
|
||||
{
|
||||
string sLibrary = GetScriptParam(LIB_LIBRARY);
|
||||
string sExist = GetScriptLibrary(sScript);
|
||||
|
||||
if (sLibrary != sExist && sExist != "")
|
||||
Warning(sLibrary + " is overriding " + sExist + "'s implementation of " + sScript);
|
||||
|
||||
int nOldEntry = GetScriptEntry(sScript);
|
||||
if (nOldEntry)
|
||||
Warning(sLibrary + " already declared " + sScript +
|
||||
" Old Entry: " + IntToString(nOldEntry) +
|
||||
" New Entry: " + IntToString(nEntry));
|
||||
|
||||
AddLibraryScript(sLibrary, sScript, nEntry);
|
||||
}
|
||||
|
||||
void LibraryReturn(int nValue)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, LIB_RETURN, nValue);
|
||||
}
|
78
_module/nss/util_i_library.nss
Normal file
78
_module/nss/util_i_library.nss
Normal file
@@ -0,0 +1,78 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_library.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Boilerplace code for creating a library dispatcher. Should only be
|
||||
/// included in library scripts as it implements main().
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_libraries"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Protoypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// This is a user-defined function that registers function names to a unique (to
|
||||
// this library) number. When the function name is run using RunLibraryScript(),
|
||||
// this number will be passed to the user-defined function OnLibraryScript(),
|
||||
// which resolves the call to the correct function.
|
||||
//
|
||||
// Example usage:
|
||||
// void OnLibraryLoad()
|
||||
// {
|
||||
// RegisterLibraryScript("MyFunction");
|
||||
// RegisterLibraryScript("MyOtherFunction");
|
||||
// }
|
||||
//
|
||||
// or, if using nEntry...
|
||||
// void OnLibraryLoad()
|
||||
// {
|
||||
// RegisterLibraryScript("MyFunction", 1);
|
||||
// RegisterLibraryScript("MyOtherFunction", 2);
|
||||
// }
|
||||
void OnLibraryLoad();
|
||||
|
||||
// This is a user-defined function that routes a unique (to the module) script
|
||||
// name (sScript) or a unique (to this library) number (nEntry) to a function.
|
||||
//
|
||||
// Example usage:
|
||||
// void OnLibraryScript(string sScript, int nEntry)
|
||||
// {
|
||||
// if (sScript == "MyFunction") MyFunction();
|
||||
// else if (sScript == "MyOtherFunction") MyOtherFunction();
|
||||
// }
|
||||
//
|
||||
// or, using nEntry...
|
||||
// void OnLibraryScript(string sScript, int nEntry)
|
||||
// {
|
||||
// switch (nEntry)
|
||||
// {
|
||||
// case 1: MyFunction(); break;
|
||||
// case 2: MyOtherFunction(); break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// For advanced usage, see the libraries included in the Core Framework.
|
||||
void OnLibraryScript(string sScript, int nEntry);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// These are dummy implementations to prevent nwnsc from complaining that they
|
||||
// do not exist. If you want to compile in the toolset rather than using nwnsc,
|
||||
// comment these lines out.
|
||||
// #pragma default_function(OnLibraryLoad)
|
||||
// #pragma default_function(OnLibraryScript)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Main Routine
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
if (GetScriptParam(LIB_ENTRY) == "")
|
||||
OnLibraryLoad();
|
||||
else
|
||||
OnLibraryScript(GetScriptParam(LIB_SCRIPT),
|
||||
StringToInt(GetScriptParam(LIB_ENTRY)));
|
||||
}
|
98
_module/nss/util_i_lists.nss
Normal file
98
_module/nss/util_i_lists.nss
Normal file
@@ -0,0 +1,98 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_lists.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Compatibility functions to convert between CSV and localvar lists.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "util_i_csvlists"
|
||||
#include "util_i_varlists"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Acceptable values for nListType in SplitList() and JoinList().
|
||||
const int LIST_TYPE_FLOAT = 0;
|
||||
const int LIST_TYPE_INT = 1;
|
||||
const int LIST_TYPE_STRING = 2;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Splits a comma-separated value list into a local variable list of the
|
||||
/// given type.
|
||||
/// @param oTarget Object on which to create the list
|
||||
/// @param sList Source CSV list
|
||||
/// @param sListName Name of the list to create or add to
|
||||
/// @param bAddUnique If TRUE, prevents duplicate list items
|
||||
/// @param nListType Type of list to create
|
||||
/// LIST_TYPE_STRING (default)
|
||||
/// LIST_TYPE_FLOAT
|
||||
/// LIST_TYPE_INT
|
||||
/// @returns JSON array of split CSV list
|
||||
json SplitList(object oTarget, string sList, string sListName = "", int bAddUnique = FALSE, int nListType = LIST_TYPE_STRING);
|
||||
|
||||
/// @brief Joins a local variable list of a given type into a comma-separated
|
||||
/// value list
|
||||
/// @param oTarget Object from which to source the local variable list
|
||||
/// @param sListName Name of the local variable list
|
||||
/// @param bAddUnique If TRUE, prevents duplicate list items
|
||||
/// @param nListType Type of local variable list
|
||||
/// LIST_TYPE_STRING (default)
|
||||
/// LIST_TYPE_FLOAT
|
||||
/// LIST_TYPE_INT
|
||||
/// @returns Joined CSV list of local variable list
|
||||
string JoinList(object oTarget, string sListName = "", int bAddUnique = FALSE, int nListType = LIST_TYPE_STRING);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
json SplitList(object oTarget, string sList, string sListName = "", int bAddUnique = FALSE, int nListType = LIST_TYPE_STRING)
|
||||
{
|
||||
json jList = JSON_ARRAY;
|
||||
|
||||
if (nListType == LIST_TYPE_STRING)
|
||||
jList = ListToJson(sList, TRUE);
|
||||
else
|
||||
jList = JsonParse("[" + sList + "]");
|
||||
|
||||
string sListType = (nListType == LIST_TYPE_STRING ? VARLIST_TYPE_STRING :
|
||||
nListType == LIST_TYPE_INT ? VARLIST_TYPE_INT :
|
||||
VARLIST_TYPE_FLOAT);
|
||||
|
||||
if (bAddUnique == TRUE)
|
||||
jList = JsonArrayTransform(jList, JSON_ARRAY_UNIQUE);
|
||||
|
||||
if (oTarget != OBJECT_INVALID)
|
||||
_SetList(oTarget, sListType, sListName, jList);
|
||||
|
||||
return jList;
|
||||
}
|
||||
|
||||
string JoinList(object oTarget, string sListName = "", int bAddUnique = FALSE, int nListType = LIST_TYPE_STRING)
|
||||
{
|
||||
string sListType = (nListType == LIST_TYPE_STRING ? VARLIST_TYPE_STRING :
|
||||
nListType == LIST_TYPE_INT ? VARLIST_TYPE_INT :
|
||||
VARLIST_TYPE_FLOAT);
|
||||
|
||||
json jList = _GetList(oTarget, sListType, sListName);
|
||||
if (jList == JsonNull() || JsonGetLength(jList) == 0)
|
||||
return "";
|
||||
|
||||
if (bAddUnique == TRUE)
|
||||
jList = JsonArrayTransform(jList, JSON_ARRAY_UNIQUE);
|
||||
|
||||
string sList;
|
||||
if (nListType == LIST_TYPE_STRING)
|
||||
sList = JsonToList(jList);
|
||||
else
|
||||
{
|
||||
sList = JsonDump(jList);
|
||||
sList = GetStringSlice(sList, 1, GetStringLength(sList) - 2);
|
||||
}
|
||||
|
||||
return sList;
|
||||
}
|
128
_module/nss/util_i_matching.nss
Normal file
128
_module/nss/util_i_matching.nss
Normal file
@@ -0,0 +1,128 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_matching.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Utilities for pattern matching.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Return whether a string matches a glob pattern.
|
||||
/// @param sString The string to check.
|
||||
/// @param sPattern A glob pattern. Supported syntax:
|
||||
/// - `*`: match zero or more characters
|
||||
/// - `?`: match a single character
|
||||
/// - `[abc]`: match any of a, b, or c
|
||||
/// - `[a-z]`: match any character from a-z
|
||||
/// - other text is matched literally
|
||||
/// @returns TRUE if sString matches sPattern; FALSE otherwise.
|
||||
int GetMatchesPattern(string sString, string sPattern);
|
||||
|
||||
/// @brief Return whether a string matches any of an array of glob patterns.
|
||||
/// @param sString The string to check.
|
||||
/// @param sPattern A json array of glob patterns.
|
||||
/// @returns TRUE if sString matches sPattern; FALSE otherwise.
|
||||
/// @see GetMatchesPattern() for supported glob syntax.
|
||||
int GetMatchesPatterns(string sString, json jPatterns);
|
||||
|
||||
/// @brief Return if any element of a json array matches a glob pattern.
|
||||
/// @param jArray A json array of strings to check.
|
||||
/// @param sPattern A glob pattern.
|
||||
/// @param bNot If TRUE, will invert the selection, returning whether any
|
||||
/// element does not match the glob pattern.
|
||||
/// @returns TRUE if any element of jArray matches sPattern; FALSE otherwise.
|
||||
/// @see GetMatchesPattern() for supported glob syntax.
|
||||
int GetAnyMatchesPattern(json jArray, string sPattern, int bNot = FALSE);
|
||||
|
||||
/// @brief Return if all elements of a json array match a glob pattern.
|
||||
/// @param jArray A json array of strings to check.
|
||||
/// @param sPattern A glob pattern.
|
||||
/// @param bNot If TRUE, will invert the selection, returning whether all
|
||||
/// elements do not match the glob pattern.
|
||||
/// @returns TRUE if all elements of jArray match sPattern; FALSE otherwise.
|
||||
/// @see GetMatchesPattern() for supported glob syntax.
|
||||
int GetAllMatchesPattern(json jArray, string sPattern, int bNot = FALSE);
|
||||
|
||||
/// @brief Filter out all elements of an array that do not match a glob pattern.
|
||||
/// @param jArray A json array of strings to filter.
|
||||
/// @param sPattern A glob pattern.
|
||||
/// @param bNot If TRUE, will invert the selection, only keeping elements that
|
||||
/// do not match the glob pattern.
|
||||
/// @returns A modified copy of jArray with all non-matching elements removed.
|
||||
/// @see GetMatchesPattern() for supported glob syntax.
|
||||
json FilterByPattern(json jArray, string sPattern, int bNot = FALSE);
|
||||
|
||||
/// @brief Filter out all elements of an array that do not match any of an array
|
||||
/// of glob patterns.
|
||||
/// @param jArray A json array of strings to filter.
|
||||
/// @param jPatterns A json array of glob patterns.
|
||||
/// @param bOrderByPatterns If TRUE, will order the results by the pattern they
|
||||
/// matched with rather than by their placement in jArray.
|
||||
/// @returns A modified copy of jArray with all non-matching elements removed.
|
||||
/// @see GetMatchesPattern() for supported glob syntax.
|
||||
json FilterByPatterns(json jArray, json jPatterns, int bOrderByPatterns = FALSE);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int GetMatchesPattern(string sString, string sPattern)
|
||||
{
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(),
|
||||
"SELECT @string GLOB @pattern;");
|
||||
SqlBindString(q, "@string", sString);
|
||||
SqlBindString(q, "@pattern", sPattern);
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : FALSE;
|
||||
}
|
||||
|
||||
int GetMatchesPatterns(string sString, json jPatterns)
|
||||
{
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(),
|
||||
"SELECT 1 FROM json_each(@patterns) WHERE @value GLOB json_each.value;");
|
||||
SqlBindString(q, "@value", sString);
|
||||
SqlBindJson(q, "@patterns", jPatterns);
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : FALSE;
|
||||
}
|
||||
|
||||
int GetAnyMatchesPattern(json jArray, string sPattern, int bNot = FALSE)
|
||||
{
|
||||
jArray = FilterByPattern(jArray, sPattern, bNot);
|
||||
return JsonGetLength(jArray) != 0;
|
||||
}
|
||||
|
||||
int GetAllMatchesPattern(json jArray, string sPattern, int bNot = FALSE)
|
||||
{
|
||||
return jArray == FilterByPattern(jArray, sPattern, bNot);
|
||||
}
|
||||
|
||||
json FilterByPattern(json jArray, string sPattern, int bNot = FALSE)
|
||||
{
|
||||
if (!JsonGetLength(jArray))
|
||||
return jArray;
|
||||
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(),
|
||||
"SELECT json_group_array(value) FROM json_each(@array) " +
|
||||
"WHERE value " + (bNot ? "NOT " : "") + "GLOB @pattern;");
|
||||
SqlBindJson(q, "@array", jArray);
|
||||
SqlBindString(q, "@pattern", sPattern);
|
||||
return SqlStep(q) ? SqlGetJson(q, 0) : JsonArray();
|
||||
}
|
||||
|
||||
json FilterByPatterns(json jArray, json jPatterns, int bOrderByPattern = FALSE)
|
||||
{
|
||||
if (!JsonGetLength(jArray) || ! JsonGetLength(jPatterns))
|
||||
return jArray;
|
||||
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(),
|
||||
"SELECT json_group_array(value) FROM " +
|
||||
"(SELECT DISTINCT v.key, v.value FROM " +
|
||||
"json_each(@values) v JOIN " +
|
||||
"json_each(@patterns) p " +
|
||||
"WHERE v.value GLOB p.value " +
|
||||
(bOrderByPattern ? "ORDER BY p.key);" : ");"));
|
||||
SqlBindJson(q, "@values", jArray);
|
||||
SqlBindJson(q, "@patterns", jPatterns);
|
||||
return SqlStep(q) ? SqlGetJson(q, 0) : JsonArray();
|
||||
}
|
177
_module/nss/util_i_math.nss
Normal file
177
_module/nss/util_i_math.nss
Normal file
@@ -0,0 +1,177 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_math.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Useful math utility functions.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Return the closest integer to the binary logarithm of a number.
|
||||
int log2(int n);
|
||||
|
||||
/// @brief Restrict an integer to a range.
|
||||
/// @param nValue The number to evaluate.
|
||||
/// @param nMin The minimum value for the number.
|
||||
/// @param nMax The maximum value for the number.
|
||||
/// @returns nValue if it is between nMin and nMax. Otherwise returns the
|
||||
/// closest of nMin or nMax.
|
||||
int clamp(int nValue, int nMin, int nMax);
|
||||
|
||||
/// @brief Restrict a float to a range.
|
||||
/// @param fValue The number to evaluate.
|
||||
/// @param fMin The minimum value for the number.
|
||||
/// @param fMax The maximum value for the number.
|
||||
/// @returns fValue if it is between fMin and fMax. Otherwise returns the
|
||||
/// closest of fMin or fMax.
|
||||
float fclamp(float fValue, float fMin, float fMax);
|
||||
|
||||
/// @brief Return the larger of two integers.
|
||||
int max(int a, int b);
|
||||
|
||||
/// @brief Return the smaller of two integers.
|
||||
int min(int a, int b);
|
||||
|
||||
/// @brief Return the sign of an integer.
|
||||
/// @returns -1 if n is negative, 0 if 0, or 1 if positive.
|
||||
int sign(int n);
|
||||
|
||||
/// @brief Return the larger of two floats.
|
||||
float fmax(float a, float b);
|
||||
|
||||
/// @brief Return the smaller of two floats.
|
||||
float fmin(float a, float b);
|
||||
|
||||
/// @brief Return the sign of a float.
|
||||
/// @returns -1 if f is negative, 0 if 0, or 1 if positive.
|
||||
int fsign(float f);
|
||||
|
||||
/// @brief Truncate a float (i.e., remove numbers to the right of the decimal
|
||||
/// point).
|
||||
float trunc(float f);
|
||||
|
||||
/// @brief Return the fractional part of a float (i.e., numbers to the right of
|
||||
/// the decimal point).
|
||||
float frac(float f);
|
||||
|
||||
/// @brief Return a % b (modulo function).
|
||||
/// @param a The dividend
|
||||
/// @param b The divisor
|
||||
/// @note For consistency with NWN's integer modulo operator, the result has the
|
||||
/// same sign as a (i.e., fmod(-1, 2) == -1).
|
||||
float fmod(float a, float b);
|
||||
|
||||
/// @brief Round a float down to the nearest whole number.
|
||||
float floor(float f);
|
||||
|
||||
/// @brief Round a float up to the nearest whole number.
|
||||
float ceil(float f);
|
||||
|
||||
/// @brief Round a float towards to the nearest whole number.
|
||||
/// @note In case of a tie (i.e., +/- 0.5), rounds away from 0.
|
||||
float round(float f);
|
||||
|
||||
/// @brief Determine if x is in [a..b]
|
||||
/// @param x Value to compare
|
||||
/// @param a Low end of range
|
||||
/// @param b High end of range
|
||||
int between(int x, int a, int b);
|
||||
|
||||
/// @brief Determine if x is in [a..b]
|
||||
/// @param x Value to compare
|
||||
/// @param a Low end of range
|
||||
/// @param b High end of range
|
||||
int fbetween(float x, float a, float b);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int log2(int n)
|
||||
{
|
||||
int nResult;
|
||||
while (n >>= 1)
|
||||
nResult++;
|
||||
return nResult;
|
||||
}
|
||||
|
||||
int clamp(int nValue, int nMin, int nMax)
|
||||
{
|
||||
return (nValue < nMin) ? nMin : ((nValue > nMax) ? nMax : nValue);
|
||||
}
|
||||
|
||||
float fclamp(float fValue, float fMin, float fMax)
|
||||
{
|
||||
return (fValue < fMin) ? fMin : ((fValue > fMax) ? fMax : fValue);
|
||||
}
|
||||
|
||||
int max(int a, int b)
|
||||
{
|
||||
return (b > a) ? b : a;
|
||||
}
|
||||
|
||||
int min(int a, int b)
|
||||
{
|
||||
return (b > a) ? a : b;
|
||||
}
|
||||
|
||||
int sign(int n)
|
||||
{
|
||||
return (n > 0) ? 1 : (n < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
float fmax(float a, float b)
|
||||
{
|
||||
return (b > a) ? b : a;
|
||||
}
|
||||
|
||||
float fmin(float a, float b)
|
||||
{
|
||||
return (b > a) ? a : b;
|
||||
}
|
||||
|
||||
int fsign(float f)
|
||||
{
|
||||
return f > 0.0 ? 1 : f < 0.0 ? -1 : 0;
|
||||
}
|
||||
|
||||
float trunc(float f)
|
||||
{
|
||||
return IntToFloat(FloatToInt(f));
|
||||
}
|
||||
|
||||
float frac(float f)
|
||||
{
|
||||
return f - trunc(f);
|
||||
}
|
||||
|
||||
float fmod(float a, float b)
|
||||
{
|
||||
return a - b * trunc(a / b);
|
||||
}
|
||||
|
||||
float floor(float f)
|
||||
{
|
||||
return IntToFloat(FloatToInt(f) - (f < 0.0));
|
||||
}
|
||||
|
||||
float ceil(float f)
|
||||
{
|
||||
return IntToFloat(FloatToInt(f) + (trunc(f) < f));
|
||||
}
|
||||
|
||||
float round(float f)
|
||||
{
|
||||
return IntToFloat(FloatToInt(f + (f < 0.0 ? -0.5 : 0.5)));
|
||||
}
|
||||
|
||||
int between(int x, int a, int b)
|
||||
{
|
||||
return ((x - a) * (x - b)) <= 0;
|
||||
}
|
||||
|
||||
int fbetween(float x, float a, float b)
|
||||
{
|
||||
return ((x - a) * (x - b)) <= 0.0;
|
||||
}
|
224
_module/nss/util_i_nss.nss
Normal file
224
_module/nss/util_i_nss.nss
Normal file
@@ -0,0 +1,224 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_nss.nss
|
||||
/// @author Daz <daztek@gmail.com>
|
||||
/// @brief Functions to assemble scripts for use with `ExecuteScriptChunk()`.
|
||||
/// @note Borrowed from https://github.com/Daztek/EventSystem
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Return a `void main()` block.
|
||||
/// @param sContents The contents of the block.
|
||||
string NssVoidMain(string sContents);
|
||||
|
||||
/// @brief Return an `int StartingConditional()` block.
|
||||
/// @param sContents The contents of the block.
|
||||
string NssStartingConditional(string sContents);
|
||||
|
||||
/// @brief Return an include directive.
|
||||
/// @param sIncludeFile The file to include.
|
||||
string NssInclude(string sIncludeFile);
|
||||
|
||||
/// @brief Return an if statement with a comparison.
|
||||
/// @param sLeft The left side of the comparison. If sComparison or sRight are
|
||||
/// blank, will be evalated as a boolean expression.
|
||||
/// @param sComparison The comparison operator.
|
||||
/// @param sRight The right side of the comparison.
|
||||
string NssIf(string sLeft, string sComparison = "", string sRight = "");
|
||||
|
||||
/// @brief Return an else statement.
|
||||
string NssElse();
|
||||
|
||||
/// @brief Return an else-if statement with a comparison.
|
||||
/// @param sLeft The left side of the comparison. If sComparison or sRight are
|
||||
/// blank, will be evalated as a boolean expression.
|
||||
/// @param sComparison The comparison operator.
|
||||
/// @param sRight The right side of the comparison.
|
||||
string NssElseIf(string sLeft, string sComparison = "", string sRight = "");
|
||||
|
||||
/// @brief Create a while statement with a comparison.
|
||||
/// @param sLeft The left side of the comparison. If sComparison or sRight are
|
||||
/// blank, will be evalated as a boolean expression.
|
||||
/// @param sComparison The comparison operator.
|
||||
/// @param sRight The right side of the comparison.
|
||||
string NssWhile(string sLeft, string sComparison = "", string sRight = "");
|
||||
|
||||
/// @brief Return a script block bounded by curly brackets.
|
||||
/// @param sContents The contents of the block.
|
||||
string NssBrackets(string sContents);
|
||||
|
||||
/// @brief Return a string wrapped in double quotes.
|
||||
/// @param sString The string to wrap.
|
||||
string NssQuote(string sString);
|
||||
|
||||
/// @brief Return a switch statement.
|
||||
/// @param sVariable The variable to evaluate in the switch statement.
|
||||
/// @param sCases A series of case statements the switch should dispatch to.
|
||||
/// @see NssCase().
|
||||
string NssSwitch(string sVariable, string sCases);
|
||||
|
||||
/// @brief Return a case statement.
|
||||
/// @param nCase The value matching the switch statement.
|
||||
/// @param sContents The contents of the case block.
|
||||
/// @param bBreak If TRUE, will add a break statement after sContents.
|
||||
string NssCase(int nCase, string sContents, int bBreak = TRUE);
|
||||
|
||||
/// @brief Return an object variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssObject(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return a string variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssString(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return an int variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssInt(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return a float variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssFloat(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return a vector variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssVector(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return a location variable declaration and/or assignment.
|
||||
/// @param sVarName The name for the variable.
|
||||
/// @param sValue The value to assign to the variable. If blank, no value will
|
||||
/// be assigned.
|
||||
/// @param bIncludeType If TRUE, the variable will be declared as well.
|
||||
string NssLocation(string sVarName, string sValue = "", int bIncludeType = TRUE);
|
||||
|
||||
/// @brief Return a call, prototype, or definition of a function.
|
||||
/// @param sFunction The name of the function.
|
||||
/// @param sArguments The list of arguments for the function.
|
||||
/// @param bAddSemicolon If TRUE, a semicolon will be assed to the end of the
|
||||
/// statement.
|
||||
string NssFunction(string sFunction, string sArguments = "", int bAddSemicolon = TRUE);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string NssVoidMain(string sContents)
|
||||
{
|
||||
return "void main() { " + sContents + " }";
|
||||
}
|
||||
|
||||
string NssStartingConditional(string sContents)
|
||||
{
|
||||
return "int StartingConditional() { return " + sContents + " }";
|
||||
}
|
||||
|
||||
string NssInclude(string sIncludeFile)
|
||||
{
|
||||
return sIncludeFile == "" ? sIncludeFile : "#" + "include \"" + sIncludeFile + "\" ";
|
||||
}
|
||||
|
||||
string NssCompare(string sLeft, string sComparison, string sRight)
|
||||
{
|
||||
return (sComparison == "" || sRight == "") ? sLeft : sLeft + " " + sComparison + " " + sRight;
|
||||
}
|
||||
|
||||
string NssIf(string sLeft, string sComparison = "", string sRight = "")
|
||||
{
|
||||
return "if (" + NssCompare(sLeft, sComparison, sRight) + ") ";
|
||||
}
|
||||
|
||||
string NssElse()
|
||||
{
|
||||
return "else ";
|
||||
}
|
||||
|
||||
string NssElseIf(string sLeft, string sComparison = "", string sRight = "")
|
||||
{
|
||||
return "else if (" + NssCompare(sLeft, sComparison, sRight) + ") ";
|
||||
}
|
||||
|
||||
string NssWhile(string sLeft, string sComparison = "", string sRight = "")
|
||||
{
|
||||
return "while (" + NssCompare(sLeft, sComparison, sRight) + ") ";
|
||||
}
|
||||
|
||||
string NssBrackets(string sContents)
|
||||
{
|
||||
return "{ " + sContents + " } ";
|
||||
}
|
||||
|
||||
string NssQuote(string sString)
|
||||
{
|
||||
return "\"" + sString + "\"";
|
||||
}
|
||||
|
||||
string NssSwitch(string sVariable, string sCases)
|
||||
{
|
||||
return "switch (" + sVariable + ") { " + sCases + " }";
|
||||
}
|
||||
|
||||
string NssCase(int nCase, string sContents, int bBreak = TRUE)
|
||||
{
|
||||
return "case " + IntToString(nCase) + ": { " + sContents + (bBreak ? " break;" : "") + " } ";
|
||||
}
|
||||
|
||||
string NssSemicolon(string sString)
|
||||
{
|
||||
return (GetStringRight(sString, 1) == ";" || GetStringRight(sString, 2) == "; ") ? sString + " " : sString + "; ";
|
||||
}
|
||||
|
||||
string NssVariable(string sType, string sVarName, string sValue)
|
||||
{
|
||||
return sType + " " + sVarName + (sValue == "" ? "; " : " = " + NssSemicolon(sValue));
|
||||
}
|
||||
|
||||
string NssObject(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "object" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssString(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "string" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssInt(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "int" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssFloat(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "float" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssVector(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "vector" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssLocation(string sVarName, string sValue = "", int bIncludeType = TRUE)
|
||||
{
|
||||
return NssVariable(bIncludeType ? "location" : "", sVarName, sValue);
|
||||
}
|
||||
|
||||
string NssFunction(string sFunction, string sArguments = "", int bAddSemicolon = TRUE)
|
||||
{
|
||||
return sFunction + "(" + sArguments + (bAddSemicolon ? ");" : ")") + " ";
|
||||
}
|
175
_module/nss/util_i_sqlite.nss
Normal file
175
_module/nss/util_i_sqlite.nss
Normal file
@@ -0,0 +1,175 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_sqlite.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @brief Helper functions for NWN:EE SQLite databases.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Alias for `SqlPreparerQueryObject(GetModule(), sSQL)`.
|
||||
sqlquery SqlPrepareQueryModule(string sSQL);
|
||||
|
||||
/// @brief Prepares and executes a query on a PC's peristent database.
|
||||
/// @param oPC The PC that stores the database.
|
||||
/// @param sQuery The SQL statement to execute.
|
||||
/// @returns Whether the query was successful.
|
||||
int SqlExecPC(object oPC, string sQuery);
|
||||
|
||||
/// @brief Prepares and executes a query on the module's volatile database.
|
||||
/// @param sQuery The SQL statement to execute.
|
||||
/// @returns Whether the query was successful.
|
||||
int SqlExecModule(string sQuery);
|
||||
|
||||
/// @brief Prepares and executes a query on a persistent campaign database.
|
||||
/// @param sDatabase The name of the campaign database file (minus extension).
|
||||
/// @param sQuery The SQL statement to execute.
|
||||
/// @returns Whether the query was successful.
|
||||
int SqlExecCampaign(string sDatabase, string sQuery);
|
||||
|
||||
/// @brief Creates a table in a PC's persistent database.
|
||||
/// @param oPC The PC that stores the database.
|
||||
/// @param sTable The name of the table.
|
||||
/// @param sStructure The SQL describing the structure of the table (i.e.,
|
||||
/// everything that would go between the parentheses).
|
||||
/// @param bForce Whether to drop an existing table.
|
||||
void SqlCreateTablePC(object oPC, string sTable, string sStructure, int bForce = FALSE);
|
||||
|
||||
/// @brief Creates a table in the module's volatile database.
|
||||
/// @param sTable The name of the table.
|
||||
/// @param sStructure The SQL describing the structure of the table (i.e.,
|
||||
/// everything that would go between the parentheses).
|
||||
/// @param bForce Whether to drop an existing table.
|
||||
void SqlCreateTableModule(string sTable, string sStructure, int bForce = FALSE);
|
||||
|
||||
/// @brief Creates a table in a persistent campaign database.
|
||||
/// @param sDatabase The name of the campaign database file (minus extension).
|
||||
/// @param sTable The name of the table.
|
||||
/// @param sStructure The SQL describing the structure of the table (i.e.,
|
||||
/// everything that would go between the parentheses).
|
||||
/// @param bForce Whether to drop an existing table.
|
||||
void SqlCreateTableCampaign(string sDatabase, string sTable, string sStructure, int bForce = FALSE);
|
||||
|
||||
/// @brief Checks if a table exists the PC's persistent database.
|
||||
/// @param oPC The PC that stores the database.
|
||||
/// @param sTable The name of the table to check for.
|
||||
/// @returns Whether the table exists.
|
||||
int SqlGetTableExistsPC(object oPC, string sTable);
|
||||
|
||||
/// @brief Checks if a table exists in the module's volatile database.
|
||||
/// @param sTable The name of the table to check for.
|
||||
/// @returns Whether the table exists.
|
||||
int SqlGetTableExistsModule(string sTable);
|
||||
|
||||
/// @brief Checks if a table exists in a peristent campaign database.
|
||||
/// @param sDatabase The name of the campaign database file (minus extension).
|
||||
/// @param sTable The name of the table to check for.
|
||||
/// @returns Whether the table exists.
|
||||
int SqlGetTableExistsCampaign(string sDatabase, string sTable);
|
||||
|
||||
/// @brief Gets the ID of the last row inserted into a PC's persistent database.
|
||||
/// @param oPC The PC that stores the database.
|
||||
/// @returns The ID of the last inserted row or -1 on error.
|
||||
int SqlGetLastInsertIdPC(object oPC);
|
||||
|
||||
/// @brief Gets the ID of the last row inserted into the module's volatile
|
||||
/// database.
|
||||
/// @returns The ID of the last inserted row or -1 on error.
|
||||
int SqlGetLastInsertIdModule();
|
||||
|
||||
/// @brief Gets the ID of the last row inserted into a persistent campaign
|
||||
/// database.
|
||||
/// @param sDatabase The name of the campaign database file (minus extension).
|
||||
/// @returns The ID of the last inserted row or -1 on error.
|
||||
int SqlGetLastInsertIdCampaign(string sDatabase);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
sqlquery SqlPrepareQueryModule(string sSQL)
|
||||
{
|
||||
return SqlPrepareQueryObject(GetModule(), sSQL);
|
||||
}
|
||||
|
||||
int SqlExecPC(object oPC, string sQuery)
|
||||
{
|
||||
return SqlStep(SqlPrepareQueryObject(oPC, sQuery));
|
||||
}
|
||||
|
||||
int SqlExecModule(string sQuery)
|
||||
{
|
||||
return SqlStep(SqlPrepareQueryModule(sQuery));
|
||||
}
|
||||
|
||||
int SqlExecCampaign(string sDatabase, string sQuery)
|
||||
{
|
||||
return SqlStep(SqlPrepareQueryCampaign(sDatabase, sQuery));
|
||||
}
|
||||
|
||||
void SqlCreateTablePC(object oPC, string sTable, string sStructure, int bForce = FALSE)
|
||||
{
|
||||
if (bForce)
|
||||
SqlExecPC(oPC, "DROP TABLE IF EXISTS " + sTable + ";");
|
||||
|
||||
SqlExecPC(oPC, "CREATE TABLE IF NOT EXISTS " + sTable + "(" + sStructure + ");");
|
||||
}
|
||||
|
||||
void SqlCreateTableModule(string sTable, string sStructure, int bForce = FALSE)
|
||||
{
|
||||
if (bForce)
|
||||
SqlExecModule("DROP TABLE IF EXISTS " + sTable + ";");
|
||||
|
||||
SqlExecModule("CREATE TABLE IF NOT EXISTS " + sTable + "(" + sStructure + ");");
|
||||
}
|
||||
|
||||
void SqlCreateTableCampaign(string sDatabase, string sTable, string sStructure, int bForce = FALSE)
|
||||
{
|
||||
if (bForce)
|
||||
SqlExecCampaign(sDatabase, "DROP TABLE IF EXISTS " + sTable + ";");
|
||||
|
||||
SqlExecCampaign(sDatabase, "CREATE TABLE IF NOT EXISTS " + sTable + "(" + sStructure + ");");
|
||||
}
|
||||
|
||||
int SqlGetTableExistsPC(object oPC, string sTable)
|
||||
{
|
||||
string sQuery = "SELECT name FROM sqlite_master WHERE type='table' AND name = @table;";
|
||||
sqlquery qQuery = SqlPrepareQueryObject(oPC, sQuery);
|
||||
SqlBindString(qQuery, "@table", sTable);
|
||||
return SqlStep(qQuery);
|
||||
}
|
||||
|
||||
int SqlGetTableExistsModule(string sTable)
|
||||
{
|
||||
string sQuery = "SELECT name FROM sqlite_master WHERE type='table' AND name = @table;";
|
||||
sqlquery qQuery = SqlPrepareQueryModule(sQuery);
|
||||
SqlBindString(qQuery, "@table", sTable);
|
||||
return SqlStep(qQuery);
|
||||
}
|
||||
|
||||
int SqlGetTableExistsCampaign(string sDatabase, string sTable)
|
||||
{
|
||||
string sQuery = "SELECT name FROM sqlite_master WHERE type='table' AND name = @table;";
|
||||
sqlquery qQuery = SqlPrepareQueryCampaign(sDatabase, sQuery);
|
||||
SqlBindString(qQuery, "@table", sTable);
|
||||
return SqlStep(qQuery);
|
||||
}
|
||||
|
||||
int SqlGetLastInsertIdPC(object oPC)
|
||||
{
|
||||
sqlquery qQuery = SqlPrepareQueryObject(oPC, "SELECT last_insert_rowid();");
|
||||
return SqlStep(qQuery) ? SqlGetInt(qQuery, 0) : -1;
|
||||
}
|
||||
|
||||
int SqlGetLastInsertIdModule()
|
||||
{
|
||||
sqlquery qQuery = SqlPrepareQueryModule("SELECT last_insert_rowid();");
|
||||
return SqlStep(qQuery) ? SqlGetInt(qQuery, 0) : -1;
|
||||
}
|
||||
|
||||
int SqlGetLastInsertIdCampaign(string sDatabase)
|
||||
{
|
||||
sqlquery qQuery = SqlPrepareQueryCampaign(sDatabase, "SELECT last_insert_rowid();");
|
||||
return SqlStep(qQuery) ? SqlGetInt(qQuery, 0) : -1;
|
||||
}
|
1060
_module/nss/util_i_strftime.nss
Normal file
1060
_module/nss/util_i_strftime.nss
Normal file
File diff suppressed because it is too large
Load Diff
422
_module/nss/util_i_strings.nss
Normal file
422
_module/nss/util_i_strings.nss
Normal file
@@ -0,0 +1,422 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_strings.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for manipulating strings.
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @details This file holds utility functions for manipulating strings.
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const string CHARSET_NUMERIC = "0123456789";
|
||||
const string CHARSET_ALPHA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
const string CHARSET_ALPHA_LOWER = "abcdefghijklmnopqrstuvwxyz";
|
||||
const string CHARSET_ALPHA_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Return the number of occurrences of a substring within a string.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSubString The substring to search for.
|
||||
int GetSubStringCount(string sString, string sSubString);
|
||||
|
||||
/// @brief Return the position of a given occurrence of a substring within a
|
||||
/// string.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSubString The substring to search for.
|
||||
/// @param nNth The occurrence to search for. Uses a zero-based index.
|
||||
/// @returns The position of the start of the nNth occurrence of the substring,
|
||||
/// or -1 if the substring did not occur at least nNth + 1 times.
|
||||
int FindSubStringN(string sString, string sSubString, int nNth = 0);
|
||||
|
||||
/// @brief Return the character at a position in a string.
|
||||
/// @param sString The string to search.
|
||||
/// @param nPos The position to check.
|
||||
/// @returns "" if sString is not nPos + 1 characters long.
|
||||
string GetChar(string sString, int nPos);
|
||||
|
||||
/// @brief Return the substring of a string bounded by a start and end position.
|
||||
/// @param sString The string to search.
|
||||
/// @param nStart The starting position of the substring to return.
|
||||
/// @param nEnd The ending position of the substring to return. If -1, will
|
||||
/// return to the end of the string.
|
||||
/// @returns "" if nStart is not at least nStart + 1 characters long or if nEnd
|
||||
/// is < nStart and not -1.
|
||||
/// @note Both nStart and nEnd are inclusive, so if nStart == nEnd, the
|
||||
/// character at that index will be returned.
|
||||
string GetStringSlice(string sString, int nStart, int nEnd = -1);
|
||||
|
||||
/// @brief Replace the substring bounded by a string slice with another string.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSub The substring to replace with.
|
||||
/// @param nStart The starting position in sString of the substring to replace.
|
||||
/// @param nEnd The ending position in sString of the substring to replace.
|
||||
string ReplaceSubString(string sString, string sSub, int nStart, int nEnd);
|
||||
|
||||
/// @brief Replace a substring in a string with another string.
|
||||
/// @param sString The string to search.
|
||||
/// @param sToken The substring to search for.
|
||||
/// @param sSub The substring to replace with.
|
||||
string SubstituteSubString(string sString, string sToken, string sSub);
|
||||
|
||||
/// @brief Replace all substrings in a string with another string.
|
||||
/// @param sString The string to search.
|
||||
/// @param sToken The substring to search for.
|
||||
/// @param sSub The substring to replace with.
|
||||
string SubstituteSubStrings(string sString, string sToken, string sSub);
|
||||
|
||||
/// @brief Return whether a string contains a substring.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSubString The substring to search for.
|
||||
/// @param nStart The position in sString to begin searching from (0-based).
|
||||
/// @returns TRUE if sSubString is in sString, FALSE otherwise.
|
||||
int HasSubString(string sString, string sSubString, int nStart = 0);
|
||||
|
||||
/// @brief Return whether any of a string's characters are in a character set.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSet The set of characters to search for.
|
||||
/// @returns TRUE if any characters are in the set; FALSE otherwise.
|
||||
int GetAnyCharsInSet(string sString, string sSet);
|
||||
|
||||
/// @brief Return whether all of a string's characters are in a character set.
|
||||
/// @param sString The string to search.
|
||||
/// @param sSet The set of characters to search for.
|
||||
/// @returns TRUE if all characters are in the set; FALSE otherwise.
|
||||
int GetAllCharsInSet(string sString, string sSet);
|
||||
|
||||
/// @brief Return whether all letters in a string are upper-case.
|
||||
/// @param sString The string to check.
|
||||
int GetIsUpperCase(string sString);
|
||||
|
||||
/// @brief Return whether all letters in a string are lower-case.
|
||||
/// @param sString The string to check.
|
||||
int GetIsLowerCase(string sString);
|
||||
|
||||
/// @brief Return whether all characters in sString are letters.
|
||||
/// @param sString The string to check.
|
||||
int GetIsAlpha(string sString);
|
||||
|
||||
/// @brief Return whether all characters in sString are digits.
|
||||
/// @param sString The string to check.
|
||||
int GetIsNumeric(string sString);
|
||||
|
||||
/// @brief Return whether all characters in sString are letters or digits.
|
||||
/// @param sString The string to check.
|
||||
int GetIsAlphaNumeric(string sString);
|
||||
|
||||
/// @brief Trim characters from the left side of a string.
|
||||
/// @param sString The string to trim.
|
||||
/// @param sRemove The set of characters to remove.
|
||||
string TrimStringLeft(string sString, string sRemove = " ");
|
||||
|
||||
/// @brief Trim characters from the right side of a string.
|
||||
/// @param sString The string to trim.
|
||||
/// @param sRemove The set of characters to remove.
|
||||
string TrimStringRight(string sString, string sRemove = " ");
|
||||
|
||||
/// @brief Trim characters from both sides of a string.
|
||||
/// @param sString The string to trim.
|
||||
/// @param sRemove The set of characters to remove.
|
||||
string TrimString(string sString, string sRemove = " ");
|
||||
|
||||
/// @brief Interpolate values from a json array into a string using sqlite's
|
||||
/// printf().
|
||||
/// @param jArray A json array containing float, int, or string elements to
|
||||
/// interpolate. The number of elements must match the number of format
|
||||
/// specifiers in sFormat.
|
||||
/// @param sFormat The string to interpolate the values into. Must contain
|
||||
/// format specifiers that correspond to the elements in jArray. For details
|
||||
/// on format specifiers, see https://sqlite.org/printf.html.
|
||||
/// @example
|
||||
/// FormatValues(JsonParse("[\"Blue\", 255]"), "%s: #%06X"); // "Blue: #0000FF"
|
||||
string FormatValues(json jArray, string sFormat);
|
||||
|
||||
/// @brief Interpolate a float into a string using sqlite's printf().
|
||||
/// @param f A float to interpolate. Will be passed as an argument to the query
|
||||
/// as many times as necessary to cover all format specifiers.
|
||||
/// @param sFormat The string to interpolate the value into. For details on
|
||||
/// format specifiers, see https://sqlite.org/printf.html.
|
||||
/// @example
|
||||
/// FormatFloat(15.0, "%d"); // "15"
|
||||
/// FormatFloat(15.0, "%.2f"); // "15.00"
|
||||
/// FormatFloat(15.0, "%05.1f"); // "015.0"
|
||||
string FormatFloat(float f, string sFormat);
|
||||
|
||||
/// @brief Interpolate an int into a string using sqlite's printf().
|
||||
/// @param n An int to interpolate. Will be passed as an argument to the query
|
||||
/// as many times as necessary to cover all format specifiers.
|
||||
/// @param sFormat The string to interpolate the value into. For details on
|
||||
/// format specifiers, see https://sqlite.org/printf.html.
|
||||
/// @example
|
||||
/// FormatInt(15, "%d"); // "15"
|
||||
/// FormatInt(15, "%04d"); // "0015"
|
||||
/// FormatInt(15, "In hexadecimal, %d is %#x"); // "In hexadecimal, 15 is 0xf"
|
||||
/// FormatInt(1000, "%,d"); // "1,000"
|
||||
string FormatInt(int n, string sFormat);
|
||||
|
||||
/// @brief Interpolate a string into another string using sqlite's printf().
|
||||
/// @param s A string to interpolate. Will be passed as an argument to the query
|
||||
/// as many times as necessary to cover all format specifiers.
|
||||
/// @param sFormat The string to interpolate the value into. For details on
|
||||
/// format specifiers, see https://sqlite.org/printf.html.
|
||||
/// @example
|
||||
/// FormatString("foo", "%sbar"); // "foobar"
|
||||
/// FormatString("foo", "%5sbar"); // " foobar"
|
||||
/// FormatString("foo", "%-5sbar"); // "foo bar"
|
||||
string FormatString(string s, string sFormat);
|
||||
|
||||
/// @brief Substitute tokens in a string with values from a json array.
|
||||
/// @param s The string to interpolate the values into. Should have tokens wich
|
||||
/// contain sDesignator followed by a number denoting the position of the
|
||||
/// value in jArray (1-based index).
|
||||
/// @param jArray An array of values to interpolate. May be any combination of
|
||||
/// strings, floats, decimals, or booleans.
|
||||
/// @param sDesignator The character denoting the beginning of a token.
|
||||
/// @example
|
||||
/// // Assumes jArray = ["Today", 34, 2.5299999999, true];
|
||||
/// SubstituteString("$1, I ran $2 miles.", jArray); // "Today, I ran 34 miles."
|
||||
/// SubstituteString("The circle's radius is $3.", jArray); // "The circle's radius is 2.53."
|
||||
/// SubstituteString("The applicant answered: $4", jArray); // "The applicant answered: true"
|
||||
string SubstituteString(string s, json jArray, string sDesignator = "$");
|
||||
|
||||
/// @brief Repeats a string multiple times.
|
||||
/// @param s The string to repeat.
|
||||
/// @param n The number of times to repeat s.
|
||||
/// @returns The repeated string.
|
||||
string RepeatString(string s, int n);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int GetSubStringCount(string sString, string sSubString)
|
||||
{
|
||||
if (sString == "" || sSubString == "")
|
||||
return 0;
|
||||
|
||||
int nLength = GetStringLength(sSubString);
|
||||
int nCount, nPos = FindSubString(sString, sSubString);
|
||||
|
||||
while (nPos != -1)
|
||||
{
|
||||
nCount++;
|
||||
nPos = FindSubString(sString, sSubString, nPos + nLength);
|
||||
}
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
int FindSubStringN(string sString, string sSubString, int nNth = 0)
|
||||
{
|
||||
if (nNth < 0 || sString == "" || sSubString == "")
|
||||
return -1;
|
||||
|
||||
int nLength = GetStringLength(sSubString);
|
||||
int nPos = FindSubString(sString, sSubString);
|
||||
|
||||
while (--nNth >= 0 && nPos != -1)
|
||||
nPos = FindSubString(sString, sSubString, nPos + nLength);
|
||||
|
||||
return nPos;
|
||||
}
|
||||
|
||||
string GetChar(string sString, int nPos)
|
||||
{
|
||||
return GetSubString(sString, nPos, 1);
|
||||
}
|
||||
|
||||
string GetStringSlice(string sString, int nStart, int nEnd = -1)
|
||||
{
|
||||
int nLength = GetStringLength(sString);
|
||||
if (nEnd < 0 || nEnd > nLength)
|
||||
nEnd = nLength;
|
||||
|
||||
if (nStart < 0 || nStart > nEnd)
|
||||
return "";
|
||||
|
||||
return GetSubString(sString, nStart, nEnd - nStart + 1);
|
||||
}
|
||||
|
||||
string ReplaceSubString(string sString, string sSub, int nStart, int nEnd)
|
||||
{
|
||||
int nLength = GetStringLength(sString);
|
||||
if (nStart < 0 || nStart >= nLength || nStart > nEnd)
|
||||
return sString;
|
||||
|
||||
return GetSubString(sString, 0, nStart) + sSub +
|
||||
GetSubString(sString, nEnd + 1, nLength - nEnd);
|
||||
}
|
||||
|
||||
string SubstituteSubString(string sString, string sToken, string sSub)
|
||||
{
|
||||
int nPos;
|
||||
if ((nPos = FindSubString(sString, sToken)) == -1)
|
||||
return sString;
|
||||
|
||||
return ReplaceSubString(sString, sSub, nPos, nPos + GetStringLength(sToken) - 1);
|
||||
}
|
||||
|
||||
string SubstituteSubStrings(string sString, string sToken, string sSub)
|
||||
{
|
||||
while (FindSubString(sString, sToken) >= 0)
|
||||
sString = SubstituteSubString(sString, sToken, sSub);
|
||||
|
||||
return sString;
|
||||
}
|
||||
|
||||
int HasSubString(string sString, string sSubString, int nStart = 0)
|
||||
{
|
||||
return FindSubString(sString, sSubString, nStart) >= 0;
|
||||
}
|
||||
|
||||
int GetAnyCharsInSet(string sString, string sSet)
|
||||
{
|
||||
int i, nLength = GetStringLength(sString);
|
||||
for (i = 0; i < nLength; i++)
|
||||
{
|
||||
if (HasSubString(sSet, GetChar(sString, i)))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int GetAllCharsInSet(string sString, string sSet)
|
||||
{
|
||||
int i, nLength = GetStringLength(sString);
|
||||
for (i = 0; i < nLength; i++)
|
||||
{
|
||||
if (!HasSubString(sSet, GetChar(sString, i)))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int GetIsUpperCase(string sString)
|
||||
{
|
||||
return GetAllCharsInSet(sString, CHARSET_ALPHA_UPPER + CHARSET_NUMERIC);
|
||||
}
|
||||
|
||||
int GetIsLowerCase(string sString)
|
||||
{
|
||||
return GetAllCharsInSet(sString, CHARSET_ALPHA_LOWER + CHARSET_NUMERIC);
|
||||
}
|
||||
|
||||
int GetIsAlpha(string sString)
|
||||
{
|
||||
return GetAllCharsInSet(sString, CHARSET_ALPHA);
|
||||
}
|
||||
|
||||
int GetIsNumeric(string sString)
|
||||
{
|
||||
return GetAllCharsInSet(sString, CHARSET_NUMERIC);
|
||||
}
|
||||
|
||||
int GetIsAlphaNumeric(string sString)
|
||||
{
|
||||
return GetAllCharsInSet(sString, CHARSET_ALPHA + CHARSET_NUMERIC);
|
||||
}
|
||||
|
||||
string TrimStringLeft(string sString, string sRemove = " ")
|
||||
{
|
||||
return RegExpReplace("^(?:" + sRemove + ")*", sString, "");
|
||||
}
|
||||
|
||||
string TrimStringRight(string sString, string sRemove = " ")
|
||||
{
|
||||
return RegExpReplace("(:?" + sRemove + ")*$", sString, "");
|
||||
}
|
||||
|
||||
string TrimString(string sString, string sRemove = " ")
|
||||
{
|
||||
return RegExpReplace("^(:?" + sRemove + ")*|(?:" + sRemove + ")*$", sString, "");
|
||||
}
|
||||
|
||||
string FormatValues(json jArray, string sFormat)
|
||||
{
|
||||
if (JsonGetType(jArray) != JSON_TYPE_ARRAY)
|
||||
return "";
|
||||
|
||||
string sArgs;
|
||||
int i, nLength = JsonGetLength(jArray);
|
||||
for (i = 0; i < nLength; i++)
|
||||
sArgs += ", @" + IntToString(i);
|
||||
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(), "SELECT printf(@format" + sArgs + ");");
|
||||
SqlBindString(q, "@format", sFormat);
|
||||
for (i = 0; i < nLength; i++)
|
||||
{
|
||||
string sParam = "@" + IntToString(i);
|
||||
json jValue = JsonArrayGet(jArray, i);
|
||||
switch (JsonGetType(jValue))
|
||||
{
|
||||
case JSON_TYPE_FLOAT: SqlBindFloat (q, sParam, JsonGetFloat (jValue)); break;
|
||||
case JSON_TYPE_INTEGER: SqlBindInt (q, sParam, JsonGetInt (jValue)); break;
|
||||
case JSON_TYPE_STRING: SqlBindString(q, sParam, JsonGetString(jValue)); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return SqlStep(q) ? SqlGetString(q, 0) : "";
|
||||
}
|
||||
|
||||
string FormatFloat(float f, string sFormat)
|
||||
{
|
||||
json jArray = JsonArray();
|
||||
int i, nCount = GetSubStringCount(sFormat, "%");
|
||||
for (i = 0; i < nCount; i++)
|
||||
JsonArrayInsertInplace(jArray, JsonFloat(f));
|
||||
return FormatValues(jArray, sFormat);
|
||||
}
|
||||
|
||||
string FormatInt(int n, string sFormat)
|
||||
{
|
||||
json jArray = JsonArray();
|
||||
int i, nCount = GetSubStringCount(sFormat, "%");
|
||||
for (i = 0; i < nCount; i++)
|
||||
JsonArrayInsertInplace(jArray, JsonInt(n));
|
||||
return FormatValues(jArray, sFormat);
|
||||
}
|
||||
|
||||
string FormatString(string s, string sFormat)
|
||||
{
|
||||
json jArray = JsonArray();
|
||||
int i, nCount = GetSubStringCount(sFormat, "%");
|
||||
for (i = 0; i < nCount; i++)
|
||||
JsonArrayInsertInplace(jArray, JsonString(s));
|
||||
return FormatValues(jArray, sFormat);
|
||||
}
|
||||
|
||||
string SubstituteString(string s, json jArray, string sDesignator = "$")
|
||||
{
|
||||
if (JsonGetType(jArray) != JSON_TYPE_ARRAY)
|
||||
return s;
|
||||
|
||||
int n; for (n = JsonGetLength(jArray) - 1; n >= 0; n--)
|
||||
{
|
||||
string sValue;
|
||||
json jValue = JsonArrayGet(jArray, n);
|
||||
int nType = JsonGetType(jValue);
|
||||
if (nType == JSON_TYPE_STRING) sValue = JsonGetString(jValue);
|
||||
else if (nType == JSON_TYPE_INTEGER) sValue = IntToString(JsonGetInt(jValue));
|
||||
else if (nType == JSON_TYPE_FLOAT) sValue = FormatFloat(JsonGetFloat(jValue), "%!f");
|
||||
else if (nType == JSON_TYPE_BOOL) sValue = JsonGetInt(jValue) == 1 ? "true" : "false";
|
||||
else continue;
|
||||
|
||||
s = SubstituteSubStrings(s, sDesignator + IntToString(n + 1), sValue);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
string RepeatString(string s, int n)
|
||||
{
|
||||
string sResult;
|
||||
while (n-- > 0)
|
||||
sResult += s;
|
||||
|
||||
return sResult;
|
||||
}
|
908
_module/nss/util_i_targeting.nss
Normal file
908
_module/nss/util_i_targeting.nss
Normal file
@@ -0,0 +1,908 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_targeting.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for managing forced targeting.
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @details
|
||||
/*
|
||||
This system is designed to take advantage of NWN:EE's ability to forcibly enter
|
||||
Targeting Mode for any given PC. It is designed to add a single-use, multi-use,
|
||||
or unlimited-use hook to the specified PC. Once the PC has satisfied the
|
||||
conditions of the hook, or manually exited targeting mode, the targeted
|
||||
objects/locations will be saved and a specified script will be run.
|
||||
|
||||
## Setup
|
||||
|
||||
1. You must attach a targeting event script to the module. For example, in your
|
||||
module load script, you can add this line:
|
||||
|
||||
SetEventScript(GetModule(), EVENT_SCRIPT_MODULE_ON_PLAYER_TARGET, "module_opt");
|
||||
|
||||
where "module_opt" is the script that will handle all forced targeting.
|
||||
|
||||
2. The chosen script ("module_opt") must contain reference to the
|
||||
util_i_targeting function SatisfyTargetingHook(). An example of this follows.
|
||||
|
||||
```nwscript
|
||||
#include "util_i_targeting"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetLastPlayerToSelectTarget();
|
||||
|
||||
if (SatisfyTargetingHook(oPC))
|
||||
{
|
||||
// This PC was marked as a targeter, do something here.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternately, if you want the assigned targeting hook scripts to handle
|
||||
everything, you can just let the system know a targeting event happened:
|
||||
|
||||
```nwscript
|
||||
void main()
|
||||
{
|
||||
object oPC = GetLastPlayerToSelectTarget();
|
||||
SatisfyTargetingHook(oPC);
|
||||
}
|
||||
```
|
||||
|
||||
If oPC didn't have a targeting hook specified, nothing happens.
|
||||
|
||||
## Usage
|
||||
|
||||
The design of this system centers around a module-wide list of "Targeting Hooks"
|
||||
that are accessed by util_i_targeting when a player targets any object or
|
||||
manually exits targeting mode. These hooks are stored in the module's organic
|
||||
sqlite database. All targeting hook information is volatile and will be reset
|
||||
when the server/module is reset.
|
||||
|
||||
This is the prototype for the `AddTargetingHook()` function:
|
||||
|
||||
```nwscript
|
||||
int AddTargetingHook(object oPC, string sVarName, int nObjectType = OBJECT_TYPE_ALL, string sScript = "", int nUses = 1);
|
||||
```
|
||||
|
||||
- `oPC` is the PC object that will be associated with this hook. This PC will be
|
||||
the player that will be entered into Targeting Mode. Additionally, the results
|
||||
of his targeting will be saved to the PC object.
|
||||
- `sVarName` is the variable name to save the results of targeting to. This
|
||||
allows for targeting hooks to be added that can be saved to different
|
||||
variables for several purposes.
|
||||
- `nObjectType` is the limiting variable for the types of objects the PC can
|
||||
target when they are in targeting mode forced by this hook. It is an optional
|
||||
parameter and can be bitmasked with any visible `OBJECT_TYPE_*` constant.
|
||||
- `sScript` is the resref of the script that will run once the targeting
|
||||
conditions have been satisfied. For example, if you create a multi-use
|
||||
targeting hook, this script will run after all uses have been exhausted. This
|
||||
script will also run if the player manually exits targeting mode without
|
||||
selecting a target. Optional. A script-run is not always desirable. The
|
||||
targeted object may be required for later use, so a script entry is not a
|
||||
requirement.
|
||||
- `nUses` is the number of times this target hook can be used before it is
|
||||
deleted. This is designed to allow multiple targets to be selected and saved
|
||||
to the same variable name sVarName. Multi-selection could be useful for DMs in
|
||||
defining DM Experience members, even from different parties, or selecting
|
||||
multiple NPCs to accomplish a specific action. Optional, defaulted to 1.
|
||||
|
||||
Note: Targeting mode uses specified by `nUses` will be decremented every time
|
||||
a player selects a target. Uses will also be decremented when a user manually
|
||||
exits targeting mode. Manually exiting targeting mode will delete the
|
||||
targeting hook, but any selected targets before exiting targeting mode will be
|
||||
saved to the specified variable.
|
||||
|
||||
To add a single-use targeting hook that enters the PC into targeting mode, allows
|
||||
for the selection of a single placeable | creature, then runs the script
|
||||
"temp_target" upon exiting target mode or selecting a single target:
|
||||
|
||||
```nwscript
|
||||
int nObjectType = OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_CREATURE;
|
||||
AddTargetingHook(oPC, "spell_target", nObjectType, "temp_target");
|
||||
```
|
||||
|
||||
To add a multi-use targeting hook that enters the PC into targeting mode, allows
|
||||
for the selection of a specified number of placeables | creatures, then runs the
|
||||
script "DM_Party" upon exiting targeting mode or selecting the specified number
|
||||
of targets:
|
||||
|
||||
```nwscript
|
||||
int nObjectType = OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_CREATURE;
|
||||
AddTargetingHook(oPC, "DM_Party", nObjectType, "DM_Party", 3);
|
||||
```
|
||||
|
||||
> Note: In this case, the player can select up to three targets to save to the
|
||||
"DM_Party" variable.
|
||||
|
||||
To add an unlmited-use targeting hook that enters the PC into targeting mode,
|
||||
allows for the selection of an unspecified number of creatures, then runs the
|
||||
script "temp_target" upon exiting targeting mode or selection of an invalid
|
||||
target:
|
||||
|
||||
```nwscript
|
||||
int nObjectType = OBJECT_TYPE_CREATURE;
|
||||
AddTargetingHook(oPC, "NPC_Townspeople", nObjectType, "temp_target", -1);
|
||||
```
|
||||
|
||||
Here is an example "temp_target" post-targeting script that will access each of
|
||||
the targets saved to the specified variable and send their data to the chat log:
|
||||
|
||||
```nwscript
|
||||
#include "util_i_targeting"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
int n, nCount = CountTargetingHookTargets(oPC, "NPC_Townspeople");
|
||||
|
||||
for (n = 0; n < nCount; n++)
|
||||
{
|
||||
object oTarget = GetTargetingHookObject(oPC, "NPC_Townspeople", n);
|
||||
location lTarget = GetTargetingHookLocation(oPC, "NPC_Townspeople", n);
|
||||
vector vTarget = GetTargetingHookPosition(oPC, "NPC_Townspeople", n);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: Target objects and positions saved to the variables are persistent while
|
||||
the server is running, but are not persistent (though they can be made so). If
|
||||
you wish to overwrite a set of target data with a variable you've already used,
|
||||
ensure you first delete the current target data with the function
|
||||
`DeleteTargetingHookTargets();`.
|
||||
*/
|
||||
|
||||
#include "util_c_targeting"
|
||||
#include "util_i_debug"
|
||||
#include "util_i_varlists"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// VarList names for the global targeting hook lists
|
||||
const string TARGET_HOOK_ID = "TARGET_HOOK_ID";
|
||||
const string TARGET_HOOK_BEHAVIOR = "TARGET_HOOK_BEHAVIOR";
|
||||
|
||||
// List Behaviors
|
||||
const int TARGET_BEHAVIOR_ADD = 1;
|
||||
const int TARGET_BEHAVIOR_DELETE = 2;
|
||||
|
||||
// Targeting Hook Data Structure
|
||||
struct TargetingHook
|
||||
{
|
||||
int nHookID;
|
||||
int nObjectType;
|
||||
int nUses;
|
||||
object oPC;
|
||||
string sVarName;
|
||||
string sScript;
|
||||
int nValidCursor;
|
||||
int nInvalidCursor;
|
||||
};
|
||||
|
||||
struct TargetingHook TARGETING_HOOK_INVALID;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Creates targeting hook data tables in the module's sqlite database.
|
||||
/// @param bReset If TRUE, attempts to drop the tables before creation.
|
||||
void CreateTargetingDataTables(int bReset = FALSE);
|
||||
|
||||
/// @brief Retrieve targeting hook data.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @returns A TargetingHook containing all targeting hook data associated with
|
||||
/// nHookID.
|
||||
struct TargetingHook GetTargetingHookDataByHookID(int nHookID);
|
||||
|
||||
/// @brief Retrieve targeting hook data.
|
||||
/// @param oPC The PC object associated with the targeting hook.
|
||||
/// @param sVarName The varname associated with the targeting hook.
|
||||
/// @returns A TargetingHook containing all targeting hook data associated with
|
||||
/// nHookID.
|
||||
struct TargetingHook GetTargetingHookDataByVarName(object oPC, string sVarName);
|
||||
|
||||
/// @brief Retrieve a list of targets.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The index of the target to retrieve from the list. If omitted,
|
||||
/// the entire target list will be returned.
|
||||
/// @returns A prepared sqlquery containing the target list associated with
|
||||
/// oPC's sVarName.
|
||||
sqlquery GetTargetList(object oPC, string sVarName, int nIndex = -1);
|
||||
|
||||
/// @brief Add a target to a target list.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param oTarget The target object to be added to the target list.
|
||||
/// @param oArea The area object where oTarget is located.
|
||||
/// @param vTarget The position of oTarget within oArea.
|
||||
/// @returns The number of targets on oPC's target list sVarName after insertion.
|
||||
int AddTargetToTargetList(object oPC, string sVarName, object oTarget, object oArea, vector vTarget);
|
||||
|
||||
/// @brief Delete oPC's sVarName target list.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
void DeleteTargetList(object oPC, string sVarName);
|
||||
|
||||
/// @brief Delete a targeting hook and all associated targeting hook data.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
void DeleteTargetingHook(int nHookID);
|
||||
|
||||
/// @brief Force the PC object associated with targeting hook nHookID to enter
|
||||
/// targeting mode using properties set by AddTargetingHook().
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @param nBehavior The behavior desired from the targeting session. Must be
|
||||
/// a TARGET_BEHAVIOR_* constant.
|
||||
void EnterTargetingModeByHookID(int nHookID, int nBehavior = TARGET_BEHAVIOR_ADD);
|
||||
|
||||
/// @brief Force the PC object associated with targeting hook nHookID to enter
|
||||
/// targeting mode using properties set by AddTargetingHook().
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nBehavior The behavior desired from the targeting session. Must be
|
||||
/// a TARGET_BEHAVIOR_* constant.
|
||||
void EnterTargetingModeByVarName(object oPC, string sVarName, int nBehavior = TARGET_BEHAVIOR_ADD);
|
||||
|
||||
/// @brief Retrieve a targeting hook id.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @returns The targeting hook id assocaited with oPC's sVarName target list.
|
||||
int GetTargetingHookID(object oPC, string sVarName);
|
||||
|
||||
/// @brief Retrieve a targeting hook's sVarName.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @returns The target list name sVarName associated with nHookID.
|
||||
string GetTargetingHookVarName(int nHookID);
|
||||
|
||||
/// @brief Retrieve a targeting hook's allowed object types.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @returns A bitmap containing the allowed target types associated with
|
||||
/// nHookID.
|
||||
int GetTargetingHookObjectType(int nHookID);
|
||||
|
||||
/// @brief Retrieve a targeting hook's remaining uses.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @returns The number of uses remaining for targeting hook nHookID.
|
||||
int GetTargetingHookUses(int nHookID);
|
||||
|
||||
/// @brief Retrieve a targeting hook's script.
|
||||
/// @param nHookID The targeting hook's ID.
|
||||
/// @returns The script associated with targeting hook nHookID.
|
||||
string GetTargetingHookScript(int nHookID);
|
||||
|
||||
/// @brief Add a targeting hook to the global targeting hook list and save
|
||||
/// targeting hook parameters for later use.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nObjectType A bitmasked value containing all object types allowed
|
||||
/// to be targeted by this hook.
|
||||
/// @param sScript The script that will be run when this target hook is
|
||||
/// satisfied.
|
||||
/// @param nUses The number of times this targeting hook is allowed to be used
|
||||
/// before it is automatically deleted. Omitting this value will yield a
|
||||
/// single use hook. Use -1 for an infinite-use hook.
|
||||
/// @param nValidCursor A MOUSECURSOR_* cursor indicating a valid target.
|
||||
/// @param nInvalidCursor A MOUSECURSOR_* cursor indicating an invalid target.
|
||||
/// @returns A unique ID associated with the new targeting hook.
|
||||
int AddTargetingHook(object oPC, string sVarName, int nObjectType = OBJECT_TYPE_ALL, string sScript = "",
|
||||
int nUses = 1, int nValidCursor = MOUSECURSOR_MAGIC, int nInvalidCursor = MOUSECURSOR_NOMAGIC);
|
||||
|
||||
/// @brief Save target data to the PC object as an object and location variable
|
||||
/// defined by sVarName in AddTargetingHook(). Decrements remaining targeting
|
||||
/// hook uses and, if required, deletes the targeting hook.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @returns TRUE if OpC has a current targeting hook, FALSE otherwise.
|
||||
int SatisfyTargetingHook(object oPC);
|
||||
|
||||
/// @brief Retrieve a targeting list's object at index nIndex.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The index at which to retrieve the target object.
|
||||
/// @returns The targeting's lists target at index nIndex, or the first
|
||||
/// target on the list if nIndex is omitted.
|
||||
object GetTargetingHookObject(object oPC, string sVarName, int nIndex = 1);
|
||||
|
||||
/// @brief Retrieve a targeting list's location at index nIndex.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The index at which to retrieve the target location.
|
||||
/// @returns The targeting's lists location at index nIndex, or the first
|
||||
/// location on the list if nIndex is omitted.
|
||||
location GetTargetingHookLocation(object oPC, string sVarName, int nIndex = 1);
|
||||
|
||||
/// @brief Retrieve a targeting list's position at index nIndex.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The index at which to retrieve the target position.
|
||||
/// @returns The targeting's lists position at index nIndex, or the first
|
||||
/// position on the list if nIndex is omitted.
|
||||
vector GetTargetingHookPosition(object oPC, string sVarName, int nIndex = 1);
|
||||
|
||||
/// @brief Determine how many targets are on a target list.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @returns The number of targets associated with the saved as sVarName
|
||||
/// on oPC.
|
||||
// ---< CountTargetingHookTargets >---
|
||||
int CountTargetingHookTargets(object oPC, string sVarName);
|
||||
|
||||
/// @brief Delete a targeting hook target.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The index at which to delete the target data. If omitted,
|
||||
/// the first target on the list will be deleted.
|
||||
/// @returns The number of targets remaining on oPC's sVarName target list
|
||||
/// after deletion.
|
||||
int DeleteTargetingHookTarget(object oPC, string sVarName, int nIndex = 1);
|
||||
|
||||
/// @brief Retrieve the target list object's internal index.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param oObject The object to find on oPC's sVarName target list.
|
||||
int GetTargetingHookIndex(object oPC, string sVarName, object oTarget);
|
||||
|
||||
/// @brief Delete target list target data by internal index.
|
||||
/// @param oPC The PC object associated with the target list.
|
||||
/// @param sVarName The VarName associated with the target list.
|
||||
/// @param nIndex The internal index of the target data to be deleted. This
|
||||
/// index can be retrieved from GetTargetingHookIndex().
|
||||
/// @returns The number of targets remaining on oPC's sVarName target list
|
||||
/// after deletion.
|
||||
int DeleteTargetingHookTargetByIndex(object oPC, string sVarName, int nIndex);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Private Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
sqlquery _PrepareTargetingQuery(string s)
|
||||
{
|
||||
return SqlPrepareQueryObject(GetModule(), s);
|
||||
}
|
||||
|
||||
string _GetTargetingHookFieldData(int nHookID, string sField)
|
||||
{
|
||||
string s = "SELECT " + sField + " " +
|
||||
"FROM targeting_hooks " +
|
||||
"WHERE nHookID = @nHookID;";
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindInt(q, "@nHookID", nHookID);
|
||||
|
||||
return SqlStep(q) ? SqlGetString(q, 0) : "";
|
||||
}
|
||||
|
||||
int _GetLastTargetingHookID()
|
||||
{
|
||||
string s = "SELECT seq FROM sqlite_sequence WHERE name = @name;";
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@name", "targeting_hooks");
|
||||
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : 0;
|
||||
}
|
||||
|
||||
string _GetTargetData(object oPC, string sVarName, string sField, int nIndex = 1)
|
||||
{
|
||||
string s = "SELECT " + sField + " " +
|
||||
"FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName " +
|
||||
"LIMIT 1 OFFSET " + IntToString(nIndex) + ";";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
|
||||
return SqlStep(q) ? SqlGetString(q, 0) : "";
|
||||
}
|
||||
|
||||
void _EnterTargetingMode(struct TargetingHook th, int nBehavior)
|
||||
{
|
||||
SetLocalInt(th.oPC, TARGET_HOOK_ID, th.nHookID);
|
||||
SetLocalInt(th.oPC, TARGET_HOOK_BEHAVIOR, nBehavior);
|
||||
EnterTargetingMode(th.oPC, th.nObjectType, th.nValidCursor, th.nInvalidCursor);
|
||||
}
|
||||
|
||||
void _DeleteTargetingHookData(int nHookID)
|
||||
{
|
||||
string s = "DELETE FROM targeting_hooks " +
|
||||
"WHERE nHookID = @nHookID;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindInt(q, "@nHookID", nHookID);
|
||||
SqlStep(q);
|
||||
}
|
||||
|
||||
void _ExitTargetingMode(int nHookID)
|
||||
{
|
||||
struct TargetingHook th = GetTargetingHookDataByHookID(nHookID);
|
||||
if (th.sScript != "")
|
||||
{
|
||||
Debug("Running post-targeting script " + th.sScript + " from Targeting Hook ID " +
|
||||
IntToString(nHookID) + " on " + GetName(th.oPC) + " with varname " + th.sVarName);
|
||||
RunTargetingHookScript(th.sScript, th.oPC);
|
||||
}
|
||||
else
|
||||
Debug("No post-targeting script specified for Targeting Hook ID " + IntToString(nHookID) + " " +
|
||||
"on " + GetName(th.oPC) + " with varname " + th.sVarName);
|
||||
|
||||
DeleteTargetingHook(nHookID);
|
||||
DeleteLocalInt(th.oPC, TARGET_HOOK_ID);
|
||||
DeleteLocalInt(th.oPC, TARGET_HOOK_BEHAVIOR);
|
||||
}
|
||||
|
||||
// Reduces the number of targeting hooks remaining. When the remaining number is
|
||||
// 0, the hook is automatically deleted.
|
||||
int _DecrementTargetingHookUses(struct TargetingHook th, int nBehavior)
|
||||
{
|
||||
int nUses = GetTargetingHookUses(th.nHookID);
|
||||
|
||||
if (--nUses == 0)
|
||||
{
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
Debug("Decrementing target hook uses for ID " + HexColorString(IntToString(th.nHookID), COLOR_CYAN) +
|
||||
"\n Uses remaining -> " + (nUses ? HexColorString(IntToString(nUses), COLOR_CYAN) : HexColorString(IntToString(nUses), COLOR_RED_LIGHT)) + "\n");
|
||||
|
||||
_ExitTargetingMode(th.nHookID);
|
||||
}
|
||||
else
|
||||
{
|
||||
string s = "UPDATE targeting_hooks " +
|
||||
"SET nUses = nUses - 1 " +
|
||||
"WHERE nHookID = @nHookID;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindInt(q, "@nHookID", th.nHookID);
|
||||
SqlStep(q);
|
||||
|
||||
_EnterTargetingMode(th, nBehavior);
|
||||
}
|
||||
|
||||
return nUses;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Function Definitions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Temporary function for feedback purposes only
|
||||
string ObjectTypeToString(int nObjectType)
|
||||
{
|
||||
string sResult;
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_CREATURE)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Creatures";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_ITEM)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Items";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_TRIGGER)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Triggers";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_DOOR)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Doors";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_AREA_OF_EFFECT)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Areas of Effect";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_WAYPOINT)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Waypoints";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_PLACEABLE)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Placeables";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_STORE)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Stores";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_ENCOUNTER)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Encounters";
|
||||
|
||||
if (nObjectType & OBJECT_TYPE_TILE)
|
||||
sResult += (sResult == "" ? "" : ", ") + "Tiles";
|
||||
|
||||
return sResult;
|
||||
}
|
||||
|
||||
void CreateTargetingDataTables(int bReset = FALSE)
|
||||
{
|
||||
object oModule = GetModule();
|
||||
|
||||
if (bReset)
|
||||
{
|
||||
string sDropHooks = "DROP TABLE IF EXISTS targeting_hooks;";
|
||||
string sDropTargets = "DROP TABLE IF EXISTS targeting_targets;";
|
||||
|
||||
sqlquery q;
|
||||
q = _PrepareTargetingQuery(sDropHooks); SqlStep(q);
|
||||
q = _PrepareTargetingQuery(sDropTargets); SqlStep(q);
|
||||
|
||||
DeleteLocalInt(oModule, "TARGETING_INITIALIZED");
|
||||
Warning(HexColorString("Targeting database tables have been dropped", COLOR_RED_LIGHT));
|
||||
}
|
||||
|
||||
if (GetLocalInt(oModule, "TARGETING_INITIALIZED"))
|
||||
return;
|
||||
|
||||
string sData = "CREATE TABLE IF NOT EXISTS targeting_hooks (" +
|
||||
"nHookID INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"sUUID TEXT, " +
|
||||
"sVarName TEXT, " +
|
||||
"nObjectType INTEGER, " +
|
||||
"nUses INTEGER default '1', " +
|
||||
"sScript TEXT, " +
|
||||
"nValidCursor INTEGER, " +
|
||||
"nInvalidCursor INTEGER, " +
|
||||
"UNIQUE (sUUID, sVarName));";
|
||||
|
||||
string sTargets = "CREATE TABLE IF NOT EXISTS targeting_targets (" +
|
||||
"nTargetID INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"sUUID TEXT, " +
|
||||
"sVarName TEXT, " +
|
||||
"sTargetObject TEXT, " +
|
||||
"sTargetArea TEXT, " +
|
||||
"vTargetLocation TEXT);";
|
||||
|
||||
sqlquery q;
|
||||
q = _PrepareTargetingQuery(sData); SqlStep(q);
|
||||
q = _PrepareTargetingQuery(sTargets); SqlStep(q);
|
||||
|
||||
Debug(HexColorString("Targeting database tables have been created", COLOR_GREEN_LIGHT));
|
||||
SetLocalInt(oModule, "TARGETING_INITIALIZED", TRUE);
|
||||
}
|
||||
|
||||
struct TargetingHook GetTargetingHookDataByHookID(int nHookID)
|
||||
{
|
||||
string s = "SELECT sUUID, sVarName, nObjectType, nUses, sScript, nValidCursor, nInvalidCursor " +
|
||||
"FROM targeting_hooks " +
|
||||
"WHERE nHookID = @nHookID;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindInt(q, "@nHookID", nHookID);
|
||||
|
||||
struct TargetingHook th;
|
||||
|
||||
if (SqlStep(q))
|
||||
{
|
||||
th.nHookID = nHookID;
|
||||
th.oPC = GetObjectByUUID(SqlGetString(q, 0));
|
||||
th.sVarName = SqlGetString(q, 1);
|
||||
th.nObjectType = SqlGetInt(q, 2);
|
||||
th.nUses = SqlGetInt(q, 3);
|
||||
th.sScript = SqlGetString(q, 4);
|
||||
th.nValidCursor = SqlGetInt(q, 5);
|
||||
th.nInvalidCursor = SqlGetInt(q, 6);
|
||||
}
|
||||
else
|
||||
Warning("Targeting data for target hook " + IntToString(nHookID) + " not found");
|
||||
|
||||
return th;
|
||||
}
|
||||
|
||||
struct TargetingHook GetTargetingHookDataByVarName(object oPC, string sVarName)
|
||||
{
|
||||
int nHookID = GetTargetingHookID(oPC, sVarName);
|
||||
return GetTargetingHookDataByHookID(nHookID);
|
||||
}
|
||||
|
||||
sqlquery GetTargetList(object oPC, string sVarName, int nIndex = -1)
|
||||
{
|
||||
string s = "SELECT sTargetObject, sTargetArea, vTargetLocation " +
|
||||
"FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName" +
|
||||
(nIndex == -1 ? ";" : "LIMIT 1 OFFSET " + IntToString(nIndex)) + ";";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
int AddTargetToTargetList(object oPC, string sVarName, object oTarget, object oArea, vector vTarget)
|
||||
{
|
||||
string s = "INSERT INTO targeting_targets (sUUID, sVarName, sTargetObject, sTargetArea, vTargetLocation) " +
|
||||
"VALUES (@sUUID, @sVarName, @sTargetObject, @sTargetArea, @vTargetLocation);";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
SqlBindString(q, "@sTargetObject", ObjectToString(oTarget));
|
||||
SqlBindString(q, "@sTargetArea", ObjectToString(oArea));
|
||||
SqlBindVector(q, "@vTargetLocation", vTarget);
|
||||
SqlStep(q);
|
||||
|
||||
return CountTargetingHookTargets(oPC, sVarName);
|
||||
}
|
||||
|
||||
void DeleteTargetList(object oPC, string sVarName)
|
||||
{
|
||||
string s = "DELETE FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
|
||||
SqlStep(q);
|
||||
}
|
||||
|
||||
void EnterTargetingModeByHookID(int nHookID, int nBehavior = TARGET_BEHAVIOR_ADD)
|
||||
{
|
||||
struct TargetingHook th = GetTargetingHookDataByHookID(nHookID);
|
||||
|
||||
if (th == TARGETING_HOOK_INVALID)
|
||||
{
|
||||
Warning("EnterTargetingModeByHookID::Unable to retrieve valid targeting data for " +
|
||||
"targeting hook " + IntToString(nHookID));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetIsObjectValid(th.oPC))
|
||||
_EnterTargetingMode(th, nBehavior);
|
||||
}
|
||||
|
||||
void EnterTargetingModeByVarName(object oPC, string sVarName, int nBehavior = TARGET_BEHAVIOR_ADD)
|
||||
{
|
||||
struct TargetingHook th = GetTargetingHookDataByVarName(oPC, sVarName);
|
||||
|
||||
if (th == TARGETING_HOOK_INVALID)
|
||||
{
|
||||
Warning("EnterTargetingModeByVarName::Unable to retrieve valid targeting data for " +
|
||||
"targeting hook " + sVarName + " on " + GetName(oPC));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetIsObjectValid(th.oPC))
|
||||
_EnterTargetingMode(th, nBehavior);
|
||||
}
|
||||
|
||||
int GetTargetingHookID(object oPC, string sVarName)
|
||||
{
|
||||
string s = "SELECT nHookID " +
|
||||
"FROM targeting_hooks " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : 0;
|
||||
}
|
||||
|
||||
string GetTargetingHookVarName(int nHookID)
|
||||
{
|
||||
return _GetTargetingHookFieldData(nHookID, "sVarName");
|
||||
}
|
||||
|
||||
int GetTargetingHookObjectType(int nHookID)
|
||||
{
|
||||
return StringToInt(_GetTargetingHookFieldData(nHookID, "nObjectType"));
|
||||
}
|
||||
|
||||
int GetTargetingHookUses(int nHookID)
|
||||
{
|
||||
return StringToInt(_GetTargetingHookFieldData(nHookID, "nUses"));
|
||||
}
|
||||
|
||||
string GetTargetingHookScript(int nHookID)
|
||||
{
|
||||
return _GetTargetingHookFieldData(nHookID, "sScript");
|
||||
}
|
||||
|
||||
int AddTargetingHook(object oPC, string sVarName, int nObjectType = OBJECT_TYPE_ALL, string sScript = "",
|
||||
int nUses = 1, int nValidCursor = MOUSECURSOR_MAGIC, int nInvalidCursor = MOUSECURSOR_NOMAGIC)
|
||||
{
|
||||
CreateTargetingDataTables();
|
||||
|
||||
string s = "REPLACE INTO targeting_hooks (sUUID, sVarName, nObjectType, nUses, sScript, nValidCursor, nInvalidCursor) " +
|
||||
"VALUES (@sUUID, @sVarName, @nObjectType, @nUses, @sScript, @nValidCursor, @nInvalidCursor);";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
SqlBindInt (q, "@nObjectType", nObjectType);
|
||||
SqlBindInt (q, "@nUses", nUses);
|
||||
SqlBindString(q, "@sScript", sScript);
|
||||
SqlBindInt (q, "@nValidCursor", nValidCursor);
|
||||
SqlBindInt (q, "@nInvalidCursor", nInvalidCursor);
|
||||
SqlStep(q);
|
||||
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
{
|
||||
Debug("Adding targeting hook ID " + HexColorString(IntToString(_GetLastTargetingHookID()), COLOR_CYAN) +
|
||||
"\n sVarName -> " + HexColorString(sVarName, COLOR_CYAN) +
|
||||
"\n nObjectType -> " + HexColorString(ObjectTypeToString(nObjectType), COLOR_CYAN) +
|
||||
"\n sScript -> " + (sScript == "" ? HexColorString("[None]", COLOR_RED_LIGHT) :
|
||||
HexColorString(sScript, COLOR_CYAN)) +
|
||||
"\n nUses -> " + (nUses == -1 ? HexColorString("Unlimited", COLOR_CYAN) :
|
||||
(nUses > 0 ? HexColorString(IntToString(nUses), COLOR_CYAN) :
|
||||
HexColorString(IntToString(nUses), COLOR_RED_LIGHT))) +
|
||||
"\n nValidCursor -> " + IntToString(nValidCursor) +
|
||||
"\n nInvalidCursor -> " + IntToString(nInvalidCursor) + "\n");
|
||||
}
|
||||
|
||||
return _GetLastTargetingHookID();
|
||||
}
|
||||
|
||||
void DeleteTargetingHook(int nHookID)
|
||||
{
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
Debug("Deleting targeting hook ID " + HexColorString(IntToString(nHookID), COLOR_CYAN) + "\n");
|
||||
|
||||
_DeleteTargetingHookData(nHookID);
|
||||
}
|
||||
|
||||
int SatisfyTargetingHook(object oPC)
|
||||
{
|
||||
int nHookID = GetLocalInt(oPC, TARGET_HOOK_ID);
|
||||
if (nHookID == 0)
|
||||
return FALSE;
|
||||
|
||||
int nBehavior = GetLocalInt(oPC, TARGET_HOOK_BEHAVIOR);
|
||||
|
||||
struct TargetingHook th = GetTargetingHookDataByHookID(nHookID);
|
||||
|
||||
if (th == TARGETING_HOOK_INVALID)
|
||||
{
|
||||
Warning("SatisfyTargetingHook::Unable to retrieve valid targeting data for " +
|
||||
"targeting hook " + IntToString(nHookID));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
string sVarName = th.sVarName;
|
||||
object oTarget = GetTargetingModeSelectedObject();
|
||||
vector vTarget = GetTargetingModeSelectedPosition();
|
||||
|
||||
int bValid = TRUE;
|
||||
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
{
|
||||
Debug("Targeted Object -> " + (GetIsObjectValid(oTarget) ? (GetIsPC(oTarget) ? HexColorString(GetName(oTarget), COLOR_GREEN_LIGHT) : HexColorString(GetTag(oTarget), COLOR_CYAN)) : HexColorString("OBJECT_INVALID", COLOR_RED_LIGHT)) +
|
||||
"\n Type -> " + HexColorString(ObjectTypeToString(GetObjectType(oTarget)), COLOR_CYAN));
|
||||
Debug("Targeted Position -> " + (vTarget == Vector() ? HexColorString("POSITION_INVALID", COLOR_RED_LIGHT) :
|
||||
HexColorString("(" + FloatToString(vTarget.x, 3, 1) + ", " +
|
||||
FloatToString(vTarget.y, 3, 1) + ", " +
|
||||
FloatToString(vTarget.z, 3, 1) + ")", COLOR_CYAN)) + "\n");
|
||||
}
|
||||
|
||||
if (GetIsObjectValid(oTarget))
|
||||
{
|
||||
if (nBehavior == TARGET_BEHAVIOR_ADD)
|
||||
{
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
{
|
||||
object oArea = GetArea(oTarget);
|
||||
|
||||
Debug(HexColorString("Saving targeted object and position to list [" + th.sVarName + "]:", COLOR_CYAN) +
|
||||
"\n Tag -> " + HexColorString(GetTag(oTarget), COLOR_CYAN) +
|
||||
"\n Location -> " + HexColorString(JsonDump(LocationToJson(Location(oArea, vTarget, 0.0))), COLOR_CYAN) +
|
||||
"\n Area -> " + HexColorString((GetIsObjectValid(oArea) ? GetTag(oArea) : "AREA_INVALID"), COLOR_CYAN) + "\n");
|
||||
}
|
||||
|
||||
AddTargetToTargetList(oPC, sVarName, oTarget, GetArea(oPC), vTarget);
|
||||
}
|
||||
else if (nBehavior == TARGET_BEHAVIOR_DELETE)
|
||||
{
|
||||
if (GetArea(oTarget) == oTarget)
|
||||
Warning("Location/Tile targets cannot be deleted; select a game object");
|
||||
else
|
||||
{
|
||||
Debug(HexColorString("Attempting to delete targeted object and position from list [" + th.sVarName + "]:", COLOR_CYAN));
|
||||
int nIndex = GetTargetingHookIndex(oPC, sVarName, oTarget);
|
||||
if (nIndex == 0 && IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
Debug(" > " + HexColorString("Target " + (GetIsPC(oTarget) ? GetName(oTarget) : GetTag(oTarget)) + " not found " +
|
||||
"on list [" + th.sVarName + "]; removal aborted", COLOR_RED_LIGHT));
|
||||
else
|
||||
{
|
||||
DeleteTargetingHookTargetByIndex(oPC, sVarName, nIndex);
|
||||
|
||||
if (IsDebugging(DEBUG_LEVEL_DEBUG))
|
||||
Debug(" > " + HexColorString("Target " + (GetIsPC(oTarget) ? GetName(oTarget) : GetTag(oTarget)) + " removed from " +
|
||||
"list [" + th.sVarName + "]", COLOR_GREEN_LIGHT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bValid = FALSE;
|
||||
|
||||
if (!bValid)
|
||||
_ExitTargetingMode(nHookID);
|
||||
else
|
||||
{
|
||||
if (th.nUses == -1)
|
||||
_EnterTargetingMode(th, nBehavior);
|
||||
else
|
||||
_DecrementTargetingHookUses(th, nBehavior);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int DeleteTargetingHookTargetByIndex(object oPC, string sVarName, int nIndex)
|
||||
{
|
||||
string s = "DELETE FROM targeting_targets " +
|
||||
"WHERE nTargetID = @nTargetID;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindInt(q, "@nTargetID", nIndex);
|
||||
SqlStep(q);
|
||||
|
||||
return CountTargetingHookTargets(oPC, sVarName);
|
||||
}
|
||||
|
||||
int GetTargetingHookIndex(object oPC, string sVarName, object oTarget)
|
||||
{
|
||||
string s = "SELECT nTargetID " +
|
||||
"FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName " +
|
||||
"AND sTargetObject = @sTargetObject;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
SqlBindString(q, "@sTargetObject", ObjectToString(oTarget));
|
||||
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : 0;
|
||||
}
|
||||
|
||||
object GetTargetingHookObject(object oPC, string sVarName, int nIndex = 1)
|
||||
{
|
||||
return StringToObject(_GetTargetData(oPC, sVarName, "sTargetObject", nIndex));
|
||||
}
|
||||
|
||||
location GetTargetingHookLocation(object oPC, string sVarName, int nIndex = 1)
|
||||
{
|
||||
sqlquery q = GetTargetList(oPC, sVarName, 1);
|
||||
if (SqlStep(q))
|
||||
{
|
||||
object oArea = StringToObject(SqlGetString(q, 1));
|
||||
vector vTarget = SqlGetVector(q, 2);
|
||||
|
||||
return Location(oArea, vTarget, 0.0);
|
||||
}
|
||||
|
||||
return Location(OBJECT_INVALID, Vector(), 0.0);
|
||||
}
|
||||
|
||||
vector GetTargetingHookPosition(object oPC, string sVarName, int nIndex = 1)
|
||||
{
|
||||
sqlquery q = GetTargetList(oPC, sVarName, 1);
|
||||
if (SqlStep(q))
|
||||
return SqlGetVector(q, 2);
|
||||
|
||||
return Vector();
|
||||
}
|
||||
|
||||
int CountTargetingHookTargets(object oPC, string sVarName)
|
||||
{
|
||||
string s = "SELECT COUNT (nTargetID) " +
|
||||
"FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName;";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : 0;
|
||||
}
|
||||
|
||||
int DeleteTargetingHookTarget(object oPC, string sVarName, int nIndex = 1)
|
||||
{
|
||||
string s = "DELETE FROM targeting_targets " +
|
||||
"WHERE sUUID = @sUUID " +
|
||||
"AND sVarName = @sVarName " +
|
||||
"LIMIT 1 OFFSET " + IntToString(nIndex) + ";";
|
||||
|
||||
sqlquery q = _PrepareTargetingQuery(s);
|
||||
SqlBindString(q, "@sUUID", GetObjectUUID(oPC));
|
||||
SqlBindString(q, "@sVarName", sVarName);
|
||||
SqlStep(q);
|
||||
|
||||
return CountTargetingHookTargets(oPC, sVarName);
|
||||
}
|
475
_module/nss/util_i_timers.nss
Normal file
475
_module/nss/util_i_timers.nss
Normal file
@@ -0,0 +1,475 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_timers.nss
|
||||
/// @author Michael A. Sinclair (Squatting Monk) <squattingmonk@gmail.com>
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for running scripts on an interval.
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @details
|
||||
/// ## Concept
|
||||
/// Timers are a way of running a script repeatedly on an interval. A timer can
|
||||
/// be created on an object. Once started, it will continue to run until it is
|
||||
/// finished iterating or until killed manually. Each time the timer elapses,
|
||||
/// its action will run. By default, this action is to simply run a script.
|
||||
///
|
||||
/// ## Basic Usage
|
||||
///
|
||||
/// ### Creating a Timer
|
||||
/// You can create a timer using `CreateTimer()`. This function takes the object
|
||||
/// that should run the timer, the script that should execute when the timer
|
||||
/// elapses, the interval between ticks, and the total number of iterations. It
|
||||
/// returns the ID for the timer, which is used to reference it in the database.
|
||||
/// You should save this timer for later use.
|
||||
///
|
||||
/// ```nwscript
|
||||
/// // The following creates a timer on oPC that will run the script "foo" every
|
||||
/// // 6 seconds for 4 iterations.
|
||||
/// int nTimerID = CreateTimer(oPC, "foo", 6.0, 4);
|
||||
/// ```
|
||||
///
|
||||
/// A timer created with 0 iterations will run until stopped or killed.
|
||||
///
|
||||
/// ## Starting a Timer
|
||||
/// Timers will not run until they are started wiuth `StartTimer()`. This
|
||||
/// function takes the ID of the timer returned from `CreateTimer()`. If the
|
||||
/// second parameter, `bInstant`, is TRUE, the timer will elapse immediately;
|
||||
/// otherwise, it will elapse when its interval is complete:
|
||||
///
|
||||
/// ```nwscript
|
||||
/// StartTimer(nTimerID);
|
||||
/// ```
|
||||
///
|
||||
/// ### Stopping a Timer
|
||||
/// Stopping a timer with `StopTimer()` will suspend its execution:
|
||||
/// ```nwscript
|
||||
/// StopTimer(nTimerID);
|
||||
/// ```
|
||||
/// You can restart the timer later using `StartTimer()` to resume any remaining
|
||||
/// iterations. If you want to start again from the beginning, you can call
|
||||
/// `ResetTimer()` first:
|
||||
/// ```nwscript
|
||||
/// ResetTimer(nTimerID);
|
||||
/// StartTimer(nTimerID);
|
||||
/// ```
|
||||
///
|
||||
/// ### Destroying a Timer
|
||||
/// Calling `KillTimer()` will clean up all data associated with the timer. A
|
||||
/// timer cannot be restarted after it is killed; you will have to create and
|
||||
/// start a new one.
|
||||
/// ```nwscript
|
||||
/// KillTimer(nTimerID);
|
||||
/// ```
|
||||
///
|
||||
/// Timers automatically kill themselves when they are finished iterating or
|
||||
/// when the object they are executed on is no longer valid. You only need to
|
||||
/// use `KillTimer()` if you want to destroy it before it is done iterating or
|
||||
/// if the timer is infinite.
|
||||
///
|
||||
/// ## Advanced Usage
|
||||
/// By default, timer actions are handled by passing them to `ExecuteScript()`.
|
||||
/// However, the final parameter of the `CreateTimer()` function allows you to
|
||||
/// specify a handler script. If this parameter is not blank, the handler will
|
||||
/// be called using `ExecuteScript()` and the action will be available to it as
|
||||
/// a script parameter.
|
||||
///
|
||||
/// For example, the Core Framework allows timers to run event hooks by calling
|
||||
/// the handler script `core_e_timerhook`, which is as follows:
|
||||
/// ```nwscript
|
||||
/// #include "core_i_framework"
|
||||
///
|
||||
/// void main()
|
||||
/// {
|
||||
/// string sEvent = GetScriptParam(TIMER_ACTION);
|
||||
/// string sSource = GetScriptParam(TIMER_SOURCE);
|
||||
/// object oSource = StringToObject(sSource);
|
||||
/// RunEvent(sEvent, oSource);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// To make this easier, `core_i_framework` contains an alias to `CreateTimer()`
|
||||
/// called `CreateEventTimer()` that sets the handler script. You can create
|
||||
/// your own aliases in the same way.
|
||||
|
||||
#include "util_i_sqlite"
|
||||
#include "util_i_debug"
|
||||
#include "util_i_datapoint"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const string TIMER_DATAPOINT = "*Timers";
|
||||
const string TIMER_INIT = "*TimersInitialized";
|
||||
const string TIMER_LAST = "*TimerID";
|
||||
const string TIMER_ACTION = "*TimerAction";
|
||||
const string TIMER_SOURCE = "*TimerSource";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Global Variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Running timers are AssignCommand()'ed to this datapoint. This ensures that
|
||||
// even if the object that issued the StartTimer() becomes invalid, the timer
|
||||
// will continue to run.
|
||||
object TIMERS = GetDatapoint(TIMER_DATAPOINT, GetModule(), FALSE);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Function Declarations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Create a table for timers in the module's volatile database.
|
||||
/// @param bReset If TRUE, will drop the existing timers table.
|
||||
/// @note This function will be run automatically the first timer one of the
|
||||
/// functions in this file is called. You only need to call this if you need
|
||||
/// the table created earlier (e.g., because another table references it).
|
||||
void CreateTimersTable(int bReset = FALSE);
|
||||
|
||||
/// @brief Create a timer that fires on a target at regular intervals.
|
||||
/// @details After a timer is created, you will need to start it to get it to
|
||||
/// run. You cannot create a timer on an invalid target or with a
|
||||
/// non-positive interval value.
|
||||
/// @param oTarget The object the action will run on.
|
||||
/// @param sAction The action to execute when the timer elapses.
|
||||
/// @param fInterval The number of seconds between iterations.
|
||||
/// @param nIterations the number of times the timer can elapse. 0 means no
|
||||
/// limit. If nIterations is 0, fInterval must be greater than or equal to
|
||||
/// 6.0.
|
||||
/// @param fJitter A random number of seconds between 0.0 and fJitter to add to
|
||||
/// fInterval between executions. Leave at 0.0 for no jitter.
|
||||
/// @param sHandler A handler script to execute sAction. If "", sAction will be
|
||||
/// called using ExecuteScript() instead.
|
||||
/// @returns the ID of the timer. Save this so it can be used to start, stop, or
|
||||
/// kill the timer later.
|
||||
int CreateTimer(object oTarget, string sAction, float fInterval, int nIterations = 0, float fJitter = 0.0, string sHandler = "");
|
||||
|
||||
/// @brief Return if a timer exists.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
int GetIsTimerValid(int nTimerID);
|
||||
|
||||
/// @brief Start a timer, executing its action each interval until finished
|
||||
/// iterating, stopped, or killed.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
/// @param bInstant If TRUE, execute the timer's action immediately.
|
||||
void StartTimer(int nTimerID, int bInstant = TRUE);
|
||||
|
||||
/// @brief Suspend execution of a timer.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
/// @note This does not destroy the timer, only stops it from iterating or
|
||||
/// executing its action.
|
||||
void StopTimer(int nTimerID);
|
||||
|
||||
/// @brief Reset the number or remaining iterations on a timer.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
void ResetTimer(int nTimerID);
|
||||
|
||||
/// @brief Delete a timer.
|
||||
/// @details This results in all information about the given timer being
|
||||
/// deleted. Since the information is gone, the action associated with that
|
||||
/// timer ID will not get executed again.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
void KillTimer(int nTimerID);
|
||||
|
||||
/// @brief Return whether a timer will run infinitely.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
int GetIsTimerInfinite(int nTimerID);
|
||||
|
||||
/// @brief Return the remaining number of iterations for a timer.
|
||||
/// @details If called during a timer script, will not include the current
|
||||
/// iteration. Returns -1 if nTimerID is not a valid timer ID. Returns 0 if
|
||||
/// the timer is set to run indefinitely, so be sure to check for this with
|
||||
/// GetIsTimerInfinite().
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
int GetTimerRemaining(int nTimerID);
|
||||
|
||||
/// @brief Sets the remaining number of iterations for a timer.
|
||||
/// @param nTimerID The ID of the timer in the database.
|
||||
/// @param nRemaining The remaining number of iterations.
|
||||
void SetTimerRemaining(int nTimerID, int nRemaining);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Private Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Private function used by StartTimer().
|
||||
void _TimerElapsed(int nTimerID, int nRunID, int bFirstRun = FALSE)
|
||||
{
|
||||
// Timers are fired on a delay, so it's possible that the timer was stopped
|
||||
// and restarted before the delayed call could fail due to the timer being
|
||||
// stopped. We increment the run_id whenever the timer is started and pass
|
||||
// it along to the delayed calls so they can check if they are still valid.
|
||||
sqlquery q = SqlPrepareQueryModule("SELECT * FROM timers " +
|
||||
"WHERE timer_id = @timer_id AND run_id = @run_id AND running = 1;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
SqlBindInt(q, "@run_id", nRunID);
|
||||
|
||||
// The timer was killed or stopped
|
||||
if (!SqlStep(q))
|
||||
return;
|
||||
|
||||
string sTimerID = IntToString(nTimerID);
|
||||
string sAction = SqlGetString(q, 3);
|
||||
string sHandler = SqlGetString(q, 4);
|
||||
string sTarget = SqlGetString(q, 5);
|
||||
string sSource = SqlGetString(q, 6);
|
||||
float fInterval = SqlGetFloat (q, 7);
|
||||
float fJitter = SqlGetFloat (q, 8);
|
||||
int nIterations = SqlGetInt (q, 9);
|
||||
int nRemaining = SqlGetInt (q, 10);
|
||||
int bIsPC = SqlGetInt (q, 11);
|
||||
object oTarget = StringToObject(sTarget);
|
||||
object oSource = StringToObject(sSource);
|
||||
|
||||
string sMsg =
|
||||
"\n Target: " + sTarget +
|
||||
" (" + (GetIsObjectValid(oTarget) ? GetName(oTarget) : "INVALID") + ")" +
|
||||
"\n Source: " + sSource +
|
||||
" (" + (GetIsObjectValid(oTarget) ? GetName(oSource) : "INVALID") + ")" +
|
||||
"\n Action: " + sAction +
|
||||
"\n Handler: " + sHandler;
|
||||
|
||||
if (!GetIsObjectValid(oTarget) || (bIsPC && !GetIsPC(oTarget)))
|
||||
{
|
||||
Warning("Target for timer " + sTimerID + " no longer valid:" + sMsg);
|
||||
KillTimer(nTimerID);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're running infinitely or we have more runs remaining...
|
||||
if (!nIterations || nRemaining)
|
||||
{
|
||||
string sIterations = (nIterations ? IntToString(nIterations) : "Infinite");
|
||||
if (!bFirstRun)
|
||||
{
|
||||
Notice("Timer " + sTimerID + " elapsed" + sMsg +
|
||||
"\n Iteration: " +
|
||||
(nIterations ? IntToString(nIterations - nRemaining + 1) : "INFINITE") +
|
||||
"/" + sIterations);
|
||||
|
||||
// If we're not running an infinite number of times, decrement the
|
||||
// number of iterations we have remaining
|
||||
if (nIterations)
|
||||
SetTimerRemaining(nTimerID, nRemaining - 1);
|
||||
|
||||
// Run the timer handler
|
||||
SetScriptParam(TIMER_LAST, IntToString(nTimerID));
|
||||
SetScriptParam(TIMER_ACTION, sAction);
|
||||
SetScriptParam(TIMER_SOURCE, sSource);
|
||||
ExecuteScript(sHandler != "" ? sHandler : sAction, oTarget);
|
||||
|
||||
// In case one of those scripts we just called reset the timer...
|
||||
if (nIterations)
|
||||
nRemaining = GetTimerRemaining(nTimerID);
|
||||
}
|
||||
|
||||
// If we have runs left, call our timer's next iteration.
|
||||
if (!nIterations || nRemaining)
|
||||
{
|
||||
// Account for any jitter
|
||||
fJitter = IntToFloat(Random(FloatToInt(fJitter * 10) + 1)) / 10.0;
|
||||
fInterval += fJitter;
|
||||
|
||||
Notice("Scheduling next iteration for timer " + sTimerID + ":" + sMsg +
|
||||
"\n Delay: " + FloatToString(fInterval, 0, 1) +
|
||||
"\n Remaining: " +
|
||||
(nIterations ? (IntToString(nRemaining)) : "INFINITE") +
|
||||
"/" + sIterations);
|
||||
|
||||
DelayCommand(fInterval, _TimerElapsed(nTimerID, nRunID));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We have no more runs left! Kill the timer to clean up.
|
||||
Debug("Timer " + sTimerID + " expired:" + sMsg);
|
||||
KillTimer(nTimerID);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void CreateTimersTable(int bReset = FALSE)
|
||||
{
|
||||
if (GetLocalInt(TIMERS, TIMER_INIT) && !bReset)
|
||||
return;
|
||||
|
||||
// StartTimer() assigns the timer tick to TIMERS, so by deleting it, we are
|
||||
// able to cancel all currently running timers.
|
||||
DestroyObject(TIMERS);
|
||||
|
||||
SqlCreateTableModule("timers",
|
||||
"timer_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"run_id INTEGER NOT NULL DEFAULT 0, " +
|
||||
"running BOOLEAN NOT NULL DEFAULT 0, " +
|
||||
"action TEXT NOT NULL, " +
|
||||
"handler TEXT NOT NULL, " +
|
||||
"target TEXT NOT NULL, " +
|
||||
"source TEXT NOT NULL, " +
|
||||
"interval REAL NOT NULL, " +
|
||||
"jitter REAL NOT NULL, " +
|
||||
"iterations INTEGER NOT NULL, " +
|
||||
"remaining INTEGER NOT NULL, " +
|
||||
"is_pc BOOLEAN NOT NULL DEFAULT 0", bReset);
|
||||
|
||||
TIMERS = CreateDatapoint(TIMER_DATAPOINT);
|
||||
SetDebugPrefix(HexColorString("[Timers]", COLOR_CYAN), TIMERS);
|
||||
SetLocalInt(TIMERS, TIMER_INIT, TRUE);
|
||||
}
|
||||
|
||||
int CreateTimer(object oTarget, string sAction, float fInterval, int nIterations = 0, float fJitter = 0.0, string sHandler = "")
|
||||
{
|
||||
string sSource = ObjectToString(OBJECT_SELF);
|
||||
string sTarget = ObjectToString(oTarget);
|
||||
string sDebug =
|
||||
"\n OBJECT_SELF: " + sSource + " (" + GetName(OBJECT_SELF) + ")" +
|
||||
"\n oTarget: " + sTarget +
|
||||
" (" + (GetIsObjectValid(oTarget) ? GetName(oTarget) : "INVALID") + ")" +
|
||||
"\n sAction: " + sAction +
|
||||
"\n sHandler: " + sHandler +
|
||||
"\n nIterations: " + (nIterations ? IntToString(nIterations) : "Infinite") +
|
||||
"\n fInterval: " + FloatToString(fInterval, 0, 1) +
|
||||
"\n fJitter: " + FloatToString(fJitter, 0, 1);
|
||||
|
||||
// Sanity checks: don't create the timer if...
|
||||
// 1. the target is invalid
|
||||
// 2. the interval is not greater than 0.0
|
||||
// 3. the number of iterations is non-positive
|
||||
// 4. the interval is more than once per round and the timer is infinite
|
||||
string sError;
|
||||
if (!GetIsObjectValid(oTarget))
|
||||
sError = "oTarget is invalid";
|
||||
else if (fInterval <= 0.0)
|
||||
sError = "fInterval must be positive";
|
||||
else if (fInterval + fJitter <= 0.0)
|
||||
sError = "fJitter is too low for fInterval";
|
||||
else if (nIterations < 0)
|
||||
sError = "nIterations is negative";
|
||||
else if (fInterval < 6.0 && !nIterations)
|
||||
sError = "fInterval is too short for infinite executions";
|
||||
|
||||
if (sError != "")
|
||||
{
|
||||
CriticalError("CreateTimer() failed:\n Error: " + sError + sDebug);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule("INSERT INTO timers " +
|
||||
"(action, handler, target, source, interval, jitter, iterations, remaining, is_pc) " +
|
||||
"VALUES (@action, @handler, @target, @source, @interval, @jitter, @iterations, @remaining, @is_pc) " +
|
||||
"RETURNING timer_id;");
|
||||
SqlBindString(q, "@action", sAction);
|
||||
SqlBindString(q, "@handler", sHandler);
|
||||
SqlBindString(q, "@target", sTarget);
|
||||
SqlBindString(q, "@source", sSource);
|
||||
SqlBindFloat (q, "@interval", fInterval);
|
||||
SqlBindFloat (q, "@jitter", fJitter);
|
||||
SqlBindInt (q, "@iterations", nIterations);
|
||||
SqlBindInt (q, "@remaining", nIterations);
|
||||
SqlBindInt (q, "@is_pc", GetIsPC(oTarget));
|
||||
|
||||
int nTimerID = SqlStep(q) ? SqlGetInt(q, 0) : 0;
|
||||
if (nTimerID > 0)
|
||||
Notice("Created timer " + IntToString(nTimerID) + sDebug);
|
||||
|
||||
return nTimerID;
|
||||
}
|
||||
|
||||
int GetIsTimerValid(int nTimerID)
|
||||
{
|
||||
// Timer IDs less than or equal to 0 are always invalid.
|
||||
if (nTimerID <= 0)
|
||||
return FALSE;
|
||||
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"SELECT 1 FROM timers WHERE timer_id = @timer_id;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : FALSE;
|
||||
}
|
||||
|
||||
void StartTimer(int nTimerID, int bInstant = TRUE)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"UPDATE timers SET running = 1, run_id = run_id + 1 " +
|
||||
"WHERE timer_id = @timer_id AND running = 0 RETURNING run_id;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
|
||||
if (SqlStep(q))
|
||||
{
|
||||
Notice("Started timer " + IntToString(nTimerID));
|
||||
AssignCommand(TIMERS, _TimerElapsed(nTimerID, SqlGetInt(q, 0), !bInstant));
|
||||
}
|
||||
else
|
||||
{
|
||||
string sDebug = "StartTimer(" + IntToString(nTimerID) + ")";
|
||||
if (GetIsTimerValid(nTimerID))
|
||||
Error(sDebug + "failed: timer is already running");
|
||||
else
|
||||
Error(sDebug + " failed: timer id does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
void StopTimer(int nTimerID)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"UPDATE timers SET running = 0 " +
|
||||
"WHERE timer_id = @timer_id RETURNING 1;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
if (SqlStep(q))
|
||||
Notice("Stopping timer " + IntToString(nTimerID));
|
||||
}
|
||||
|
||||
void ResetTimer(int nTimerID)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"UPDATE timers SET remaining = timers.iterations " +
|
||||
"WHERE timer_id = @timer_id AND iterations > 0 RETURNING remaining;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
if (SqlStep(q))
|
||||
{
|
||||
Notice("ResetTimer(" + IntToString(nTimerID) + ") successful: " +
|
||||
IntToString(SqlGetInt(q, 0)) + " iterations remaining");
|
||||
}
|
||||
}
|
||||
|
||||
void KillTimer(int nTimerID)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"DELETE FROM timers WHERE timer_id = @timer_id RETURNING 1;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
if (SqlStep(q))
|
||||
Notice("Killing timer " + IntToString(nTimerID));
|
||||
}
|
||||
|
||||
int GetIsTimerInfinite(int nTimerID)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"SELECT iterations FROM timers WHERE timer_id = @timer_id;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
return SqlStep(q) ? !SqlGetInt(q, 0) : FALSE;
|
||||
}
|
||||
|
||||
int GetTimerRemaining(int nTimerID)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"SELECT remaining FROM timers WHERE timer_id = @timer_id;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
return SqlStep(q) ? SqlGetInt(q, 0) : -1;
|
||||
}
|
||||
|
||||
void SetTimerRemaining(int nTimerID, int nRemaining)
|
||||
{
|
||||
CreateTimersTable();
|
||||
sqlquery q = SqlPrepareQueryModule(
|
||||
"UPDATE timers SET remaining = @remaining " +
|
||||
"WHERE timer_id = @timer_id AND iterations > 0;");
|
||||
SqlBindInt(q, "@timer_id", nTimerID);
|
||||
SqlBindInt(q, "@remaining", nRemaining);
|
||||
SqlStep(q);
|
||||
}
|
1139
_module/nss/util_i_times.nss
Normal file
1139
_module/nss/util_i_times.nss
Normal file
File diff suppressed because it is too large
Load Diff
375
_module/nss/util_i_unittest.nss
Normal file
375
_module/nss/util_i_unittest.nss
Normal file
@@ -0,0 +1,375 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file util_i_unittest.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Functions for managing unit test reporting.
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @details
|
||||
///
|
||||
/// Variable Conventions:
|
||||
///
|
||||
/// Tests can be written in just about any format, however since tests tend to be
|
||||
/// repetitive, having a variable and formatting convention can make building
|
||||
/// multiple tests quick and easy. Following are variable naming conventions
|
||||
/// and an example that showcases how to use them.
|
||||
///
|
||||
/// Variable Naming:
|
||||
/// ix - Function Input Variables
|
||||
/// ex - Expected Function Result Variables
|
||||
/// rx - Actual Function Result Variables
|
||||
/// bx - Boolean Test Result Variables
|
||||
/// tx - Timer Variables
|
||||
///
|
||||
/// Convenience Functions:
|
||||
/// _i : IntToString
|
||||
/// _f : FloatToString; Rounds to significant digits
|
||||
/// _b : Returns `True` or `False` (literals)
|
||||
///
|
||||
/// _q : Returns string wrapped in single quotes
|
||||
/// _qq : Returns string wrapped in double quotes
|
||||
/// _p : Returns string wrapped in parenthesis
|
||||
///
|
||||
/// Timers:
|
||||
/// To start a timer:
|
||||
/// t1 = Timer(); : Sets timer variable `t1` to GetMicrosecondCounter()
|
||||
///
|
||||
/// To end a timer and save the results:
|
||||
/// t1 = Timer(t1); : Sets timer variable `t1` to GetMicrosecondCounter() - t1
|
||||
///
|
||||
/// The following example shows how to create a grouped assertion and display
|
||||
/// only relevant results, assuming only assertion failures are of
|
||||
/// interest. If you always want to see expanded results regardless of test
|
||||
/// outcome, set UNITTEST_ALWAYS_EXPAND to TRUE in `util_c_unittest`.
|
||||
///
|
||||
/// For example purposes only, this unit test sample code will run a unittest
|
||||
/// against the following function, which will return:
|
||||
/// -1, if n <= 0
|
||||
/// 20 * n, if 0 < n <= 3
|
||||
/// 100, if n > 3
|
||||
///
|
||||
/// ```nwscript
|
||||
/// int unittest_demo_ConvertValue(int n)
|
||||
/// {
|
||||
/// return n <= 0 ? -1 : n > 3 ? 100 : 20 * n;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The following unit test will run against the function above for three test cases:
|
||||
/// - Out of bounds (low) -> n <= 0;
|
||||
/// - In bounds -> 0 < n <= 3;
|
||||
/// - Out of bounds (high) -> n > 3;
|
||||
///
|
||||
/// ```nwscript
|
||||
/// int unittest_ConvertValue()
|
||||
/// {
|
||||
/// int i1, i2, i3;
|
||||
/// int e1, e2, e3;
|
||||
/// int r1, r2, r3;
|
||||
/// int b1, b2, b3, b;
|
||||
/// int t1, t2, t3, t;
|
||||
///
|
||||
/// // Setup the input values
|
||||
/// i1 = -10;
|
||||
/// i2 = 2;
|
||||
/// i3 = 12;
|
||||
///
|
||||
/// // Setup the expected return values
|
||||
/// e1 = -1;
|
||||
/// e2 = 40;
|
||||
/// e3 = 100;
|
||||
///
|
||||
/// // Run the unit tests with timers
|
||||
/// t = Timer();
|
||||
/// t1 = Timer(); r1 = unittest_demo_ConvertValue(i1); t1 = Timer(t1);
|
||||
/// t2 = Timer(); r2 = unittest_demo_ConvertValue(i2); t2 = Timer(t2);
|
||||
/// t3 = Timer(); r3 = unittest_demo_ConvertValue(i3); t3 = Timer(t3);
|
||||
/// t = Timer(t);
|
||||
///
|
||||
/// // Populate the results
|
||||
/// b = (b1 = r1 == e1) &
|
||||
/// (b2 = r2 == e2) &
|
||||
/// (b3 = r3 == e3);
|
||||
///
|
||||
/// // Display the result
|
||||
/// if (!AssertGroup("ConvertValue()", b))
|
||||
/// {
|
||||
/// if (!Assert("Out of bounds (low)", b1))
|
||||
/// DescribeTestParameters(_i(i1), _i(e1), _i(r1));
|
||||
/// DescribeTestTime(t1);
|
||||
///
|
||||
/// if (!Assert("In bounds", b2))
|
||||
/// DescribeTestParameters(_i(i2), _i(e2), _i(r2));
|
||||
/// DescribeTestTime(t2);
|
||||
///
|
||||
/// if (!Assert("Out of bounds (high)", b3))
|
||||
/// DescribeTestParameters(_i(i3), _i(e3), _i(r3));
|
||||
/// DescribeTestTime(t3);
|
||||
/// } DescribeGroupTime(t); Outdent();
|
||||
/// }
|
||||
/// Note: Use of ResetIndent() or another indentation function, such as
|
||||
/// Outdent(), may be required if moving to another group assertion.
|
||||
|
||||
#include "util_c_unittest"
|
||||
#include "util_i_strings"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string TEST_INDENT = "TEST_INDENT";
|
||||
|
||||
string TEST_PASS = HexColorString("PASS", COLOR_GREEN_LIGHT);
|
||||
string TEST_FAIL = HexColorString("FAIL", COLOR_RED_LIGHT);
|
||||
string TEST_DELIMITER = HexColorString(" | ", COLOR_WHITE);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Prototypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/// @brief Establishes or calculates a timer or elapsed value.
|
||||
/// @param t Previous timer value derived from this function.
|
||||
/// @note Calling this function without parameter `t` specified will
|
||||
/// return a starting value in microseconds. When the code in
|
||||
/// question has been run, call this function again and pass
|
||||
/// the previously returned value as parameter `t` to calculate
|
||||
/// the total elapsed time for between calls to this function.
|
||||
int Timer(int t = 0);
|
||||
|
||||
/// @brief Reset the indentation level used in displaying test results.
|
||||
/// @returns The indenation string used to pad test result output.
|
||||
string ResetIndent();
|
||||
|
||||
/// @brief Indent test results display by one indentation level.
|
||||
/// @param bReset If TRUE, will reset the indentation level to 0 before
|
||||
/// adding an indentation level.
|
||||
/// @returns The indenation string used to pad test result output.
|
||||
string Indent(int bReset = FALSE);
|
||||
|
||||
/// @brief Outdent test results display by one indentation level.
|
||||
/// @returns The indenation string used to pad test result output.
|
||||
string Outdent();
|
||||
|
||||
/// @brief Provide a test suite description.
|
||||
/// @param sDescription The description to display.
|
||||
/// @note Test suite description will always display at indentation level
|
||||
/// 0 and will reset the indentation level for the subsequest assertions.
|
||||
void DescribeTestSuite(string sDescription);
|
||||
|
||||
/// @brief Provide a test group description.
|
||||
/// @param sDescription The description to display.
|
||||
/// @note Test groups are used to minimize unit test output if all tests
|
||||
/// within a group pass. This function only provides a header for the
|
||||
/// test group. To provide a test group description combined with
|
||||
/// test group ouput, use AssertGroup().
|
||||
void DescribeTestGroup(string sDescription);
|
||||
|
||||
/// @brief Display the parameter used in a test.
|
||||
/// @param sInput The input data.
|
||||
/// @param sExpected The expected test result.
|
||||
/// @param sReceived The actual test result.
|
||||
/// @note Each paramater is optional. If any parameter is an empty string,
|
||||
/// that parameter will not be output.
|
||||
void DescribeTestParameters(string sInput = "", string sExpected = "", string sReceived = "");
|
||||
|
||||
/// @brief Display function timer result.
|
||||
/// @param nTime Function timer result, in microseconds.
|
||||
/// @note This function is intended to use output from GetMicrosecondCounter().
|
||||
void DescribeTestTime(int nTime);
|
||||
|
||||
/// @brief Display function timer result.
|
||||
/// @param nTime Function timer result, in microseconds.
|
||||
/// @note This function is intended to use output from GetMicrosecondCounter().
|
||||
void DescribeGroupTime(int nTime);
|
||||
|
||||
/// @brief Display the results of a unit test.
|
||||
/// @param sTest The name of the unit test.
|
||||
/// @param bAssertion The results of the unit test.
|
||||
/// @returns The results of the unit test.
|
||||
int Assert(string sTest, int bAssertion);
|
||||
|
||||
/// @brief Display the results of a group test.
|
||||
/// @param sTest The name of the group test.
|
||||
/// @param bAssertion The results of the group test.
|
||||
/// @returns The results of the group test.
|
||||
int AssertGroup(string sGroup, int bAssertion);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Private Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string _GetIndent(int bReset = FALSE)
|
||||
{
|
||||
if (bReset)
|
||||
ResetIndent();
|
||||
|
||||
string sIndent;
|
||||
int nIndent = GetLocalInt(GetModule(), TEST_INDENT);
|
||||
if (nIndent == 0)
|
||||
return "";
|
||||
|
||||
while (nIndent-- > 0)
|
||||
sIndent += " ";
|
||||
|
||||
return sIndent;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
string _i(int n) { return IntToString(n); }
|
||||
string _f(float f) { return FormatFloat(f, "%!f"); }
|
||||
string _b(int b) { return b ? "True" : "False"; }
|
||||
|
||||
string _q(string s) { return "'" + s + "'"; }
|
||||
string _qq(string s) { return "\"" + s + "\""; }
|
||||
string _p(string s) { return "(" + s + ")"; }
|
||||
|
||||
int Timer(int t = 0)
|
||||
{
|
||||
return GetMicrosecondCounter() - t;
|
||||
}
|
||||
|
||||
string ResetIndent()
|
||||
{
|
||||
DeleteLocalInt(GetModule(), TEST_INDENT);
|
||||
return _GetIndent();
|
||||
}
|
||||
|
||||
string Indent(int bReset = FALSE)
|
||||
{
|
||||
if (bReset)
|
||||
ResetIndent();
|
||||
|
||||
int nIndent = GetLocalInt(GetModule(), TEST_INDENT);
|
||||
SetLocalInt(GetModule(), TEST_INDENT, ++nIndent);
|
||||
return _GetIndent();
|
||||
}
|
||||
|
||||
string Outdent()
|
||||
{
|
||||
int nIndent = GetLocalInt(GetModule(), TEST_INDENT);
|
||||
SetLocalInt(GetModule(), TEST_INDENT, max(0, --nIndent));
|
||||
return _GetIndent();
|
||||
}
|
||||
|
||||
void DescribeTestSuite(string sDescription)
|
||||
{
|
||||
sDescription = HexColorString("Test Suite ", UNITTEST_TITLE_COLOR) +
|
||||
HexColorString(sDescription, UNITTEST_NAME_COLOR);
|
||||
Indent(TRUE);
|
||||
HandleUnitTestOutput(sDescription);
|
||||
}
|
||||
|
||||
void DescribeTestGroup(string sDescription)
|
||||
{
|
||||
sDescription = HexColorString("Test Group ", UNITTEST_TITLE_COLOR) +
|
||||
HexColorString(sDescription, UNITTEST_NAME_COLOR);
|
||||
HandleUnitTestOutput(_GetIndent() + sDescription);
|
||||
Indent();
|
||||
}
|
||||
|
||||
void DescribeTestParameters(string sInput, string sExpected, string sReceived)
|
||||
{
|
||||
Indent();
|
||||
if (sInput != "")
|
||||
{
|
||||
json jInput = JsonParse(sInput);
|
||||
if (jInput != JSON_NULL && JsonGetLength(jInput) > 0)
|
||||
{
|
||||
if (JsonGetType(jInput) == JSON_TYPE_ARRAY)
|
||||
{
|
||||
string s = "WITH atoms AS (SELECT atom FROM json_each(@json)) " +
|
||||
"SELECT group_concat(atom, ' | ') FROM atoms;";
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(), s);
|
||||
SqlBindJson(q, "@json", jInput);
|
||||
sInput = SqlStep(q) ? SqlGetString(q, 0) : sInput;
|
||||
}
|
||||
else if (JsonGetType(jInput) == JSON_TYPE_OBJECT)
|
||||
{
|
||||
string s = "WITH kvps AS (SELECT key, value FROM json_each(@json)) " +
|
||||
"SELECT group_concat(key || ' = ' || (IFNULL(value, '\"\"\"\"')), ' | ') FROM kvps;";
|
||||
sqlquery q = SqlPrepareQueryObject(GetModule(), s);
|
||||
SqlBindJson(q, "@json", jInput);
|
||||
sInput = SqlStep(q) ? SqlGetString(q, 0) : sInput;
|
||||
}
|
||||
|
||||
sInput = RegExpReplace("(?:^|\\| )(.*?)(?= =)", sInput, HexToColor(COLOR_BLUE_STEEL) + "$&</c>");
|
||||
sInput = RegExpReplace("\\||=", sInput, HexToColor(COLOR_WHITE) + "$&</c>");
|
||||
}
|
||||
|
||||
sInput = _GetIndent() + HexColorString("Input: ", UNITTEST_PARAMETER_COLOR) +
|
||||
HexColorString(sInput, UNITTEST_PARAMETER_INPUT);
|
||||
|
||||
HandleUnitTestOutput(sInput);
|
||||
}
|
||||
|
||||
if (sExpected != "")
|
||||
{
|
||||
sExpected = _GetIndent() + HexColorString("Expected: ", UNITTEST_PARAMETER_COLOR) +
|
||||
HexColorString(sExpected, UNITTEST_PARAMETER_INPUT);
|
||||
|
||||
HandleUnitTestOutput(sExpected);
|
||||
}
|
||||
|
||||
if (sReceived != "")
|
||||
{
|
||||
sReceived = _GetIndent() + HexColorString("Received: ", UNITTEST_PARAMETER_COLOR) +
|
||||
HexColorString(sReceived, UNITTEST_PARAMETER_RECEIVED);
|
||||
|
||||
HandleUnitTestOutput(sReceived);
|
||||
}
|
||||
Outdent();
|
||||
}
|
||||
|
||||
void DescribeTestTime(int nTime)
|
||||
{
|
||||
if (nTime <= 0)
|
||||
return;
|
||||
|
||||
Indent();
|
||||
string sTimer = _f(nTime / 1000000.0);
|
||||
string sTime = _GetIndent() + HexColorString("Test Time: ", UNITTEST_PARAMETER_COLOR) +
|
||||
HexColorString(sTimer + "s", UNITTEST_PARAMETER_INPUT);
|
||||
Outdent();
|
||||
|
||||
HandleUnitTestOutput(sTime);
|
||||
}
|
||||
|
||||
void DescribeGroupTime(int nTime)
|
||||
{
|
||||
if (nTime <= 0)
|
||||
return;
|
||||
|
||||
string sTimer = _f(nTime / 1000000.0);
|
||||
string sTime = _GetIndent() + HexColorString("Group Time: ", UNITTEST_PARAMETER_COLOR) +
|
||||
HexColorString(sTimer + "s", UNITTEST_PARAMETER_INPUT);
|
||||
|
||||
HandleUnitTestOutput(sTime);
|
||||
}
|
||||
|
||||
int Assert(string sTest, int bAssertion)
|
||||
{
|
||||
sTest = HexColorString("Test ", UNITTEST_TITLE_COLOR) +
|
||||
HexColorString(sTest, UNITTEST_NAME_COLOR);
|
||||
|
||||
HandleUnitTestOutput(_GetIndent() + sTest + TEST_DELIMITER + (bAssertion ? TEST_PASS : TEST_FAIL));
|
||||
|
||||
if (!bAssertion)
|
||||
HandleUnitTestFailure(sTest);
|
||||
|
||||
return UNITTEST_ALWAYS_EXPAND ? FALSE : bAssertion;
|
||||
}
|
||||
|
||||
int AssertGroup(string sGroup, int bAssertion)
|
||||
{
|
||||
sGroup = HexColorString("Test Group ", UNITTEST_TITLE_COLOR) +
|
||||
HexColorString(sGroup, UNITTEST_NAME_COLOR);
|
||||
|
||||
HandleUnitTestOutput(_GetIndent() + sGroup + TEST_DELIMITER + (bAssertion ? TEST_PASS : TEST_FAIL));
|
||||
Indent();
|
||||
|
||||
if (!bAssertion)
|
||||
HandleUnitTestFailure(sGroup);
|
||||
|
||||
return UNITTEST_ALWAYS_EXPAND ? FALSE : bAssertion;
|
||||
}
|
2352
_module/nss/util_i_variables.nss
Normal file
2352
_module/nss/util_i_variables.nss
Normal file
File diff suppressed because it is too large
Load Diff
2158
_module/nss/util_i_varlists.nss
Normal file
2158
_module/nss/util_i_varlists.nss
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@ void main ()
|
||||
|
||||
AddJournalQuestEntry("xprules", 1, oPlayer, FALSE, FALSE, FALSE);
|
||||
AddJournalQuestEntry("lvl_adj", 1, oPlayer, FALSE, FALSE, FALSE);
|
||||
AddJournalQuestEntry("JRNL_PRC8", 1, oPlayer, FALSE, FALSE, FALSE);
|
||||
|
||||
cs_DestroyStolenItems(oPlayer); // Destroy any stolen items
|
||||
cs_LimitGoldInBank(oPlayer, 20000000); // Limit gold in bank
|
||||
|
Reference in New Issue
Block a user