Gosub / Choicescript_stats Confusion


#1

In the wiki they provide with the below code snippet example, but I don’t really understand how it works. Does it automatically run in every scene because it was declared in choicescript_stats? Or do I need to specify it under a *label and treat it like a gosub routine? How about multiple subroutines?

*temp wound_text
*if wounds = 0
  *set wound_text "Uninjured"
  *goto chart

*elseif wounds = 1
  *set wound_text "Battle-scarred"
  *goto chart

*elseif wounds = 2
  *set wound_text "Permanently wounded"
  *goto chart

*elseif wounds = 3
  *set wound_text "Permanently weakened"
  *goto chart

*elseif wounds = 4
  *set wound_text "At Death's door"
  *goto chart

*label chart

*stat_chart
  text wound_text Wounds

#2

IIRC that’s example code taken from Choice of a Dragon, simply showing how a numerical value can be turned into text for displaying on your Stats page, rather than always having to use numbers or percentile bars. Take a look at that game again (it’s free to play on CoG’s website) to see the end result in-game and get a better idea of its purpose.

But to answer the other part, yes, there’s no reason why something like this couldn’t be a labeled subroutine using *gosub / *return for including conditional text in story narrative, in an ordinary scene file.


#3

I tried to put a couple of subroutines into choicescript_stats, but only the first one worked while the others did not. Tried with and without *label, makes no difference and when with label, I tried calling it from a scene file but it didn’t work ‘bad label’. Admittedly, it was probably not the right way.

What I’m looking for is to make these scripts permanent in every page; that is to declare one time in choicescrip_stats and just use it throughout the whole game (since these will be checked again and again). Or must I declare them at the start of every scene file and gosub? Would appreciate an example, thanks!

*label yourwoundcheck
*if yourwound = 0
  *set yourwound_text "Eh."
  *goto chart
*elseif yourwound = 1
  *set yourwound_text "Aiita."
  *goto chart
*elseif yourwound = 2
  *set yourwound_text "Kuso!"
  *goto chart
*elseif yourwound = 3
  *set yourwound_text "Yameteh!"
  *goto chart
*elseif yourwound = 4
  *set yourwound_text "Soshite boku wa shinu."
  *goto chart
*label mcomapasscheck
*if mcompass <= 0
  *set mcompass 0
  *set mcompass_text "Unleashed"
  *goto chart
*elseif mcompass < 3
  *set mcompass_text "Freedom"
  *goto chart
*elseif mcompass = 8
  *set mcompass_text "I am who I am."
  *goto chart
*elseif mcompass < 10
  *set mcompass_text "Righteous"
  *goto chart
*elseif mcompass >= 10
  *set mcompass 10
  *set mcompass_text "Puritan"
  *goto chart

#4

Well, I can’t say I’m an expert coder, but I have been working with some similar things recently, and the first question is the basic one. Did you *create yourwound and mcompass? Second, your math on mcompass looks a bit off. When mcompass is < 10, you get “Righteous”, but that means that you will never get the tags for “I am who I am”, “Freedom”, or “Unleashed”. You need a bottom variable for the range to establish the parameter. Just my two cents.


#5

The important thing to bear in mind (and where I suspect you may be going wrong) is that a subroutine always needs two things - a unique *label name for *gosub to reference, and at least one *return command. Without both of those, it’s not a valid subroutine for *gosub purposes. It’s worth taking another look at the Wiki page on the subject to better understand how a subroutine works, paying particular attention to the explanation accompanying the example code:

To achieve what you’re aiming for, though, the command you actually want to use is *gosub_scene [scene_name] [label_name], e.g.

*gosub_scene routines yourwoundcheck

This would allow you to place all of your subroutines in a single scene file called ‘routines’ (or whatever you choose - just don’t use choicescript_stats), able to be accessed from any scene in the game using the above command. Each subroutine in there would have its own unique label (e.g. yourwoundcheck), but do remember that each one must also end with a *return command. In the case of yourwoundcheck, for example, you would simply use *return in place of every current *goto chart - that’s what makes it a subroutine.

Edit: I should also add that every use of *if in combination with *elseif should ideally end with an *else (with no condition of its own), as a ‘catch-all’ in the event that none of the above conditions apply - otherwise the game may crash.


#6

Not entirely correct. It’s worth remembering that ChoiceScript reads literally a line at a time (just like a human, only much faster!) which means that the conditions for “Unleashed”, “Freedom” and “I am who I am” are entirely valid, because it checks all of those before it gets to the one for “Righteous”. If those were all listed in reverse order, however (with “Puritan” first, then “Righteous”, etc.) then yes, it would indeed never get past “Righteous”…

That make sense?


#7

Ahh, I see, so that’s how it’s done. It was mentioned in the Wikia that the code snippet was a modified example to show in a basic way how things work, but I was confused as to how it really worked in context. I think that’s exactly what I need - thank you really much!


#8

Excuse me, but i have one more question (hopefully the last):

  1. I’ve read that if you are using *gosub, you must end both *choice or *fake_choice with a *goto. In that case, does that mean that *fake_choice has become meaningless when you use *gosub; because it’s no different from a *choice anymore, and you must go to a *label no matter what? In that case, wouldn’t it be very convoluted, since there are a tonne of labels I have to make with almost every *choice option?

Basically, I just want to display a description that adjusts accordingly when the stats Wound and Moral Compass changes. I also want to make sure these values don’t go above or below the cap. But if I have to change the entire structure (replacing *fake_choice with *choice) to do it, well… is there a better way?

My sincerest apologies if I’m troubling you with my ineptitude.


#9

I’m not sure if this will help, but I have a method I use in most of my games to calculate stats and descriptions before any major scenes. I have a separate scene called “calculate.txt” and basically whenever I want the player to have correct information I drop this line of code:

*Gosub_scene calculate

At the end of calculate.txt I have *return and that brings me back to wherever I called the subroutine. The player never knows it even ran, but now the game has the correct text and numbers for all the variables I wanted to calculate.

I run *gosub_scene calculate at the top of ChoiceScript_stats (this keeps my stats page clean, plus I can calculate without displaying stats) and before any combat in the story, basically it calculates how much damage the player would do, how much health they have, etc. Similar to what you have there.


#10

Thanks for the suggestion. I tested your advice and after a bunch of experiments I think it’s working right now?

  1. If I’m trying to cap stats, I should use *if all the way. I can put all kinds of stats under the same criteria and *return at the end. But I haven’t tested if it will work if I try to return more than one value, so I’ll be checking once I finish replying this.

EDIT: Nope doesn’t work that way, I’ll need to call them again for each *set. Still, it worked!

  1. If I’m trying to change the description, then it’s better to use *elseif with a *return under every *elseif. Also an *else as mentioned by Vendetta to catch a crash.

#11

Haha yeah, I rarely RARELY ever use else or elseif. I just use *if. If the condition is met, the code will *return.

In order to pass a quickest just add *return on its own, unindented line at the end of all your *if checks.

It’s also important to check for blank variables ("") so say if you unequip a weapon, you can set damage to 0, instead of having “” equipped and 15 damage. For example.

*if weapon = "sword"
	*set damage 10
*if weapon = "axe"
	*set damage 12
*if weapon = ""
	*set damage 0
*return

But in my actual code I wouldn’t return after just that, I would check every single possible variable, THEN *return, and everything would be set. If you did this, for example, you would never be able to check your armor stats:

*if weapon = "sword"
  *set damage 10
  *return
*if weapon = "axe"
  *set damage 12
  *return
*if weapon = ""
  *set damage 0
  *return
*return

*if equippedarmor = ""
  *set armor 0
  *return
*return