RoT2_PRC8/_module/nss/util_i_targeting.nss
Jaysyn904 379c5dce03 Added persistent player storage
Added persistent player storage.  Fixed store items.  Full compile.  Updated release archive.
2025-03-09 20:14:36 -04:00

909 lines
35 KiB
Plaintext

/// ----------------------------------------------------------------------------
/// @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);
}