Code to get a list of who's-called-what

In my current project, I have a number of *gosub calls. If there’s an error inside those *gosubbed subroutines and I use *bug to report it, I don’t find out where in my game the call came from. I just get the reference to the subroutine’s line number.

To work around that, I created a subroutine that finds out where in the game the *gosub call was from. (It also works for *gosub_scene.) Note that this is prying open ChoiceScript internals and so may not work in the future. But it does right now! Note that this subroutine stores its result in a variable called return_1, so you’’ need a *create return_1 false or *temp return_1 statement in your game so the subroutine can store its results.

*comment Generate a stack trace from *gosub and *gosub_scene statements
*label stacktrace
*temp scratch false
*temp trace_contents ""
*script temps["_stacktrace_temps"] = {...temps};

*script this.setVar("scratch", (stats.choice_subscene_stack !== undefined && stats.choice_subscene_stack.length > 0));
*if choice_quicktest
    *script stats.choice_subscene_stack = [];
*if scratch
    *script temps["_stacktrace_subscene_stack"] = [...stats.choice_subscene_stack];
*else
    *script temps["_stacktrace_subscene_stack"] = [];

*gosub stacktrace_loop

*set return_1 trace_contents
*return


*label stacktrace_loop
*temp scratch false
*temp stack_length
*temp stack_scene
*temp stack_line

*script this.setVar("scratch", (temps["_stacktrace_temps"].choice_substack !== undefined && temps["_stacktrace_temps"].choice_substack.length > 0));
*if scratch
    *if choice_quicktest
        *script temps["_stacktrace_temps"].choice_substack = [];
    *script temps["_current_stack"] = [...temps["_stacktrace_temps"].choice_substack];
    *label loop1
    *script this.setVar("stack_length", temps["_current_stack"].length);
    *if stack_length > 0
        *script temps["_current_frame"] = temps["_current_stack"].pop();
        *if choice_quicktest
            *script temps["_current_frame"] = { name: '', lineNum: 0 };
        *script this.setVar("stack_scene", String(temps["_current_frame"].name));
        *script this.setVar("stack_line", temps["_current_frame"].lineNum);
        *set trace_contents "${stack_scene} (${stack_line+1}) -> ${trace_contents}"
        *goto loop1

*script this.setVar("stack_length", temps["_stacktrace_subscene_stack"].length);
*if stack_length > 0
    *script temps["_current_frame"] = temps["_stacktrace_subscene_stack"].pop();
    *if choice_quicktest
        *script temps["_current_frame"] = { name: '', lineNum: 0 };
    *script this.setVar("stack_scene", String(temps["_current_frame"].name));
    *script this.setVar("stack_line", temps["_current_frame"].lineNum);
    *set trace_contents "${stack_scene} (${stack_line}) -> ${trace_contents}"
    *script temps["_stacktrace_temps"] = {...temps["_current_frame"].temps};
    *gosub stacktrace_loop

*return

Here’s an example of how I use this inside a subroutine:

*if <an error occurred>
    *gosub stacktrace
    *bug An error occurred! Stack: ${return_1}
7 Likes

That’s pretty amazing, thanks for sharing. Do you know if there’s a way to find out if a variable have been used at all in the game? I have a ton of variables in my game and sometimes I just create new ones as I need them, and I was wondering if there was a way to know if a variable created in the start up page is not repeated anywhere else.

Not automatically, as far as I know. I made a ChoiceScript extension for Visual Studio Code, a text editor, that will show you every place you’ve used a variable. If you load your game in Visual Studio with the extension, right-click a variable and select “Find All References” (or press Alt+Shift+F12 when your cursor in on the variable). The reference list will pop up on the left. If there’s only one entry, for when you created the variable, then you haven’t used it anywhere else.

3 Likes

Awesome! Thanks.