reset (select) ?

is there any way to “reset” a (select), that is, manually force it to start over at the first branch?

i’m thinking this is a compiler thing and not a dialog thing, but just asking.

Unfortunately not. There’s no technical reason it couldn’t be done—under the hood, there’s a byte of memory where each (select) block holds its state, and that byte could be zeroed out to go back to the beginning—but the language currently offers no means to do that.

As far as adding the capability—the problem is, there’s no real way to reference a particular (select) statement in Dialog syntax, and I can’t think of a good way to add one. One could imagine a (reset) builtin that resets whichever (select) it’s inside of, but you’d mostly want to do this outside the (select), which means needing some way to choose the appropriate one.

For now, the best way to do this is to basically reimplement the (select) behavior with your own global variable.

yeah, sounds like more trouble than it’d be worth. the functionality isn’t hard to reproduce “manually”. i was just curious since (select) is so freaking convenient.

It really is! And if you think of a nice way for it to work syntactically, it wouldn’t be hard to add to the language. But part of the convenience of (select) is not needing to keep track of labels for them, and I don’t want to lose that.

Something like this?

    (select #wotsit)  %% optional id
    ...
    (or)
    ...
    (cycling)

    %% elsewhere
    (reset select #wotsit)

That would be doable, yeah! Perhaps also a way to access the most recent value of it (the most recent branch printed), but that risks exposing too many implementation details and causing problems for future development.

At that point, there are two ways to handle this:

  • The ID works like a style class ID, in that it has to be a compile-time constant, converted to the appropriate select address when compiling
  • The ID works like a resource ID, in that it can be any sort of value, and the appropriate select address is looked up at runtime

The former is much easier to implement, and I suspect will be enough in most situations.

Yeah.

You might want three operations:

  • reset to beginning
  • pause/stop
  • restart a paused select

The first one sounds much simpler to reason about and also like it would produce much simpler (Z-machine/Å-machine) code. Is there an obvious use case for the second thing that’s common enough to be worth the marginal benefit of not having to write your own logic for it?

Not that I can think of, honestly! It would be much nicer to have non-constants for style classes, but that’s built into the structure of the Å-machine at this point.

I can see the use cases for all of them, but at the same time the goal of Dialog is to stay light and elegant wherever possible, so I don’t want to add too much complexity.

What would pausing a select even do?

I think the intent is to keep it from advancing, basically freezing its current value in place and not letting it change.

Never update its state so it would always go to the same branch? Not sure about the at random ones, though.

Wouldn’t adding labels to selects also help with the debugger? It would allow it to remember their state between modifications and not reset them.

But all in all I don’t think this feature is worth that much, because it’s easy to make your own version if needed, even if it’s less ergonomic.

It would potentially help with the debugger, but the debugger currently has a staggering amount of logic to figure out on its own which (select)s correspond to one another, and I’m afraid to even touch it!

There’s a reason for it now: if you write a suite of unit tests for a game that has side effects happen on a particular output from a (select) (Cloak of Darkness does this), you really want the (clean up $) for that test to reset the (select) after the fact so that you don’t lose your ability to test that code in later tests.

Some of the fancier options in this thread are spiffy-looking, but honestly, I’d settle for just one master reset that reset all of the (select)s in the game back to their initial state. Or, alternatively, a master master reset that put everything back to the way that it was when the game finished loading. (If this were Scheme instead of Dialog, saving a continuation at the end of the intro to call/cc back to would be just the thing.)

It sounds like what’s really desired here is a way to persist some state across a (restore), (undo), or (restart). That way you don’t have to manually keep track of what needs to be reset.

That’s definitely a thing that I desire, but this wasn’t the case for that, and I’m not following how that helps here.

Persisting a little bit of state across a (restart), especially if the interpreter can be made to restart a different game file, would allow you to write arbitrarily large games on vintage hardware such as the C64, so long as you divided your game up into discrete “acts” that only needed to pass a little bit of state (which of several endings was reached, what events happened, which NPCs bit the dust, and so forth) from one to the other. That would also let usefully large IF games to be played on systems with only a tape drive. You’d want to limit the amount of state you were passing around, because the fallback would be giving the player a string of alphanumerics to type in on the keyboard if you’re playing the game on an interpreter that doesn’t support passing state from one invocation to the next.

But that’s a whole other conversation, not really related to reseting (select). (Which I’m less hot on now that I’ve seen how easy it was to rewrite Cloak of Darkness to not use side effects from a (select).)

Specifically, this:

That’s pretty much exactly what (restart) does, but presumably you’d want some bit of state (which test comes next) to be persistent, otherwise you’d just run the same test again and again.

You could also do something like this:

(exhaust) {
	*(test $Test)
	(if) (save undo 0) (then)
		%% set up and run the test
		(undo)
	(endif)
}

But then the program would have no way to know if a previous test failed or not. The results would persist on the screen for the author to see, but you couldn’t switch the bar from green to red, or set the program exit status. Each test would exist in its own pristine universe with no knowledge of how the previous ones ended.

(You can work around this by using (error $ entry point) and deliberately crashing the game, but I really wouldn’t recommend that.)

So it seems like what’s really needed here is a way to reset everything except some particular bit of state (a global variable, the program counter, something like that). The (select)s are only a small part of the relevant whole, right?