Multiple-Choice-Library für Inform

Natürlich kann man Multiple-Choice-Abenteuer in QBasic schreiben. Aber Inform ist weit geeigneter: Das fertige Spiel kann auch auf einem Apple, Psion oder Palm gespielt werden. Und der objektorientierte Code ist übersichtlicher, als IF x=2 GOTO 70 erlaubt.

Die Mini-Library CYOA besteht aus zwei Dateien. Eine (die Datei cyoad.h mit den Deklarationen) wird per include-Statement zu Beginn in das Abenteuer mit einbezogen, die andere (cyoa.h, die eigentliche Library) ganz zum Schluss. Vor dem zweiten include sollte die Routine init mit der Initialisierung des Spiels stehen. Der Rumpf sieht dann so aus:

include "cyoad.h";

! Hier werden die Objekte (Räume) eingefügt.

[Init;
  print "DEMO^
        CYOA in Inform 6.21^^
        Bitte drücke H für ~Hilfe~!^^";

  goto(Wiese);
];

include "cyoa.h";

In der Init-Routine sollte man natürlich das print-Statement durch eigenen Text ersetzen. Der Befehl goto() benötigt in Klammern den Namen eines Objektes - des Raums, in dem sich der Spieler zu Beginn befindet. Im Beispiel habe ich ihn mit Wiese angegeben.

Der Code wird nur fehlerfrei kompiliert, wenn das Objekt Wiese tatsächlich existiert. Also füge ich ein solches Objekt nach dem ersten include-Statement ein:

Object Wiese
  with text "Diese herrliche Wiese ist grün vor
         weichem Gras. Du wirst schläfrig von ihrem
         Duft.^^",
       option
         "schau dir die Wiese genauer an"
         "halte Mittagsschlaf"
         "schau den Bienen zu",
       active 1 1 0,
       exec [choice;
         switch (choice) {
         0: print "Die Blümchen mit ihren Blättchen
              sind alle gleich - hypnotisierend
              langweilig. Einzig die Bienen summen
              von Blüte zu Blüte.^^";
         1: print "Du lässt dich ins Gras fallen,
              schlägst die Beine übereinander und
              legst den Kopf auf die Arme. Schon
              entschwindest du in die surreale
              Welt der Träume...^^";
         2: print "Du blickst den Bienen hinterher,
              die fleißig sammeln, damit Menschen
              Wachs für Kerzen und Honig für süßen
              Tee haben.^^";
         }
       ];

Das Objekt Wiese besitzt eine Reihe von so genannten Properties, deren Definition durch das Wort with eingeleitet wird. Text ist einfach eine Beschreibung, wie sie in jedem Textadventure durch Eingabe von LOOK hervorgerufen wird. (Die zwei Dächer (^^) bewirken einen neuen Absatz und eine Leerzeile.) Der in der Init-Routine erteilte goto-Befehl druckt automatisch diesen Text mit aus.

Unter option finden sich die Optionen, die dem Spieler angeboten werden, in diesem Fall drei. Achtung - die Strings werden nicht durch Kommas getrennt. Stattdessen leitet das Komma zur nächsten Property über: active. Für jede vorher angeführte Option ist hier festgelegt, ob sie zu Beginn des Spiels aktiv ist oder nicht. Da zunächst nur die beiden ersten erscheinen sollen, habe ich für die dritte Option 0 eingetragen. (Wer möchte, kann statt 1 und 0 auch true und false verwenden.)

Schließlich gibt es mit exec einen Ausführungsblock, der je nach gewählter Option reagiert. An den Zahlen ist gleich erkennbar, dass die vorhandenen drei Optionen nicht von 1 bis 3, sondern von 0 bis 2 durchnummeriert werden. Also Obacht - hier schleichen sich leicht Programmierfehler ein. Der angegebene Ausführungsblock ist ziemlich langweilig - er tut nichts, außer ein wenig Text durch einen print-Befehl auszugeben.

Ich erweitere den Ausführungsteil also ein wenig. Option 0 (die erste Option) soll nicht nur den Text wie bisher ausgeben, sie soll auch die dritte Option (Nummer 2!) aktivieren und sich selbst deaktivieren, sodass der Spieler nur einmal die Wiese genauer anschauen, aber dafür anschließend den Bienen nachblicken kann. Ich füge dazu nach dem print-Befehl zwei neue Zeilen ein:

set(2, Wiese)    ! setzt die dritte Option auf aktiv
unset(0, Wiese)  ! setzt die erste Option (sich
                 selbst) auf inaktiv

Klar, oder? Die Routine set setzt den Wert (auf 1), unset löscht ihn (setzt auf 0). Der Objektname muss nicht angegeben werden. Nennt man kein bestimmtes Objekt, nimmt die Library an, dass current_room gemeint ist.

Nach der Ausführung der beiden neuen Befehle lautet Wiese.active also nicht mehr wie zu Beginn 1 1 0, sondern 0 1 1.

Nun soll aber die zweite Option, sich hinlegen, den Spieler in einen Traum befördern. Ich füge nach dem print-Befehl für Option Nummer 1 (die zweite!) folgende Zeilen ein:

goto(Traum);

Der aktuelle Raum ist ab da das Objekt Traum, das ich vor dem Kompilieren natürlich anlegen muss. Die Library wird nach dem Zug nicht mehr die Optionen für die Wiese ausgeben, sondern die für den Traum. Außerdem wird der Beschreibungstext des Objektes Traum ausgegeben.

Abschließend einige Hinweise. Das Spiel wird durch den Befehl

game_over=true;

beendet. CYOA unterscheidet nicht zwischen gewonnen und verloren. Der Autor muss entsprechende Nachrichten von Hand ausgeben, wie dies im unten stehenden Bei-Spiel der Fall ist.

Für die Programmierung einfacher Rätsel ist nützlich, dass jeder Raum das Attribut general besitzen kann. Ein Beispiel für den Einsatz dieser Flagge findet sich ebenfalls im Mini-Abenteuer keller.inf unten.

Es ist sehr einfach, auch die Library zu verändern. Der Code setzt nur die Kenntnis der Kapitel 1 bis 3 des Inform Designer's Manual 4 voraus - S.5 bis 37.

Die Bestandteile des Pakets: