New in ChoiceScript: RandomTest will warn you if you *goto_scene after *gosub_scene without *return

There’s a new version of ChoiceScript available from Github that handles a very subtle bug.

Meet the “Titan Submersible Bug”

There’s a weird kind of bug that can happen in a ChoiceScript game. I’m calling this bug the “Titan Submersible Bug.” The Titan Submersible Bug happens when you use *gosub_scene but you forget to *return.

(The bug is named after a famous submarine that did not successfully return to the surface.)

Here’s how *gosub_scene is supposed to work, with *return

For example, let’s say you have a file called chapter3.txt, with code like this:

*comment chapter3.txt

Start of chapter 3.

*gosub_scene tools

The rest of chapter 3.

And then, in tools.txt, you have code like this:

*comment tools.txt

example code, lorem ipsum, etc. etc.

*return

When you *return from tools.txt, the player will jump back to where they left off in chapter 3, allowing them to read the rest of chapter 3.

In the Titan Submersible Bug, you forget to *return

Perhaps tools.txt might look like this, instead:

*comment tools.txt

example code, lorem ipsum, etc. etc.

*goto_scene chapter4

Since the *return is missing, players would shoot straight on ahead to Chapter 4, without seeing the rest of Chapter 3.

The Titan Submersible Bug created a major issue when submitting post-release updates

The details are… a lot. So I’m going to put them in a collapsible details section here.

Click here to see the full story

“Autosaves” vs. “Backup” saves, for updating

When you play published ChoiceScript games (on our website, in our apps, or if you export your game using the Export to HTML tool), ChoiceScript automatically keeps an “autosave” as you play. The autosave includes all of your current stats and temps, and it includes the name of the file you’re currently in, (e.g. chapter6.txt) and the line number you’re currently on.

The “autosave” ensures that if you quit the app or refresh the page, you can continue playing where you left off.

autosave:
file: chapter6.txt
line: 1234
strength: 57
leadership: 68
...

But that won’t work if you’re playing halfway through chapter6.txt and then we have to update the file while you’re playing. If you paused playing the game at line number 1234, what does “line number 1234” mean when chapter6.txt has changed? In the old version of chapter6.txt, line number 1234 might have been the result of a major *choice, but in the new version of chapter6.txt, that could be smack dab in the middle of a paragraph.

To workaround this, whenever you enter a new scene/chapter file, we record a “backup” save, including all of your stats, with the “line number” set to line 1.

When we update the game, we check to see if the scene file you’re currently in has changed. If it has changed, we throw away the current autosave and restore from the “backup” save, rewinding time to the start of the chapter.

Since most ChoiceScript games are a linear series of medium-sized chapters, this means that you’ll only lose your progress in chapter6.txt, hopefully only fifteen or twenty minutes at most.

We only create a backup save if you’re not in a subscene

If you’re in chapter6.txt, and you *gosub_scene subscene.txt, we don’t set a backup at the start of subscene.txt. We only set a backup at the start of a top-level scene.

During updates, the Titan Submersible Bug would rewind time all the way back to the chapter when you first called *gosub_scene

After the player trips over the Titan Submersible Bug, the player would never *return from a subscene, so the backup save would never be created ever again for the rest of that playthrough. Whenever doing any future game updates, the player would have time rewinded back to the top of the chapter that first called *gosub_scene and triggered the bug.

If you have the Titan Submersible Bug at the very start of the game, that would mean any mid-game updates would restart the entire game, defeating the purpose of our mid-game update system.

(This is exactly what happened to The Book of Hungry Names when we first launched it.)

We’ve implemented a workaround so the Titan Submersible Bug no longer blocks backup saves

Now, when you *goto_scene after *gosub_scene, we’ll treat the *goto_scene scene as a “top-level scene”, not as a subscene.

Since that new behavior is quite confusing, we recommend (but don’t require) that authors fix their Titan Submersible Bugs in their own game.

Now, code with the Titan Submersible Bug will show a warning when you run RandomTest

The warning looks like this:

WARNING tools line 3: You should *return before *goto_scene after *gosub_scene from chapter3 line 63

When this happens, instead of using *goto_scene in tools.txt, you’ll need to update your code to use *return instead, or to *goto_scene tools instead of *gosub_scene tools, if that’s what you intend to do.

It’s just a warning, not a failure, because many of our games have a Titan Submersible Bug, and it’s fine

Using RandomTest, I detected 26 published games that had the Titan Submersible Bug. (You can run RandomTest on your own game to find the bug and fix it.)

The Titan Submersible Bug is confusing, but it’s mostly harmless, and it’s usually pretty straightforward to fix it, now that the Titan Submersible Bug no longer breaks game updates.

So, we recommend (but don’t require) that authors fix their Titan Submersible Bugs in their own game by running RandomTest and addressing any warnings you find.

26 Likes

I’m probably missing something here, but wouldn’t the biggest problem caused by the missing *return be the omission of a large part of the narrative during gameplay, from moving on to the next chapter before finishing the current one?

2 Likes

Presumably that problem would be much more easily spotted by the human(s) testing the game than a problem that, if I’ve understood this correctly, is basically “backup save stops saving”.

Now that this workaround has been implemented, hopefully what you describe will be the biggest problem the missing *return causes.

2 Likes

I’m guessing Révolution Diabolique has…a bunch of these. It felt like half my testing was tracking down incorrect narrative skips.

Surprisingly, no! There might be other skipped-narrative bugs, but Diabolique (and Machinations) do not have this particular new warning.

1 Like

I don’t program in ChoiceScript. However, I am a Commodore-64 hobbyist who programs in BASIC.

Anyone who programs in any version of BASIC that has GOSUB and RETURN will be quite familiar with this sort of error; and yes, using GOTO instead of RETURN can indeed cause all manner of weird behavior in a program. I smile. :slight_smile:

3 Likes

I’m not sure about this though

there might be intentional branchings where it doesn’t have to return to the original file at all

the solution should be: changing the syntax of gosub_scene to goto_scene if the author doesn’t want to return after moving to another file

Thanks SO much!!! :blush: :blush: :blush: :blush: :blush:

My games have looking suffered from this type of bug (I abuse the use of gosub_scene, and sometimes it can be difficult to find this issue).

I wonder if I can make a request? (And feel completely free to ignore). Another of the most common types of bugs I get is the can’t add to non-percentile…

For example:

*create relationship_john 50

*set relationship_john %+55

Ok

*set relationship_john +55

Produces error because I forgot the % sign. In my last game maybe 70% of bugs in first two weeks involved such issues (partially maybe due to my games having cheat codes, which makes this issue more prominent than in other games?)

Could there be a way in the code to declare variables, so that the code could automatically detect such issues?

Like

*create relationship_john percentage 50

(Maybe this is already possible and I missed it?)

It should work fine if you have a space after the +.

Well, maybe not completely fine since then relationship_john will be 105, which is higher than 100, so if you’re using that percent bar to represent relationship_john then it will overflow on the stats screen. But at least you shouldn’t get an error.

2 Likes

What happens to the temp variable space when you gosub_scene out and never come back? Or does the goto_scene listed just reset the lingering held values anyway, the way that finishing a chapter and moving forward works?

I’m looking to have a scene that can recur (with lots of inline tweaks so is refreshed each time — this is an intentional reuse of some material with other values that decontextualize it each time) via a gosub_scene from more than one chapter file.

There aren’t any temp / local vars with critical long term values managed (there are three global vars that manage that!) but I did have some assumptions about putting some temp var assignments into each of these “trips” that has to do with countdown incrementation for dispensing this repeated snippet each time triggered.

What happens if you have the same line with a *temp var established every chapter or so? Does it hold its values despite *gosub_scene jumps to external files over and over until a new scene file or *goto_scene hits?

Maybe this doesn’t matter as long as you carefully manage temp vars within each scene file, but for the sake of understanding, here’s my weird scenario:

Chapter 2:

  • at the top of chapter, temp variables established for countdown and threshold — values I’m happy to lose this value when reader advances to chapter 3!
  • they read:

*temp countdown 10
*temp threshold 4

  • partway thru, scene fragment is trigger, accessed via *gosub_scene countdown-scene dreamy
  • Within countdown-scene.txt, the label “dreamy” uses the countdown and threshold vars when first arriving to this label
  • I am assuming countdown would remain “10” and threshold “4” because neither have been decremented yet, and I haven’t loaded a new scene file “chapter.”
  • dreamy sequence continues with some looping (that has to do with how much of the scene is dispensed) that decrements countdown until countdown matches the threshold value, in this case “4”
  • Use of *return sends the reader back to chapter 2 to keep reading there…
  • If a value is checked for countdown, I assume countdown would remain “4” and threshold remain “4” because we haven’t left the scene
  • At the very end of chapter 2…… the threshold value is set to “1” and player is sent back via *gosub _scene to the same dreamy label
  • I assume countdown value remains “4” and threshold remains “1”
  • Now that code continues and countdown decrements while more bits of the snippet are delivered until countdown decrements to “1” which matches the test against threshold and the reader is sent back to chapter 2 via *return
  • If checked in the remaining content for chapter 2, I assume the vars countdown and threshold would both have the value of “1”
  • chapter 2 ends! We head to chapter 3!
  • What value does countdown and threshold have before set with a new *temp countdown and *temp threshold command?
  • Well, they are next established with new values and the reader hits that dreamy label again……

And what happens in a Titan moment if I foolishly jump to chapter 3 from a gosub_scene visit to this instead of *return? How will those temp vars work?

Yes, this is an annoying example, but knowing if my assumptions are wrong could really help me!

The point of “never coming back” is that you must have gone somewhere else with *goto_scene.

When you’re in chapter3.txt and you *goto_scene chapter4, the temps from chapter3.txt are erased/forgotten, which is only natural, because there’s no way to *return when you *goto_scene.

Temps are meant to be transient. Put anything you want to save in global stats.

4 Likes

Good, then this is what I expected. Certainly I’m not setting up to FORCE extending value holding for temp variables. Was just curious if my assumptions were correct for values at each stage. I’ll be focusing on gosub_scene + return strategy, so sounds like I’ll be great and can push values for temp each chapter while using the same tools/snippets in external files to main loaded scene/chapter file. Thank you, Dan!