Kurzdokumentation zu deform
Einbinden der Dateien
Im Quelltext des Spiels müssen die Dateien wie folgt eingebunden werden:
!... Story und Headline
!... Ersetzen von Routinen wenn gewünscht
Include "Parser";
Include "VerbLib";
!... Hauptteil der Definitionen
Include "GermanG";
!... Eigene Grammatikdefinitionen
Obwohl nur drei Dateien direkt mit Include eingebunden werden, werden fast alle *.h
-Dateien benutzt; sie werden aus den anderen drei aufgerufen:
Datei | Inhalt |
---|---|
Parser.h |
Hauptmodul |
→ linklpa.h |
Definition von Properties und Attributen |
→ (linklv.h ) |
(nur beim Verlinken vorkompilierter Module) |
→ parserm.h |
Parser (Analyse der Eingabe) |
→ German.h |
Ausgaberoutinen und Lib-Texte |
VerbLib.h |
Spielwelt |
→ verblibm.h |
Aktionen und Listen |
GermanG.h |
Grammatik |
→ (infix.h ) |
Infix-Debugger, nur mit -X (Siehe §7 im DM4) |
Die Schreibweise sollte so sein, wie hier angegeben: Die drei direkt eingebundenen Dateien sowie German.h
haben Großbuchstaben, alle anderen sind durchweg klein geschrieben. (Das ist unter Windows egal, aber andere Systeme unterscheiden Groß- und Kleinschreibung bei Dateien.)
In deform wird nicht language_name
, sondern immer German.h
eingebunden. (Wer die Library Messages komplett oder zum großen Teil ersetzen möchte, sollte daher LanguageLM
mit Replace
ersetzen und neu definieren.)
In der Vergangenheit ist es öfters zu Konfusionen gekommen, da sich die Dateien der deutschen Lib von den enlischen unterscheiden, aber bis auf German.h
und GermanG.h
, die im Original English.h
und Grammar.h
heißen, die selben Namen haben. Daher wird empfohlen, die Lib-Dateien in einem separaten Ordner aufzubewahren, und die Lib-Erweiterungen in einem zweiten. Der Compiler wird dann aufgerufen mit
inform +include_path=./lib/deform/,./lib/opt/ spiel
(Der Compiler muss übrigens nicht unbedingt inform
heißen.) Mit dem neuen Compiler Inform 6.30 ist es möglich, die ICL-Kommandos (Inform Control Language) mit einer Art Shebang, dem Kommentarzeichen !
gefolgt von einem Prozentzeichen, in den Kopf der Datei zu schreiben:
!% -G ! Glulx, bitte
!% -DS ! Volles Debug-Programm
!% +include_path=./lib/deform/ ! Lib-Path deform
!% $MAX_OBJECTS=600 ! Viele Objekte
Diese Anweisungen müssen die ersten im Quelltext sein.
In jedem Fall wird am Ende von GermanG.h
sichergestellt, dass nur deform- Dateien eingebunden wurden und dass alle Dateien von derselben Release sind.
Low Strings
Diese Lib macht Gebrauch von den so genannten Low Strings, die mit der Notation @xx
in Texten eingebunden werden können. Es gibt 32 dieser Strings, folgende werden von der Lib benutzt:
String | Bedeutung |
---|---|
@00 |
Adjektivendung |
@01 |
Endung -n für Plural-Substantive im Dativ |
@02 |
Endung -en für männl. Substantive |
@03 |
Endung -s für Substantive im Genitiv |
@04 |
Endung -es für Substantive im Genitiv |
@30 |
›ss‹ für schweizerische Spiele, Eszett für alle anderen |
@31 |
Eszett für alte Rechtschreibung, ›ss‹ für neue Rechtschreibung und schweizerische Spiele |
Die ersten Strings ändern sich ständig, sie werden bei jedem Aufruf von (den)
, (dem)
, (eine)
usw. angepasst, siehe unten.
Die Eszett-Strings bestimmen das Erscheinungsbild der Texte. Wenn man sich für eine Variante entscheidet, kann man seine eigenen Texte einfach mit dieser Variante schreiben. Wenn man es zulassen möchte, dass der Spieler selbst zwischen den Varianten umschalten kann, sollten die eigenen Texte ebenfalls die Low Strings verwenden, etwa:
print_ret "Du reibst ein wenig Ru@30 von dem
Kessel und mu@31t niesen.";
Das ist allerdings viel Arbeit.
Veröffentlichte Erweiterungen der Lib sollten diesen Mechanismus aber implementieren, damit sie universell einsetzbar bleiben.
Die neue deutsche Rechtschreibung ist der Default:
string 30 "ß"; string 31 "ss";
DIALECT_TRADITIONAL
, alte Rechtschreibung:
string 30 "ß"; string 31 "ß";
DIALECT_SWISS
, schweizerische Rechtschreibung:
string 30 "ss"; string 31 "ss";
Schema für die Ausgabe von Objektnamen
Jedes Objekt, das im Spiel sichtbar ist, sollte einen short_name
und eines (und nur eines) der Attribute pluralname
, male
, female
oder neuter
besitzen, um seinen Genus zu kennzeichnen. Der short_name
kann eine Routine oder ein String sein.
Objekte ohne Adjektive kommen in der Regel mit einem einfachen String aus. Für kompliziertere Objekte gibt es zwei Methoden:
Traditionell
Zu jedem Objekt wird eine Property dekl
angegeben, die den Deklinationsmodus festlegt. Die folgende Deklinationstypen, die in der offiziellen Lib verwendet werden, werden auch von deform verstanden:
No. | Genera | Singular | Plural |
---|---|---|---|
1 |
m, n | -(e)s im Genitiv | -n im Dativ |
2 |
m, n | -s im Genitiv | -n im Dativ |
3 |
m, n | -(e)s im Genitiv | — |
4 |
m, n | -(e)s im Genitiv | -n im Dativ |
5 |
m, n | -(e)s im Genitiv | — |
6 |
m | -en außer im Nominativ | — |
7 |
f | — | -n im Dativ |
8 |
f | — | -n im Dativ |
9 |
f | — | — |
10 |
f | — | — |
Die Deklinationen, die hier als gleich beschrieben werden, unterscheiden sich in der Pluralbildung. Da Inform aber nie den Plural selbständig bilden muss, ist diese Unterscheidung praktisch nutzlos. Daher gibt es jetzt vier neue Deklinationsformen:
Dekl. | Beispiel |
---|---|
Dativ_n |
die Zwerge, den Zwerge-n |
Akkusativ_en |
der Student, den/dem/des Studenten |
Genitiv_s |
der/den/dem Apfel, des Apfel-s |
Genitiv_es |
das/dem Haus, des Haus-es |
Wenn short_name
ein String ist, werden passende Endungen einfach angehängt:
Object with short_name "Regale", dekl 2,
has pluralname;
Wenn short_name
eine Routine ist, müssen die beiden Routinen print_adj
und print_subst
verwendet werden, um die passenden Endungen anzuhängen:
Object
with short_name [;
print (print_adj) "alt",
(print_subst) " Regale",
" aus Buchenholz";
], dekl 2, has pluralname;
Die Property dekl
kann auch (analog zum alten suffix
) ein Feld mit vier Strings für die Endungen im Nominativ, Genitiv. Dativ und Akkusativ oder eine Routine, der der Fall übergeben wird, sein. Für die Regale:
dekl "" "" "n" "", ...
oder
dekl [kasus; if (kasus==Dat) print "n"; ], ...
Bei Pluralobjekten muss der short_name
im Plural angegeben werden, der Plural wird nicht, wie in der offiziellen Lib, durch dekl
bestimmt. Wenn es ein Objekt »Häuser« gibt, ist short_name "Häuser"
, nicht "Häus"
! (Der Singular wird eh nie verwendet und die Umlautumwandlung hat die offizielle Lib auch nicht beherrscht.)
Vereinfacht
Vereinfacht: Der short_name
enthält Low strings für Endungen (siehe oben), typischerweise @00
für Adjektive. Die Property dekl
wird nicht benötigt:
Object
with short_name "rot@00 Grütze",
has female;
Object
with short_name "leblos@00 Körper des Drachen",
has male;
Meistens wird nur @00
benötigt. @01
und @02
werden gelegentlich bei männlichen und sächlichen Substantiven im Plural und bei männlichen Substantiven verwendet:
Object
with short_name "alt@00 Regale@01 aus Holz",
has pluralname;
Object
with short_name "Student@02",
has male animate;
@03
und @04
werden nur benötigt, wenn Objekte im Genitiv ausgegeben werden sollen, was die Lib aber nie macht, obwohl es die Routinen (des)
und (eines)
gibt.
Diese Methode entspricht den ^
und ~
in T.A.G. (Und sieht wegen der kruden @
-Syntax etwas hässlich aus. Die paar Zahlen lassen sich aber wohl besser merken als die Deklinationstypen.)
Besonderheiten
Es gibt ein paar Sonderkonstanten für die Objektausgabe. Die Eigenschaft article
, die nur bei der Ausgabe mit unbestimmtem Artikel, zum Beispiel bei (ein)
oder (einen)
, herangezogen wird, kann außer einem String oder einer Routine zur Textausgabe folgende Werte haben:
yours
Dem Objekt wird die passende Form von »dein« vorangestellt, zum Beispiel: »dein original elbisches Schwert«
definite
Das Objekt hat immer einen bestimmten Artikel, wie zum Beispiel »das Amulett der Ewigen Verdammnis ™«
no_article
Das Objekt wird in unbestimmten Fall ohne Artikel ausgegeben, wie bei »frische Milch« oder »Brennholz«. Der Unterschied zu
proper
ist, dass beiproper
nie Artikel verwendet werden, auch bei der Ausgabe mit bestimmten Artikel nicht. Der Unterschied zu einem leerenarticle
ist, dass mitno_article
kein ungewolltes Leerzeichen vorangestellt wird.
Außerdem kann short_name
den Wert no_short_name
haben, was bedeutet, dass die Ausgabe des short_name
unterdrückt wird. Artikel werden aber ausgegeben, ebenso adj
und post
, und nur im Zusammenhang mit diesen beiden Properties ist no_short_name
sinnvoll, zum Beispiel:
Object -> Binder_Mann
with name 'blind' 'mann',
adj "Blind",
short_name no_short_name,
has male animate;
Im vereinfachten System reicht hierzu der short_name "Blind@00"
.
Routinen für die Ausgabe der Objektnamen
Die englische Lib definiert folgende Ausgaberoutinen:
(The) |
Objekt mit bestimmtem Artikel, groß |
(the) |
Objekt mit bestimmtem Artikel |
(a) |
Objekt mit unbestimmtem Artikel |
(name) |
Objektname ohne Artikel |
Diese Routinen stehen auch im deutschen zur Verfügung, sollten aber nicht benutzt werden. Dazu kommen Ausgaberoutinen für Verben, wie (ThatOrThose)
oder (TheyreOrThats)
, die in dieser Lib nicht definiert sind.
In der deutschen Lib muss der Fall der Ausgabe berücksichtigt werden. Es stehen folgende Routinen zur Ausgabe zur Verfügung:
(der/des/dem/den) o
Objekt mit bestimmtem Artikel. Diese Routinen rufen
DefArt(o, Fall)
auf.(GDer/GDes/GDem/GDen) o
Objekt mit bestimmtem Artikel, der erste Buchstabe wird groß ausgegeben, ruft
DefArt(o, Fall)
auf(ein/eines/einem/einen) o
Objekt mit unbestimmtem Artikel, ruft
IndefArt(o, Fall)
auf(kein/keines/keinem/keinen) o
Negiertes Objekt, umgeleitet zu
NegativeArt(o, Fall)
(er/seiner/ihm/ihn) o
Personalpronomen, das zum Objekt passt, Wird umgeleitet zu
PersonalPron(o, Fall)
(WithoutArt) o
Objekt ohne Artikel im Nominativ. Dies ersetzt
(name)
o und kann mitWithoutArt(o, Fall)
in anderen Fällen benutzt werden.
Weiterhin gibt es einige Routinen, um Verben an ein Subjekt angepasst auszugeben:
(ist) o |
»ist« oder »sind« |
(hat) o |
»hat« oder »haben« |
(wird) o |
»wird« oder »werden« |
(___t) o |
»t« oder »en« (das sind drei Unterstriche) |
(___et) o |
»et« oder »en« |
plur(p, s, o) |
String p oder String s , zum Beispiel plur ("müssen", "muss", noun); |
In der Lib kann man nur Objekte mit bestimmtem Artikel groß ausgeben, da dies wohl am häufigsten werwendet wird. Manchmal will man aber auch anderes groß ausgeben. dann kann man die Routine RunCapitalised(r, o);
verwenden, die die Ausgabe einer Routine groß ausgibt, zum Beispiel:
RunCapitalised(einen, noun);
" ohne richtiges Werkzeug zu schälen ist echt knifflig.";
Natürlich steht es jedem Autoren frei, sich Routinen wie GEin
, GEs
usw. zu definieren.
Synonyme
Um die Kontraktionen aus Präpositionen und Artikeln (ins, zum usw.) effizient zu behandeln, ohne alle mühselig von Hand mit LTI_Insert
zu implementieren, gibt es ein Synonym-System. Der Autor kann eigene Synonyme definieren, indem er vor dem Einbinden der Lib einen Table Synonyms
definiert, in dem zu ersetzende Vokabeln und die ersetzten Strings paarweise stehen, zum Beispiel:
Array Synonyms table
'fuers' "fuer das"
'doch' ""
;
Achtung, der zweite Eintrag in jedem Paar ist ein String in doppelten Anführungszeichen, der natürlich keine Großbuchstaben und Umlaute enthalten darf.
Ein ähnliches System, bei dem immer zwei aufeinanderfolgende Wörter ersetzt werden sind die »Zwillinge«, die analog dazu im Feld Twins
in Dreiergruppen angegeben werden:
Array Twins table
'prof' './/' "prof"
'10' './/' "zehnte"
;
Endungen
Der Parser schneidet Endungen ab und berücksichtigt weder den Fall des Tokens (es gibt nur noun
) noch den Genus des untersuchten Worts. Dies ist eine praktikable Vorgehensweise. Im Einzelnen:
Es werden nur folgende Endungen abgeschnitten:
Endung Vorkommen 'e'
Verben und Adjektive 'em'
Adjektive* 'en'
Adjektive* und Substantive wie »Student« 'er'
Adjektive* 'es'
Adjektive* und Genitiv-es 's'
Genitiv-s 'n'
im Dativ mancher Plurale *) und Possesiv- und Demonstrativpronomen Endungen wie ›-ern‹ werden nicht berücksichtigt, da der deform-Parser verlangt, dass Wörter sowohl für die Eingabe als auch für die Ausgabe im Plural in ihrer kompletten Form angegeben werden. Vokabeln wie
'haeus'
wenn eigentlich'haeuser'
gemeint ist, sind damit hinfällig.Verben werden nicht per se beschnitten, sondern auch nur nach den hier beschriebenen Regeln. Die meisten Verben haben wie in der offiziellen Lib ihr End-e in der Definition abgeschnitten, das erkennt
'leg'
und'lege'
. ('lage'
hat in deform aber ein e, da'lag'
kein sinnvoller Imperativ ist.) Diese Vereinfachung umgeht die Suche nach dem richtigen Verb, die zwar meist trivial ist, aber in Fällen wie »fuchs, gute nacht« oder »setz dich hin. steh auf. leg dich hin« umständlich sein kann.Es wird abgeschnitten, wenn das momentane Wort unbekannt ist. Wenn der Parser also das Wort ›zwergen‹ findet, macht er folgendes:
1. Wenn es
'zwergen'
gibt, nichts.2. Wenn es
'zwerge'
gibt, wird ein'n'
abgeschnitten.3. Wenn es
'zwerg'
gibt, wird ein'en'
abgeschnitten.4. Wenn es keines der drei Wörter gibt, nichts.
In jedem Fall hat der Spieler Zugriff auf die Original-Eingabe, die in
orig_buffer
undorig_parse
steht. Mit den RoutinenOriginalLength(w)
undOriginalAddress(w)
kann man darauf zugreifen. Diese beiden Routinen berücksichtigen, dass sich die Wörter durch Synonymbildung verschieben können: »gehe ins haus« wird zu »gehe in das haus«,OriginalAddress(4)
schaut sich das dritte Wort des Originaleintrags an.
Durch das Abschneiden kann es zu Konflikten kommen. Wenn es in einem Spiel im Krankenhaus eine 'trage'
gibt, so wird das Verb 'trage'
nicht mehr als 'trag'
erkannt. In diesem Fall sollte man die Trage als 'trag'
definieren, damit beides funktioniert.
In komplexeren (aber auch selteneren) Fällen kann man das Originalwort in parse_name
heranziehen und die abgeschnittene Endung betrachten.
Wenn der Debug-Modus aktiv ist, kann man mit »echo on/off« jede Zeile so ausgeben lassen, wie der Parser sie sieht, oder das wieder abstellen.
Die Konstanten zum Festegen der Beschneidung aus der offiziellen Lib, USE_OLD_GERMAN_SUFFIX_ROUTINE
und GERMAN_SUFFIXES_PEDANTIC
haben hier keine Bedeutung, da der deform-Parser von Haus aus pedantischer ist als die pedantische Version der offiziellen Lib (und trotzdem bessere Ergebnisse liefert, behaupte ich mal).
Satzzeichen
Satzzeichen wie Kommas und Punkte werden in Inform als word separators bezeichnet, das heißt ein solches Zeichen gilt immer als eigenes Wort, auch wenn es direkt, ohne trennendes Leerzeichen an einem anderen Wort klebt, wie es bei nachgestellten Zeichen üblich ist. Das ist nütztlich für die Lib, auch wenn es in einzelnen Fällen, wie etwa Abkürzungen (»Dr. Müller«) etwas ärgerlich sein kann. Dies kann man aber mit Synonymen beheben. Der dritte word separator in Inform ist das Anführungszeichen ("
).
Frage- und Ausrufezeichen, Strichpunkte und Doppelpunkte werden in Inform nicht als word separators betrachtet, so dass in 'was ist ein graus?'
das vierte Wort 'graus?'
inklusive des Fragezeichens ist, und nicht etwa nur 'graus'
.
Zur besonderen Behandlung dieser Satzzeichen gibt es unter deform drei Möglichkeiten, die durch verschiedene Konstanten aktiviert werden:
IGNORE_PUNCTUATION
Die Satzzeichen werden einfach durch Leerzeichen ersetzt. Dieser pragmatische Ansatz wird auch in der offiziellen Lib verwendet, wenn man die Konstante
NO_PUNCTUATION
setzt. (Diese Konstante wird von deform als Synonym zuIGNORE_PUNCTUATION
verstanden.)REPLACE_PUNCTUATION
Hier werden die Satzzeichen durch Punkte ersetzt. (Was im Fall von Frage- und Ausrufezeichen sinnvoll ist, bei den Anführungszeichen wohl weniger.)
SEPARATE_PUNCTUATION
Hier werden die Satzzeichen so von den angrenzenden Wörtern abgerückt, dass sie eigene Wörter sind, wie Punkt und Komma. Dann muss man aber auch die Tokens anpassen, also
Verb 'was' 'wer' * 'ist/'sind' scope=Topic -> WhatIs * 'ist/'sind' scope=Topic '?' -> WhatIs ;
In deform werden Frage- und Ausrufezeichen als Satzzeichen verstanden und damit so behandelt wie oben beschrieben wenn man die passende Konstante definiert hat. Die offizielle Lib berücksichtigt auch das Anführungszeichen. Was genau ein Satzzeichen ist, bestimmt die Routine Is_Punctuation
, die man ersetzen kann. Diese Routine bekommt ein ZSCII-Zeichen als Argument übergeben und gibt wahr oder falsch zurück, je nachdem ob das Zeichen als Satzzeichen betrachet werden soll oder nicht. Man kann also auch Doppel- und Strichpunkte besonders behandeln, wenn man möchte.
Man kann nur eine der drei Konstanten sinnvoll definieren. (Wenn man mehrere definiert, hat man eine Kombination der drei Methoden, was genausogut ist wie IGNORE_PUNCTUATION
.)
Verben
Die Verben müssen im Imperativ der zweiten Person Singular angegeben werden, Die Konvention ist hier, dass der Spieler das Spiel duzt. Die regelmäßigen Verben lassen hier mist zwei Forme zu, die sich nur durch ein angehängtes 'e'
unterscheiden, etwa 'schau'
und 'schaue'
.
In der offizielle Lib wird das 'e'
automatisch vom Parser abgeschnitten, daher dürfen dort Verb-Definitionen kein 'e'
am Ende haben. Hier dürfen Verben ein 'e'
am Ende haben, was besonders bei »Verben«, die keine Verben, sondern Substantive oder englische Debug-Kommandos sind sinnvoll ist. Wenn ein Verb aber zwei Formen hat und beide erkannt werden sollen, sollte man nur die Form ohne e definieren, also 'schau'
, 'geh'
, 'spring'
usw.
Die Verben dürfen wie alle Vokabeln keine Umlaute enthalten, es müssen die Umschreibungen 'ae'
, 'oe'
, 'ue'
und 'ss'
verwendet werden.
Verbkonstruktionen sind im Deutschen nicht immer eindeutig. In GermanG.h
wird zum Beispiel »zieh ... auf« als ##Wear
interpretiert, etwa um einen Hut aufzuziehen. Wenn es nun aber im Spiel eine Spieluhr gibt, die man auch aufziehen kann, so sollte man nach dem Einbinden von GermanG.h
das Verb ertweitern, entweder über ein Attribut, das die Spieluhr besitzt oder uber ein noun=Routine-Token:
Extend 'zieh' first
* clocklike 'auf' -> WindUp;
mit dem neu definierten Attribut clocklike
(für ein Spiel mit vielen Uhren) oder:
[ is_Clocklike;
if (noun == Spieluhr or Standuhr) rtrue; rfalse;
];
Extend 'zieh' first
* noun=is_Clocklike 'auf' -> WindUp;
Wichtig ist, dass diese Bedingung in einem Satzmuster vor der üblichen Zeile, die auf ##Wear
verweist steht. Es muss also die Option first
angegeben werden.
Die einschränkenden Tokens attribute, noun=
Routine und in gewissem Maße auch creature
sollten nur dazu verwendet werden, verschiedene Bedeutungen gleicher Satzmuster zu unterscheiden, wie im Beispiel oben gezeigt.
Wenn man die Gültigkeit eines Tokens bereits in der Grammatikdefinition einschränkt, so kann dies zu ungewollten Fehlermeldungen führen. Wenn der Autor zum Beispiel ein neues Verb einführt, das nur für Musikinstrumente gilt:
[ is_Instrument;
if (noun ofclass Instrument) rtrue; rfalse;
];
Verb 'spiel'
* noun=is_Instrument -> Play
* 'auf' noun=is_Instrument -> Play;
dann scheint das auf den ersten Blick logisch – man kann nur Instrumente spielen. Gibt der Spieler jedoch »spiele Karten« ein, so wird CANTSEE_PE
, also »Du siehst hier so etwas nicht« ausgegeben, auch wenn ein Kartenspiel direkt vor dem Spieler auf dem Tisch liegt. Deshalb ist es hier besser, alle Objekte zuzulassen und in der Aktionsroutine eine Absage zu erteilen:
[ PlaySub;
print_ret (GDer) noun , " ",
(ist) noun, "nichts zum Spielen.";
];
Verb 'spiel'
* noun -> Play
* 'auf' noun -> Play;
Der Code für das Spielen würde dann in before
der Klasse für Musikinstrumente definiert.
Lange Wörter
Im Deutschen gibt es viele zusammengesetzte Wörter, die sehr lang sind. Im z-Code können die Vokabeln aber nur neun Zeichen lang sein. (Das heißt in den Versionen fünf und später. In Version drei ist ein Eintrag ins Wörterbuch nur sechs Zeichen lang. In Glulx kann man die Länge der Vokabeln mit einer Konstante definieren, aber die Voreinstellung ist auch hier neun Zeichen.)
In vielen Fällen ist es egal, ob nach dem neunten Zeichen noch etwas Sinnvolles steht. Wenn der Spieler »Kaffeetasche« eingibt, und das als 'kaffeetas'
mit dem Ergebnisobjekt Kaffeetasse geparst wird, ist das sicherlich kein Beinbruch. In manchen Fällen muss man aber das ganze Wort parsen. Dazu stehen in deform zwei Methoden zur Verfügung.
Genaue Wortanalyse in parse_name
In Inform kann man mit der Property parse_name
die übliche Analyse über name
ersetzen oder erweitern. Um lange Wörter parsen zu können, steht in deform die Routine WordMatch(s)
zur Verfügung. s
ist hier ein String zwischen doppelten Anführungszeichen, der so aussehen muss wie eine Vokabel, das heißt er darf keine Umlaute oder Großbuchstaben besitzen.
Die Routine untersucht das Wort an der Stelle wn
und gibt false
zurück, wenn das Wort nicht passt oder die Länge des Strings (die einen wahren Wert hat), wenn das Wort übereinstimmt. In diesem Fall wird auch der Wortmarker wn
um eins weitergerückt. Auf diese Weise sind in parse_name
Prüfungen wie folgende möglich:
Object -> Hauptsicherung "Sicherungsschalter"
with article definite,
name 'schalter' 'notstrom' 'hebel',
parse_name [n;
while (WordMatch("sicherungsschalter")
|| WordMatch("sicherungshebel")
|| WordInProperty(NextWord(),
self, name)) n++;
return n;
],
has male static;
Bitte beachten: Die reine Oder-Klausel ist wahr, wenn eines ihrer Glieder wahr ist. Es wird von links ausgewertet, und die erste wahre Bedingung zählt wn
um eins weiter – NextWord()
macht dies auch – und springt in den Ausführungsblock der Schleife. Hier wird n
hochgezählt. Es rückt also in diesem Schema immer nur ein Aufruf den Wortmarker vor.
WordMatch
prüft nur über die Länge des Worts; alles, was danach kommt, wird ignoriert. Mit WordMatch(s, true)
kann man eine genaue Übereinstimmung erwzingen.
Class -> Streichholz "Streichholz"
with name 'holz', 'hoelzer//p',
parse_name [n b;
do {
b = false;
if (WordMatch("streichholz", 1)) {
b = true;
n++;
}
if (WordMatch("streichhoelzer", 1) {
b = true;
parser_action = ##PluralFound;
}
} until (~~b);
if (n) return n;
return -1;
],
plural "Streichhölzer",
has neuter;
Abtrennen der Köpfe und Schwänze
Oben im Quelltext, bevor Parser.h
eingebunden wird, kann man ein Feld CompundHeads
definieren. Es enthält »Köpfe« von Wörtern die abgetrennt werden und dann, mit einem angehängten Bindestrich, eigene Wörter sind.
Die Streichhölzer oben sähen mit dieser Methode so aus:
Array CompoundHeads table
"streich" 0
"zuend" 0
;
Include "Parser.h";
Include "VerbLib.h";
Class -> Streichholz "Streichholz"
with name 'streich-' 'zuend-' 'holz', 'hoelzer//p',
plural "Streichhölzer",
has neuter;
Nun wird die Eingabe »streichholz« umgewandelt in »streich- holz«, und damit kann der Inform-Parser gut umgehen.
Analog zu den CompoundHeads
gibt es die CompoundTails
, die ein Wort von hinten beschneiden. Mit der Definition
Array CompoundTails table
"schluessel" 0
"karte" 0
;
könnte man nun die ganzen Holz-, Eisen-, Stahl-, Gold-, Molybdän- und was weiß ich nicht noch für Schlüssel unterscheidbar machen, indem man überall das Präfix 'eisen-'
usw. und das Wort 'schluessel'
angibt. Hierbei werden die üblichen Endungen brücksichtigt, das heißt auch 'landkarten'
würde in 'land- karte'
umgewandelt. (Es sei denn, es gibt das Wort 'karten'
auch, dann würde es 'land- karten'
heißen – es wird zunächst geprüft, ob das Wort inklusive einer der möglichen Endungen passt, dann wird getrennt, und dann nach den üblichen Regeln das zweite Wort beschnitten. Die Angabe von "karte"
in CompoundTails ist also noch keine Garantie dafür, dass das zweite Wort auch 'karte'
ist.
Jeder »Kopf« und jeder »Schwanz« in CompoundHeads
und CompoundTails
muss zwei Feldeinträge haben. Der zweite ist üblicherweise Null, kann aber Eind sein, um anzuzeigen, dass kein Bindestrich eingefügt werden soll. Statt 'haus- tuer'
hieße es dann 'haus tuer'
. (Wozu das genau nützlich sein kann, weiß ich nicht, aber es ist implementiert, und irgendwie schien es auch eine gute Idee zu sein.)
Eine Sache, die man beachten sollte, ist, dass die Köpfe immer abgeschnitten werden. Wenn man also die Vorsilbe "oel"
abtrennt, so kann man nicht 'oelbild'
oder 'oelung'
oder 'oeler'
als name
für ein Objekt definieren. Diese Vokabeln werden durch die Heads untypable. Das Wort 'oel'
, ohne weitere Endung, kann man aber definieren, sei es als Verb oder als Substantiv. Im Zweifelsfall sollte man sich mit dem »Echo« das Resultat anschauen und überlegen, ob das abtrennen der Wortteile sinnvoll ist.
Wer selbst noch Änderungen im Textpuffer vornehmen möchte, kann dies mit den beiden Einhängern PreInformese
und PostInformese
tun, die vor und nach den Informisierungsmechanismen von deform aufgerufen werden.
Descriptors
Als Descriptors bezeichnet Inform Wörter, die vor einem Objekt stehen können und dies näher beschreiben. Dazu gehören Artikel, Zahlenangaben, Possessiv- und Demonstrativpronomen und allgemein gültige Adjektive.
In deform werden nur die Artikel und die selten benutzen Demonstrativpronomen 'dies'
und 'jene'
(ohne Endungen, die soll der Parser abschneiden, sie werden eh nicht betrachtet) definiert. Die Personalpronomen werden meiner Meinung nach sowieso fast nie benutzt, und dann nicht so, wie der Spieler es will. Auf diese Weise sind Possessivpronomen keine Descriptors und können als Vokabeln angegeben werden:
Object -> meine_Tasse "Kaffeetasse"
with article yours,
name 'mein' 'tasse' 'kaffeetasse' 'rot',
description
"Wann ist eigentlich die Sitte aufgekommen,
bunte Tassen mit blöden Sprüchen im Büro zu
benutzen? Diese Tasse ist rot und behauptet
~Ich bin hier der Boss~.",
has female container;
Object -> Bernds_Tasse "Bernds Kaffeetasse"
with name 'sein' 'bernds' 'tasse'
'kaffeetasse' 'weiss',
description
"Bernd ist in seinem Kaffetassengeschmack
(und auch sonst) langweiliger als du.
Seine Tasse ist weiß mit einem winzig
kleinen Logo des Deutschen Roten Kreuzes
neben dem Henkel.",
has female proper container;
Wer das gesamte Spektrum der Possessivpronomen benutzen will wie im Original der kann die Konstante TRADITIONAL_DESCRIPTORS
definieren.
Genera für Vokabeln
Normalerweise betrachtet Inform den Genus von Vokabeln nicht. Das ist ärgerlich, wenn man ein Objekt anders nennt, dieser andere Name auch erkannt wird, aber nachfolgende Pronomen nicht:
> u die jacke
Der Anorak ist marineblau mit einem Besatz aus künstlichem Eisbärenfell. Auf dem rechten Ärmel steht »go nw«.> zieh sie an
Mir ist nicht klar, worauf sich »sie« bezieht.
In der alten deutschen Lib war es noch ärgerlicher, da das Pronomen oft zur Ausgabe verwendet wurde. deform ist hier etwas expliziter und gibt immer den ganzen Namen des Objekts aus, also »Die rostige Tür ist zu.« statt nur »Sie ist zu.«
In der ofiziellen deutschen Lib gibt es hierzu den Mechanismus changing gender, der auch in deform implementiert ist, wenn auch etwas einfacher. Vokabeln, deren Genus nicht dem des Objekts entspricht, werden als Attribut hintenangestellt:
Object -> Beutel "Beutel"
with name 'beutel' 'tasche' female 'tuete' female,
has male;
Jetzt werden ›tasche‹ und ›tuete‹ als weiblich erkannt und Eingabe wie »öffne die Tasche und leere sie« verstanden. Wenn man ein Pronomen mit (er)
, (ihn)
usw. ausgibt, wird auch der Genus aus der Eingabe verwendet – bis eine neue Eingabe geparst wird oder eine andere Art der Ausgabe mit dem »richtigen« Genus des Objekts aufgerufen wird, zum Beispiel (der)
oder (einer).
Etwas ärgerlich ist es, dass der Compiler anmeckert, dass in der name
-Property Attribute stehen. name
ist eine besondere Property, die nur Vokabeln enthalten soll. Andere Werte sind legal, aber es wird gewarnt. (Vokabeln können in name
, und nur da, auch in doppelten Anführungszeichen stehen. Diese Praxis ist aber veraltet und sollte nicht verwendet werden.)
In deform kann man anstelle der Attribute auch die untypable words 'm.'
, 'f.'
, 'n.'
und 'p.'
verwenden, also:
with name 'beutel' 'tasche' 'f.' 'tuete' 'f.',
(»Untypable words« sind Wörter, die niemals erkannt werden, weil sie Trennzeichen wie Punkt oder Komma enthalten. Die Eingabe »f.« würde vom Interpreter in die beiden Wörter 'f//'
und './/'
aufgeteilt.)
Wenn man in parse_name
den changing gender setzen möchte, benutzt man dazu die Routine GenderNotice(obj, attr)
:
Class Lampion
with short_name [;
if (self has light) print "hell";
else print "dunkl"; print "@00 Lampion";
rtrue;
],
parse_name [ wd n adj;
if (self has light) adj = 'hell';
else adj = 'dunkel';
wd = NextWordStopped();
while (wd == 'lampion' or 'laterne' or adj) {
n++;
if (wd == 'laterne')
GenderNotice(self, female);
wd = NextWordStopped();
}
return n;
],
...,
has male ~light;
Wenn man WordInProperty
benutzt, wird der changing_gender
automatisch gesetzt:
Class Lampion
with name 'lampion' 'laterne' 'f.'
parse_name [ wd n adj;
if (self has light) adj = 'hell';
else adj = 'dunkel';
wd = NextWordStopped();
while (wd == adj
|| WordInProperty(wd, self, name)) {
n++; wd = NextWordStopped();
}
return n;
],
...,
has male ~light;
Dieser Code ist äquivalent zum Code oben.
Früher musste man zu jedem Objekt, das vom Hauptgenus abweichende Genera verwendet hat, das Attribut changing_gender
definieren. Neuere Versionen von deform verwenden ein Feld, auf dem die geänderten Genera abgelegt werden. Man kann also zu jedem Objekt ohne Weiteres andere Genera in name
definieren. (Die Angabe von Genera funktioniert aber auch in anderen Properties, die man dann in parse_name
mit WordInProperty
untersuchen kann.)
Der changing gender funktioniert ganz gut, es gibt aber Einschränkungen, wenn man Pronomen verwendet:
Du siehst hier ein Beil.
> frotz die Axt
Sie leuchtet nun hell.> frotz sie
Es leuchtet nun hell.
Das Beil wird zwar richtig erkannt, weil sich »sie« auf das vorher erwähnte Synonym »Axt« bezieht, aber in der Ausgabe nicht richtig angesprochen. Die Information, welchen Genus das Pronomen hatte, wird im Pronomen-System von Inform nicht abgelegt.
Keine der Standardantworten von deform verwendet jedoch die reine Ausgabe mit Pronomen. Wenn Pronomen verwendet werden, geht immer eine normale Ausgabe voran, die den changing gender zurücksetzt.
Erweitertes Parsen
Mit der Eigenschaft parse_name
und dem Einhänger ParseNoun(obj)
kann der Autor eigene Regeln zum Parsen schreiben. Manche Regeln kommen aber öfter vor, so dass es nützlich ist, den Parser zu erweitern.
Wenn die Konstante EXTENDED_PARSER
zu Spielbeginn definiert wird, stehen neben den üblichen Möglichkeiten der Wortanalyse folgende Besonderheiten zur Verfügung:
Ein Objektname enthält eine Präposition, zum Beispiel »Postkarte« aus Australien». Wenn die Präposition in
name
enthalten ist, wird bei einem Satz wie «nimm die Karte aus dem Postkasten» die Präposition «aus" der Karte zugeschlagen, und der Parser läuft ins Leere.Daher kann man in der Eigenschaft
prep
eine Liste von Präpositionen angeben, die zusätzlich zuname
verstanden wird, aber nicht als letztes Wort einer Kette. Außerdem werden Descriptors, also Artikel und Demonstrativpronomen verstanden. Die Karte sähe dann so aus:Object -> -> Karte_aus_Australien "Karte aus Australien" with name 'karte' 'postkarte' 'post' 'gruss' 'australien' 'christine' 'mein' 'dein' 'nachbarin' 'sydney', prep 'von' 'aus', description "Von deiner Nachbarin Christine, mit Sylyestergrüßen aus Sydney." has female;
Dann wird »Karte aus Sydney«, »Karte von meiner Nachbarin« usw. verstanden.
Ein Objekt bezieht sich auf ein anderes Objekt, wie zum Beispiel ein Loch im Zaun oder ein Fleck auf dem Mantel. In diesem Fall definiert man wieder eine oder mehrere Präpositionen mit
prep
. Zusätzlich gibt man eine Eigenschaftparse_ref
an, die ein Objekt enthält:Object -> Loch "Loch im Bauzaun" with name 'loch' 'guckloch' 'oeffnung', prep 'in' 'von', parse_ref Bauzaun, has scenery neuter;
Dann wird zunächst das Objekt selbst untersucht. Wenn eine der Präpositionen folgt, wird das Objekt in
parse_ref
untersucht, das auch eineparse_name
haben oder vonParseNoun()
erkannt werden kann.Da hier die Präposition vorhanden sein muss, müssen Artikel im Dativ, also
'des'
und'der'
als Präposition angegeben werden, damit »Logbuch des Kapitäns« oder »Tasche der Frau« verstanden werden. (Bei »der« kann es aber wieder zu Problemen kommen: »gib Tasche der Frau« wird hier nicht richtig verstanden, da sich die komplette Phrase auf die Tasche bezieht.)Die Eigenschaft
parse_ref
kann auch eine Routine sein, die ein Objekt zurückgibt.
Diese beiden Fälle funktionieren auch beim Disambiguisieren, wenn nicht allzutief verschachtelt wird.
Disambiguisierung
Oft muss der Parser zwischen mehreren Objekten mit gleichen Namen auswählen oder fehlende Objeke erraten. Diese Methode wird in der Original-Lib (und auch in der offiziellen deutschen Lib) sehr rudimentär vorgenommen und führt oft zu seltsamen Annahmen.
In deform wird ein neues System verwendet. Beim Disambiguisieren – das ist der Fall flag==2
in ChooseObjects
– wird wie folgt vorgegangen:
Die Eigenschaft
disambig
des Objekts wird herangezogen. Sie kann eine Priorität zwischen −3 (niedrig) und 10 (hoch) zurückgeben.Sonst wird
ChooseObjects(obj, 2)
aufgerufen, wie es in Abschnitt 33 des DM4 beschrieben ist. Bitte beachten: Der Defaultwert für die Priorität ist drei, das heißt wenn man einen Wert kleiner als drei zurückgibt, wird das Objekt heruntergestuft!Die Routine
Disambiguate
der Lib macht allgemeine Annahmen über Objekte im Zusammenhang mit den Standard-Verben. Zum Beispiel werden beim Öffnen Objekte mit den Attributenopenable
und~open
bevorzugt. Diese Routine kann mitReplace
ersetzt werden. Objekte mit den Attributenscenery
undconcealed
werden leicht benachteiligt (2).
Wenn in (a) oder (b) ein von Null verschiedener Wert zurückgegeben wird, werden die nachfolgenden Punkte nicht mehr betrachet.
Die Property disambig
kann herangezogen werden, um einzelne Objekte hervor- zuheben, damit der Spieler nicht immer alles eingeben muss. So könnte zum Beispiel ein Lexikon folgendes definieren:
disambig [; Consult: return 5; ],
um dem Spieler die Nachfrage nach dem Nachschlagewerk zu ersparen:
> schlage erinnyen nach
(in Baxters Kompakter Ezyklopädie der Antiken Mythologie)Erinnyen [grch. »die Zürnenden«]: Die drei griechischen Rachegöttinnen →Tisiphone, →Allekto und →Megaira. Beschönigend auch Eumeniden [grch. »die Wohlgesinnten«] genannt.
Eine andere Anwendung ist das Bevorzugen oder Benachteiligen bestimmter Objekte je nach durchgeführter Aktion:
Object -> Warnschild "Warnschild"
with name 'schild' 'warnschild' 'warnung',
description "~ Bitte viermal klingeln! ~",
disambig [;
Examine: return 3;
default: return -1;
],
has neuter scenery;
Object -> Buckelschild "Buckelschild"
with name 'bronzen' 'schild' 'buckelschild'
'bronzeschild' 'buckel',
description
"Ein bronzener Schild mit Buckel, der
einige Schläge abhält wenn du ihn an
deinem Schildarm trägst.",
has male clothing;
Hier wird das Warnschild nur beim Lesen, beziehungsweise Untersuchen bevorzugt, das dies die Haupteigenschaft eines Schildes ist: beachtet zu werden. Trotzdem sollte man hier zusätzlich zu 'schild'
weitere Vokabeln angeben, um die beiden Objekte eindeutig unterscheidbar zu machen, wenn der Spieler es so will. (Die Benachteiligung mit −1 ist redundant, da das Warnschild als scenery
-Objekt eh schlechter abschneidet.)
Um unterscheiden zu können, ob gerade noun
oder second
betrachtet wird, kann man die globale Variable parameters
benutzen, die 0 für noun
und 1 für second
ist:
Object -> Taschenmesser
with name 'messer' 'taschenmesser'
disambig [;
Cut: if (parameters==1) return 5;
],
before [;
Cut:
if (noun hasnt cuttable)
"Das kann man nicht schneiden.";
give noun cut_up ~cuttable;
"Du schneidest ", (den) noun, " durch.";
],
has neuter;
Wer die von der Lib vorgenommenen Annahmen nicht verwenden möchte, der kann die Konstante TRADITIONAL_CHOOSE_OBJECTS
definieren. Ein Überschreiben der Annahmen mit disambig
funktioniert dann allerdings weiterhin.
Wer ändern möchte, wie sich der Parser bei »nimm alles« verhält, kann die Routine DisambiguateAll
ersetzen.
Explizite Fehlermeldungen
Wenn der Inform-Parser ein Wort nicht kennt, sagt er das üblicherweise nicht, sondern hält die Fehlermeldungen eher vage: »So etwas kannst du hier nicht sehen«, lautet die Fehlermeldung oder »Ich habe nur Folgendes verstanden: ...«.
Die offizielle Erklärung ist, dass der Spieler Hinweise auf implementierte Objekte, die er nocht nicht kennt, bekommen kann, wenn die Fehlermeldungen explizit sind. Ich finde das sehr verwirrend:
> stecke die Codekarte in das Lesgerät
So etwas kannst du hier nicht sehen.
Na schön, was kann ich nicht sehen? Wahrscheinlich das falsch eingegebene »Lesgerät«, aber sicher kann ich mir da nicht sein. Oder:
> u gelbe Bank
Ich habe nur folgendes verstanden: die gelben Blumen betrachten.
Diese Art von Fehler tritt auf, wenn es die Vokabeln 'gelb'
und 'bank'
zwar gibt, sie aber nicht beim selben Objekt definiert sind.
Wer dem Spieler etwas mehr Information geben möchte, kann vor dem Einbinden des Parsers die Konstante EXPLICIT_ERROR_MESSAGES
definieren. Dann werden die nicht oder falsch verstandenen Wörter genannt:
> u gelbe Bank
Ich verstehe das Wort »bank« in diesem Zusammenhang nicht.> stecke die Codekarte in das Lesgerät
Ich kenne das Wort »Lesgeraet« nicht.
Die beiden neuen Meldungen sind ##Miscellany
Nummer 98 und 99, die wie üblich mit der Eigenschaft before
im Objekt LibraryMessages
überschrieben werden können.
Die erste Meldung kommt, wenn das Wort dem Spiel bekannt ist, das heißt, wenn es im Wörterbuch des Spiels steht. Lange Wörter, die als Strings mit WordMatch
untersucht werden, werden nicht berücksichtigt. Der Einhänger WordIsKnown
bietet dem Autor die Möglichkeit, den Sprachschatz des Spiels zu erweitern oder einzuschränken. In dieser Routine wird das Wort an der Stelle wn
untersucht. Wenn diese Routine true
oder false
zurüpckgibt, gilt das Wort als bekannt oder unbekannt. Wenn die Routine −1 zurückgibt, entscheidet der Parser.
Listen
Der List Writer funktioniert wie in der Original-Lib. Um die Liste in einem bestimmten Fall auszugeben, kann man WriteListFromCase
benutzen, dem man den Fall als drittes Argument übergibt:
WriteListFromCase(obj, style, case)
Das ISARE_BIT
ist nur sinnvoll, wenn die Liste im Nominativ ausgegeben wird. Ist dieses Bit gesetzt und die Liste soll in einem anderen Fall ausgegeben werden, so wird der Fall automatisch auf den Nominativ gesetzt. Der jeweils zur Ausgabe benutzte Fall steht in der globalen Variable short_name_case
. Die Fälle sind von null bis drei surchnummeriert und entsprechen den Konstanten Nom
, Gen
, Dat
, Akk
.
In der Original-Lib werden Listen ineinandergeschachtelt, so dass man leicht den Überblick verliert:
Du hast einen Wanderrucksack (der offen ist), darin eine durchsichtige Plastikdose, darin ein Butterbrot mit Käse, ein Butterbrot mit Wurst, ein hartgekochtes Ei und eine Tomate, eine Flasche, darin etwas Apfelschorle und einen Anorak bei dir.
Mit dem APPEND_BIT
(das zusätzlich zu RECURSE_BIT
gesetzt werden kann oder nicht) werden Listen nacheinander ausgegeben. Die Inhalte der vorher erwähnten Objekte werden in einem jeweils eigenen Satz ausgegeben.
Du hast einen Wanderrucksack (der offen ist) bei dir.
In dem Wanderrucksack sind eine durchsichtige Plastikdose, eine Flasche und ein Anorak. In der Flasche ist etwas Apfelschorle. In der durchsichtigen Plastikdose sinds ein Butterbrot mit Käse, ein Butterbrot mit Wurst, ein hartgekochtes Ei und eine Tomate.
Jedes Objekt auf der oberen Ebene, das eigenen Inhalt hat, bekommt einen Absatz, alle Objekte darunter werden mit im selben Absatz behandelt. Lange Listen von Objekte sind nie sehr schön, aber ich finde sie in eigenen Sätzen übersichtlicher. Mit der Konstante NO_NESTED_LISTS
kann man erwzingen, dass alle Listen, die ENGLISH_BIT
und RECURSE_BIT
haben auch das APPEND_BIT
bekommen.
Die angehängten Sätze werden mit der neu eingefügten Library Message (##Look, -1)
geschrieben, die natürlich ersetzt werden kann. Wer selbst WriteListFrom
aufruft und dabei das APPEND_BIT
setzt oder NO_NESTED_LISTS
definiert hat, sollte auf jeden Fall nach dem Satz, der den List-Writer aufruft, die Routine WriteSubLists()
aufrufen. Diese Routine gibt die Anzahl der geschriebenen Sätze zurück, so dass man Zeilennumbrüche und Leerzeichen schreiben kann, je nachdem, ob etwas augegeben wurde oder nicht. (Es erfordert meist etwas Herumspielen, bis es funktioniert. Am besten, man schaut sich die passenden Lib-Messages einmal an.)
Die Einrückung von Listen mit INDENT_BIT
kann man über die Konstante INVENTORY_INDENT
steuern, Default ist eine Einrückung um zwei Leerzeichen in jeder Ebene. Mit der Konstante INVENTORY_BULLET
kann man jedem Listen- eintrag ein Aufzählungszeichen voranstellen. Um z.B. einen Spiegelstrich zu verwenden definiert man am Anfang des Quelltexts:
Constant INVENTORY_BULLET = "- ";
(Ziemliche Spielerei, ich weiß. Aber ich finde die Listen oft zu wenig eingerückt und mit Aufzählungszeichen besser lesbar.)
Initialisierung
Jedes Spiel muss die Routine Initialise
definieren. Dort wird meist ein Anfangstext ausgegeben. Auf jeden Fall muss die Variable location
auf den Startraum gesetzt werden.
Hier werden auch andere Dinge gemacht, wie zum Beispiel Dämonen gestartet oder Objekte ins Inventar des Spielers verschoben. Das ist unübersichtlich, da diese objektbezogenen Initialisierungen nicht beim Objekt definiert werden. Mit der Property init
kann man bei jedem Objekt Initialisierungen vornehmen:
init [;
move self to player;
StartDaemon(self);
self.colour = random("kadmiumgelb",
"malvenfarben", "himmelblau", "kirschrot");
], ...
In init
-Properties sollte kein Text ausgegeben werden.
Besonderheiten beim Umstieg
Normalerweise sollten sich Dateien, die für die offizielle deutsche Lib erstellt wurden, auch mit deform kompilieren lassen. Einige Dinge gibt es jedoch zu beachten:
Einige (wenige) Bezeichner haben sich geändert, insbesondere:
(endT)
→ (___t)
(endET)
→ (___et)
definit
→ definite
Diese Bezeichner kommen nicht allzu oft vor, und man kann sie leicht per Hand ausbessern, oder folgendes nach dem Einbinden von
Parser.h
definieren:[ endT o; ___t(o); ]; [ endET o; ___et(o); ]; Constant definit = definite;
Die Deklinationsformen können unter Umständen im Genitiv abweichen. Da deform nicht auf die Endung der Wörter schaut, können -es und -s schon einmal vertauscht werden. (Habe ich noch nicht beobachtet, ist aber denkbar.) In diesem Fall bitte
dekl
aufGenitiv_s
oderGenitiv_es
setzen.Die offizielle Lib definiert eine
LiftSub
, die allerdings nur aufLookUnder
umlenkt.
Diese Punkte kann man umgehen, indem man die Konstante COMPATIBILITY_MODE
definiert. Die folgenden Punkte muss man allerdings von Hand nachziehen:
Plurale werden nicht von deform, sondern vom Autor gebildet. Deshalb muss man, wenn ein Objekt im Plural steht, auch den Plural angeben. Statt
Object -> "Frau" with dekl 9, name 'frau' has pluralname female;
heißt es
Object -> "Frauen" with name 'frauen' has pluralname;
Attribut
pluralname
nicht vergessen! (Der Plural wird wie in T.A.G. als eigener Genus betrachtet, es wird nicht zwischen Plural männlich, weiblich und sächlich unterschieden, und jedes Objekt sollte nur eins der Attributemale
,female
,neuter
undpluralname
haben.)Der Algorithmus zum Beschneiden der Vokabeln hat sich geändert, daher können sich in einzelnen Fällen Vokabeln in deform anders verhalten als in der offiziellen Lib. Das kann man mit
echo
im Debug-Modus gut prüfen.Wer direkt auf die
ta_
irgendwas-Routinen zugegriffen hat, muss jetzt umstricken. Dieta
-Routinen sind zusammen mittgerman.h
verschwunden. Wie man was am besten macht, kann man sich in den Library Messages abgucken. Oder fragen. Gute Orte zum Nachsehen sind die FelderLanguageArticles
,LanguageSuffixes
undPersonalPronouns
.