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
- Was bedeutet »No compilation requested«?
- Ich bekomme unerklärliche Fehlermeldungen in der Lib.
- Eine eingebundene Lib-Erweiterung funktioniert nicht.
- Wie binde ich eigene Libs mit Klassen und Grammatik ein?
Das Wetmodell
- Wie platziere ich Dinge in und auf anderen?
- Warum funktioniert
in
bei verschachtelten Objekten nicht? - Wann benutze ich
before
, wannreact_before
? - Was ist eine Fake Action?
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 extend
et 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?
Mehr dazu:
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?
Mehr dazu:
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?
Mehr dazu:
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?
Mehr dazu:
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.