'subroutines' and every turn

There are several subroutine-ish things in I7…

Function-like things (i.e., taking parameters and returning values):

  • Definitions take 1 parameter (some specified kind of value) and return a truth state (i.e., true or false)†
  • To decide what/which <kind of value> phrases take 0 or more parameters and return 1 value (but the <kind of value> can’t be a truth state; To decide if phrases create conditions, which isn’t the same thing as returning a truth state)
  • Rulebooks take 0 or 1 parameters and return nothing or 1 parameter
  • texts with adaptive text are really functions that return a text on demand when you output them or ask for their substituted form

It’s a pain but if you really want multiple-parameter output you can make the one parameter an object with multiple properties, or a list of objects (or other kinds of values)… or, well, get used to an over-reliance on global variables.

Subroutine-like things (can’t return values)

  • To phrases/To say phrases take 0 or more parameters and execute some amount of code. Each can do everything the other can with one important distinction: you can use say phrases for adaptive text within texts by invoking them within brackets. (With a related second important low-level distinction: this provides the easy way to get text that’s output by print statements in Inform 6-level routines into Inform 7 text variables.)
  • Rules don’t take parameters on a per rule basis, but if they’re part of a rulebook that takes a parameter, they can get access to that parameter. A rule can be invoked discretely with follow the this-specific-rule-name rule;. A rule within a rulebook that produces a value may produce a value on the rulebook’s behalf, but even if the rulebook produces a value, any given rule doesn’t have to, and it’s common that many of them won’t.
  • Rulebooks can be viewed as one big subroutine. The rule preambles are essentially a flow control mechanism, determining which bits get run.
  • Activities are basically 3 rulebooks, and can be viewed as one even bigger subroutine. (They take 0 or 1 parameters but cannot return a value.)

The way you make an every turn rule get ignored when it’s not relevant is by doing nothing and not worrying about it. Say you have something that’s triggered only when the moon is blue and you’ve implemented it with every turn when the moon is blue:. But you know there’s just one period in the game when the moon will be blue, and once the moon’s no longer blue, there’s no need to check that anymore, so you don’t want that check wastefully consuming cycles for the whole game.

…except every scheme you come up with to check whether you need to make that check will still involve a check every turn.

You can make Blue Moon a non-recurring scene (that’s the default for scenes) as an organizational device, but the most straightforward way to implement related rules (other than the when scene begins and when scene ends rules) is still every turn when blue moon is happening.

So don’t write every turn rules of the form every turn when x is not the optimal solution to the travelling salesperson problem... and otherwise relax and don’t worry about it. (This isn’t to say that you can’t get into speed problems with large games, but you’d have to cross that bridge when you came to it by figuring out what the bottleneck for that situation was.)

† edited to clarify: well, sort of… Definitions are written to answer yes or no for some given test, but it’s not the case that they return a truth state per se. They create adjectives which can be used in multiple places in Inform 7, including as the basis for conditions.