"We've already returned from the last gosub"

This is a really weird error.

I’ve got a complicated set-up which may contribute to the weirdness of it all. Basically, after completing certain tasks, I give the game three parameters (names of people you might meet) and then roll randomly whether or not the “meet a new person” triggers at all. If it does trigger, it randomly picks one of those three parameters and introduces you to that person. And you’ve already met that person, it does nothing.

The code looks like this:

*create encounter 0
*create choose_mortal 0
*create mortal_interest ""


*gosub mortals "Person 1" "Person 2" "Person 3"


*label mortals

*rand encounter 0 2

*if (encounter = 2)
  *gosub mortal_interest

*label mortal_interest

*rand choose_mortal 0 2

*if (choose_mortal = 0)
  *set mortal_interest "${param_1}"
*if (choose_mortal = 1)
  *set mortal_interest "${param_2}"
*if (choose_mortal = 2)
  *set mortal_interest "${param_3}"

*if ((mortal_interest = "Person 1") and (person1 = false))
  *set person1 true
  *goto_scene mortals person1


*label person1

It's Person1!


The idea is that the *return in the mortals scene takes you back to *gosub mortal_interest, then you immediately trigger the next *return back to *gosub mortals.

But, when I run this routine, it generates this error:

mortals line 47: invalid return; we've already returned from the last gosub

That’s specifically on the *return part by the way, though I assume that was obvious.

The weird thing is this:

When I run this chunk of code through the scene with the “mortals” label in it (the scene with “*gosub mortals etc etc” and “label mortals”), it fails. But when I run it through another scene using this code:

*gosub_scene skills mortals "Person1" "Person2" "Person3"

… it works perfectly!

What the hell is going on here? Any ideas?

Often I can figure it out by writing a post like this and then I just delete my post and make the changes myself, but in this case it has only strengthened my bafflement.

Once you hit *return you need to *gosub again.

Glancing at the code, if the second time “encounter” rolls =/= 2, it will go to *label mortals again while subroutine hasn’t been called. Hence there’s nowhere to return. Why not keep subs in a separate scene anyway?

I just took a quick look but:

*if ((mortal_interest = "Person 1") and (person1 = false))
  *set person1 true
  *goto_scene mortals person1

In this part I assume mortals is a file called mortals.txt correct? Also be careful with labelling things similarly, since you have a label in this other file you’re currently on also named mortals which might bring confusion.

Anyway, since you have a *return in person1 you’d need to use *gosub_scene mortals person1 instead, not *goto_scene. Since then it will look for a *return to go back from where it was called. If it was *goto_scene it wouldn’t know to expect a *return and would be confused (as in, throw the error when it finds it).

@anon8836198 Good catch! But there’s a huge chunk of code between the gosub and label that I excerpted that makes it impossible to get to that label without a *goto. Such is the limitations of posting something this complicated on the forum.

@GoldenSilver I’ll try that, but wouldn’t that mean there are three *gosubs and two *returns? And how come it works when I start outside of the scene, but not when I start within it?

Update: It worked!

I have absolutely no idea why.

Here’s the code that fixed it:

*if ((mortal_interest = "Person 1") and (person1 = false))
  *set person1 true
  *gosub_scene mortals person1

This works with both *gosub and *gosub_scene.

Technically I added one gosub and one return, and somehow that fixed it? No idea why, considering we went from two gosubs and two returns to three gosubs and three returns. Must be some finagly thing with ChoiceScript and switching between scenes using gosub.

I know I’m editing my post a lot but I think I figured it out. I think that the *gosub command can only be returned to from within its own scene! So if you gosub in one scene and move to another, you can’t use a return from the new scene to the old scene. Somehow using *gosub_scene counteracted that in some respects even though there were still some returns between scenes.

All this because I was super invested in trying out the *params command.

Well like I said I didn’t read much, but I assumed that part after the . . . was the mortals.txt and its label person1 right?

Because with *gosub_scene it will temporarily open that scene (while still keeping the previous one in memory) and keep going there until it reaches the *return, which at that point it will return to the same location where it was called. If you used just *goto_scene it would have a problem once it reached the *return, because *goto_scene does not accept *return statements (it will completely close the .txt it’s departing from memory).

Well the thing is that you can use as much *gosubs inside another as you want, but when you find a *return, it will return to the most recent one called. Since you’ve used *goto_scene it will completely remove the file you were before from memory, so there won’t be anything to *return to because it was trashed from memory.

The way you’ve done here is the right one:

*if ((mortal_interest = "Person 1") and (person1 = false))
  *set person1 true
  *gosub_scene mortals person1

Because it will go to person1 and do whatever it has to do there and come back, then it will continue down, at this point this other *return is for the other *gosub (which is mortal_interest).