1768 lines
63 KiB
Plaintext
1768 lines
63 KiB
Plaintext
#include "mn_i_uservars"
|
|
#include "mn_i_persist"
|
|
#include "mn_i_util"
|
|
|
|
// Varnames on module
|
|
const string MODULE_DEFAULT_CLEANUP_POLICY = "DEFAULT_CLEANUP_POLICY"; // (integer) Corresponds to CLEANUP_POLICY. Default value, module scope
|
|
const string MODULE_DEFAULT_CLEANUP_TARGETS = "DEFAULT_CLEANUP_TARGETS"; // (integer) Corresponds to OBJECT_TYPE or CLEANUP_TARGET, module scope
|
|
|
|
// Varnames on areas
|
|
const string AREA_EXPLORE_FULLEXPLORE = "EXPLORE_TOTAL"; // (integer) The sum of all explorationids + 1 (the 1 is from the EXPLORE_DISCOVERED). Manually calculated.
|
|
const string AREA_DEFAULT_CLEANUP_POLICY = "DEFAULT_CLEANUP_POLICY"; // (integer) Corresponds to CLEANUP_POLICY. Default value, area scope
|
|
const string AREA_DEFAULT_CLEANUP_TARGETS = "DEFAULT_CLEANUP_TARGETS"; // (integer) Corresponds to OBJECT_TYPE or CLEANUP_TARGET, area scope
|
|
const string AREA_BLOCK_TELEPORT_INCOMING = "BLOCK_TELEPORT_INCOMING"; // (integer) Corresponds to TELEPORT_*. Blocks _incoming_ teleportation to area.
|
|
const string AREA_BLOCK_TELEPORT_OUTGOING = "BLOCK_TELEPORT_OUTGOING"; // (integer) Corresponds to TELEPORT_*. Blocks _outgoing_ teleporation to area.
|
|
const string AREA_ID = "ID"; // (string) The id of the area. Defaults to resref if no ID is specified
|
|
|
|
// Varnames on objects
|
|
const string OBJ_EXPLORE_NODEID = "EXPLORE_ID"; // (integer) The explorationid of a exploration landmark trigger (integer).
|
|
const string OBJ_EXPLORE_NODEFOUND = "EXPLORE_FOUND_COMMENT"; // (string) The string spoken by a PC when he explores the trigger the first time
|
|
const string OBJ_EXPLORE_NODEBACK = "EXPLORE_BACK_COMMENT"; // (string) The string spoken by a PC when he finds the trigger again
|
|
|
|
const string OBJ_CLEANUP = "CLEANUP"; // (integer) Tag used for marking objects for cleanup. Corresponds to CLEANUP_POLICY constant.
|
|
const string OBJ_TELEPORT_PREFIX = "TELEPORT_";
|
|
const string OBJ_TELEPORT_DESTINATION = "_DESTINATION"; // (string) Tag used for specifying the destination of a teleportation item or placeable
|
|
const string OBJ_TELEPORT_DESTINATION_NAME = "_DESTINATION_NAME"; // (string) Name used for specifying the name of the destination of a teleportation item or placeable
|
|
const string OBJ_TELEPORT_TYPE = "_TYPE"; // (integer) Tag used for specifying the teleportation type of a teleportation item or placeable.
|
|
const string OBJ_TELEPORT_SPEED = "_SPEED"; // (integer) Tag used for specifying the teleportation type of a teleportation item or placeable.
|
|
const string OBJ_TELEPORT_REQ_QUEST_ID = "_REQ_QUEST_ID"; // (string) Quest id for the quest which must be completed before the teleportation can be performed.
|
|
const string OBJ_TELEPORT_ANIMATION = "_ANIMATION"; // (integer) Tag used for specifying the animation to be used by a teleportation item or placeable.
|
|
const string OBJ_TELEPORT_PARTY = "_PARTY"; // (integer) Whether teleportation affects entire party
|
|
|
|
const string OBJ_DESCRIPTION = "DESCRIPTION"; // (string) Tag used for specifying the description of the object. Generic field, with specific usage for specific cases.
|
|
const string OBJ_UNIQUE_POWER_ID = "UNIQUE_POWER_ID"; // (int) The UNIQUE_POWER_* constant specifying how to interpret the unique power of the item.
|
|
const string OBJ_UNIQUE_POWER_NAME = "UNIQUE_POWER_NAME"; // (string) The name of the script to run when the unique power is executed.
|
|
|
|
const string OBJ_ID = "ID"; // (string) The id of the object. Without an ID, no persistance functions will be allowed for this object.
|
|
|
|
// Varnames on PCs
|
|
const string PC_P_BLOCK_TELEPORT = "BLOCK_TELEPORT"; // (integer) Local teleportation override, restricting player outbound teleportation. Corresponds to TELEPORT_*
|
|
|
|
// Custom tokens
|
|
const int TOKEN_TELEPORTATION_NAME = 8000;
|
|
|
|
// General constants
|
|
const int EXPLORE_DISCOVERED = 1;
|
|
const int EXPLORE_POINT_1 = 2;
|
|
const int EXPLORE_POINT_2 = 4;
|
|
const int EXPLORE_POINT_3 = 8;
|
|
const int EXPLORE_POINT_4 = 16;
|
|
const int EXPLORE_POINT_5 = 32;
|
|
const int EXPLORE_POINT_6 = 64;
|
|
const int EXPLORE_POINT_7 = 128;
|
|
const int EXPLORE_POINT_8 = 256;
|
|
const int EXPLORE_POINT_9 = 512;
|
|
|
|
const int QUEST_UNKNOWN = 0;
|
|
const int QUEST_BEGUN = 1;
|
|
const int QUEST_COMPLETED = 2;
|
|
const int QUEST_REJECTED = 4;
|
|
const int QUEST_FAILED = 8;
|
|
const int QUEST_BLOCKED = 16;
|
|
|
|
const int TELEPORT_DYNAMIC = 1; // Spells, creatures, and items
|
|
const int TELEPORT_STATIONARY = 2; // Placeables
|
|
const int TELEPORT_DIVINE = 4; // Extraordinary, such as reborn power
|
|
const int TELEPORT_OOC = 8; // Crash ring etc.
|
|
const int TELEPORT_NONE = 0;
|
|
const int TELEPORT_ALL = 15;
|
|
|
|
const int TELEPORT_ANIMATION_NONE = 0;
|
|
const int TELEPORT_ANIMATION_UNSUMMONEFFECT = 1;
|
|
|
|
const int TELEPORT_SPEED_DELAYED = 0;
|
|
const int TELEPORT_SPEED_BLINK = 1;
|
|
|
|
const string TELEPORT_UNKNOWN_DESTINATION = "an unknown destination";
|
|
const string TELEPORT_TARGET_SELF = "SELF";
|
|
|
|
// positive number
|
|
const int CLEANUP_POLICY_NONE = 0; // Deletes nothing
|
|
const int CLEANUP_POLICY_DROPPED_BY_PLAYERS = 1; // Deletes player dropped objects
|
|
const int CLEANUP_POLICY_ENVIRONMENT_SPAWNS = 2; // Deletes automatic (encounter) spawns (including loot bags)
|
|
const int CLEANUP_POLICY_DM_SPAWNS = 4; // Deletes DM spawns
|
|
const int CLEANUP_POLICY_EXEMPT = 8; // Deletes stuff explicitly marked as exempt from cleanup!
|
|
const int CLEANUP_POLICY_UNMARKED = 16; // Deletes unmarked!
|
|
const int CLEANUP_POLICY_MARKED = 7; // Deletes all marked objects (except for exempt).
|
|
const int CLEANUP_POLICY_ALL = 31; // Deletes everything!
|
|
|
|
const int CLEANUP_TARGET_NONE = 0; // Matches none
|
|
const int CLEANUP_TARGET_ALL_VALID_TARGETS = 83; // Matches OBJECT_TYPE creature, item, area of effect and placeable, but not trigger, door, waypoint, store, or encounters
|
|
|
|
const string EXCHANGE_PREFIX = "EX_";
|
|
const string EXCHANGE_TAKE_ITEM = "_TAKE_ITEM_"; // Tag of taken item.
|
|
const string EXCHANGE_TAKE_ITEM_AMOUNT = "_TAKE_ITEM_AMOUNT_"; // Number of taken item to be taken.
|
|
const string EXCHANGE_TAKE_GOLD = "_TAKE_GOLD"; // Amount of gold taken.
|
|
const string EXCHANGE_TAKE_XP = "_TAKE_XP"; // Amount of XP taken.
|
|
const string EXCHANGE_QUEST_ID = "_QUEST_ID"; // Quest to increment when quest is performed.
|
|
const string EXCHANGE_QUEST_REPEAT = "_QUEST_REPEAT"; // Number of times the quest can be completed. -1 means unlimited.
|
|
const string EXCHANGE_MIN_LEVEL = "_MIN_LVL"; // Minimum total levels to make exchange (inclusive).
|
|
const string EXCHANGE_MAX_LEVEL = "_MAX_LVL"; // Maximum total level allowed in order to get this reward (inclusive).
|
|
const string EXCHANGE_ALLOW_BATCH = "_ALLOW_BATCH"; // Whether the NPC can loop through exchanges until no longer valie instead of only one at a time.
|
|
const string EXCHANGE_UNKNOWN_OK = "_UNKNOWN_OK"; // Whether the quest can be completed without it being open (known) for the player.
|
|
const string EXCHANGE_JOURNAL = "_JOURNAL"; // Whether the quest has journal entries.
|
|
|
|
const string EXCHANGE_GIVE_ITEM = "_GIVE_ITEM_"; // Resref of item to give
|
|
const string EXCHANGE_GIVE_ITEM_AMOUNT = "_GIVE_ITEM_AMOUNT_"; // Number of given item to give
|
|
const string EXCHANGE_GIVE_GOLD = "_GIVE_GOLD"; // Amount of gold to give
|
|
const string EXCHANGE_GIVE_XP = "_GIVE_XP"; // Amount of xp to give
|
|
const string EXCHANGE_OPEN_QUEST = "_OPEN_QUEST"; // Open quest as reward. If questID, happens when quest is marked as completed.
|
|
const string EXCHANGE_VISUALEFFECT = "_VFX"; // The VFX_FNF or VFX_IMP constant to play on the PC when the quest is completed, or 0 if none.
|
|
|
|
const int EXCHANGE_ALLOWED = 0;
|
|
const int EXCHANGE_INSUFFICIENT_GOLD = 1;
|
|
const int EXCHANGE_INSUFFICIENT_XP = 2;
|
|
const int EXCHANGE_INSUFFICIENT_ITEMS = 4;
|
|
const int EXCHANGE_LEVEL_TOO_LOW = 8;
|
|
const int EXCHANGE_LEVEL_TOO_HIGH = 16;
|
|
const int EXCHANGE_QUEST_ALREADY_COMPLETED = 32;
|
|
const int EXCHANGE_QUEST_BLOCKED = 64;
|
|
const int EXCHANGE_QUEST_FAILED = 128;
|
|
const int EXCHANGE_QUEST_REJECTED = 256;
|
|
const int EXCHANGE_QUEST_MISSING_ITEM = 512;
|
|
const int EXCHANGE_QUEST_UNKNOWN = 1024;
|
|
|
|
const int EXCHANGE_SUCCEEDED = 0;
|
|
const int EXCHANGE_FAILED = 1;
|
|
|
|
const int UNIQUE_POWER_BY_LOCAL_HANDLER = 0;
|
|
const int UNIQUE_POWER_BY_TAG = 1;
|
|
const int UNIQUE_POWER_BY_RESREF = 2;
|
|
const int UNIQUE_POWER_BY_SCRIPT = 3;
|
|
const int UNIQUE_POWER_TELEPORT = 4;
|
|
const int UNIQUE_POWER_MAP = 5;
|
|
|
|
|
|
// Please notice that when using local caching of quest status, this cache isn't reset when questDB is (re)initialized
|
|
// Since I cannot iterate through variables on user, I have disabled this functionality for the time being.
|
|
const int QUESTS_USE_LOCAL_CACHE = FALSE;
|
|
|
|
|
|
// ********** PROTOTYPES **********
|
|
|
|
// ***** Quest scripts *****
|
|
|
|
// Returns the QUEST_* status code
|
|
int GetQuestStatus(object oPC, string questID);
|
|
|
|
// Returns TRUE if the QUEST_* questStatus corresponds to the current quest-status for that quest.
|
|
int CheckQuestStatus(object oPC, string questID, int questStatus);
|
|
|
|
// Sets the QUEST_* status for the quest. If it is a numbered quest, use SetGlobalQuestCompletedTimes instead.
|
|
void SetQuestStatus(object oPC, string questID, int status);
|
|
|
|
// Sets the number of times the quest has been completed. Must be at least 1.
|
|
void SetQuestCompletedTimes(object oPC, string questID, int number);
|
|
|
|
// Gets the number of times the quest has been completed, or -1 if not applicable.
|
|
int GetQuestCompletedTimes(object oPC, string questID);
|
|
|
|
// Returns the QUEST_* status code for the global quest
|
|
int GetGlobalQuestStatus(string entityId, string questID);
|
|
|
|
// Returns TRUE if the QUEST_* questStatus corresponds to the current quest-status for that global quest.
|
|
int CheckGlobalQuestStatus(string entityId, string questID, int questStatus);
|
|
|
|
// Sets the QUEST_* status for the global quest. If it is a numbered quest, use SetGlobalQuestCompletedTimes instead.
|
|
void SetGlobalQuestStatus(string entityId, string questID, int status);
|
|
|
|
// Sets the number of times the global quest has been completed. Must be at least 1.
|
|
void SetGlobalQuestCompletedTimes(string entityId, string questID, int number);
|
|
|
|
// Gets the number of times the global quest has been completed, or -1 if not applicable.
|
|
int GetGlobalQuestCompletedTimes(string entityId, string questID);
|
|
|
|
// Helper method. Do not call directly
|
|
void SetPQuestStatus(object obj, string questID, int status);
|
|
|
|
// Helper method. Do not call directly
|
|
int GetPQuestStatus(object obj, string questID);
|
|
|
|
// Helper method. Do not call directly
|
|
void SetGlobalPQuestStatus(string globalId, string questID, int status);
|
|
|
|
// Helper method. Do not call directly
|
|
int GetGlobalPQuestStatus(string globalId, string questID);
|
|
|
|
// Exploration scripts
|
|
|
|
// Calls the FoundExploreArea and RevealExploredArea methods in succession.
|
|
// Convenience method for calling from within area onEnter script.
|
|
void WrapExploreOnEnterArea(object oPC, int exploreFull);
|
|
|
|
// Updates exploration status for first entering an area, and gives bonus if applicable.
|
|
void FoundExploreArea(object oPC, string areaId);
|
|
|
|
// Reveals entered area to player, if it is explored.
|
|
// This is the case if the player has explored all landmarks or memorized has memorized a map of the area.
|
|
void RevealExploredArea(object oPC, string areaId, int exploreFull);
|
|
|
|
// Calls the ExploreNodeFound and RevealsExploredArea methods in succession.
|
|
// Convenience method for calling from within trigger onEnter script.
|
|
void WrapExploreNodeFound(object oPC, int exploreID, int exploreFull);
|
|
|
|
// Updates exploration status for first entering an exploration node/landmark.
|
|
void ExploreNodeFound(object oPC, int exploreID);
|
|
|
|
// Handles reading or examining of a map. Returns text to show to player. Called from onActivated or (with events) from examining the map.
|
|
string ReadExploreMap(object oPC, object oMap);
|
|
// 'or' with total-1
|
|
|
|
// Helper method. Do not call directly
|
|
int GetPExplored(object obj, string areaID);
|
|
|
|
// Helper method. Do not call directly
|
|
void SetPExplored(object obj, string areaID, int status);
|
|
|
|
// Helper method. Do not call directly
|
|
void AddPExplored(object obj, string areaID, int status);
|
|
|
|
// Admin scripts
|
|
|
|
// Resets server. Delay is in minutes.
|
|
void ResetServer(int delay=0);
|
|
|
|
// Misc scripts
|
|
|
|
// Wraps around getLocalInt, so that marker variables can be imported from database
|
|
int GetMarkerInt(object obj, string varname, int persistantVar);
|
|
|
|
// Wraps around getLocalFloat, so that marker variables can be imported from database
|
|
float GetMarkerFloat(object obj, string varname, int persistantVar);
|
|
|
|
// Wraps around getLocalString, so that marker variables can be imported from database
|
|
string GetMarkerString(object obj, string varname, int persistantVar);
|
|
|
|
// Wraps around setLocalInt, so that marker variables can be exported to database
|
|
void SetMarkerInt(object obj, string varname, int value, int persistantVar);
|
|
|
|
// Wraps around setLocalFloat, so that marker variables can be exported to database
|
|
void SetMarkerFloat(object obj, string varname, float value, int persistantVar);
|
|
|
|
// Wraps around setLocalString, so that marker variables can be exported to database
|
|
void SetMarkerString(object obj, string varname, string value, int persistantVar);
|
|
|
|
// Wraps around DeleteLocalString, so that marker variables can be deleted from database
|
|
void DeleteMarkerString(object obj, string varname, int persistantVar);
|
|
|
|
// Wraps around DeleteLocalFloat, so that marker variables can be deleted from database
|
|
void DeleteMarkerFloat(object obj, string varname, int persistantVar);
|
|
|
|
// Wraps around DeleteLocalInt, so that marker variables can be deleted from database
|
|
void DeleteMarkerInt(object obj, string varname, int persistantVar);
|
|
|
|
// Returns the effective level from an xp amount
|
|
int GetLevelFromXP(int xp);
|
|
|
|
// Returns the minimum xp required for the given level.
|
|
int GetXPMinForLevel(int level);
|
|
|
|
// Return the number of xp needed to go from current xp to wanted level (if 0, then the amount needed to go up one level.)
|
|
int GetXPNeededForLevel(int currentXP, int wantedLevel =0);
|
|
|
|
// Checks if PC has the necessary prerequisites for getting a reward
|
|
int CheckExchangeBlocked(object PC, object NPC, int index = 1);
|
|
|
|
// Takes prerequisite items from PC, and give reward to PC
|
|
void PerformExchange(object PC, object NPC, int index = 1);
|
|
|
|
// Creates items as normal, but also initializes necessary local variables. Always call this instead of CreateItemOnObject
|
|
object CreateItemOnObjectMN( string sItemTemplate, object oTarget=OBJECT_SELF, int nStackSize=1, string sNewTag="", string creationOptions="" );
|
|
|
|
int NewValidate(object oPC);
|
|
|
|
int LevelupValidate(object oPC);
|
|
|
|
void StripPlayerOfItems(object oPC);
|
|
|
|
int ProcessIncomingPlayer(object oPC);
|
|
|
|
void FlushPInventory(object container);
|
|
|
|
void StorePInventory(object container, int emptyInventoryAfterwards = TRUE);
|
|
|
|
void GetStoredPInventory(object container, int emptyInventoryBefore = FALSE);
|
|
|
|
// Returns the Alangara ID for the requested object
|
|
string GetId(object obj);
|
|
|
|
// Cleans up the target area, deleting all masked OBJECT_TYPE objects with masked CLEANUP_POLICY flags.
|
|
void CleanupArea(object area, int cleanupTargets, int cleanupPolicy);
|
|
|
|
// Delete an object. If the object has an inventory, also delete the inventory, recursively (e.g. inventory of inventory items are also deleted)
|
|
void RecursiveDeleteObject(object obj, float timeOffset = 0.0, int ignorePlot = FALSE);
|
|
|
|
// Checks if flag is set in value.
|
|
int CheckFlag(int value, int flag);
|
|
|
|
// RestXyz
|
|
|
|
// Teleport
|
|
|
|
// Teleport a creature. Information about the teleportation is read from the teleporter object.
|
|
void DoTeleport( object oPC, object teleporter, int index = 1 , int teleportBlocksMovement = TRUE);
|
|
|
|
// Teleport a creature to the waypoint with the specified tag, using the specified method (sourceType). The script checks for teleportation blocking.
|
|
void DoScriptTeleport( object oPC, object destinationObject, int teleportationType = TELEPORT_OOC, int teleportationAnimation = TELEPORT_ANIMATION_NONE, int teleportationSpeed = TELEPORT_SPEED_BLINK, string questRequired = "", int teleportBlocksMovement = TRUE);
|
|
|
|
|
|
// Sends message to first PC
|
|
void Debug(string msg);
|
|
|
|
// ********** Business Methods **********
|
|
|
|
int CheckFlag(int value, int flag)
|
|
{
|
|
return ( (value & flag) != 0 );
|
|
}
|
|
|
|
// Helper method, converts varname plus index to the name of the variable to read from.
|
|
string TeleportVar(string var, int index)
|
|
{
|
|
string returnValue = OBJ_TELEPORT_PREFIX+IntToString(index)+var;
|
|
return returnValue;
|
|
}
|
|
|
|
int ShowTeleportConversationOption( object oPC, object teleporter, int index = 1 )
|
|
{
|
|
int showNode = TRUE;
|
|
|
|
string tokenText = TELEPORT_UNKNOWN_DESTINATION;
|
|
|
|
// Retrieve destination
|
|
string destinationTag = GetLocalString(teleporter, TeleportVar(OBJ_TELEPORT_DESTINATION , index) );
|
|
if ( destinationTag == "" )
|
|
{
|
|
// No destination for this index, so don't show the node
|
|
return FALSE;
|
|
}
|
|
|
|
// Retrieve custom text
|
|
// If text is set on the teleporter, it is used. Else, check if the description is set on the destination, and if
|
|
// so, use that. If neither text is filled out, set the text on the teleporter to the unknown constant.
|
|
string destinationText = GetLocalString(teleporter, TeleportVar(OBJ_TELEPORT_DESTINATION_NAME , index) );
|
|
|
|
if (destinationText == "")
|
|
{
|
|
// Destination on teleporter was not set in toolset.
|
|
// Try to read value from destination instead
|
|
object destWp = GetWaypointByTag(destinationTag);
|
|
if (GetIsObjectValid(destWp))
|
|
{
|
|
destinationText = GetLocalString(destWp, OBJ_DESCRIPTION) ;
|
|
}
|
|
|
|
// If text wasn't on destination description either, then default it to the unknown constant.
|
|
// In any case, cache locally on teleporter for later lookups (so we don't have to seach for the destination
|
|
// each time).
|
|
if (destinationText == "")
|
|
{
|
|
SetLocalString(teleporter, TeleportVar(OBJ_TELEPORT_DESTINATION_NAME , index), TELEPORT_UNKNOWN_DESTINATION);
|
|
}
|
|
else
|
|
{
|
|
SetLocalString(teleporter, TeleportVar(OBJ_TELEPORT_DESTINATION_NAME , index), destinationText);
|
|
}
|
|
}
|
|
|
|
|
|
// Check quest prereq
|
|
int known = TRUE;
|
|
string questId = GetLocalString(teleporter, TeleportVar(OBJ_TELEPORT_REQ_QUEST_ID , index) );
|
|
if ( questId != "")
|
|
{
|
|
known = CheckQuestStatus( oPC, questId, QUEST_COMPLETED );
|
|
}
|
|
|
|
if (known && destinationText != "")
|
|
{
|
|
tokenText = destinationText;
|
|
}
|
|
|
|
SetCustomToken(TOKEN_TELEPORTATION_NAME+index, tokenText);
|
|
|
|
return showNode;
|
|
}
|
|
|
|
void DoScriptTeleport( object oPC, object destinationObject, int teleportationType = TELEPORT_OOC, int teleportationAnimation = TELEPORT_ANIMATION_NONE, int teleportationSpeed = TELEPORT_SPEED_BLINK, string questRequired = "", int teleportBlocksMovement = TRUE)
|
|
{
|
|
if (oPC == destinationObject)
|
|
{
|
|
// Trying to teleport to itself
|
|
return;
|
|
}
|
|
|
|
object originArea = GetArea(oPC);
|
|
|
|
location destination = GetLocation ( destinationObject );
|
|
object destinationArea = GetAreaFromLocation(destination);
|
|
|
|
// Check for errors, abort if any error found.
|
|
if ( !GetIsObjectValid(oPC) || ! GetIsObjectValid(destinationObject) || ( !GetIsPC(oPC) && GetObjectType(oPC) != OBJECT_TYPE_CREATURE ) || !GetIsObjectValid(originArea) || !GetIsObjectValid(destinationArea) || !GetIsObjectValid(destinationArea) || teleportationType < 1 || teleportationType > TELEPORT_ALL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check if teleport is blocked
|
|
int outgoingBlock = GetLocalInt( originArea, AREA_BLOCK_TELEPORT_OUTGOING );
|
|
int incomingBlock = GetLocalInt( destinationArea, AREA_BLOCK_TELEPORT_INCOMING );
|
|
int personalBlock = GetLocalInt( oPC, PC_P_BLOCK_TELEPORT );
|
|
|
|
int blocked = CheckFlag(teleportationType, outgoingBlock) || CheckFlag(teleportationType, incomingBlock) || CheckFlag(teleportationType, personalBlock);
|
|
|
|
// Check for attunement, if applicable
|
|
int attuned = TRUE;
|
|
if ( questRequired != "")
|
|
{
|
|
attuned = CheckQuestStatus(oPC, questRequired, QUEST_COMPLETED);
|
|
}
|
|
|
|
// Perform the teleportation, unless either blocked or unattuned
|
|
if (blocked)
|
|
{
|
|
FloatingTextStringOnCreature( "Something interferes with your teleportation", oPC, FALSE );
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DAZED_S), oPC);
|
|
}
|
|
else if (!attuned)
|
|
{
|
|
FloatingTextStringOnCreature( "Your lack of attunement to the teleportation source prevents your translocation.", oPC, FALSE );
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DAZED_S), oPC);
|
|
}
|
|
else
|
|
{
|
|
AssignCommand(oPC, ClearAllActions());
|
|
|
|
float delay = 3.0f;
|
|
switch (teleportationSpeed)
|
|
{
|
|
case TELEPORT_SPEED_BLINK:
|
|
delay = 0.0f;
|
|
break;
|
|
case TELEPORT_SPEED_DELAYED:
|
|
delay = 3.0f;
|
|
break;
|
|
}
|
|
|
|
AssignCommand(oPC, ClearAllActions());
|
|
if (delay > 0.0f)
|
|
{
|
|
if (teleportBlocksMovement)
|
|
{
|
|
effect blockMovement = EffectCutsceneImmobilize();
|
|
FloatingTextStringOnCreature( "Debug: Block movement", oPC, FALSE );
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, blockMovement, oPC, delay);
|
|
// DelayCommand(delay, AssignCommand(oPC, RemoveEffect(oPC, blockMovement)));
|
|
}
|
|
DelayCommand(delay, AssignCommand(oPC, ActionJumpToLocation(destination)));
|
|
}
|
|
else
|
|
{
|
|
if (teleportBlocksMovement)
|
|
{
|
|
effect blockMovement = EffectCutsceneImmobilize();
|
|
FloatingTextStringOnCreature( "Debug: Block movement", oPC, FALSE );
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, blockMovement, oPC, 0.1f);
|
|
// DelayCommand(delay, AssignCommand(oPC, RemoveEffect(oPC, blockMovement)));
|
|
}
|
|
AssignCommand(oPC, ActionJumpToLocation(destination));
|
|
}
|
|
|
|
// Play animation if applicable
|
|
switch (teleportationAnimation)
|
|
{
|
|
case TELEPORT_ANIMATION_UNSUMMONEFFECT:
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_UNSUMMON), oPC);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_UNSUMMON), destination);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void DoTeleport( object oPC, object teleporter, int index = 1, int teleportBlocksMovement = TRUE )
|
|
{
|
|
string destinationTag = GetLocalString(teleporter, TeleportVar( OBJ_TELEPORT_DESTINATION, index ) );
|
|
string questRequired = GetLocalString(teleporter, TeleportVar( OBJ_TELEPORT_REQ_QUEST_ID, index ) );
|
|
int sourceType = GetLocalInt(teleporter, TeleportVar( OBJ_TELEPORT_TYPE, index ) );
|
|
int teleportationAnimation = GetLocalInt(teleporter, TeleportVar( OBJ_TELEPORT_ANIMATION, index ) );
|
|
int teleportSpeed = GetLocalInt(teleporter, TeleportVar( OBJ_TELEPORT_SPEED, index ) );
|
|
int partyTeleport = GetLocalInt(teleporter, TeleportVar( OBJ_TELEPORT_PARTY, index ) );
|
|
|
|
|
|
object targetObject;
|
|
if ( destinationTag == TELEPORT_TARGET_SELF )
|
|
{
|
|
targetObject = oPC;
|
|
}
|
|
else
|
|
{
|
|
targetObject = GetWaypointByTag(destinationTag);
|
|
}
|
|
|
|
if ( partyTeleport )
|
|
{
|
|
object partyMember = GetFirstFactionMember(oPC, TRUE);
|
|
while(GetIsObjectValid(partyMember) == TRUE)
|
|
{
|
|
DoScriptTeleport( partyMember, targetObject, sourceType, teleportationAnimation, teleportSpeed, questRequired, teleportBlocksMovement);
|
|
partyMember = GetNextFactionMember(oPC, TRUE);
|
|
}
|
|
|
|
// We always disable the animation for NPC members - let's try to keep down the VFX ;-)
|
|
object partyMemberNpc = GetFirstFactionMember(oPC, FALSE);
|
|
while(GetIsObjectValid(partyMemberNpc) == TRUE)
|
|
{
|
|
DoScriptTeleport( partyMemberNpc, targetObject, sourceType, TELEPORT_ANIMATION_NONE, teleportSpeed, questRequired, teleportBlocksMovement);
|
|
partyMemberNpc = GetNextFactionMember(oPC, FALSE);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DoScriptTeleport( oPC, targetObject, sourceType, teleportationAnimation, teleportSpeed, questRequired, teleportBlocksMovement);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void RecursiveDeleteObject(object obj, float timeOffset = 0.0, int ignorePlot = TRUE)
|
|
{
|
|
if ( !GetIsPC(obj) && ( CheckFlag(GetObjectType(obj), (OBJECT_TYPE_PLACEABLE|OBJECT_TYPE_CREATURE|OBJECT_TYPE_ITEM|OBJECT_TYPE_AREA_OF_EFFECT) ) ) )
|
|
{
|
|
if (GetObjectType(obj) == OBJECT_TYPE_CREATURE)
|
|
{
|
|
// Delete equipped items
|
|
// SendMessageToPC(GetFirstPC(), "Check equipped");
|
|
int slot = 0;
|
|
for (slot = 0; slot < NUM_INVENTORY_SLOTS; slot++)
|
|
{
|
|
object item = GetItemInSlot(slot, obj);
|
|
if ( GetIsObjectValid(item) )
|
|
{
|
|
SetPlotFlag( item, FALSE );
|
|
DestroyObject ( item, timeOffset+0.1 );
|
|
// SendMessageToPC(GetFirstPC(), "Destroyed "+GetName(item));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GetHasInventory(obj))
|
|
{
|
|
// Delete inventory as well
|
|
// SendMessageToPC(GetFirstPC(), "Check inventory");
|
|
object oItem = GetFirstItemInInventory(obj);
|
|
while( GetIsObjectValid( oItem ))
|
|
{
|
|
SetPlotFlag( oItem, FALSE );
|
|
|
|
DestroyObject( oItem, GetHasInventory( oItem) ? timeOffset+0.2 : timeOffset+0.1);
|
|
// SendMessageToPC(GetFirstPC(), "Destroyed "+GetName(oItem));
|
|
oItem = GetNextItemInInventory(obj);
|
|
}
|
|
}
|
|
|
|
// Delete object
|
|
if (ignorePlot)
|
|
{
|
|
SetPlotFlag( obj, FALSE );
|
|
}
|
|
|
|
DestroyObject (obj, timeOffset+0.3);
|
|
// SendMessageToPC(GetFirstPC(), "Destroyed "+GetName(obj));
|
|
}
|
|
|
|
}
|
|
|
|
void CleanupArea(object area, int cleanupTargets, int cleanupPolicy)
|
|
{
|
|
if ( GetIsObjectValid( area ) )
|
|
{
|
|
object obj = GetFirstObjectInArea( area );
|
|
while ( GetIsObjectValid ( obj ) )
|
|
{
|
|
// Never delete PCs and DMs, or their familars/followers
|
|
if ( GetIsPC(obj) || (GetMaster(obj) != OBJECT_INVALID ) )
|
|
{
|
|
// do nothing
|
|
// SendMessageToPC(GetFirstPC(), "Do nothing");
|
|
|
|
}
|
|
// Else check if target is valid
|
|
else if ( (cleanupTargets != CLEANUP_TARGET_NONE) && ( (cleanupTargets & GetObjectType(obj)) != 0 ) )
|
|
{
|
|
// SendMessageToPC(GetFirstPC(), "Valid target");
|
|
// Check if object flag corresponds to the chosen cleanup policy
|
|
int cleanupTag = GetLocalInt(obj, OBJ_CLEANUP);
|
|
|
|
// Ok to delete if both unmarked and if unmarked deletion is ok, or if marked and the mark corresponds with the cleanup policy.
|
|
if ( ( cleanupTag == 0 && (cleanupPolicy & CLEANUP_POLICY_UNMARKED) != 0 ) || ( cleanupTag != 0 && (cleanupTag & cleanupPolicy ) != 0 ) )
|
|
{
|
|
// SendMessageToPC(GetFirstPC(), "Deletion is ok");
|
|
|
|
// Delete object, and it's inventory. Always delete inventory, disregarding cleanup tag.
|
|
RecursiveDeleteObject(obj);
|
|
}
|
|
}
|
|
|
|
obj = GetNextObjectInArea( area );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***** QUEST RELATED METHODS *****
|
|
int GetQuestStatus(object oPC, string questID)
|
|
{
|
|
int returnValue = 0;
|
|
|
|
if (QUESTS_USE_LOCAL_CACHE)
|
|
{
|
|
returnValue = GetLocalInt(oPC, "Q_"+questID);
|
|
}
|
|
|
|
if (returnValue == 0)
|
|
{
|
|
returnValue = GetPQuestStatus(oPC, questID);
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
int CheckQuestStatus(object oPC, string questID, int questStatus)
|
|
{
|
|
int status = GetPQuestStatus(oPC, questID);
|
|
|
|
int returnValue = ( (questStatus == QUEST_UNKNOWN && status == QUEST_UNKNOWN) || ( (status & questStatus) != 0 ) );
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
void SetQuestStatus(object oPC, string questID, int status)
|
|
{
|
|
SetPQuestStatus(oPC, questID, status);
|
|
int journalState = status;
|
|
if (status > 20)
|
|
{
|
|
// No seperate entries for multiple completion quests.
|
|
journalState = 20;
|
|
}
|
|
|
|
/* No journal support for quests yet
|
|
if (journalState == QUEST_UNKNOWN)
|
|
{
|
|
RemoveJournalQuestEntry(questID, oPC, FALSE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
AddJournalQuestEntry(questID, journalState, oPC, FALSE, FALSE, TRUE);
|
|
}
|
|
|
|
if (QUESTS_USE_LOCAL_CACHE)
|
|
{
|
|
SetLocalInt(oPC, "Q_"+questID, status);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void SetQuestCompletedTimes(object oPC, string questID, int number)
|
|
{
|
|
SetQuestStatus(oPC, questID, number+20);
|
|
}
|
|
|
|
// Returns -1 for queststatus below 21, or queststatus-20 otherwise.
|
|
int GetQuestCompletedTimes(object oPC, string questID)
|
|
{
|
|
int returnValue = -1;
|
|
|
|
int questStatus = GetPQuestStatus(oPC, questID);
|
|
if (questStatus > 20)
|
|
{
|
|
returnValue = questStatus-20;
|
|
}
|
|
return returnValue;
|
|
}
|
|
|
|
// Calls the FoundExploreArea and RevealExploredArea methods in succession.
|
|
// Convenience method for calling from within area onEnter script.
|
|
void WrapExploreOnEnterArea(object oPC, int exploreFull)
|
|
{
|
|
|
|
}
|
|
|
|
// Updates exploration status for first entering an area, and gives bonus if applicable.
|
|
void FoundExploreArea(object oPC, string areaId)
|
|
{
|
|
|
|
}
|
|
|
|
// Reveals entered area to player, if it is explored.
|
|
// This is the case if the player has explored all landmarks or memorized has memorized a map of the area.
|
|
void RevealExploredArea(object oPC, string areaId, int exploreFull)
|
|
{
|
|
|
|
}
|
|
|
|
// Calls the ExploreNodeFound and RevealsExploredArea methods in succession.
|
|
// Convenience method for calling from within trigger onEnter script.
|
|
void WrapExploreNodeFound(object oPC, int exploreID, int exploreFull)
|
|
{
|
|
|
|
}
|
|
|
|
// Updates exploration status for first entering an exploration node/landmark.
|
|
void ExploreNodeFound(object oPC, int exploreID)
|
|
{
|
|
int exploration = GetPExplored(oPC, GetId(GetArea(oPC)));
|
|
|
|
}
|
|
|
|
// Handles reading or examining of a map. Returns text to show to player. Called from onActivated or (with events) from examining the map.
|
|
string ReadExploreMap(object oPC, object oMap)
|
|
{
|
|
string returnValue = "";
|
|
|
|
// int oMap = GetLocalInt
|
|
|
|
return returnValue;
|
|
}
|
|
// 'or' with total-1
|
|
|
|
// ***** ADMIN METHODS *****
|
|
|
|
void ResetServer(int delay=0)
|
|
{
|
|
// SendMessageToPC( GetFirstPC(), "Entering server reset" );
|
|
if (delay != 0)
|
|
{
|
|
object source = GetObjectByTag("SRVMSG");
|
|
AssignCommand(source, ActionSpeakString("Warning! Server will shut down in "+IntToString(delay*60)+" seconds!", TALKVOLUME_SHOUT) );
|
|
DelayCommand( IntToFloat(delay * 60), SetLocalString(GetModule(), "NWNX!RESETPLUGIN!SHUTDOWN", "0") );
|
|
}
|
|
else
|
|
{
|
|
// Reset
|
|
// TODO Log reset action
|
|
SetLocalString(GetModule(), "NWNX!RESETPLUGIN!SHUTDOWN", "0");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ********** Persistance helper methods **********
|
|
|
|
// ***** QUEST RELATED METHODS *****
|
|
|
|
// Sets the quest-status for the given PC
|
|
void SetPQuestStatus(object obj, string questID, int status)
|
|
{
|
|
StorePInt( QUESTPROGRESS_TABLE, GetId(obj), questID, status );
|
|
}
|
|
|
|
// Gets the quest-status for the given PC
|
|
int GetPQuestStatus(object obj, string questID)
|
|
{
|
|
return FetchPInt(QUESTPROGRESS_TABLE, GetId(obj), questID );
|
|
}
|
|
|
|
// Sets the quest-status for the given PC
|
|
void SetGlobalPQuestStatus(string globalId, string questID, int status)
|
|
{
|
|
StorePInt( QUESTPROGRESS_TABLE, globalId, questID, status );
|
|
}
|
|
|
|
// Gets the quest-status for the given PC
|
|
int GetGlobalPQuestStatus(string globalId, string questID)
|
|
{
|
|
return FetchPInt(QUESTPROGRESS_TABLE, globalId, questID );
|
|
}
|
|
|
|
// ***** EXPLORATION RELATED METHODS *****
|
|
|
|
// Gets the mapexploration-status for the given PC
|
|
int GetPExplored(object obj, string areaID)
|
|
{
|
|
// SendMessageToPC(GetFirstPC(), "FetchPInt("+EXPLORATION_TABLE+", "+GetId(obj)+", "+areaID+");");
|
|
return FetchPInt(EXPLORATION_TABLE, GetId(obj), areaID );
|
|
}
|
|
|
|
// Sets the mapexploration-status for the given PC
|
|
void SetPExplored(object obj, string areaID, int status)
|
|
{
|
|
// SendMessageToPC(GetFirstPC(), "StorePInt("+EXPLORATION_TABLE+", "+GetId(obj)+", "+areaID+", "+IntToString(status)+");");
|
|
StorePInt(EXPLORATION_TABLE, GetId(obj), areaID, status );
|
|
}
|
|
|
|
// Updates the mapexploration-status for the given PC
|
|
void AddPExplored(object obj, string areaID, int status)
|
|
{
|
|
int oldValue = GetPExplored(obj, areaID);
|
|
int newValue = oldValue | status;
|
|
// SendMessageToPC(GetFirstPC(), "StorePInt("+EXPLORATION_TABLE+", "+GetId(obj)+", "+areaID+", "+IntToString(newValue)+");");
|
|
StorePInt(EXPLORATION_TABLE, GetId(obj), areaID, newValue );
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
int NewValidate(object oPC)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
int LevelupValidate(object oPC)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void StripPlayerOfItems(object oPC)
|
|
{
|
|
object item = GetFirstItemInInventory(oPC);
|
|
while (item != OBJECT_INVALID)
|
|
{
|
|
DestroyObject(item);
|
|
item = GetNextItemInInventory(oPC);
|
|
}
|
|
TakeGoldFromCreature(GetGold(oPC), oPC, TRUE);
|
|
}
|
|
|
|
int ProcessIncomingPlayer(object oPC)
|
|
{
|
|
string accountName = EncodeSpecialChars( GetPCPlayerName(oPC) );
|
|
string characterName = EncodeSpecialChars( GetName(oPC) );
|
|
string cdkey = GetPCPublicCDKey(oPC);
|
|
int id = ResolveUserID(accountName, characterName);
|
|
|
|
if (IsAccountOrKeyBanned( accountName, cdkey ) )
|
|
{
|
|
BootPC(oPC);
|
|
string errorMessage = "Warning - account "+accountName+" tried to login with key "+cdkey+". One of both of these are registered as banned!";
|
|
SendMessageToAllDMs(errorMessage);
|
|
DbLog(errorMessage, LOGTYPE_UNATHORIZED, "", LOGSUSPECT_VIOLATION);
|
|
}
|
|
|
|
else if ( id == 0 )
|
|
{
|
|
int validated = TRUE;
|
|
// Not in DB
|
|
// Verify correctness of new oPC
|
|
if (GetXP(oPC) != 0 )
|
|
{
|
|
string errorMessage = "Warning - account "+accountName+" tried to login with new character named "+characterName+", with more than 0 XP!";
|
|
SendMessageToAllDMs(errorMessage);
|
|
DbLog(errorMessage, LOGTYPE_UNATHORIZED, "", LOGSUSPECT_VIOLATION);
|
|
validated = FALSE;
|
|
}
|
|
validated = validated & NewValidate(oPC);
|
|
|
|
// Verify that the player has no token
|
|
|
|
if (validated)
|
|
{
|
|
// Strip char of start items
|
|
StripPlayerOfItems(oPC);
|
|
// Enter player in database
|
|
// Give token and start equipment/gold to player, and set XP to 1
|
|
SetXP(oPC, 1);
|
|
// Set local vars on character (corresponding to a ok login)
|
|
SetLocalInt(oPC, "auth", AUTH_PLAYER);
|
|
SetLocalInt(oPC, "id", ResolveUserID(accountName, characterName, cdkey) );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
int validated = TRUE;
|
|
// Check for valid cd key
|
|
if (ResolveUserID(accountName, characterName, cdkey) == 0)
|
|
{
|
|
|
|
}
|
|
// Check for valid token
|
|
// Check for valid pass-code
|
|
}
|
|
if (GetXP(oPC) == 0)
|
|
{
|
|
object token = GetItemPossessedBy(oPC, "mn_servertoken");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// This method deletes the contents of the given object's inventory from the database
|
|
void FlushPInventory(object container)
|
|
{
|
|
ClearTable(OBJECTSTORAGE_TABLE, GetTag(container), "");
|
|
}
|
|
|
|
// This method stores the contents of the given object's inventory to the database. Optional parameter empties the inventory afterwards.
|
|
// This version always flushes the existing inventory! (This to avoid having to implement logic for finding the next unique ID)
|
|
void StorePInventory(object container, int emptyInventoryAfterwards = TRUE)
|
|
{
|
|
// Flush persistant inventory
|
|
FlushPInventory(container);
|
|
|
|
// Store items persistently in inventory
|
|
int counter = 1;
|
|
object item = GetFirstItemInInventory(container);
|
|
object skip;
|
|
string containerid = GetTag(container);
|
|
{
|
|
while (GetIsObjectValid(item))
|
|
{
|
|
StorePObject(OBJECTSTORAGE_TABLE, containerid, "SLOT_"+IntToString(counter), item );
|
|
counter++;
|
|
if (GetHasInventory(item))
|
|
{
|
|
skip = GetFirstItemInInventory(item);
|
|
while (GetIsObjectValid(skip))
|
|
{
|
|
GetNextItemInInventory(container);
|
|
skip = GetNextItemInInventory(item);
|
|
}
|
|
}
|
|
item = GetNextItemInInventory(container);
|
|
}
|
|
}
|
|
if (emptyInventoryAfterwards == TRUE)
|
|
{
|
|
object item = GetFirstItemInInventory(container);
|
|
while (GetIsObjectValid(item))
|
|
{
|
|
DestroyObject(item);
|
|
item = GetNextItemInInventory(container);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This method gets the contents of the given object's inventory from the database and adds it to the object's inventory.
|
|
void GetStoredPInventory(object container, int emptyInventoryBefore = FALSE)
|
|
{
|
|
// Empty local inventory before loading new stuff
|
|
if (emptyInventoryBefore)
|
|
{
|
|
object item = GetFirstItemInInventory(container);
|
|
while (GetIsObjectValid(item))
|
|
{
|
|
DestroyObject(item);
|
|
item = GetNextItemInInventory(container);
|
|
}
|
|
}
|
|
|
|
// Load persistent inventory into chest
|
|
int counter = 1;
|
|
int loop = TRUE;
|
|
object item;
|
|
string containerID = GetTag(container);
|
|
|
|
while (loop)
|
|
{
|
|
item = FetchPObject(OBJECTSTORAGE_TABLE, containerID, "SLOT_" + IntToString(counter), container );
|
|
if (!GetIsObjectValid(item))
|
|
loop = FALSE;
|
|
else
|
|
counter++;
|
|
}
|
|
}
|
|
|
|
string GetId(object obj)
|
|
{
|
|
string id = "";
|
|
|
|
if (GetIsObjectValid(obj))
|
|
{
|
|
if (GetIsDM(obj))
|
|
{
|
|
id = "DM";
|
|
}
|
|
else if (GetIsPC(obj))
|
|
{
|
|
id = GetLocalString(obj, OBJ_ID);
|
|
if (id == "")
|
|
{
|
|
if (PERSISTENCE_TYPE == PERSISTENCE_METHOD_BIOWARE_DB)
|
|
{
|
|
// If using bioware DB (for debugging), there is a limit to var length, so shorten id to name in this case.
|
|
// Note that this has the weakness of sharing variables between PCs with the same name.
|
|
// Also, malfunction is a risk for PCs with long names, since the varname + char name cannot exceed 32 characters.
|
|
id = GetName(obj);
|
|
}
|
|
else
|
|
{
|
|
// Generate full id
|
|
id = GetPCPublicCDKey(obj)+GetPCPlayerName(obj)+GetName(obj);
|
|
}
|
|
|
|
|
|
SetLocalString(obj, OBJ_ID, id);
|
|
}
|
|
}
|
|
else if (GetIsDMPossessed(obj) || GetIsPossessedFamiliar(obj))
|
|
{
|
|
id = "";
|
|
}
|
|
else if (GetIsAreaNatural(obj) != AREA_INVALID)
|
|
{
|
|
// Clumsy hack, in order to identify an area
|
|
// TODO Test if it works
|
|
string tempID = GetLocalString(obj, AREA_ID);
|
|
if (tempID == "")
|
|
{
|
|
tempID = GetResRef(obj);
|
|
}
|
|
id = tempID;
|
|
}
|
|
else
|
|
{
|
|
switch (GetObjectType(obj))
|
|
{
|
|
case OBJECT_TYPE_CREATURE:
|
|
id = GetLocalString(obj, OBJ_ID);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return id;
|
|
}
|
|
|
|
object CreateItemOnObjectMN( string sItemTemplate, object oTarget=OBJECT_SELF, int nStackSize=1, string sNewTag="", string creationOptions = "" )
|
|
{
|
|
return CreateItemOnObject(sItemTemplate, oTarget, nStackSize, sNewTag);
|
|
}
|
|
|
|
// Helper method, converts varname plus indexes to the name of the variable to read from.
|
|
string ExchangeVar(string var, int index, int itemIndex = 0)
|
|
{
|
|
string returnValue = EXCHANGE_PREFIX+IntToString(index)+var+((itemIndex == 0)?"":IntToString(itemIndex));
|
|
// Debug(returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
int CheckExchangeBlocked(object PC, object NPC, int index = 1)
|
|
{
|
|
int returnValue = 0;
|
|
// Init variables
|
|
int takenGoldAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_GOLD, index ) );
|
|
int takenXpAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_XP, index ) );
|
|
string questId = GetLocalString(NPC, ExchangeVar( EXCHANGE_QUEST_ID, index ) );
|
|
int questTimes = GetLocalInt(NPC, ExchangeVar( EXCHANGE_QUEST_REPEAT, index ) );
|
|
int minLevel = GetLocalInt(NPC, ExchangeVar( EXCHANGE_MIN_LEVEL, index ) );
|
|
int maxLevel = GetLocalInt(NPC, ExchangeVar( EXCHANGE_MAX_LEVEL, index ) );
|
|
int allowBatch = GetLocalInt(NPC, ExchangeVar( EXCHANGE_ALLOW_BATCH, index ) );
|
|
int givenGoldAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_GOLD, index ) );
|
|
int givenXpAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_XP, index ) );
|
|
string unlockQuest = GetLocalString(NPC, ExchangeVar( EXCHANGE_OPEN_QUEST, index ) );
|
|
int allowUnknown = GetLocalInt(NPC, ExchangeVar( EXCHANGE_UNKNOWN_OK, index ) );
|
|
int hasJournalEntry = GetLocalInt(NPC, ExchangeVar( EXCHANGE_JOURNAL, index ) );
|
|
|
|
// Perform checks
|
|
|
|
// Check if has enough gold, if applicable
|
|
if (takenGoldAmount >= 1)
|
|
{
|
|
int hasPrereq = (GetGold(PC) >= takenGoldAmount);
|
|
if (!hasPrereq)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_INSUFFICIENT_GOLD;
|
|
}
|
|
}
|
|
|
|
// Check if have enough XP to take, if applicable
|
|
if (takenXpAmount >= 1)
|
|
{
|
|
int hasPrereq = (GetXP(PC) >= takenXpAmount);
|
|
if (!hasPrereq)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_INSUFFICIENT_XP;
|
|
}
|
|
}
|
|
|
|
// Check if fulfills minimum level requirement, if applicable
|
|
if (minLevel >= 2)
|
|
{
|
|
int hasPrereq = (GetLevelFromXP(GetXP(PC)) >= minLevel);
|
|
if (!hasPrereq)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_LEVEL_TOO_LOW;
|
|
}
|
|
}
|
|
|
|
// Check if fulfills max level requirement, if applicable
|
|
if (maxLevel >= 1)
|
|
{
|
|
int hasPrereq = (GetLevelFromXP(GetXP(PC)) <= maxLevel);
|
|
if (!hasPrereq)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_LEVEL_TOO_HIGH;
|
|
}
|
|
}
|
|
|
|
// Check if quest not already completed
|
|
if (questId != "")
|
|
{
|
|
int questStatus = GetQuestStatus ( PC, questId );
|
|
// Debug(questId+"!!!"+IntToString(questStatus));
|
|
|
|
int numberPerformed = 0;
|
|
if (questStatus > 20)
|
|
{
|
|
numberPerformed = questStatus - 20;
|
|
}
|
|
|
|
if (numberPerformed > 0)
|
|
{
|
|
if (numberPerformed >= questTimes)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_QUEST_ALREADY_COMPLETED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (questStatus)
|
|
{
|
|
case QUEST_COMPLETED:
|
|
returnValue = returnValue | EXCHANGE_QUEST_ALREADY_COMPLETED;
|
|
break;
|
|
case QUEST_BLOCKED:
|
|
returnValue = returnValue | EXCHANGE_QUEST_BLOCKED;
|
|
break;
|
|
case QUEST_FAILED:
|
|
returnValue = returnValue | EXCHANGE_QUEST_FAILED;
|
|
break;
|
|
case QUEST_REJECTED:
|
|
returnValue = returnValue | EXCHANGE_QUEST_REJECTED;
|
|
break;
|
|
case QUEST_UNKNOWN:
|
|
if (!allowUnknown)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_QUEST_UNKNOWN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if in possession of needed objects
|
|
// Logic: If atomic item (only one item, with amount = 1), check for itemPossessedBy
|
|
// If missing, abort with error.
|
|
// If multiple items, loop through inventory, accumulating count (count stacks)
|
|
// If by end of inventory, any count is less than amount, abort with error.
|
|
// Supports up to 9 items
|
|
string takeItemTag1 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 1 ));
|
|
int takeItemAmount1 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 1 ));
|
|
int itemCount1 = 0;
|
|
string takeItemTag2 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 2 ));
|
|
int takeItemAmount2 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 2 ));
|
|
int itemCount2 = 0;
|
|
string takeItemTag3 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 3 ));
|
|
int takeItemAmount3 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 3 ));
|
|
int itemCount3 = 0;
|
|
string takeItemTag4 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 4 ));
|
|
int takeItemAmount4 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 4 ));
|
|
int itemCount4 = 0;
|
|
string takeItemTag5 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 5 ));
|
|
int takeItemAmount5 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 5 ));
|
|
int itemCount5 = 0;
|
|
string takeItemTag6 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 6 ));
|
|
int takeItemAmount6 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 6 ));
|
|
int itemCount6 = 0;
|
|
string takeItemTag7 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 7 ));
|
|
int takeItemAmount7 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 7 ));
|
|
int itemCount7 = 0;
|
|
string takeItemTag8 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 8 ));
|
|
int takeItemAmount8 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 8 ));
|
|
int itemCount8 = 0;
|
|
string takeItemTag9 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 9 ));
|
|
int takeItemAmount9 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 9 ));
|
|
int itemCount9 = 0;
|
|
|
|
|
|
if (takeItemTag1 != "")
|
|
{
|
|
if (takeItemTag2 == "" && takeItemAmount1 <= 1)
|
|
{
|
|
takeItemAmount1 = 1;
|
|
}
|
|
/*
|
|
if (takeItemTag2 == "" && takeItemAmount1 <= 1)
|
|
{
|
|
// Simple check - Check directly
|
|
object oItem = GetItemPossessedBy(PC, takeItemTag1);
|
|
if ( !GetIsObjectValid(oItem) )
|
|
{
|
|
returnValue = returnValue | EXCHANGE_INSUFFICIENT_ITEMS;
|
|
}
|
|
}
|
|
else
|
|
{ */
|
|
// Advanced check - loop through entire inventory
|
|
object item = GetFirstItemInInventory(PC);
|
|
while (GetIsObjectValid(item))
|
|
{
|
|
string tag = GetTag(item);
|
|
int stackSize = GetNumStackedItems(item);
|
|
|
|
if (tag == takeItemTag1)
|
|
{
|
|
itemCount1 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag2)
|
|
{
|
|
itemCount2 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag3)
|
|
{
|
|
itemCount3 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag4)
|
|
{
|
|
itemCount4 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag5)
|
|
{
|
|
itemCount5 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag6)
|
|
{
|
|
itemCount6 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag7)
|
|
{
|
|
itemCount7 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag8)
|
|
{
|
|
itemCount8 += stackSize;
|
|
}
|
|
else if (tag == takeItemTag9)
|
|
{
|
|
itemCount9 += stackSize;
|
|
}
|
|
|
|
item = GetNextItemInInventory(PC);
|
|
}
|
|
|
|
int tooFew = (itemCount1<takeItemAmount1) ||(itemCount2<takeItemAmount2) ||(itemCount3<takeItemAmount3) ||(itemCount4<takeItemAmount4) ||(itemCount5<takeItemAmount5) ||(itemCount6<takeItemAmount6) ||(itemCount7<takeItemAmount7) ||(itemCount8<takeItemAmount8) ||(itemCount9<takeItemAmount9);
|
|
|
|
if (tooFew)
|
|
{
|
|
returnValue = returnValue | EXCHANGE_INSUFFICIENT_ITEMS;
|
|
}
|
|
// }
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
int TakeItem(object PC, object item, int stackSize, int takeAmount)
|
|
{
|
|
if (takeAmount > 0)
|
|
{
|
|
if (stackSize <= takeAmount)
|
|
{
|
|
// Remove entire stack
|
|
takeAmount -= stackSize;
|
|
DestroyPersistentVarsOnObject ( GetId(item) );
|
|
ActionTakeItem( item, PC );
|
|
DestroyObject(item);
|
|
}
|
|
else
|
|
{
|
|
// Remove part of stack
|
|
SetItemStackSize(item, stackSize - takeAmount);
|
|
takeAmount = 0;
|
|
}
|
|
}
|
|
|
|
return takeAmount;
|
|
}
|
|
|
|
// Helper method for PerformExchange. Wraps CreateItemOnObjectMN,
|
|
// but increases number to 1 if lower than 1, returns
|
|
// without doing anything if resref is "", and loops through
|
|
// item creation rather than setting stack size.
|
|
void GiveItemToPC(object PC, string resref, int number = 1)
|
|
{
|
|
if (resref == "")
|
|
{
|
|
return;
|
|
}
|
|
if (number < 1)
|
|
{
|
|
number = 1;
|
|
}
|
|
|
|
int i;
|
|
for (i = 0; i < number; i++)
|
|
{
|
|
CreateItemOnObjectMN(resref, PC, 1, "", "");
|
|
}
|
|
}
|
|
|
|
void PerformExchange(object PC, object NPC, int index = 1)
|
|
{
|
|
// We check again to prevent cheats
|
|
if ( !CheckExchangeBlocked(PC, NPC, index) )
|
|
{
|
|
// Step 1: Init variables
|
|
int takenGoldAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_GOLD, index ) );
|
|
int takenXpAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_XP, index ) );
|
|
string questId = GetLocalString(NPC, ExchangeVar( EXCHANGE_QUEST_ID, index ) );
|
|
int questTimes = GetLocalInt(NPC, ExchangeVar( EXCHANGE_QUEST_REPEAT, index ) );
|
|
int minLevel = GetLocalInt(NPC, ExchangeVar( EXCHANGE_MIN_LEVEL, index ) );
|
|
int maxLevel = GetLocalInt(NPC, ExchangeVar( EXCHANGE_MAX_LEVEL, index ) );
|
|
int allowBatch = GetLocalInt(NPC, ExchangeVar( EXCHANGE_ALLOW_BATCH, index ) );
|
|
int givenGoldAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_GOLD, index ) );
|
|
int givenXpAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_XP, index ) );
|
|
string unlockQuest = GetLocalString(NPC, ExchangeVar( EXCHANGE_OPEN_QUEST, index ) );
|
|
int visualEffect = GetLocalInt(NPC, ExchangeVar( EXCHANGE_VISUALEFFECT, index ) );
|
|
|
|
// Display visual effect
|
|
if (visualEffect != 0)
|
|
{
|
|
effect vfx = EffectVisualEffect(visualEffect);
|
|
ApplyEffectToObject( DURATION_TYPE_INSTANT, vfx, PC);
|
|
}
|
|
|
|
// Step 2: Take cost
|
|
|
|
// Take gold
|
|
if (takenGoldAmount > 0)
|
|
{
|
|
TakeGoldFromCreature(takenGoldAmount, PC, TRUE);
|
|
}
|
|
|
|
// Take XP - this will lower PC's level - beware of exploits, BETA!
|
|
if (takenXpAmount > 0)
|
|
{
|
|
SetXP(PC, GetXP(PC)-takenXpAmount);
|
|
}
|
|
|
|
// Increment quest if applicable, and mark quest as completed, if applicable
|
|
int completed = FALSE;
|
|
if (questId != "")
|
|
{
|
|
int questStatus = GetQuestStatus(PC, questId);
|
|
int completedTimes = GetQuestCompletedTimes(PC, questId);
|
|
|
|
if (questTimes == -1)
|
|
{
|
|
// This quest can be performed an unlimited amount of times,
|
|
// so do nothing
|
|
|
|
}
|
|
else if (questTimes > 0 )
|
|
{
|
|
if ( completedTimes > 0 )
|
|
{
|
|
completedTimes++;
|
|
}
|
|
else
|
|
{
|
|
completedTimes = 1;
|
|
}
|
|
|
|
if (completedTimes >= questTimes)
|
|
{
|
|
// Quest is completed
|
|
SetQuestStatus(PC, questId, QUEST_COMPLETED);
|
|
completed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Increment quest
|
|
SetQuestCompletedTimes(PC, questId, completedTimes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// One time quest
|
|
SetQuestStatus(PC, questId, QUEST_COMPLETED);
|
|
completed = TRUE;
|
|
}
|
|
}
|
|
|
|
// Begin unlocked quest, if applicable
|
|
// (we use the "completed" variable from earlier, so that the quest is
|
|
// only unlocked after the last iteration of a multiple iteration quest)
|
|
if ( completed && unlockQuest != "" )
|
|
{
|
|
SetQuestStatus(PC, unlockQuest, QUEST_BEGUN);
|
|
}
|
|
|
|
// take item or items
|
|
string takeItemTag1 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 1 ));
|
|
int takeItemAmount1 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 1 ));
|
|
if (takeItemTag1 != "" && takeItemAmount1 == 0)
|
|
{
|
|
takeItemAmount1 = 1;
|
|
}
|
|
|
|
string takeItemTag2 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 2 ));
|
|
int takeItemAmount2 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 2 ));
|
|
if (takeItemTag2 != "" && takeItemAmount2 == 0)
|
|
{
|
|
takeItemAmount2 = 1;
|
|
}
|
|
|
|
string takeItemTag3 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 3 ));
|
|
int takeItemAmount3 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 3 ));
|
|
if (takeItemTag3 != "" && takeItemAmount3 == 0)
|
|
{
|
|
takeItemAmount3 = 1;
|
|
}
|
|
|
|
string takeItemTag4 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 4 ));
|
|
int takeItemAmount4 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 4 ));
|
|
if (takeItemTag4 != "" && takeItemAmount4 == 0)
|
|
{
|
|
takeItemAmount4 = 1;
|
|
}
|
|
|
|
string takeItemTag5 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 5 ));
|
|
int takeItemAmount5 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 5 ));
|
|
if (takeItemTag5 != "" && takeItemAmount5 == 0)
|
|
{
|
|
takeItemAmount5 = 1;
|
|
}
|
|
|
|
string takeItemTag6 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 6 ));
|
|
int takeItemAmount6 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 6 ));
|
|
if (takeItemTag6 != "" && takeItemAmount6 == 0)
|
|
{
|
|
takeItemAmount6 = 1;
|
|
}
|
|
|
|
string takeItemTag7 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 7 ));
|
|
int takeItemAmount7 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 7 ));
|
|
if (takeItemTag7 != "" && takeItemAmount7 == 0)
|
|
{
|
|
takeItemAmount7 = 1;
|
|
}
|
|
|
|
string takeItemTag8 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 8 ));
|
|
int takeItemAmount8 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 8 ));
|
|
if (takeItemTag8 != "" && takeItemAmount8 == 0)
|
|
{
|
|
takeItemAmount8 = 1;
|
|
}
|
|
|
|
string takeItemTag9 = GetLocalString(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM, index, 9 ));
|
|
int takeItemAmount9 = GetLocalInt(NPC, ExchangeVar( EXCHANGE_TAKE_ITEM_AMOUNT, index, 9 ));
|
|
if (takeItemTag9 != "" && takeItemAmount9 == 0)
|
|
{
|
|
takeItemAmount9 = 1;
|
|
}
|
|
|
|
if (takeItemTag1 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag1, takeItemAmount1);
|
|
}
|
|
if (takeItemTag2 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag2, takeItemAmount2);
|
|
}
|
|
if (takeItemTag3 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag3, takeItemAmount3);
|
|
}
|
|
if (takeItemTag4 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag4, takeItemAmount4);
|
|
}
|
|
if (takeItemTag5 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag5, takeItemAmount5);
|
|
}
|
|
if (takeItemTag6 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag6, takeItemAmount6);
|
|
}
|
|
if (takeItemTag7 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag7, takeItemAmount7);
|
|
}
|
|
if (takeItemTag8 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag8, takeItemAmount8);
|
|
}
|
|
if (takeItemTag9 != "")
|
|
{
|
|
RemoveXItemsByTag(PC, takeItemTag9, takeItemAmount9);
|
|
}
|
|
|
|
/*
|
|
if (takeItemTag2 == "" && takeItemAmount1 <= 1)
|
|
{
|
|
// Simple check - Check directly
|
|
object oItem = GetItemPossessedBy(PC, takeItemTag1);
|
|
if ( GetIsObjectValid(oItem) )
|
|
{
|
|
int iNumStackedItems = GetNumStackedItems(oItem);
|
|
if (iNumStackedItems>takeItemAmount1)
|
|
{
|
|
SetItemStackSize(oItem,iNumStackedItems-takeItemAmount1);
|
|
}
|
|
else
|
|
{
|
|
DestroyPersistentVarsOnObject ( GetId(oItem) );
|
|
ActionTakeItem( oItem, PC );
|
|
DestroyObject(oItem);
|
|
}
|
|
// SetLocalObject(OBJECT_SELF, "DELETE_ITEM", oItem);
|
|
// ExecuteScript("util_deleteitem", OBJECT_SELF);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Advanced check - loop through entire inventory
|
|
object item = GetFirstItemInInventory(PC);
|
|
while (GetIsObjectValid(item))
|
|
{
|
|
string tag = GetTag(item);
|
|
int stackSize = GetNumStackedItems(item);
|
|
|
|
if (tag == takeItemTag1)
|
|
{
|
|
takeItemAmount1 = TakeItem(PC, item, stackSize, takeItemAmount1);
|
|
}
|
|
else if (tag == takeItemTag2)
|
|
{
|
|
takeItemAmount2 = TakeItem(PC, item, stackSize, takeItemAmount2);
|
|
}
|
|
else if (tag == takeItemTag3)
|
|
{
|
|
takeItemAmount3 = TakeItem(PC, item, stackSize, takeItemAmount3);
|
|
}
|
|
else if (tag == takeItemTag4)
|
|
{
|
|
takeItemAmount4 = TakeItem(PC, item, stackSize, takeItemAmount4);
|
|
}
|
|
else if (tag == takeItemTag5)
|
|
{
|
|
takeItemAmount5 = TakeItem(PC, item, stackSize, takeItemAmount5);
|
|
}
|
|
else if (tag == takeItemTag6)
|
|
{
|
|
takeItemAmount6 = TakeItem(PC, item, stackSize, takeItemAmount6);
|
|
}
|
|
else if (tag == takeItemTag7)
|
|
{
|
|
takeItemAmount7 = TakeItem(PC, item, stackSize, takeItemAmount7);
|
|
}
|
|
else if (tag == takeItemTag8)
|
|
{
|
|
takeItemAmount8 = TakeItem(PC, item, stackSize, takeItemAmount8);
|
|
}
|
|
else if (tag == takeItemTag9)
|
|
{
|
|
takeItemAmount9 = TakeItem(PC, item, stackSize, takeItemAmount9);
|
|
}
|
|
|
|
if (takeItemAmount1+takeItemAmount2+takeItemAmount3+takeItemAmount4+takeItemAmount5+takeItemAmount6+takeItemAmount7+takeItemAmount8+takeItemAmount9 == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
item = GetNextItemInInventory(PC);
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
// Step 3: Give reward
|
|
|
|
// Give gold
|
|
if (givenGoldAmount > 0)
|
|
{
|
|
GiveGoldToCreature(PC, givenGoldAmount);
|
|
}
|
|
|
|
// Give XP
|
|
if (givenXpAmount > 0)
|
|
{
|
|
SetXP(PC, GetXP(PC)+givenXpAmount);
|
|
}
|
|
|
|
// Give items
|
|
string giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 1) );
|
|
int giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 1) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 2) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 2) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 3) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 3) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 4) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 4) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 5) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 5) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 6) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 6) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 7) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 7) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 8) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 8) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
giveItemResref = GetLocalString(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM, index, 9) );
|
|
giveItemAmount = GetLocalInt(NPC, ExchangeVar( EXCHANGE_GIVE_ITEM_AMOUNT, index, 9) );
|
|
GiveItemToPC(PC, giveItemResref, giveItemAmount);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
int GetLevelFromXP(int xp)
|
|
{
|
|
return FloatToInt(0.5 + sqrt(0.25 + ( IntToFloat(xp) / 500 )));
|
|
}
|
|
|
|
int GetXPMinForLevel(int level)
|
|
{
|
|
return ((level) *(level-1) *500);
|
|
}
|
|
|
|
int GetXPNeededForLevel(int currentXP, int wantedLevel = 0)
|
|
{
|
|
int minNeeded;
|
|
|
|
if (wantedLevel == 0)
|
|
{
|
|
minNeeded = GetXPMinForLevel(GetLevelFromXP(currentXP)+1);
|
|
}
|
|
else
|
|
{
|
|
minNeeded = GetXPMinForLevel(wantedLevel);
|
|
}
|
|
|
|
return minNeeded-currentXP;
|
|
}
|
|
|
|
// Wraps around getLocalInt, so that marker variables can be imported from database
|
|
int GetMarkerInt(object obj, string varname, int persistantVar)
|
|
{
|
|
int result = GetLocalInt(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS && PERSIST_LOCAL_MARKERS_LAZY_INIT && result == 0)
|
|
{
|
|
result = FetchPInt(MARKERS_TABLE, GetId(obj), varname );
|
|
SetLocalInt(obj, varname, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
float GetMarkerFloat(object obj, string varname, int persistantVar)
|
|
{
|
|
float result = GetLocalFloat(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS && PERSIST_LOCAL_MARKERS_LAZY_INIT && result == 0.0f)
|
|
{
|
|
result = FetchPFloat(MARKERS_TABLE, GetId(obj), varname );
|
|
SetLocalFloat(obj, varname, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Wraps around getLocalString, so that marker variables can be imported from database
|
|
string GetMarkerString(object obj, string varname, int persistantVar)
|
|
{
|
|
string result = GetLocalString(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS && PERSIST_LOCAL_MARKERS_LAZY_INIT && result == "")
|
|
{
|
|
result = FetchPString(MARKERS_TABLE, GetId(obj), varname );
|
|
SetLocalString(obj, varname, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Wraps around setLocalInt, so that marker variables can be exported to database
|
|
void SetMarkerInt(object obj, string varname, int value, int persistantVar)
|
|
{
|
|
SetLocalInt(obj, varname, value);
|
|
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
StorePInt(MARKERS_TABLE, GetId(obj), varname, value);
|
|
}
|
|
}
|
|
|
|
void SetMarkerFloat(object obj, string varname, float value, int persistantVar)
|
|
{
|
|
SetLocalFloat(obj, varname, value);
|
|
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
StorePFloat(MARKERS_TABLE, GetId(obj), varname, value);
|
|
}
|
|
}
|
|
|
|
|
|
// Wraps around setLocalString, so that marker variables can be exported to database
|
|
void SetMarkerString(object obj, string varname, string value, int persistantVar)
|
|
{
|
|
SetLocalString(obj, varname, value);
|
|
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
StorePString(MARKERS_TABLE, GetId(obj), varname, value);
|
|
}
|
|
}
|
|
|
|
|
|
// Wraps around DeleteLocalString, so that marker variables can be deleted from database
|
|
void DeleteMarkerString(object obj, string varname, int persistantVar)
|
|
{
|
|
DeleteLocalString(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
DeletePString(MARKERS_TABLE, GetId(obj), varname);
|
|
}
|
|
}
|
|
|
|
// Wraps around DeleteLocalFloat, so that marker variables can be deleted from database
|
|
void DeleteMarkerFloat(object obj, string varname, int persistantVar)
|
|
{
|
|
DeleteLocalFloat(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
DeletePString(MARKERS_TABLE, GetId(obj), varname);
|
|
}
|
|
}
|
|
|
|
// Wraps around DeleteLocalInt, so that marker variables can be deleted from database
|
|
void DeleteMarkerInt(object obj, string varname, int persistantVar)
|
|
{
|
|
DeleteLocalInt(obj, varname);
|
|
if (persistantVar && PERSIST_LOCAL_MARKERS)
|
|
{
|
|
DeletePString(MARKERS_TABLE, GetId(obj), varname);
|
|
}
|
|
}
|
|
|
|
void Debug(string msg)
|
|
{
|
|
// object oPC = GetFirstPC();
|
|
|
|
// FloatingTextStringOnCreature(msg, oPC, FALSE); Disable debug in production
|
|
}
|
|
|
|
//void main(){}
|