Repeating "It is illegal to fall out of a *choice statement" error


#1

I have been getting this error consistantly for the past year and a half that I’ve been writing.

It happens every time I create a particularly long branching chain of choices. When a choice leads to other choices, and then start adding in fake choices and *if statements, and creating a long stretch of code where I spend about a minute just going from one of the original choices to the other.

Example
*choice
	#Option
		*if (variable =1)
			*choice
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
`		*if (variable =2)
			*choice
				#Option
					*fake_choice
						#Option

						#Option

					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*if (variable =w)
						*choice
							#Option
								*finish
							#Option
								*finish
					*if (variable =x)
						*choice
							#Option
								*finish
							#Option
								*finish
	#Option
		*if (variable =1)
			*choice
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
`		*if (variable =2)
			*choice
				#Option
					*fake_choice
						#Option

						#Option

					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*if (variable =w)
						*choice
							#Option
								*finish
							#Option
								*finish
					*if (variable =x)
						*choice
							#Option
								*finish
							#Option
								*finish
	#Option
		*if (variable =1)
			*choice
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*choice
						#Option
							*finish
						#Option
							*finish
`		*if (variable =2)
			*choice
				#Option
					*fake_choice
						#Option

						#Option

					*choice
						#Option
							*finish
						#Option
							*finish
				#Option
					*if (variable =w)
						*choice
							#Option
								*finish
							#Option
								*finish
					*if (variable =x)
						*choice
							#Option
								*finish
							#Option
								*finish

As expected, I run into quite a few problems. Sometimes a choice is mispelled, other times I forgot to put in a certain choice, or forgot to put in dialoge under a choice. These errors get caught and the fix is generaly easy to implement.

Yet this one error, “It is illegal to fall out of a *choice statement; you must *goto or *finish before the end of the indented block.” Is the one that I have never been able to figure out the cause of.
As far as I can tell, in a line like that, everything is taken care of. Every branch is going somewhere, either to a *finish or to a *goto_scene.

I’ve done workarounds; I’ve taken branches of choices and given them their own scene file (leading to a cluttered file system that is difficult to edit in bulk) and I’ve created *labels further down the line and placed the option branches there (which has created cluttered scenes that are difficult to sort through).
What I haven’t been able to do is figure out why this keeps happening.


#2

To make it simple, every choice needs a *goto in that choice segment easiest way around that is just use *fake_choice and not needing to use *finish or *goto.


#3

If you’re going to use *choice, you need *gotos. In that code you posted, you’d need a lot of *gotos and *labels. Li’l sample below to show what I mean, but I’m with @Pace675 here–*fake_choice might be more reliable here.

[Sample text.]
*choice
  #Option
    *if (variable = 1)
      *goto SubChoiceA

*label SubChoiceA
[Sample text.]
*choice
  #Option
    *goto SubChoiceA1
  #Option
    *goto SubChoiceA2

*label SubChoiceA1
[Sample text.]
*choice
  #Option
    *finish
  #Option
    *finish

*label SubChoiceA2
[Sample text.]
*choice
  #Option
    *finish
  #Option
    *finish

#4

Just to offer a different take on this… The most likely cause IMO, at a glance, is that you are relying on there being very specific cases (that the value of ‘variable’ is always either ‘1’ or ‘2’ for each of the main options). Ideally you should be using *if / *else, not *if / *if, so you don’t need to specify a condition for the *else and it can act as a ‘catch-all’ and never have to ‘fall out’ of the *choice.

If it could be more than ‘1’ or ‘2’ then you should be using *if / *elseif / *else, etc.

Whether you use *finish or *goto for the redirection is pretty much immaterial (just so long as you do have one or the other for each segment, or another redirectional command such as *ending or *goto_scene) and *finish alone is in no way causing you to ‘fall out’ of the *choice statement.


#5

Caveat: I am by no means a coding expert. I did run into this problem repeatedly in one particular scene of mine that had a lot of nested *choice sections, though. In my case, it was partly because I would edit that section, and then accidentally break something I couldn’t see in another part of the long, long chain of nested *choice.

It is definitely possible to nest choices instead of using *label, as long as the final choice in the chain has a proper *goto or *finish. I did it, to ten levels, with one of my games. I was finding I kept accidentally introducing bugs, though. Then it was very difficult to pinpoint the exact bug when I was falling out of choices because it was 2000 lines of ridiculously indented code, and had loops, and the problems weren’t necessarily anywhere near the line number of the error.

But something like this definitely works:


*choice
  #Red.
    *choice
      #Dancing shoes.
        *choice
          #Ballet.
            *finish
          #Tap.
            *finish
          #Jazz.
            *finish
      #Boiled sweets.
        *choice
          #Strawberry.
            *finish
          #Raspberry.
            *finish
          #Snozzberry.
            *finish
      #Fish.
        *choice
          #Saltwater.
            *finish
          #Freshwater.
            *finish
  #Green.
    *choice
      #Trees.
        *choice
          #Elm.
            *finish
          #Oak.
            *finish
          #Alder.
            *finish
      #Peppermints.
        *choice
          #Soft.
            *finish
          #Hard.
            *finish
          #Jelly.
            *finish
      #Myna birds.
        *choice
          #Wild.
            *finish
          #Pets.
            *finish

After trying to debug my crazy scene so many times, I did start using *label much more often.
For me, at least, I’ve found that if I keep my labels in the same order as the options I present, it makes it easier for me to figure out what’s going where. It’s also easier to look at when I come back a few months later in editing. That’s just my experience though, of course; I know other authors have much different approaches to organising complex code sequences.

I think, if I’m remembering correctly, that *fake_choice can also cause problems if there are more than a few layers of indentation (or the wrong kind of *if indentations), so that was usually one of my first checks.

I did have one falling-out bug that was really sticky, and I finally solved it with a step-through function using @CJW’s CSIDE, which I was beta testing. (And it should be out in the near future, and available to everyone! Yaaaay.) It turned out to be a sketchy *if sequence, like @Vendetta suggested.

I’d be curious what some of the authors here who have very complex code think of labels versus nested choices, or any thoughts on when to use what, or how many nested choices (if ever) are too many.


#6

I’m a novice but the KISS (Keep It Simple …) principle should always be a rule of thumb. With a novice perspective, the label keeps things simpler - I know that the more loops I go through, the dizzier I get :wink:


#7

Tried this and ran it through my random tester (which takes a really long time due to the number of variations).
Didn’t work. Got the same error.

I’m not sure what you did in that code that I wasn’t already doing in my own.

Could that potentially be the problem I’m having? At least, this time around?

In the game I’m currently working on, there are many instances where the player an die. Rather than start the game over, I was merciful and gave the player two options.
Give up, and *goto beginning_of_fight
If that created a loop, could that be the potential cause of my current problems? (And in that case, what’s caused all my previous problems? This is the first time I’ve had an intentional loop).

I don’t know what that is.


#8

Sorry - its an acronym for Keep it simple … something I always refer back to while scripting.


#9

Er, sorry, no difference…that was my point, since it was suggested that the problem was not using *goto and *label. Nested choices are fine; if there’s an error, it’s coming from something other than just nesting *choice as long as the final options are finished correctly.

The problem wasn’t that I had a loop; the loop was intentional and worked correctly once I’d fixed the bug-causing bits. The problem was that I was using *if statements in my choices, and some of the permutations of the loop, and the options the player could choose, created a situation where I was falling out of a *choice if the loop was played through in a certain order.

Is the code sample you posted at top the actual framework of the code where you’re having a problem? If so, I’d be willing to try and figure out what’s happening, if you’d like.


#10

That’s what I try to do, but I’m beginning to think I have a Complexity Addiction.
Every time I think of something that a player should be able to do, I make it my mission to make that possible. But at the same time, I hate complicated stuff, so I try to perform complex paths in the simplest way possible and stick to nesting the choices rather than have dozens of *gotos and labels to keep track of.

Then I run into this error, which to this day, I say is a lie. All my choices have ends! I have not fallen out of anything! The code is a lie!

I can’t actually do that.
I tried, and the full thing went over the number of characters allowed for this text box. (Note: At this time, only about 1/7th of the scene is actually written.)

You can find the code at this web address:
https://dashingdon.com/play/interestedparty/daemoniacus-altor-dark-tech-version/mygame/scenes/2-village.txt


#11

I haven’t read the whole topic yet, but looking at your sample code, I see several instances where a *choice command ends without a command that tells the code where to go next (*goto, *finish, *ending, etc.)

Specifically, chains like this:

*if (variable =2)
  *choice
    #Option
      *fake_choice
        #Option

The final step in the chain may very well be a *fake_choice that can operate without a destination, but the *choice above it requires a destination for every single branch in contains. That one of the branches contains a *fake_choice won’t exempt it — the *choice above will still require somewhere to go.

Now it’s time for me to read the rest of the topic, and see if this has already been addressed and I’m beating a dead horse.


#12

I think I’ve found a few errors, all to do with *if statements…would you mind if I PM you so I can copy/paste a bunch of code, or would you rather I continue here? (Or would you rather I stop tinkering, haha.)


#13
More Tinkering!

For science!


#14

The pm idea is fine.


#15

Argh, late to the party.
Just wanna restating @Minnow’s thought.

You got *fake_choice inside normal *choice. This should be the one which causes your problem.

TL;DR

This :negative_squared_cross_mark:

*choice
  #Option1
    *fake_choice
      #Fake1
      #Fake2
  #Option2
    *fake_choice
      #Fake1
      #Fake2

Should be like this :white_check_mark:

*choice
  #Option1
    *fake_choice
      #Fake1
      #Fake2
    *finish <<<
  #Option2
    *fake_choice
      #Fake1
      #Fake2
    *finish <<<

#16

I’ve been messing with this and it finally works! :wink:
Here’s what I did with it, but I’ll go ahead and say, there was no way around taking out the *fakechoice and using *label and *goto…

Startup file

 >  *scene_list
   >   startup
   >   sample
> *create variable 0
> *create letter "w"

Scene file

*choice
> 	 #Option1_a
> 		*if (variable =1)
> 			*goto var_1
> 		*if (variable =2)
> 			*goto var_2
> 		*else
> 			*choice
> 				#Option1_b
> 					*if (letter = "w")
> 						*goto var_w
> 					*if (letter = "x")
> 						*goto var_x
> 					*else
> 						*goto else1

> 	#Option2_a
> 		*if (variable =1)
> 			*goto var_1
> 		*if (variable =2)
> 			*goto var_2
> 		*else
> 			*goto else1
> 	#Option3_a
> 		*if (variable =1)
> 			*goto var_1
> 		*if (variable =2)
> 			*goto var_2
> 		*else
> 			*goto else1
> *label var_1
> *choice
> 	#Option1_b
> 		*choice
> 			#Option1_c
> 				*finish
> 			#Option2_c
> 				*finish
> 	#Option2_b
> 		*choice
> 			#Option3_c
> 				*finish
> 			#Option4_c
> 				*finish

> *label var_2
> *choice
> 	#Option1_b
> 		*choice
> 			#Option1_c
> 				*choice
> 					#Option1_d
> 						*finish
> 					#Option2_d
> 						*finish
> 			#Option2_c
> 				*choice
> 					#Option3_d
> 						*finish
> 					#Option4_d
> 						*finish
> 	#Option2_b
> 		*if (letter = "w")
> 			*goto var_w
> 		*if (letter = "x")
> 			*goto var_x
> 		*else
> 			*goto else1
> *label var_x
> *choice
> 	#Option1_d
> 		*finish
> 	#Option2_d
> 		*finish
> *label var_w
> *choice
> 	#Option1_d
> 		*finish
> 	#Option2_d
> 		*finish
> *label else1
> *choice
> 	#choice_a
> 		*finish
> 	#choice_b
> 		*finish
> 	#choice_c
> 		*finish