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.
710 lines
28 KiB
Plaintext
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);
|
|
}
|