Inform 7 for Programmers/Part 4b

From IFWiki
Jump to: navigation, search

Time, Turns, and Tenses

Time comes in at least two flavors, instants and durations, which are as different as a point is from a line segment. "At 3:30 PM" would be an instant, a specific point on the timeline. Three and a half hours would be a duration. Internally, both flavors are stored as the number of elapsed minutes since 4 AM, and only Understand directives distinguish between the two, with "time" being an instant and "time period" being a duration.

Instants and durations can also be measured in turns and used in rule header adornments like "when the turn count is 1" for the very first turn of a new game, and "(condition) for at least 4 turns" which is true only when the inner condition has remained true for four (or more) turns in a row. "The turn count" relates to "the time of day" by the ratio 1 turn per 1 minute, though extensions can adjust that.

Math with instants and durations is straightforward. The sum or difference of two durations produces a duration. Negative durations print as "<no time>" though the exact value is still in there. The sum or difference between a duration and an instant produces a new instant: 3:30 PM plus an hour yields 4:30 PM. Two instants may be subtracted for a duration, but the sum of two instants is nonsense.

English succinctly expresses temporal information through verb tense. Besides the past / present / future axis, there is the simple / perfect axis and the instantaneous / continuous axis, the latter of which corresponds to instants and durations. Inform uses the simple continuous present tense to describe the current action because the entire run of rulebooks from Persuasion to Every Turn happens during that action:

Every turn while [we are] taking something fragile, [the "we are" is optional]
if [we are] taking something fragile, ["we are taking", not "we take"]

Verbs of State and Verbs of Change

English divides its verbs into "verbs of state" and "verbs of action" based on if the verb supports continuous tenses. For example, watch is a verb of action: "He is watching TV" makes sense. Own is a verb of state: "He is owning a car" doesn't work in continuous tense; only "He owns a car" is correct. Implementation of verbs in Inform very roughly follows this guideline: verbs of action are implemented as Actions; verbs of state are implemented as Relations. The purpose of almost all Actions is to set or unset a Relation. For example, Taking and Dropping modify the containment relation.

(Furthermore, various-to-one relations (among others) are frequently implemented as properties on objects. For example, physical location relates various people to one room -- a person can only be in one room, but a room can hold many people. This is implemented as giving people a "location" property set to the one room they're in. In this section when we refer to Relations we are also referring to such object properties, and theoretically to all object properties, and perhaps even to data in general.)

We distiniguish between the verbs of state and change because past tenses only work on verbs of state and the implementation differs for present-perfect tense. Also, while it is possible to declare a verb as both an Action and a Relation simultaneously without ambiguity, it's inadvisable because a particular if-statement may not be checking what you think it's checking unless you are very careful with your syntax.

Present-Perfect Tense : has ever been true

Inform uses the perfect tenses to assert if something has ever been true. For example:

if Grognar has carried the Sword of Villain-Smiting... [present-perfect tense on a verb of state; "carrying" is a relation]
if we have taken the lantern... [present-perfect tense on a verb of action; "taking" is an Action; "we have" is required]
if Sam has carried the One Ring... [present-perfect tense on a verb of state]
if the One Ring has been carried by Sam... [present-perfect tense on a verb of state, in passive voice]
if the One Ring has been carried... [passive voice is useful for "by anyone"]

Once any one of these becomes true with a successful TAKE, it remains true for the rest of the game. This means that perfect tenses only change state at most once. If it was already true at the beginning of the game, then its state will never change. The implementation difference between verbs of state and change is what is remembered. For actions, the combination of action with object is remembered -- the actor could have been anybody. But relations are special-cased: there's essentially a variable named Sam_has_carried_One_Ring which kept updated. Obviously using variables like "the noun" within a present-perfect verb of state is a bad idea: a single variable named Sam_has_carried_the_noun likely doesn't work as intended.

The intended usage of perfect tenses is narrative: stories are about irrevocable developments. While the condition "if Grognar carries the Sword of Villain-Smiting" is correct when we're checking to see if he can swing the sword, it isn't correct if an character asks him to describe the sword. Sure, if he has never encountered the mythical blade he has no first-hand knowledge of it, and if he does carry it then he certainly can describe it when asked. But if late in the story the sword is temporarily separated from him, asking him under the simple present tense ("carries"; "does carry") will produce a false negative. Grognar has learned what the blade looks like, and that is as irrevocable as discovering the villain is his own father. This then is where the perfect tenses come in: knowledge and plot points.

Two Past Tenses : only for relation verbs on a case-by-case basis

If you've ever implemented a linked list, you likely know how useful a "previous" node pointer is in addition to the "current" node pointer, especially for updating those very node linkages. Similarly, when the condition of an if-statement is asked in past tense, it queries the previous turn's game state, not the current one. For example, when phrased in present tense the follow lines of code would be broken: the candle would always be lit afterward regardless its state beforehand. But written in past tense, the lines indeed toggle the candle's binary state:

if the candle was lit, now the candle is unlit;
if the candle was unlit, now the candle is lit;

In Inform, the present becomes the past at the end of a turn, during the update chronological records rule, found in the Turn Sequence rulebook. Out of world actions do not affect time.

The past-perfect is to the present-perfect as the simple past is to the simple present. In other words, the past-perfect remembers the previous turn's present-perfect value. It is written as "if X had been Y". Since the present-perfect is copied into the past-perfect at the end of the turn, and since the perfect tenses do not change once set, this means that the only time throughout the entire game when the past-perfect isn't equal to its present-perfect twin is during the back half of the turn that changes the present-perfect. In other words, for a half turn between the Carry Out rules and the end of the turn.

Turns in a row, Times that started

Let us now add occurrences to the above concepts of instants and durations. An event such as a lightsaber duel begins on a particular instant, stretches over a particular duration of time, and ends on a second particular instant. (It goes without saying that another duration of time follows in which the event is not happening.) But an event can occur more than once. This second occurrence has its own start point and endpoint, and its length can be measured similarly. In Inform, each occurrence is called a time, and the length of the current occurrence is measured in turns. We can write rule header amendments that check how many turns a condition has held true as well as amendments that check which occurrence is occurring. (The last of the following examples show using the greater-than-or-equal-to operation "at least" on the duration length to print a message, every turn, starting on the fifth turn following a TAKE POISON.)

Every turn when the player does not carry the bottled sprite for 3 turns: say "The sprite begins to sing a lonely song."
Before taking the candle for the second time: say "You guess you'll need that candle again after all."
Every turn when the player carries the slow-acting poison for at least 5 turns: say "You feel ill."

It is fairly safe to amend a relation's condition, as any particular occurrence can be a duration of many, many turns. But verbs of action have a caveat: these amendments lump successful and unsuccessful actions together. This means the times and turns amendments should be confined to rules that are guaranteed for consideration every turn: Before and Every Turn, and early in Persuasion and Instead Of. Any later than that and we must take precaution that the rule isn't pre-empted, missing the chance to even see the Xth attempt or the Nth tick.

After taking the candle for the second time: say "If the Check Taking rules block the second attempt, this rule never fires."

The narrative use of these amendments is for varying the narration of repetition. I-F differs from video games in that a first success is worth reading about, and the second only to ensure that you've learned the skill, but after that why tell the reader again. It's old news. Of course, repetitive failure is not much fun either, but it at least has a narrative role as struggle. And so, Inform's "for the Xth time" lets us hook into multiple attempts, not multiple successes.

Currently, there is no point in using the perfect tenses with times -- perfect tense conditions never return to being false, meaning they never end, so they can never re-occur. For example, "if we have taken the candle twice" will never fire.

The Future is Scheduled

We can schedule a rule to fire in the future, either by hard-coding the rule to the in-game clock:

At 12:00 PM: say "The lunch bell rings!"

Or by imperatively providing a time with "at":

Carry out setting the watch to: the watch will beep at the time understood.
At the time when the watch will beep: say "Your Casio beeps at you urgently."

Or by imperatively providing a countdown, in either turns or minutes, with "in . . . from now":

Carry out pushing the watch: the watch will beep in six minutes from now.
Carry out pushing the watch: the watch will beep in six turns from now.
At the time when the watch will beep: say "Your Casio beeps at you urgently."

In the above example, "the watch will beep" is an implicitly created rule in an opaque pseudo-rulebook called "at" or "at the time when".

Inform 7 for Programmers by Ron Newcomb
Contents - Part 1 - Part 2 - Part 3 - Part 4 - Part 4b - Part 5