Skip to content

Commit

Permalink
Engine: support StopDialog run in dialog script (schedule stop)
Browse files Browse the repository at this point in the history
ivan-mogilko committed Oct 28, 2024
1 parent 1fce7fd commit 78aa1f9
Showing 6 changed files with 40 additions and 16 deletions.
18 changes: 10 additions & 8 deletions Engine/ac/dialog.cpp
Original file line number Diff line number Diff line change
@@ -1462,23 +1462,25 @@ bool is_in_dialog()
}

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

dialogScriptsInst->returnValue = dlgopt_result;
void set_dialog_result_stop()
{
assert(dialogExec && dialogScriptsInst);
if (dialogScriptsInst)
dialogScriptsInst->returnValue = RUN_DIALOG_STOP_DIALOG;
}

bool handle_state_change_in_dialog_request(const char *apiname, int dlgreq_retval, bool expect_dialog_request)
bool handle_state_change_in_dialog_request(const char *apiname, int dlgreq_retval)
{
// Test if we are inside a dialog state AND dialog_request callback
if ((dialogExec == nullptr) || (play.stop_dialog_at_end == DIALOG_NONE))
{
// Some command may only work inside dialog_request (?)
if (expect_dialog_request)
debug_script_warn("%s: not in a dialog_request(), ignored", apiname);
return false; // not handled, process command as normal
}

8 changes: 5 additions & 3 deletions Engine/ac/dialog.h
Original file line number Diff line number Diff line change
@@ -32,16 +32,18 @@ void Dialog_Start(ScriptDialog *sd);
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);
// Commands dialog executor to goto a different dialog topic after current option's script have finished executing
void set_dialog_result_goto(int dlgnum);
// Commands dialog executor to stop a dialog after current option's script have finished executing
void set_dialog_result_stop();
// 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
int run_dialog_option(int dlgnum, int dialog_choice, int sayChosenOption, bool run_script);
// Handles a game-state changing command (such as StartDialog) inside "dialog_request" callback.
// Returns whether the change was handled in "dialog's way", and further processing is not necessary.
// Otherwise should process the command as normal.
bool handle_state_change_in_dialog_request(const char *apiname, int dlgreq_retval, bool expect_dialog_request = false);
bool handle_state_change_in_dialog_request(const char *apiname, int dlgreq_retval);

extern std::vector<ScriptDialog> scrDialog;
extern std::vector<DialogTopic> dialog;
6 changes: 5 additions & 1 deletion Engine/ac/global_dialog.cpp
Original file line number Diff line number Diff line change
@@ -45,7 +45,11 @@ void RunDialog(int tum)

void StopDialog()
{
handle_state_change_in_dialog_request("StopDialog", DIALOG_STOP, true);
if (handle_state_change_in_dialog_request("StopDialog", DIALOG_STOP))
return; // handled

if (inside_script)
get_executingscript()->QueueAction(PostScriptAction(ePSAStopDialog, 0, "StopDialog"));
}

void SetDialogOption(int dlg, int opt, int onoroff, bool dlg_script)
15 changes: 13 additions & 2 deletions Engine/script/executingscript.cpp
Original file line number Diff line number Diff line change
@@ -38,15 +38,26 @@ void ExecutingScript::QueueAction(PostScriptAction &&act)
// been queued, don't allow a second thing to be queued
switch (prev_act.Type)
{
// A number of scheduled commands prevent ANY other scheduled command to be added
case ePSANewRoom:
case ePSARestoreGame:
case ePSARestoreGameDialog:
case ePSARunAGSGame:
case ePSARestartGame:
quitprintf("!%s: Cannot run this command, since there was a %s command already queued to run in \"%s\", line %d",
debug_script_warn("!%s: Cannot run this command, since there was a %s command already queued to run in \"%s\", line %d",
act.Name.GetCStr(), prev_act.Name.GetCStr(),
prev_act.Position.Section.GetCStr(), prev_act.Position.Line);
break;
return;
// Dialog-state changing commands are mutually exclusive
case ePSARunDialog:
case ePSAStopDialog:
if (act.Type == ePSARunDialog || act.Type == ePSAStopDialog)
{
debug_script_warn("!%s: Cannot run this command, since there was a %s command already queued to run in \"%s\", line %d",
act.Name.GetCStr(), prev_act.Name.GetCStr(),
prev_act.Position.Section.GetCStr(), prev_act.Position.Line);
return;
}
default:
break;
}
4 changes: 3 additions & 1 deletion Engine/script/executingscript.h
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@ struct QueuedScript
QueuedScript() = default;
};

// Actions that can be scheduled for until the current script completes
enum PostScriptActionType
{
ePSAUndefined,
@@ -73,7 +74,8 @@ enum PostScriptActionType
ePSARunDialog,
ePSARestartGame,
ePSASaveGame,
ePSASaveGameDialog
ePSASaveGameDialog,
ePSAStopDialog
};

struct PostScriptAction
5 changes: 4 additions & 1 deletion Engine/script/script.cpp
Original file line number Diff line number Diff line change
@@ -689,13 +689,16 @@ void post_script_cleanup()
case ePSARunDialog:
if (is_in_dialog())
{
set_dialog_option_result(thisData);
set_dialog_result_goto(thisData);
}
else
{
do_conversation(thisData);
}
break;
case ePSAStopDialog:
set_dialog_result_stop();
break;
case ePSARestartGame:
cancel_all_scripts();
restart_game();

0 comments on commit 78aa1f9

Please sign in to comment.