Inform.de – Fragen und Antworten

Diese Fragen sind irgendwann einmal von Inform-Benutzern gestellt worden und werden hier kurz beantwortet. Eine umfassendere Sammlung von Fragen und Antworten zu Inform und der (englischen) Lib bietet Roger Firths Inform FAQ.

Allgemeines

Das Wetmodell

Ein- und Ausgabe

* * *

Wenn ich ich etwas kompilieren möchte, erscheint die Meldung: »no compilation requested«.

Mehr dazu:

Der Inform-Compiler muss wissen, welche Datei kompiliert werden soll. Also etwa so:

inform +language_name=German opus.inf

Achtung: Der Compiler muss nicht unbedingt inform heißen. Man kann die Definition der Sprache und einige andere Optionen auch in eine ICL-Datei (Inform Control Language) packen, die dann zwischen Klammern steht:

inform (opus.icl) opus.inf

* * *

Beim Kompilieren mit der deutschen Lib bekomme ich viele Fehlermeldungen, unter anderem über nicht deklarierte Variablen und falsche Opcodes. Was ist da passiert?

Mehr dazu:

Die Lib ist mittlerweile angepasst worden, so dass man mit ihr Z-Code und Glulx-Dateien erzeugen kann. Ob für Glulx oder für Z-Code kompiliert werden soll, muss man im Quelltext mit Konstanten festlegen. Für Z-Code muss man folgendes am Anfang des Quelltexts platzieren:

Constant TARGET_ZCODE 1;
Constant WORDSIZE 2;

Wenn man eine Glulx-Datei erzeugen will, heißen die Konstanten:

Constant TARGET_GLULX 1;
Constant WORDSIZE 4;

Wenn man mit dem Biplatform-Compiler arbeitet, kann man sich die Definition dieser Konstanten ersparen. WORDSIZE gibt an, wie groß ein »Wort« ist und wird benutzt, um die Anzahl der Einträge in einem Objekt-Property zu ermitteln, zum Beispiel noun.#name/WORDSIZE.

* * *

Ich habe aus dem Archiv die Erweiterung Scenic.h heruntergeladen und eingebunden. Ich kann das Spiel kompilieren, aber es kommen eigenartige Laufzeitfehler.

Die im Archiv oder auf inform-fiction.org abgelegten Library-Erweiterungen funktionieren meist nur für englische Spiele, sie müssen für die Benutzung mit der deutschen Library angepasst werden. Im Fall von Scenic.h gibt es Probleme bein Setzen der englischen Pronomen mit SetPronoun. Wenn man diese Zeilen auskommentiert, funktioniert es.

Wer eine Library-Erweiterung übersetzt hat, reicht sie am besten an den Archivar weiter.

* * *

Ich habe eine Library geschrieben, die Klassen und Verben enthält. Wenn ich sie am Anfang einbinde, funktioniert extend nicht, wenn ich sie am Schluss einbinde, kann ich die Klassen nicht benutzen. Was mache ich da?

Mehr dazu:

Da Grammatikdefinitionen generell immer am Schluss stehen, ist es zweckmäßig, die Library in zwei Teile zufzuteilen, etwa so:

Include "parser";
Include "VerbLib";
Include "segeln";    ! Klassen	

! Piratenabenteuer hier	

Include "germanG";
Include "segelnG";   ! Grammatik

Hier muss der Autor natürlich aufpassen, dass beide Dateien eingebunden werden. Wenn die Lib nur bislang von der Inform-Lib nicht benutzte Verben benutzt, also nichts extendet werden muss, kann alles auch in einer Datei stehen.

* * *

Ich habe einen Schrank, der supporter und container ist. Wie kann ich nun Objekte in, wie welche auf den Schrank legen?

Ein Objekt kann nie gleichzeitig container und supporter sein. Die Lösung für dieses Problem ist, den Schrank als Behälter zu definieren und ein zweites Objekt auf_dem_Schrank zu erzeugen, das als Ablage für den Schrank fungiert. Das macht man am besten mit einem Unterobjekt ohne Vokabular, das mit add_to_scope am Hauptobjekt befestigt ist:

Object -> Kommode "Kommode"
with dekl 9,
     name 'kommode' 'schubfach' 'schublade'
         'fach' 'lade',
     add_to_scope Kommode_Ablage,
     before [;
         Receive:
             if (receive_action == ##PutOn)
             <<PutOn noun Kommode_Ablage>>;
         LetGo:
             if (noun in Kommode_Ablage)
             <<Remove noun Kommode_Ablage>>;
     ],
 has container openable static;	

Object Kommode_Ablage "Kommode"
with dekl 9,
 has supporter static;

* * *

Ich habe einen Tisch, auf dem eine Tischdecke liegt, darauf steht eine Vase. Wieso kann ich mit (Vase in Tisch) nicht prüfen, ob die Vase auf dem Tisch ist?

Mit in kann nur überprüft werden, ob ein Objekt ein direktes Kind eines anderen Objekts ist, (a in b) ist äquivalent zu (parent(a)==b). In diesem Beispiel müsste also (Vase in Decke) geprüft werden.

Tiefere Verschachtelungen können mit der Library-Routine IndirectlyContains(b, a) überprüft werden. Eine weitere Routine, CommonAncestor(a, b) findet das am tiefsten im Objektbaum liegende Objekt, das beide angegebenen Objekte indirekt enthält oder nichts.

* * *

Was ist der Unterschied zwischen react und react_before? Wann benutze ich was?

Die before-Eigenschaft eines Objekts wird dann aufgerufen, wenn das erste Objekt eines Befehls, noun dieses Objekt ist. Bei <<Take Pudding>> wird also before des Puddings aufgerufen, wenn der Pudding diese Eigenschaft hat. before dient dazu, Objekten ein individuelle Reaktion auf bestimmte Handlungen des Spielers zu beschreiben, in die sie selbst verwickelt sind.

Manche Verben wie Look, Smell oder Sing verlangen kein Objekt, und wenn diese ausgeführt werden, wird auch kein before irgendeines Objekts ausgeführt.

Die react_before-Routine wird bereits vorher aufgerufen, und zwar für jedes Objekt, das sich in Sicht befindet, und ungeachtet des Werts von noun oder second. Diese Eigenschaft wird weitaus seltener verwendet und dient dazu, dass Drittobjekte eine bestimmte Aktion unterbinden können:

Objekt -> Mama "Mama"
  with ...
       react_before [;
           Take, Remove:
               "~Finger weg!~, ruft Mama als du
               die Hände nach ", (dem) noun,
               " ausstreckst. Du gehorchst.";
       ],
   has animate female propername;

Hier greift die Mutter bei jedem Objekt ein, das aufgehoben werden soll, wenn sie »in der Nähe«, d.h. im selben Raum wie der Spieler ist, sogar bei der Aktion <<Take Mama>>. Bei react_before muss man aufpassen, dass man nicht zuviel abfängt, was leicht passiert. Im Allgemeinen ist before das, was man will.

Sowohl before als auch react_before brechen eine Handlung des Spielers vorzeitig ab, wenn true zurückgegeben wird.

* * *

Was hat es mit den Fake Actions auf sich?

Bei der vorigen Frage wurde beschrieben, wie man mit before Handlungen des Spielers, die mit noun zu tun haben, abfängt.

Was passiert aber, wenn eine Aktion zwei Objekte verlangt, wie zum Beispiel PutOn? Hier kommen so genannte Fake Actions zum Zuge. Bei <<PutOn Apfel Tisch>> wird (nach allen react_before der Objekte im Raum) der PutOn-Zweig im before für den Apfel ausgeführt, danach der Receive-Zweig im before des Tischs. Receive ist die Fake Action zu PutOn, die bedeutet: Mit mir soll etwas angestellt werden, aber ich bin das zweite Objekt im Befehl, nicht das erste.

Für Aktionen des Spielers existieren die Fake Actions ##Receive, ##LetGo und ##ThrownAt. (Es gibt noch weitere, die aber eine andere Bedeutung haben.) Selbst Fake Actions zu erzeugen, ist recht kompliziert und wird besser anders gelöst.

* * *

Ich möchte Zahlen als Wort ausgeben. Dabei erhalte ich etwas wie »neunzig1«. Wo kommt die Eins her?

Innerhalb einer print-Anweisung kann man eine Routine zur Textausgabe nicht aufrufen, man muss eine printing rule verwenden:

print_ret "Sie ist nun schon ",
    Englishnumber(self.age), "alt.";

Dies schreibt alles, was die Routine ausgibt und anschließend den Rückgabewert der Routine, meistens Eins. Diese Syntax ist hier falsch, kann aber dazu verwendet werden, Rückgabewerte von Routinen auszugeben.

print_ret "Sie ist nun schon ",
    (Englishnumber) self.age, "alt.";

Dies schreibt nur das, was die Routine ausgibt, der Rückgabewert verfällt. Dies ist in der Regel das, was gewünscht wird.

* * *

Ich habe ein neues Verb »erwecke zum Leben« definiert, das nicht akzeptiert wird. Was mache ich falsch?

Mehr dazu:

Bevor der Parser auf die Eingabe des Spielers angesetzt wird, werden einige Änderungen daran vorgenommen. Zum Beispiel werden in der deutschen Library alle Umlaute in ae, oe und ue umgewandelt. Außerdem werden einige aus Präpositionen und Artikeln kontraktierte Wörter getrennt, um dem parser die Arbeit zu erleichtern. So wird »zum« zu »zu dem« und der Parser kann nie ein etwas wie 'zum' finden. Anstatt:

extend only 'erweck' 'weck'
    * noun 'zum' 'leben' -> UnCurse;

muss es heißen:

extend only 'erweck' 'weck'
    * noun 'zu' 'dem' 'leben' -> UnCurse;

Ähnlich ist es mit Abkürzungen wie in »Dr. Mabuse«, die nicht von Objekten mit

name 'doktor' 'dr.' 'mabuse', ...

erkannt werden. Warum? Weil 'dr.' eine Vokabel ist, die nie auftritt, da sie einen Punkt enthält. Der Parser, oder besser der Opcode zum Aufteilen des Texts, @tokenise, macht daraus immer die Wörter 'dr' und './/'. Hier kann man den Punkt zum Vokabular hinzufügen, was Probleme bei verketteten Befehlen geben kann, man kann dem Objekt einen parse_name geben oder man kann den Punkt im EinhängerBeforeParsing erweitern, wie im Inform FAQ beschrieben.