Go Subroutine help

Hi guys,

Here’s my code that I just can’t make it work:

*set minute 3
*set seconds 0

*comment detonation timer subroutine
*label bombtime

*if (seconds = 0)
	*set seconds 30
	*set minute -1
	T - ${minute} Minute ${seconds} Seconds to Detonation
        *return

*elseif (seconds = 30)
	*set seconds 0
	T - ${minute} Minute ${seconds} Seconds to Detonation
	*return                 <------------------------- ~it crashes here on this line~

*elseif ((minute = 0) and (seconds = 0))
	Bomb goes off, you've been killed.
        *goto death

The above sub routine is used on every player choice, reduces the time counter by 30 seconds, but everytime this runs within choices embedded in another choice , it’ll say “error, invalid return, we’ve already return from the last gosub.” on that line I highlighted.

please help me as I cannot figure out how to make this work.

Thanks so much

My brain’s super groggy at the moment so trying to make sense of the code is like wading through syrup.

I think your code needs rewritten. I’m sure someone who’s brain is functioning will be able to assist.

That check to see if the bomb goes off is never going to be reached. The code will always read one of those first two conditions since seconds will always be either 0 or 30.

I’d say load up CJW’s IDE https://dl.dropboxusercontent.com/u/7840892/CJW/choicescript/tools/IDE/main.html and start fiddling around. See if you can make the code work by reorganising and rearranging and changing things. That’s pretty much how I learned to code and debug, with the wiki open in another screen. I just keep trial and erroring it until it finally worked how I wanted it to. Hopefully someone will come along and help you out before too long though.

According to the wiki ( http://choicescriptdev.wikia.com/wiki/Gosub ) you should use the *return after your list of possible options, not after the options themselves.
Also, I don’t know if you can use a *goto within a subroutine.

thank you both for the input, yes i have read the entire wiki prior already, unfortunately, the wiki only provides basic use of *gosub. In response to cecillia, the *return does work after each options in the subroutine, i have another long script of code that does exactly that and it works good. The *goto also works within the subroutine, I’ve proven that aswell with another set of code where a different time counter reach 0 from a subroutine, it can directly use *goto to end the game.

i think there are a number of ways in using the gosub thats not covered in the wiki as i’ve already found, but it gets very buggy and complicated because it’ll work sometimes and wont in another. and the error doesnt make sense, normally the error message is very clear on what needs to be fixed like indentations and whatnot, but it makes no sense in this case. i tried using a single *return for that bugged subroutine, and it doesnt work either.

For that last *elseif never being scanned, thats an easy fix, just put that section of the code at the top and use *if instead and it will get scanned as priority before the other conditions and it’ll work, good catch on that one though

I have written a functioning timer for my game but heading out the door for work. If you have not solved the problem by I get home this afternoon will be happy to help.

Well, the problem does not seem to be in the code provided based on the error. The error you’re getting is because the game is hitting more *returns than *gosubs. Automated testing will probably help here (so you can see a line by line break down of what the code is hitting). Either that check the flow manually. See what lines it’s hitting and double check to see that there is exactly one *return for every *gosub (and that none of your *gosubs are something like *gotos).

I typed your code in and can’t actually get a crash on that second *return

Do you have a link to all of the code including the *gosub sections?

Incidentally, if you move the bomb goes off to to the first if, you’ve an issue. If the code runs at 30 seconds, then that second elseif will run and display 0 seconds to detonation but it doesn’t seem like it’ll hit the bomb kaboom.

Is that all the code of the subroutine?

If so, change this line:
*elseif ((minute = 0) and (seconds = 0))

to
*else

And let us know how that runs.

@lordirish thanks, i have not figure it out yet, when you are free, i would really appreciated if you help me out. thanks again.

@reaperoa yes, I agree the game is hitting one too many *returns at some point, do you have a link for the automated testing program that I can run and trace line by line? also, i went through the program and made sure all of my *gosub are not *goto before already, but you are right, that would trigger errors, thanks reaperoa.

@FairyGodfeather The code is actually incredibly long, but perhaps try using this subroutine in the 3rd embedded choice, (choice within a choice within a choice), as it seems to happen on the 3rd embedded for me, the 1st and 2nd layers of embedded choices does not trigger the error. I’m not sure about what you’re saying regarding the problem of moving the bomb goes off to first if, because the condition only triggers when both minutes and seconds are at 0, it doesn’t rely purely on the seconds, also, i do want to set the seconds to 0 from 30 seconds because the subroutine is used on every player choice, so the timer continues to count down. Maybe i’m just not fully understanding what you mean? thanks for help by the way

@JimD I don’t think that will work because the seconds are always 0 or 30, so the last *else will never trigger, it has to be a condition where both the minutes and seconds are 0.

What I mean is you can get a point where if you have 30 seconds left when the code runs you’ll qualify for

*elseif (seconds = 30)
*set seconds 0
T - {minute} Minute {seconds} Seconds to Detonation
*return

The text displaying there will be T - 0 Minute 0 Seconds to Detonation. Doesn’t that mean the bomb has then exploded? There is no time left. But the code instead returns you, lets you make another choice, and only then when the subroutine runs is there an explosion.

O, i see what you mean now, it makes sense, you are absolutely correct, I’ll have to embed the bomb goes off condition inside the 30 seconds condition then, so when it reach 0 mins and 0 seconds, it triggers bomb goes off straight away. Appreciated the great catch !

As for the original issue, I’m still trying out different ways to get around it, haven’t figure it out yet.

Zanity, sorry I wasn’t clear. Is the code you posted all of that block?

*if and *elseif require an *else. Your last check has to be *else or it doesn’t work. If that block of code is all there is under *label bombtime, it will fail because you have no *else. If you need (minute = 0) and (seconds = 0), restructure it.

*set minute 3
*set seconds 0

*comment detonation timer subroutine
*label bombtime

*if ((minute = 0) and (seconds = 0))
	Bomb goes off, you've been killed.
        *goto death
*if (seconds = 0)
	*set seconds 30
	*set minute -1
	T - ${minute} Minute ${seconds} Seconds to Detonation
        *return
*else
        *set seconds 0
	T - ${minute} Minute ${seconds} Seconds to Detonation
	*return

O I see what you’re saying now ! it makes sense, thanks so much. I tried your script and the error still shows up unfortunately, i do believe in all of you saying that the error is triggered else where, for me, it’s any of the options in the 3rd embedded choice. (choice whthin choice within choice)

on a side note you pointed out by accident, What exactly is the difference between elseif and if ? it seems like they both do exactly the same thing, elseif just seems like a redundant command because if can do everything elseif can do.

Ok, here’s my long winded script that uses the bombtime subroutine, you should see the return error if you try this out:

Begin test

*gosub bombtime
*choice
	#I run towards the end of the corridor while firing at the marines behind me
		
            You decided to break for the other end of the corridor. As you run, you open fire backwards towards the enemy as they enter. Two marines go down, but the rest of them took cover and took aim. You were an easy target in the long straight corridor. 
		
		The marines showered your body with bullets. Your first feeling was stupefied surprise. You never thought it would end like this, though you knew the risk of every choice you've made. With imminent death before you, you thought about the future, all the things you wanted to accomplish, now at last, you involuntarily relax your body, for there's nothing more to do, after all, you tried your best and now it's time for you to die.
		
		GAME OVER
		
		*goto death
	
	#I return to the security room and wait for them to pass
		You hid in the security room and peak through the gap in the door. Five NUCP marines rush pass you and continues down the corridor. 
		
		*gosub bombtime
		
		You Decided to:
		*choice
			#Get back into the corridor and open fire from behind them
				You return to the corridor. All the marines have their backs turned to you when you open fired, three of them are killed instantly, injuring the forth. Only one marine was able to dive into the corner for cover. 
				
				The injured marine screams in pain as he attempts to crawl further away from you:
				
				*gosub bombtime
				
				*choice
					
					#I finish both of them with the frag grenade
						*goto frag1
					
					#I end the injured marine's misery and deal with the other one
						The agonizing scream ends suddenly when you spray another set of rapid fire into his back. The other marine fires at you but misses as you duck for cover.
						
						*gosub bombtime
						*page_break
						You exchange fire with the last marine for a while, eventually hitting him and concluding this fight.
						
						*gosub bombtime
						*goto labs
						
					#I use the injured marine as bait to lure out the other marine from cover
						It worked ! The last standing marine reached out to pull the injured into cover, exposing his arms. You fire your ${weapon} again at his arms, the impact forced him to fall out of cover and you end both of their misery.
						
						*gosub bombtime
						*goto labs
			
			#I finish them all with my frag grenade
				After they ran passed you a good distance, you let out a battle cry "EAT THIS!"
				*goto frag1
			
			#I let them pass through
				You decided to let them pass through for now, you are after all, tight for time. Yet you can't help the feeling that you should have took the advantage and take care of them as they may be harder to deal with later.
				
				*set guards 1
				*goto labs

*label frag1
throw grenade...

*label labs
end test script
*finish

The auto test is right in the files. Assuming you haven’t pulled the web folder out specifically, look for the files called quicktest.html and randomtest.html in the first folder (If you have just pulled out the web folder, extract the whole folder again and replace the extracted web folder with your own).

I tried punching it in, and I didn’t get any errors. Of course I’m not sure about how exactly it’s all set up on your end considering I had to put it in piecemeal. Is it perhaps that your gosub is at the top of the scene and gets hit before anything else, or somehow the game can bypass all the possible *finishes and hit the bottom of the scene where the gosubs are?

no, my gosub section is near the end, it doesn’t get hit first, actually, i just realize the error is not triggered inside the 3rd embedded choice options, it’s when it tries to come back out, that section of the program i didnt paste, but basically if you add the “gosub bombtime” into both “label frag1” and “label labs” like this:

*label frag1
*gosub bombtime
throw grenade…
*goto label labs

*label labs
*gosub bombtime
end test script
*finish

then the error triggers as it tries to exit from the embedded choice saying routine already return…

update: Ok, this is very strange, I close the CS-IDE, reloaded the file again, and now it works without error =s

Still don’t know why this happened, but thanks for all the help guys, really appreciated it.

Sorry little late to the party but happy it is working for you.

while still on the topic of sub routines, does anyone know if i can use gosub and return from a different scene text file? kind of like *goto_scene

Yes you can, *gosub_scene what_ever_the_page_name and/or label_name then *return from there.