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