Skip to content

Commit

Permalink
Engine: fix RunDialog command spawning a nested dialog state
Browse files Browse the repository at this point in the history
This fixes RunDialog script command (or Dialog.Start) spawning a nested dialog state if called within a dialog option script. Something that it should not be doing.
Instead, check if we are inside the dialog, and override a option script's return value, which dialog executor will handle upon receiving control back.
  • Loading branch information
ivan-mogilko committed Oct 27, 2024
1 parent 4b9ede5 commit 1fce7fd
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 5 deletions.
22 changes: 22 additions & 0 deletions Engine/ac/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,13 @@ void DialogExec::Run()

void do_conversation(int dlgnum)
{
assert(dialogExec == nullptr);
if (dialogExec)
{
Debug::Printf(kDbgMsg_Error, "ERROR: tried to start a new dialog state while a dialog state is running.");
return;
}

EndSkippingUntilCharStops();

// AGS 2.x always makes the mouse cursor visible when displaying a dialog.
Expand All @@ -1449,6 +1456,21 @@ void do_conversation(int dlgnum)
dialogExec = {};
}

bool is_in_dialog()
{
return dialogExec != nullptr;
}

// NOTE: this is ugly, but I could not come to a better solution at the time...
void set_dialog_option_result(int dlgopt_result)
{
assert(dialogExec && dialogScriptsInst);
if (!dialogExec || !dialogScriptsInst)
return;

dialogScriptsInst->returnValue = dlgopt_result;
}

bool handle_state_change_in_dialog_request(const char *apiname, int dlgreq_retval, bool expect_dialog_request)
{
// Test if we are inside a dialog state AND dialog_request callback
Expand Down
4 changes: 4 additions & 0 deletions Engine/ac/dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ void Dialog_Start(ScriptDialog *sd);

// Starts a dialog
void do_conversation(int dlgnum);
// Tells if the game is currently running a dialog
bool is_in_dialog();
// Assigns a return value to pass to the dialog state after current option's script have finished executing
void set_dialog_option_result(int dlgopt_result);
// Displays dialog options, and returns the chosen number, or CHOSE_TEXTPARSER if parser input was activated
int show_dialog_options(int dlgnum, bool runGameLoopsInBackground);
// Handles a dialog option, optionally "sais" its text, optionally run corresponding dialog script's entry
Expand Down
13 changes: 10 additions & 3 deletions Engine/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,8 @@ String make_interact_func_name(const String &base, int param, int subd)
return fname;
}

void post_script_cleanup() {
void post_script_cleanup()
{
// should do any post-script stuff here, like go to new room
if (cc_has_error())
quit(cc_get_error().ErrorString);
Expand All @@ -645,7 +646,6 @@ void post_script_cleanup() {
else {
curscript = nullptr;
}
// if (abort_executor) user_disabled_data2=aborted_ip;

int old_room_number = displayed_room;

Expand Down Expand Up @@ -687,7 +687,14 @@ void post_script_cleanup() {
load_new_game = thisData;
return;
case ePSARunDialog:
do_conversation(thisData);
if (is_in_dialog())
{
set_dialog_option_result(thisData);
}
else
{
do_conversation(thisData);
}
break;
case ePSARestartGame:
cancel_all_scripts();
Expand Down
4 changes: 2 additions & 2 deletions Engine/script/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ String GetScriptName(ccInstance *sci);
// Makes a old-style interaction function name (for interaction list "run script" command)
String make_interact_func_name(const String &base, int param, int subd);
// Performs various updates to the game after script interpreter returns control to the engine.
// Executes actions and does changes that are not executed immediately at script command, for
// optimisation and other reasons.
// Executes scheduled commands and does changes that are not executed immediately during script
// (either for logical reasons, and for optimization).
void post_script_cleanup();
void quit_with_script_error(const String &fn_name);
int get_nivalue (InteractionCommandList *nic, int idx, int parm);
Expand Down

0 comments on commit 1fce7fd

Please sign in to comment.