How to fix an invalid return from a gosub?

I have a subroutine to cap all stats and relationships at 0/100, filed under *label stat_cap

It is as follows:

*if vampire_like < 0
  *set vampire_like 0
*if vampire_like > 100
  *set vampire_like 100
*return

(Except that everything before the *return is a complete list of all of my stats, subbed into that formula.)

After adding to any stats during the scene, I put in a line:

*gosub stat_cap

This is working perfectly for my first scene, which has that gosub after several options (multiple options and also multiple choices - practically every option changes stats, which then directs to it.)

I then have a second scene that has the identical subroutine (everything from *label to *return) pasted at the bottom of that text file. I used the exact same format to *gosub to it.

The weird thing is, it also works perfectly - until I get to the very last set of options I’ve written into that scene. Then it gives me this:

The bug report line refers to 154, which is the line with the single *return on it.

I did a “find” in my second scene, and the word “return” only appears once, in the *return at the end of the subroutine (which is identical to the one from the first scene.) So, how can my code be returning with no problems from multiple gosub commands, then suddenly think there is a second return somewhere which only breaks the last option of the second scene? I should also add, all options in scene 2 worked fine before adding in the *gosub lines.

Here is the complete code for the option that keeps breaking my subroutine (has minor spoilers for Monster High):

*label hunter_threat
As you pass near his desk, you're surprised when he speaks; normally he sticks to brooding at you.

It's just one muttered word: "[i]Freak[/i]." You whirl around to stare at him. It takes a second to believe what you've heard, but then you say...

*choice
   *selectable_if (Popular >=70) # "WHAT did you just say to me??"
      You wait a few long moments, waiting for everyone to start whispering and staring. Then you say, "You're the freak, you jerk. Do you have [i]any[/i] friends?" With that you give him a superior smile and head to your assigned seat. Assorted giggles and snickers tell you that you have gained social status and he has lost it.

      Victory is sweet.
      *set Popular +5
      *set Hunter_like -10
      *gosub stat_cap
      *goto start_of_class
   *selectable_if (Humanity >=35) #"You must be a very unhappy person to bully other people for no reason."
      *set Serenity +5
      *set Hunter_Like +5
      *gosub stat_cap
      *goto start_of_class
   #"Why do you have to insult me all the time? Y'know, I wish we could just get along."
      *set Humanity +5
      *set Hunter_Like +10
      *gosub stat_cap
      *goto start_of_class
   *selectable_if ((Attractive >=50) and (orientation !="Asexual")) # "Darling, I know you have the hots for me - and believe me, the feeling is mutual. But I fear our love is not meant to be... so let's stop flirting in class, okay?"
      *set Attractive +5
      *set Hunter_Like +10
      *gosub stat_cap
      *goto start_of_class
   #"Nice to see you too, ${Hunter_name}. Is that a new pair of 'look at me, I'm a badass' boots? They really go with the douchey hair."
      *set Persuasion +5
      *set Hunter_Like -10
      *gosub stat_cap
      *goto start_of_class
   *if species!="Goblin"
      *selectable_if (Humanity <30) # "I wonder what your skin would look like as a hat."
         *set Humanity -10
         *set Hunter_Like -5
         *gosub stat_cap
         *goto start_of_class
   #Nothing. I'm unsettled by what this might mean... could he know about my real species?
      *set Cunning +5
      *gosub stat_cap
      *goto start_of_class
*label Artemis_entrance
This is where you should end up if the Hunter is female.

*goto start_of_class
*label start_of_class

This is the start of class.
*if vampire_like < 0
 *set vampire_like 0
 *return    
*if vampire_like > 100
 *set vampire_like 100
 *return

That should work.

But I have only one return line at the end of my first scene’s subroutine, which works fine; also, every other option from scene 2 is fine. Also, doesn’t that mean I have to put *gosub after EVERY SINGLE STAT adjustment, rather than adjusting the numbers after setting, say, three of them in a row?

Another note: I do not believe I have actually hit a 0 or a 100 that needs re-adjusting yet; I coded this stuff in preparation for doing some stat re-balancing, so I wouldn’t accidentally miss something that added up to 101 or negative later.

HA, I fixed it!

In scene #1, there is a *finish command just above all of my subroutines. In scene #2, I had not yet added my *finish command at the end, so after choosing an option it went to the subroutine, the label it was supposed to, the text following that label… and then the subroutine a second time.

*finish was all it needed.

This is now the second time I have solved my own insurmountable coding problem while figuring out how to describe it to people. But the first time I ended up learning a better way even after it was solved, and maybe someone else can learn from this thread too. I found a bunch of references to this error, but didn’t see explanations for how to fix it.

Nicely worked out!

Worth remembering that you can now also essentially put all of your subroutines in a file of their own and *gosub straight there -

*gosub_scene thisfile thislabel

This not only avoids the problem you had there, it also means that when / if you change anything, you only have to edit your subroutines in a single place (thisfile) rather than in every scene in which you use identical subroutines.

I’m assuming *gosub_Scene must not produce a “Next Chapter” button unless you forget to put in a *return. But are there ever loading delays, even slightly, if you use *gosub_scene as opposed to a repeated *gosub?

Given the likely (i.e. very tiny in comparison) size of a dedicated subroutines file, I’m assuming not. However I haven’t fully converted my own game over yet so perhaps someone else has more experience of the end result?

In the software development industry we call this rubber ducking. You’re stuck, you get frustrated, you call your teammate over to explain to them this horrible, ridiculous problem you can’t figure out and, in explaining it to them, you figure it out. Sometimes before even finishing the explanation. The idea is that you might as well be explaining it to a rubber duck for all the actual feedback the other person gave you. :wink:

It’s wonderful when it happens.

As I as reading your posts, I was thinking, “Oh! I just had this same issue. How did I solve it?!?” So good on you for asking, since now this is encoded in the forum and maybe someone else will find it via search later on.

2 Likes

choicescript will only throw up a “Next Chapter” button if you put *finish at the end of the file.

I use *gosub_scene in my updated version of Unnatural as it makes things a lot easier. Now instead of having to have a partner choice in every episode I just put in *gosub_scene partner_choice and then end partner_choice with *return and that works great,

1 Like

Thanks! I will save some file space by not putting my stat capping routine in every single scene. Also, thanks for explaining “Next chapter” - I’ll have to replace some *finish commands with *goto_scene commands to eliminate those buttons from shorter transitions.

You’re welcome. I’m happy for people to learn from my old mistakes, quite a lot of the update will be minor changes to assist with the code side of things as well as making it easier to hunt for bugs.