PRC8/nwn/nwnprc/trunk/include/inc_dynconv.nss
Jaysyn904 57b8d88878 Renamed inc_array to stop nwnx include collisions
Renamed inc_array to stop nwnx include collisions  Added missing bonus feat 2da for Forest Master. Changed prc_newspellbook.hak to prc_nsb.hak to prevent issues with nwserver.  Updated tester module.  Updated release archive.
2024-03-03 18:06:25 -05:00

710 lines
28 KiB
Plaintext

//:://////////////////////////////////////////////
//:: Dynamic Conversation System include
//:: inc_dynconv
//:://////////////////////////////////////////////
/** @file
@author Primogenitor
@date 2005.09.23 - Rebuilt the system - Ornedan
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant definitions */
//////////////////////////////////////////////////
const int DYNCONV_EXITED = -2;
const int DYNCONV_ABORTED = -3;
const int DYNCONV_SETUP_STAGE = -1;
const int DYNCONV_TOKEN_HEADER = 99;
const int DYNCONV_TOKEN_REPLY_0 = 100;
const int DYNCONV_TOKEN_REPLY_1 = 101;
const int DYNCONV_TOKEN_REPLY_2 = 102;
const int DYNCONV_TOKEN_REPLY_3 = 103;
const int DYNCONV_TOKEN_REPLY_4 = 104;
const int DYNCONV_TOKEN_REPLY_5 = 105;
const int DYNCONV_TOKEN_REPLY_6 = 106;
const int DYNCONV_TOKEN_REPLY_7 = 107;
const int DYNCONV_TOKEN_REPLY_8 = 108;
const int DYNCONV_TOKEN_REPLY_9 = 109;
const int DYNCONV_TOKEN_EXIT = 110;
const int DYNCONV_TOKEN_WAIT = 111;
const int DYNCONV_TOKEN_NEXT = 112;
const int DYNCONV_TOKEN_PREV = 113;
const int DYNCONV_MIN_TOKEN = 99;
const int DYNCONV_MAX_TOKEN = 113;
const int DYNCONV_STRREF_PLEASE_WAIT = 16824202; // "Please wait"
const int DYNCONV_STRREF_PREVIOUS = 16824203; // "Previous"
const int DYNCONV_STRREF_NEXT = 16824204; // "Next"
const int DYNCONV_STRREF_ABORT_CONVO = 16824212; // "Abort"
const int DYNCONV_STRREF_EXIT_CONVO = 78; // "Exit"
const string DYNCONV_SCRIPT = "DynConv_Script";
const string DYNCONV_VARIABLE = "DynConv_Var";
const string DYNCONV_STAGE = "DynConv_Stage";
const string DYNCONV_TOKEN_BASE = "DynConv_TOKEN";
const string DYNCONV_CHOICEOFFSET = "ChoiceOffset";
/**
* Exiting the conversation is not allowed. The exit
* choice is not shown
*/
const int DYNCONV_EXIT_NOT_ALLOWED = 0;
/**
* Exiting the conversation is allowed and it is
* forced to exit due to no nodes being shown.
*/
const int DYNCONV_EXIT_FORCE_EXIT = -1;
/**
* Exiting the conversation is allowed and the exit
* choice is shown.
*/
const int DYNCONV_EXIT_ALLOWED_SHOW_CHOICE = 1;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Sets the header token and reply tokens for the PC to values stored
* via SetHeader and AddChoice, respectively.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetupTokens(object oPC = OBJECT_INVALID);
/**
* Builds the local variable name for a token.
*
* @param nTokenID One of the DYNCONV_TOKEN_* constants
*/
string GetTokenIDString(int nTokenID);
/**
* Sets the dynamic conversation header. ie, the "NPC"'s reply.
*
* @param sText The text to set the header to
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeader(string sText, object oPC = OBJECT_INVALID);
/**
* A wrapper for SetHeader() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID);
/**
* Add a reply choice to be displayed. The replies are displayed in
* the same order as they are added.
*
* @param sText The text of the choice
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID);
/**
* A wrapper for AddChoice() that uses TLK references.
*
* @param nStrRef The TLK entry to use
* @param nValue The numeric value of the choice. This is what will be
* returned by GetChoice()
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID);
/**
* Sets the custom token at nTokenID to be the given string and stores
* the value in a local variable on OBJECT_SELF.
* Used by the dyynamic onversation system to track token assignment.
*
* @param nTokenID The custom token number to store the string in
* @param sString The string to store
* @param oPC The PC whose conversation this token belongs to
*/
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF);
/**
* Sets the default values for the Exit, Wait, Next and Previous
* tokens. The values will be as follows, or their translated
* equivalents should a non-english TLK be used.
*
* Exit = "Exit"
* Wait = "Please wait"
* Next = "Next"
* Previous = "Previous"
*/
void SetDefaultTokens();
/**
* Changes the conversation stage. If the new stage given is
* the same as the current, nothing happens. Otherwise
* the stage is changed and the choices stored for the old
* stage are deleted.
*
* @param nNewStage The stage to enter
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
*/
void SetStage(int nNewStage, object oPC = OBJECT_INVALID);
/**
* Gets the current stage of the conversation.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The current stage of the conversation, as previously
* set via SetStage() or 0 if no calls to SetStage()
* have been done yet.
*/
int GetStage(object oPC = OBJECT_INVALID);
/**
* Gets the value of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The value of the choice the PC made, as set
* by a call to AddChoice().
*/
int GetChoice(object oPC = OBJECT_INVALID);
/**
* Gets the text of the choice selected by the PC.
*
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used
* @return The text of the choice the PC made, as set
* by a call to AddChoice().
*/
string GetChoiceText(object oPC = OBJECT_INVALID);
/**
* Starts a dynamic conversation. Results are unspecified if called while
* already inside a dynamic conversation.
*
* @param sConversationScript The script to use for controlling the conversation.
* @param oPC The PC that is to be doing the responding in the conversation.
* @param bAllowExit One of the DYNCONV_EXIT_* constants.
* @param bAllowAbort If TRUE, the PC is allowed to aborts the conversation by moving / doing
* some other action or being involved in combat. This can be changed later
* on using AllowAbort()
* @param bForceStart If TRUE, the PC's actions are cleared, so the conversation starts immediately
* and cannot be avoided by the PC cancelling the action while it is in the queue.
* @param oConverseWith The object to speak the "NPC" side of the conversation. Usually, this is also
* the PC, which will be used when this parameter is left to it's default value.
* NOTE: If this parameter is given a value other than OBJECT_INVALID, no validity
* testing is performed upon that object. The function caller needs to make sure
* the object exists.
*/
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID);
/**
* Starts using another dynamic conversation script while inside a
* dynamic conversation. Should only be called from a dynamic conversation
* script.
* The current conversation's script and allow exit/abort variables are
* saved. When the conversation entered via this call exits, the system
* returns to the current conversation, with stage being the one specified
* in the call to this function.
* NOTE: Any stage setup markers are not stored for the return.
*
* @param sConversationToEnter The conversation script to use in the branch
* @param nStageToReturnTo The value of stage variable upong return
* from the branch.
* @param bAllowExit The branch's initial exit allowance state. See
* StartDynamicConversation() for more details.
* @param bAllowAbort The branch's initial abort allowance state. See
* StartDynamicConversation() for more details.
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int bAllowExit = TRUE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID);
/**
* Marks the current dynconvo as exitable via the exit conversation
* choice.
*
* @param nNewValue One of the DYNCONV_EXIT_* constants
* @param bChangeExitTokenText If this is TRUE, then changes the text on
* DYNCONV_TOKEN_EXIT to "Exit"
* @param oPC The PC involved in the conversation. If left
* to default, GetPCSpeaker is used.
*/
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID);
/**
* Marks the conversation as abortable, meaning that the player is
* allowed to leave the conversation via means other than the
* exit conversation choice.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void AllowAbort(object oPC = OBJECT_INVALID);
/**
* Checks whether the given stage is marked as already set up.
*
* @param nStage The stage to check
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks a stage as being set up. This means that when
* the conversation script is called to set up the
* stage, nothing is done and old values are used instead.
* This is useful for scrolling lists, as CPU is not
* wasted on rebuilding the exact same list.
*
* @param nStage The stage to set marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Marks the stage as not set up. This is used to undo
* the effects of MarkStageSetUp() when there is
* need to rerun the stage's builder.
* An example of such situation would be returning to
* a stage from another.
*
* @param nStage The stage to unset marker for
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID);
/**
* Clears the current stage's choices and marks it not set up.
*
* @param oPC The PC involved in the conversation. If left to
* default, GetPCSpeaker is used.
*/
void ClearCurrentStage(object oPC = OBJECT_INVALID);
//////////////////////////////////////////////////
/* Include section */
//////////////////////////////////////////////////
#include "prc_inc_array"
#include "inc_debug"
//////////////////////////////////////////////////
/* Internal function prototypes */
//////////////////////////////////////////////////
void _DynConvInternal_ExitedConvo(object oPC, int bAbort);
void _DynConvInternal_RunScript(object oPC, int nDynConvVar);
void _DynConvInternal_PreScript(object oPC);
void _DynConvInternal_PostScript(object oPC);
object _DynConvInternal_ResolvePC(object oPC);
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
void SetupTokens(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Set header
SetCustomToken(DYNCONV_TOKEN_HEADER, GetLocalString(oPC, "DynConv_HeaderText"));
// Set reply tokens. Assumes that the tokens used are a continuous block.
int nOffset = GetLocalInt(oPC, DYNCONV_CHOICEOFFSET);
int i;
for (i = 0; i < 10; i++)
{
SetToken(DYNCONV_TOKEN_REPLY_0 + i, array_get_string(oPC, "ChoiceTokens", nOffset + i), oPC);
}
}
void SetHeader(string sText, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
SetLocalString(oPC, "DynConv_HeaderText", sText);
}
void SetHeaderStrRef(int nStrRef, object oPC = OBJECT_INVALID)
{
SetHeader(GetStringByStrRef(nStrRef), oPC);
}
string GetTokenIDString(int nTokenID)
{
return DYNCONV_TOKEN_BASE + IntToString(nTokenID);
}
void AddChoice(string sText, int nValue, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "ChoiceTokens"))
array_create(oPC, "ChoiceTokens");
if(!array_exists(oPC, "ChoiceValues"))
array_create(oPC, "ChoiceValues");
array_set_string(oPC, "ChoiceTokens", array_get_size(oPC, "ChoiceTokens"), sText);
array_set_int (oPC, "ChoiceValues", array_get_size(oPC, "ChoiceValues"), nValue);
}
void AddChoiceStrRef(int nStrRef, int nValue, object oPC = OBJECT_INVALID)
{
AddChoice(GetStringByStrRef(nStrRef), nValue, oPC);
}
void SetToken(int nTokenID, string sString, object oPC = OBJECT_SELF)
{
// Set the token
SetCustomToken(nTokenID, sString);
// Set a marker on the PC for the reply conditional scripts to check
SetLocalString(oPC, GetTokenIDString(nTokenID), sString);
}
string GetToken(int nTokenID, object oPC = OBJECT_SELF)
{
// Set a marker on the PC for the reply conditional scripts to check
return GetLocalString(oPC, GetTokenIDString(nTokenID));
}
void SetDefaultTokens()
{
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
SetCustomToken(DYNCONV_TOKEN_WAIT, GetStringByStrRef(DYNCONV_STRREF_PLEASE_WAIT));
SetCustomToken(DYNCONV_TOKEN_NEXT, GetStringByStrRef(DYNCONV_STRREF_NEXT));
SetCustomToken(DYNCONV_TOKEN_PREV, GetStringByStrRef(DYNCONV_STRREF_PREVIOUS));
}
void _DynConvInternal_ExitedConvo(object oPC, int bAbort)
{
// Restart convo if not allowed to leave yet
if(bAbort && !GetLocalInt(oPC, "DynConv_AllowAbort")) // Allowed to abort?
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Conversation aborted, restarting.");
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
// Allowed to exit? Technically, the only way this branch should ever be run is by there not being any response choices available
else if(!bAbort &&
(GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): ERROR: Conversation exited via exit node while exiting not allowed!\n"
+ "DYNCONV_SCRIPT = '" + GetLocalString(oPC, DYNCONV_SCRIPT) + "'\n"
);
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
SetLocalInt(oPC, "DynConv_RestartMarker", TRUE);
}
else{
// Run the conversation script's exit handler
SetLocalInt(oPC, DYNCONV_VARIABLE, bAbort ? DYNCONV_ABORTED : DYNCONV_EXITED);
ExecuteScript(GetLocalString(oPC, DYNCONV_SCRIPT), OBJECT_SELF);
// If there are entries remaining in the stack, pop the previous conversation
if(GetLocalInt(oPC, "DynConv_Stack"))
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Exited a branch");
// Clean up after the previous conversation
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
// Pop the data from the stack
int nStack = GetLocalInt(oPC, "DynConv_Stack");
int nStage = GetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
int nAllowExit = GetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
int nAllowAbort = GetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
string sScript = GetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
// Delete the stack level
DeleteLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack));
DeleteLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack));
DeleteLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack));
if(nStack - 1 > 0) SetLocalInt(oPC, "DynConv_Stack", nStack - 1);
else DeleteLocalInt(oPC, "DynConv_Stack");
// Store the date in the conversation variables
SetLocalInt(oPC, DYNCONV_STAGE, nStage);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", nAllowAbort);
SetLocalString(oPC, DYNCONV_SCRIPT, sScript);
// Restart the conversation
AssignCommand(oPC, ClearAllActions(TRUE));
AssignCommand(oPC, ActionStartConversation(oPC, "dyncov_base", TRUE, FALSE));
}
// Fully exited the conversation. Clean up
else
{
if(DEBUG) DoDebug("_DynConvInternal_ExitedConvo(): Fully exited conversation");
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, "DynConv_AllowExit");
DeleteLocalInt(oPC, "DynConv_AllowAbort");
DeleteLocalInt(oPC, DYNCONV_VARIABLE);
DeleteLocalInt(oPC, DYNCONV_STAGE);
DeleteLocalString(oPC, DYNCONV_SCRIPT);
DeleteLocalString(oPC, "DynConv_HeaderText");
int i;
for(i = DYNCONV_MIN_TOKEN; i <= DYNCONV_MAX_TOKEN; i++)
DeleteLocalString(oPC, GetTokenIDString(i));
}
}
}
void _DynConvInternal_RunScript(object oPC, int nDynConvVar)
{
if(!GetLocalInt(oPC, "DynConv_RestartMarker"))
{
_DynConvInternal_PreScript(oPC);
string sScript = GetLocalString(oPC, DYNCONV_SCRIPT);
SetLocalInt(oPC, DYNCONV_VARIABLE, nDynConvVar);
ExecuteScript(sScript, OBJECT_SELF);
_DynConvInternal_PostScript(oPC);
}
else
{
SetupTokens(oPC);
DeleteLocalInt(oPC, "DynConv_RestartMarker");
}
}
void _DynConvInternal_PreScript(object oPC)
{
// Create the choice arrays
array_create(oPC, "ChoiceTokens");
array_create(oPC, "ChoiceValues");
}
void _DynConvInternal_PostScript(object oPC)
{
// If debugging is active, check that the conversations have at least one response node
// when exiting is off
if(DEBUG)
{
if(GetLocalInt(oPC, DYNCONV_VARIABLE) == DYNCONV_SETUP_STAGE &&
GetLocalInt(oPC, "DynConv_AllowExit") == DYNCONV_EXIT_NOT_ALLOWED &&
array_get_size(oPC, "ChoiceTokens") == 0
)
{
DoDebug("Dynconvo ERROR: No response tokens set up and exiting not allowed!");
}
}
}
object _DynConvInternal_ResolvePC(object oPC)
{
return oPC == OBJECT_INVALID ? GetPCSpeaker() : oPC; // If no valid PC reference was passed, get it via GetPCSpeaker
}
void SetStage(int nNewStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// No need to act if the stage wasn't changed
if(nNewStage != GetStage(oPC))
{
SetLocalInt(oPC, DYNCONV_STAGE, nNewStage);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
}
}
int GetStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return GetLocalInt(oPC, DYNCONV_STAGE);
}
int GetChoice(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_int(oPC, "ChoiceValues", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
string GetChoiceText(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
return array_get_string(oPC, "ChoiceTokens", GetLocalInt(oPC, DYNCONV_VARIABLE) // Number of choice
- 1 // Which begins at index 1 instead of the index 0 we need here
+ GetLocalInt(oPC, "ChoiceOffset"));
}
void StartDynamicConversation(string sConversationScript, object oPC,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
int bForceStart = FALSE, object oConverseWith = OBJECT_INVALID)
{
if(IsInConversation(oPC))
{
if(DEBUG) DoDebug("StartDynamicConversation(): Aborting--already in conversation");
return;
}
if(DEBUG) DoDebug("StartDynamicConversation(): Starting new dynamic conversation, parameters:\n"
+ "sConversationScript = '" + sConversationScript + "'\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "bForceStart = " + DebugBool2String(bForceStart) + "\n"
+ "oConverseWith = " + DebugObject2Str(oConverseWith) + "\n"
);
// By default, the PC converses with itself
oConverseWith = oConverseWith == OBJECT_INVALID ? oPC : oConverseWith;
if(DEBUG) if(!GetIsObjectValid(oConverseWith)) DoDebug("StartDynamicConversation(): ERROR: oConverseWith is not valid!");
// Store the exit control variables
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
// Initiate conversation
if(bForceStart) AssignCommand(oPC, ClearAllActions(TRUE));
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationScript);
AssignCommand(oPC, ActionStartConversation(oConverseWith, "dyncov_base", TRUE, FALSE));
}
void BranchDynamicConversation(string sConversationToEnter, int nStageToReturnTo,
int nAllowExit = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bAllowAbort = FALSE,
object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("BranchDynamicConversation(): Entering another dynamic conversation, parameters:\n"
+ "sConversationToEnter = '" + sConversationToEnter + "'\n"
+ "nStageToReturnTo = " + IntToString(nStageToReturnTo) + "\n"
+ "nAllowExit = " + (nAllowExit == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nAllowExit == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nAllowExit == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nAllowExit)
) + "\n"
+ "bAllowAbort = " + DebugBool2String(bAllowAbort) + "\n"
+ "oPC = " + DebugObject2Str(oPC) + "\n "
);
oPC = _DynConvInternal_ResolvePC(oPC);
// Get current stack level
int nStack = GetLocalInt(oPC, "DynConv_Stack") + 1;
// Push the return data onto the stack
SetLocalInt(oPC, "DynConv_Stack_ReturnToStage_" + IntToString(nStack), nStageToReturnTo);
SetLocalInt(oPC, "DynConv_Stack_AllowExit_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowExit"));
SetLocalInt(oPC, "DynConv_Stack_AllowAbort_" + IntToString(nStack),
GetLocalInt(oPC, "DynConv_AllowAbort"));
SetLocalString(oPC, "DynConv_Stack_Script_" + IntToString(nStack),
GetLocalString(oPC, DYNCONV_SCRIPT));
SetLocalInt(oPC, "DynConv_Stack", nStack);
// Clean the current conversation data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
array_delete(oPC, "StagesSetup");
DeleteLocalInt(oPC, "ChoiceOffset");
DeleteLocalInt(oPC, DYNCONV_STAGE);
// Set the new conversation as active
SetLocalString(oPC, DYNCONV_SCRIPT, sConversationToEnter);
SetLocalInt(oPC, "DynConv_AllowExit", nAllowExit);
SetLocalInt(oPC, "DynConv_AllowAbort", bAllowAbort);
}
/// @todo Rename to SetExitable
void AllowExit(int nNewValue = DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, int bChangeExitTokenText = TRUE, object oPC = OBJECT_INVALID)
{
if(DEBUG) DoDebug("AllowExit():\n"
+ "nNewValue = " + (nNewValue == DYNCONV_EXIT_NOT_ALLOWED ? "DYNCONV_EXIT_NOT_ALLOWED" :
nNewValue == DYNCONV_EXIT_FORCE_EXIT ? "DYNCONV_EXIT_FORCE_EXIT" :
nNewValue == DYNCONV_EXIT_ALLOWED_SHOW_CHOICE ? "DYNCONV_EXIT_ALLOWED_SHOW_CHOICE" :
"ERROR: Unsupported value: " + IntToString(nNewValue)
) + "\n"
+ "bChangeExitTokenText = " + DebugBool2String(bChangeExitTokenText) + "\n"
+ "oPC = " + DebugObject2Str(_DynConvInternal_ResolvePC(oPC)) + "\n"
);
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowExit", nNewValue);
if(bChangeExitTokenText)
SetCustomToken(DYNCONV_TOKEN_EXIT, GetStringByStrRef(DYNCONV_STRREF_EXIT_CONVO));
}
/// @todo Replace with SetAbortable(int bAllow, object oPC = OBJECT_INVALID)
void AllowAbort(object oPC = OBJECT_INVALID)
{
SetLocalInt(_DynConvInternal_ResolvePC(oPC), "DynConv_AllowAbort", TRUE);
}
int GetIsStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return FALSE;
return array_get_int(oPC, "StagesSetup", nStage);
}
void MarkStageSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
array_create(oPC, "StagesSetup");
array_set_int(oPC, "StagesSetup", nStage, TRUE);
}
void MarkStageNotSetUp(int nStage, object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
if(!array_exists(oPC, "StagesSetup"))
return;
array_set_int(oPC, "StagesSetup", nStage, FALSE);
}
void ClearCurrentStage(object oPC = OBJECT_INVALID)
{
oPC = _DynConvInternal_ResolvePC(oPC);
// Clear the choice data
array_delete(oPC, "ChoiceTokens");
array_delete(oPC, "ChoiceValues");
DeleteLocalInt(oPC, "ChoiceOffset");
MarkStageNotSetUp(GetStage(oPC), oPC);
}