Grr...More restrictions found on the stats screen

(Looks like I accidentally posted as @dfabu, now posting as @dfabulich correctly.)

Actually, it turns out “some point” is right now. :slight_smile:

I’ve been putting some more thought into this topic and wanted to write down some of my musings.

A lot of the weirdness of choicescript_stats has to do with the “refreshability” goal of ChoiceScript.

Note that in published games on, if you refresh your browser while playing the game on the web, it remembers where you left off (assuming you have cookies enabled). Something similar happens if you quit the downloadable apps (iOS, Android, and Steam apps) and reopen them.

Suppose you have code like this:

*set leadership %+20
Now your Leadership is ${leadership}.

When I first implemented ChoiceScript, when you set a stat, we’d update your stats right at that moment. This created a bug where if you refresh the page on code like this, your Leadership would keep going up and up and up.

So, instead, the policy is to accumulate all temp/stat changes and only actually save them when the player clicks “Next.” Suppose you start with Leadership 50, so %+ 20 gives you Leadership 60. When you see the “Next” button, your saved Leadership score is still 50; it would only increase to 60 at the moment you click “Next.”

If, instead of clicking “Next,” you refresh the page (or quit/reopen the app, or whatever) we’d restore the game based on your old Leadership score of 50 (since the stat bump wasn’t yet saved). We’d then re-apply the stat bump, giving you a Leadership of 60 again; only once you click Next would the changes stick.

That worked pretty well, but it created a major bug on the stat screen, which I then had to work around: if you check your stats right after your score goes up, you’d see the old Leadership score (50), not the new one (60). It was especially embarrassing when the text just told you what your new score is, but then you’d check the stats screen and it would already be out of date.

To work around this bug, I created two saved games, one “regular” save that would be used for refreshing and restoring the main game, and one “temp” save that would be updated immediately after stats changed. In the regular save, Leadership would be set to 50; in the “temp” save, Leadership would be set to 60. Then, the stats screen would use the temp save. When returning from the stats screen, we’d refresh the game based on the regular save.

But that created a new problem, which, at the time, I thought was pretty minor: you can’t *set any permanent stats on the stat screen, because anything you *set would be set in the temp save, which would be lost when you navigated away from the stat screen.

I still don’t have a good way to handle this. What should happen in this case?


*set leadership %+20
Your Leadership is ${leadership}.
*if Leadership > 70
  Your leadership is high enough.
  Your leadership is too low. You lose reputation.
  *set reputation %- 20

*label start
  #Boost leadershp
    *set leadership %+30
    *goto start
  #Boost strength
    *set strength %+30
    *goto start

Today, main.txt won’t truly save the stat bump until you click “Next Chapter,” and the stats screen will show Leadership=60. If you bump Leadership on the stats screen, it will appear to work, but the changes will be lost when you dismiss the stat screen.

Suppose I tried to let you modify stats permanently on the stats screen. If the stat_chart shows Leadership 60, then presumably Leadership %+ 30 should give you a Leadership of 72. But what should main.txt say when you return from the stat screen? Should it still say “Your Leadership is 60; too low”, even though it’s now 72? Should it undo the reputation change? How would it know to say 72 and not 77 (72 %+ 20)? What should we show/do if you then refresh the main page/game?

In a very real way, letting you set stats on the stat screen means you’re playing the same game in two panels at once (especially on iPad, where both panels are visible simultaneously), where neither panel is strictly “primary." What should happen to the left panel when the right panel changes something, and vice versa?

1 Like

Very interesting analysis of the problem. I have tended to think of the stats screen as a snapshot of the game at the moment I consult it, not an action screen where I can change things. I would put actions and options that can change my stats into the main line of the game.

One workaround for those wanting to allow actions there would be to put a big, honking WARNING onscreen that the stats on the stats screen and those displayed in the main screen may not match until you end the scene. Doesn’t really feel like smooth game play, though…

@dfabulich Ah, it’s great to see you replying. I was wondering how you viewed this idea. That does sound complicated, CJW mentioned something to that effect… I shouldn’t really even try to come up with a suggestion as I don’t know enough of JavaScript, and I don’t know what you’ve tried either, buuut, what about adding another permanent variable then?

The temporary one gets set to the first permanent one yeah?
Then what about setting a second permanent one to the temporary one when you leave the stats screen, and then setting the first permanent one to the second one as you return to main?


*set temp_var one_perm_var (entering statsscreen)
*set second_perm_var temp_var (leaving statsscreen)
*set one_perm_var second_perm_var (entering game)

I dunno if this is at all feasible, just trying to be of help. I’d love to see the option of having a “living” statsscreen, that you can update in real time, realized.

@MutonElite I’m not sure I understand your suggestion.

Concretely, how would you answer the questions I asked for the second example above? What should the game say when you return from the stat screen? I can think of only two possible answers.

Answer 1: Immediate refresh. It should say, “Your Leadership is 72,” and the reputation hit should be undone, which should be immediately reflected on the stat screen (e.g. on iPad, where the stat screen and the main screen are visible simultaneously).

Answer 2: Delayed effect. It should say what it said before, “Your Leadership is 60; too low.” Stat bumps on the stat screen shouldn’t affect the main game right away, but only take effect when something else happens, e.g. when you click “Next” in the main game.

I’m afraid that Answer 1 may result in infinite loops. To pick a perverse example, what if the game looks like this?

*set switch not(switch)
Switch is ${switch}.

*set switch not(switch)
Switch is ${switch}.

If the stats screen can affect the main game, which can then automatically update the stat screen, which affects the main game… where does it end?

Answer 2 won’t result in infinite loops, I think. In the perverse example above, if the Switch variable starts off false, then main.txt would say “Switch is true,” and the stat screen would say “Switch is false.” After you click “Next” in main.txt, the main game would see that the Switch is now false again.

It won’t result in infinite loops, but it seems like a bug that the main game would continue to say “Switch is true” even when the Switch variable is actually false, or rather, it will be false as soon as you click “Next.”

Answering these questions really requires us to figure out what exactly why people want to set stats directly on the stats screen. Examples I’m aware of include:

a) Tin Star lets you set a “display mode” variable on the stats screen, determining how your stats are displayed. The default (IIRC) is *stat_chart mode, but you can switch it to be a purely textual description, instead. Unfortunately, every time you leave the stat screen, it forgets your preference, so if you prefer the other mode, you have to manually switch into it every time you visit the stats screen.

b) Putting ambient/alternative choices in the stat screen. For example, the player might have an inventory of collected items shown on the stats screen; you might want people to select an inventory item on the stats screen to use it in the main game.

In (b), Answer 2 (Delayed effect) would clearly be unacceptable. But I don’t think the stat screen is the right way to handle that anyway. Indeed, ChoiceScript is not at all designed to let the player choose to do something that isn’t an #option in a *choice. I feel like this would/should require a totally different approach to scripting the game. You’d want a scripting system that felt more like Inform or AGS.

I’m not aware of any other reasons to set stats on the stats screen. Are there others?

As a closing aside, @MutonElite mentioned, “I’d love to see the option of having a “living” statsscreen, that you can update in real time, realized.”

I’m not totally clear on what you mean by that, but maybe that’s exactly what we already have on iPad? On iPad, the stats screen is always visible (if you hold the iPad in landscape mode) and the stats screen instantly refreshes when stats change in the main game. Of course, the main game never changes in response to stat screen changes, because the stat screen today can have no effect on the main game.

For ref, here’s what Muton earlier said he’d like to do with choices in the stat screen:

See in particular the first and last posts.

@dfabulich What about instead of trying to modify the stats in the stat screen, you had another screen specifically for things like inventory and stat modification (if the game is set up for it)? Or basically adding another button next to the “stats” button. This screen could have built-in slots for items and such, and you could modify the stats if the author has that enabled. Maybe something like this

*inventory health_potions health - 1

Like maybe at the top of the scene file each element could have a true/false switch of some sort, which could be then enabled by the author or whatever. I know something similar can be achieved with *gosub_scene and such, but the player would only be able to access it when they have the option put in, whereas with this the player could access it at any time just like the stat screen.

@dfabulich I feel like I’m too much of a novice to get all of it. But essentially, where we’re at right now, is that a variable can be changed on the stats-screen but the change doesn’t carry over or last, like you said.

I’m not sure I understand how that would create an infinite loop though, if you close the stats screen, reopen the game, and the stats update, or vice versa, pause the game and open the stats screen and the stats update. Won’t that just happen once, when you open and when you close it? I honestly don’t know. I get what you’re saying that currently it’s set to update only when you click next or the equivalent. Is there no way around that then? Updating it when you reload the main game returning from the stats screen or arrive at the stats screen?

I haven’t played any of these games on an ipad, didn’t know they differed that much. That sounds like it’s a whole different system then? I suppose you can’t “close” the stats screen at all then in the ipad version, thus negating any fix I could think of.

Like @fantom said; "I know something similar can be achieved with *gosub_scene and such, but the player would only be able to access it when they have the option put in, whereas with this the player could access it at any time just like the stat screen. "

This is essentially what I’ve been saying, if you have something like an inventory system on the stats screen, then you won’t have to insert code everywhere, gosubbing to it. That’s what I’ve been hoping for. Though I dunno if adding another button would work either, because then we’d just be having the same problems? Unless you could create a permanent gosub button.

And thank you to @Havenstone for linking, I wrote a few examples there as well, of a few things that could be achieved if the stats screen could update and stay updated.

If the only way to update it is through next and it can’t be changed, then I’m stumped. Creating your own gosub button up among the stats and the achievement ones though, how does that sound?

Let’s focus on the iPad version for a moment, not least because I began thinking about this topic as I considered bringing the iPad approach to the web.

It looks like this:

Here’s how it works today.

  1. Load/restore the current scene file from the “main” autosave slot.
  2. Play the current scene file until it reaches a “Next” button (*page_break, *choice, *finish)
  3. Save the updated stats into a “temp” autosave slot.
  4. Refresh and re-run choicescript_stats.txt in the stats screen, using the “temp” autosave slot.
  5. The user clicks “Next” in the main game. Now we save the updated stats into the “main” autosave slot.
  6. Return to Step 1, running through Step 4. If we then refresh the game at this point, we can run and re-run Steps 1 through 4 as many times as we like, without double-counting stat bumps, etc.

(The web version is exactly the same, except we don’t run Step 4 until the player clicks “Show Stats.”)

The solution I called “Answer 1: Immediate refresh” would insert a step between Step 4 and Step 5:

4.5) If the user clicks “Next” in the stats screen, save the “main” autosave slot and go to Step 1.

That could easily cause an infinite loop.

The solution I called “Answer 2: Delayed effect” would be easier to implement, and would at least fix the Tin Star bug.

In that solution, we’d modify Step 5 to copy the “temp” save on top of the “main” save, so changes that happened in the stats screen would eventually have an effect, just not right away.

Regarding an inventory panel, that goes to my point about ambient options. If you write a *choice, what exactly is supposed to happen when someone clicks a button that isn’t an #option in that choice?

Inform has a mechanism called a “rulebook,” where you can write, “Whenever X happens, Y happens as a result.” The whole game is written in that style. You’d kinda need to add rulebooks to ChoiceScript. But ChoiceScript is a completely different philosophy from rulebooks, and I’m afraid that mixing and matching them would result in a jumbled mess.

For example, suppose I do somehow sort out the infinite loop problem. Would you write a puzzle like this?

*if key_used
  The door unlocks!
  *set key_used false
*if chicken_used
  The chicken does nothing.
  *set chicken_used false

*label door
You see a door.
  #Knock on the door.
    No one answers.
    *goto door
  #Open the door.
    The door is locked.
    *goto door

*label start
  *if (key) #Use the key.
    *set key_used true
    *goto start
  *if (chicken) #Use the rubber chicken.
    *set chicken_used true
    *goto start

That looks like an enormous hassle. What if there were dozens of items?

Instead, a proper “inventory” system would be needed. Maybe something like this:

*label door
You see a door.
  #Knock on the door.
    No one answers.
    *goto door
  #Open the door.
    The door is locked.
    *goto door
  *inventory key
    The door unlocks!

But now we’re talking about building an inventory system, not just setting stats on the stat screen, and it’s barely a step toward a general system for handling “ambient options” of all kinds. (e.g. a “give me a hint” button). And what happens if the user tries to click on the chicken at this point, where the author forgot to mention the chicken in the list of options?

A rulebook system would be much better.

Whenever the player tries to use the key, if the door is nearby, unlock it, else say, "There's nothing here to unlock.

But that’s a completely different language!

@dfabulich What are you saying exactly? It can’t be done? You’re stumped? I was kinda hoping a brain-thrust would form here and toss ideas around, as I’m woefully unfit myself. :-/ Having more options as coders is something that ought to interest everyone making a COG. But I suppose in terms of suggestions/ideas, noone knows more about the engine than you do, most of us are only driving the car, we have no idea what makes it go forward…

This ipad stuff feels like an anvil around my neck, I don’t much care about it myself as it’s not my platform of choice but obviously it would be unfair to offer limited experiences or even to break games just because the user is on another platform. So yeah, I dunno… I dunno. I have seen games with custom made buttons where they have modified the JS file instead, I’m curious as to how that affected the ipad users.

But yeah, I hadn’t really considered what would happen if you choose an item in the supposed inventory screen like that, where it would move forward from then. Potions/Health packs and the equivalent would work fine because they’d just modify a stat, but items that drive the story forward is a whole nother matter, depending on how you code it. I dunno if those things NEED to be accessed from the inventory screen though, in the case of the key, that would be much smoother to just *if (key) #Open, rather than having to go switch screens for it obviously.

I can still see a lot of uses for such a screen though, you could potentially switch between dimensions, like in Soul Reaver, doesn’t even need to be a pure inventory screen, it could depend on what you need/want. And even if you can’t use all items directly on the screen, you could still play around with variables, combining items, inspect items, use anything that would affect pure stats, since it’s a *gosub there wouldn’t be the same delay either. It’s sorta like key-items vs restorative items. In RPGs, you usually don’t need to tamper with the key-items, just having them will trigger the event they’re meant for. And even if it would be a hassle, it would still be an optional thing after all. I’d hate to give up on this idea as I can see so many possibillities emerge from it.

OK, here’s what I’ve got.

  1. *redirect_scene: A New Variant of *goto_scene

Previously, when using *goto_scene in the stats screen, it was just buggy; the game was partially in stats mode and partially not in stats mode. A few weeks ago, I “fixed” it so *goto_scene and *gosub_scene would reliably leave you in stats mode, requiring the user to actually click a button to leave stats mode.

The *redirect_scene command only works in stats mode; it exits stats mode and executes a *goto_scene command back in the main game. In tablet mode, the stats screen can’t be “exited” (it’s always visible as a panel on the side of the screen) so we just *goto_scene back in the main game and then refresh the stats screen.

Like *goto_scene, you can add a label name, e.g. *redirect_scene party invitation to redirect to party.txt at *label invitation.

I haven’t written up a lot of documentation about it yet, because I’m not 100% convinced that I like the name *redirect_scene. I’d like to call it *exit_stats_and_goto_scene_in_main_game if that weren’t such a mouthful…!

  1. Saving In Stats Kinda Works Now

In the latest version of ChoiceScript up on github, *set commands on the stat screen will take permanent effect, but only after you return to the main game and click Next.

So, for example, if you have code like this:

*create count 0
*set count +1
page 1: ${count}
page 2: ${count}

*set count +1
  text Count

Now suppose you start the game and visit the stats screen eight times without doing anything else.

Surprisingly, even though you visited the stats screen eight times, the counter will show “page 1: 1” in the main game and “Count: 1” on the stats screen. But as soon as you click Next, it will correctly show “page 2: 9,” one for each visit to the stat screen plus the initial +1 for starting the game.

In other words, we refresh the stat screen when the main screen changes, but we don’t refresh the main screen when the stats screen changes. (That would be an infinite loop.)

As a result, players can now set preferences on the stats screen, e.g. it mostly fixes the bug in Tin Star where you can’t force it to remember that you want the stats screen to stay in “story mode.”

(That is, the Tin Star bug is completely fixed in tablet mode, where there’s no way to exit stats mode. In non-tablet mode, if you select story mode, exit stats and immediately re-enter stats, your preference will be forgotten. But if you exit stats, click Next and then re-enter stats, the preference will stick.)

If you want to make a change on the stat screen that has an immediate effect on the main game, use *redirect_scene instead of just *set.

What do you think? Close enough?


Wow! Hmm, will it trigger before anything else then? Like before the code after the choice. Because if so, it is practically instantaneous and the only lag would be if you had a display in the main game right?

Like if you used a health potion in stats before you choose get punched or something, if it triggers/updates directly once you click next then that’s awesome. grovels in reverence :smiley: The only thing I can see, is if, let’s say the choice is dependant on the update to be selected, like if you have a choice that says, costs a 100 gold, then you go into the stats screen and select break piggy bank and get 100 gold but still can’t select that option. That would be the only thing, but I’m happy to get this much still. Great job, thank you so much!

I’m curious about the redirect scene. It basicly functions like a normal *goto scene, but from the stats screen? What happens with the original position you were in, in the main game then, is it forgotten/overwritten? So let’s say you’re at apartment.txt, go into the stats screen and select open invitation, it transitions you to ball.txt, and forgets the apartment then?

I guess one could save what chapter and what label one is at, and use the *goto_scene to jump back to that place after one has gone via the route of *redirect_scene? Like so;

*set chapters "chapter_one"
*set labels "home_sweet_home"
*label home_sweet_home

  #Drink Potion
    *redirect_scene potions

*set health 100
*goto_scene ${chapters} ${labels}

Something like that?

Yup. If you want to have an instantaneous effect on the main game, you’d have to do *redirect_scene and try to jump back to the right spot.

Yes, because it is actually ambiguous. e.g. in this code:

*set health -20
Now what?

If you drink a health potion right before punching, it’s not clear whether you’d want to “go back” to the *page_break line (and re-run the *set command) or go back to just the *choice (skipping “Now what?”). So the author has to decide exactly where to go back.

*goto_scene doesn’t accept ${} variables. I think you’d have to do it with *if/*elseif. But I think something like that would work.


Mhm, okay. Awesome, then at least there’s now a way to work around it. Thanks again! Super excited now! XD

@dfabulich Just thought it might be worth suggesting; if the save stat bug is completely fixed on tablets due to how the stat screen is displayed, surely making the web client operate in the same (or similar way) would be preferable to get rid of the problem altogether?

I’m not familiar with JS at all but if users might feel bothered by constantly having stats displayed at the side of the browser window, would it be possible to contain them in a collapsible panel?

Either way, thanks a lot for this commit! :slight_smile:

I’m a little late coming to this conversation, but I feel I should say, in regards to creating infinite loops due to changing variables in the stat page, really, it’s up to the programmer/writer to avoid doing this, like with anything. Theoretically, one can create an infinite loop with labels and goto after all.

Couldn’t there be a separate div for the stat chart? This div would be invisible most of the time but made visible and placed over the regular game div when the stat button is pressed. This would make it like the tablet version, just that it wouldn’t be visible all the time.

I’ll say the same thing here as I did on the discord server:

I don’t get it, isn’t there a way for the devs to keep track of if you’ve visited the same page before? Can’t you just implement some background variable that keeps track of if you’ve refreshed the page, and if the variable thinks you have, ignore other variable changes on the page if you update? That way you wouldn’t really need to have multiple types of variables.

What’s wrong with

*set nextscene "scene1"

*goto ${nextscene}

EDIT: Oh wow didn’t realise how significantly this thread had been necro’d.

1 Like

That syntax didn’t exist at the time. Yep, I’m going to close this. I don’t think there’s much to add.