Variables and Where to Store Them - What's Best Practice?

I’ve recently completed my first gamebook and have a question that - maybe - I should have thought of before I started.
In my game, I set variables just before they’re needed. For example, if room 2 contains Goblin A that you’re going to have to fight, I set Goblin A’s health stats variables in room 1. (This example assumes there’s no way of returning to room 1 once you’re in room 2 so the variables won’t be re-set)
I’ve done that throughout the story, so if there’s Goblin B in room 100, I set those variables in room 99.
Does anyone see any issues with this method? Or should I be storing Goblins A and B variables in a separate “Story variables” passage right at the start of the game?
Is there a best practice to follow? :slight_smile:

I’m sure some people have very strong opinions on this (I suspect on the “initialize them all at the beginning of the game” side), but I think it’s up to you and how you like to work (and how your game is designed). Here are some general reasons that I can think of why you might decide one way or the other…

Setting variables just before they’re needed:

  • You keep all the code for that one-off (?) encounter together in closely-related passages.
  • You can’t see the whole game state in any one place: you’d have to look through all of your code.
  • You have to be careful that you don’t add a way to go back to the previous room and reset them.
  • You have to be careful that you don’t add a way to get to the fight without going through the previous room that sets them.

Setting the variables in a startup-tagged passage has the flip side of those:

  • You can see the entire game state in one place.
  • But then you have to manage code for that encounter in two places that might be (?) more separated than just being the previous passage.
  • You don’t have to worry about the variables getting accidentally reset.
  • You don’t have to worry that there might be a way to get to the fight without initializing the variables.
5 Likes

You should do it the way you want to, and it sounds like you’ve been successful.

The only issue you might run into is if you have a big game and you forget what one of your variables is specifically named, (Is it money or Money or cash or Cash?) you might spend some time searching for it. I’ve done the horrible thing where I started misspelling a weird variable partway through a game and it took some intricate global search and replace guessing to find them all.

One solution is to set all the non-temp variables in the first passage, or a specific “Variables” passage the game passes through before the game starts so you know where to look for them.

But in general, do what works for you. Unless you’re collaborating and more than one person needs to keep track of game data then it’s good to have them all referenced in one specific place to look so your collaborator doesn’t create $cash after you’ve created $money.

1 Like

as Hanon says; Keeping the non-local variable in a “variable passage” (ugh… perhaps “passage for variable” is much less ambiguous ?)

Best regards from Italy,
dott. Piergiorgio.

1 Like

It’s worth mentioning that if you work with Harlowe and you don’t initialize your main variables on an startup tagged passage, then you need to take some extra care when using them (especially when testing individual passages).

An unitialized var used like this:

(if: $myVar)[This var is true.]

will break your macro:

whereas this:

(if: $myVar is true)[This var is true.]

will work as expected. My guess is that Harlowe does not treat undefined as “falsy” by default, and the explicit check causes the value to be properly cast to boolean.

3 Likes

Thanks all, that’s useful. I’ve definitely encountered some of those issues like forgetting the name of a variable and wondering why, during testing, my character couldn’t use what I knew they had.

As and when I write my second, I think I’ll go down the road of a “passage for variables” right at the start for the non-temporary stuff.

Thanks for the thoughts.

A couple of things about the Harlowe scripting/macro language.

  • Unlike some other Story Format’s Harlowe’s language is not a thin abstraction layer over JavaScript. And this is why JavaScript language features like the following don’t work: data-type cohesion; Truthy and Falsy; Bracket and Dot Notations.
  • any variable that is referenced before it has been initialised is automatically assigned a value of numerical zero. Thus there is no equivalent of JavaScript’s “undefined”.
  • Harlowe doesn’t do automatic data-type casting when performing an operation on values that have different data-types. Which is why a Numerical zero isn’t equal to Boolean false.
2 Likes