
deform
inoffizielle deutsche Inform-Library
auf dem Stand von Inform-Lib 6/11

KURZDOKUMENTATION

EINBINDEN DER DATEIEN

Im Quelltext des Spiels mssen die Dateien wie folgt eingebunden werden:

    !... Story und Headline
    !... Ersetzen von Routinen wenn gewnscht

    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:

    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 Grobuchstaben, alle anderen
sind durchweg klein geschrieben. (Das ist fr 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 groen Teil ersetzen mchte,
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 heien,
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' heien.) Mit dem neuen
Compiler Inform 6.30 ist es mglich, 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 mssen die ersten im Quelltext sein.)

In jedem Fall wird am Ende von GermanG.h sichergestellt, dass nur deform-
Dateien eingebunden wurden und das 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 knnen. Es gibt 32 dieser Strings,
folgende werden von der Lib benutzt:

    @00     Adjektivendung
    @01     Endung -n fr Plural-Substantive im Dativ
    @02     Endung -en fr mnnl. Substantive
    @03     Endung -s fr Substantive im Genitiv
    @04     Endung -es fr Substantive im Genitiv

    @30     'ss' fr schweizerische Spiele
            Eszett fr alle anderen
    @31     Eszett fr alte Rechtschreibung
            'ss' fr reformierte und schweizerische Spiele

Die ersten Strings ndern sich stndig, sie werden bei jedem Aufruf von
(den), (dem) usw. angepasst (siehe unten).

Die Eszett-Strings bestimmen das Erscheinungsbild der Texte. Wenn man sich
fr eine Variante entscheidet, kann man seine eigenen Texte einfach mit
dieser Variante schreiben. Wenn man es zulassen mchte, dass der Spieler
selbst zwischen den Varianten umschalten kann, sollten die eigenen Texte
ebenfalls die Low strings verwenden, etwa: "Du reibst ein wenig Ru@30 vom
Kessel und mu@31t niesen." (Das ist allerdings viel Arbeit!)

Verffentlichte 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";

Constant DIALECT_TRADITIONAL: alte Rechtschreibung:
    string 30 ""; string 31 "";

Constant DIALECT_SWISS: schweizerische Rechtschreibung:
    string 30 "ss"; string 31 "ss";



SCHEMA FR 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.
Fr kompliziertere Objekte gibt es zwei Methoden:

(1) Traditionell: Zu jedem Objekt wird eine Property 'dekl' angegeben, die
    den Deklinationsmodus festlegt. Es gibt folgende Deklinationstypen:

        #   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 auer im Nominativ  --
        7   f       --                      -n im Dativ
        8   f       --                      -n im Dativ
        9   f       --                      --
       10   f       --                      --

    Die Deklinationen, die hier gleich beschrieben werden, unterscheiden
    sich in der Pluralbildung. Da Inform aber *nie* den Plural selbstndig
    bilden muss, ist diese Unterscheidung praktisch nutzlos. Daher gibt es
    jetzt vier neue Deklinationsformen:

        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
    angehngt:

        Object with short_name "Regale", dekl 2, has pluralname;

    Wenn short_name eine Routine ist, mssen die beiden Routinen print_adj
    und print_subst verwendet werden, um die passenden Endungen anzuhngen:

        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 fr die Endungen im Nominativ, Genitiv. Dativ und Akkusativ
    oder eine Routine, der der Fall bergeben wird, sein. Fr 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 "Huser" gibt, ist short_name "Huser", nicht "Hus"!
    (Der Singular wird eh nie verwendet und die Umlautumwandlung hat die
    offizielle Lib auch nicht beherrscht.)

(2) Vereinfacht: Der short_name enthlt Low strings fr Endungen (siehe
    oben), typischerweise @00 fr Adjektive. Die Property 'dekl' wird nicht
    bentigt:

        Object with short_name "rot@00 Grtze", has female;
        Object with short_name "leblos@00 Krper des Drachen", has male;

    Meistens wird nur @00 bentigt. @01 und @02 werden gelegentlich bei
    mnnlichen und schlichen Substantiven im Plural und bei mnnlichen
    Substantiven bentigt:

        Object with short_name "alt@00 Regale@01 aus Holz", has pluralname;
        Object with short_name "Student@02", has male animate;
        Object with short_name "klein@00 Junge@02", has male animate

    @03 und @04 werden nur bentigt, 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 hsslich aus. Die paar Zahlen lassen sich aber
    wohl besser merken als die Deklinationbstypen.)

Es gibt ein paar Sonderkonstanten fr die Objektausgabe. Die Eigenschaft
article, die nur bei (ein), (einen) usw. herangezogen wird, kann auer 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 [tm]"

    no_article: Das Objekt wird in unbestimmten Fall ohne Artikel
              ausgegeben. Der Unterschied zu proper ist, dass bei proper nie
              Artikel verwendet werden, auch bei der Ausgabe mit bestimmten
              Artikel nicht. Ist das ntzlich? Kaum, aber was soll's?

Auerdem kann short_name den Wert no_short_name haben, was bedeutet, dass
die Ausgabe des short_name unterdrckt wird. Artikel werden aber ausgegeben,
ebenso art und poat, 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 FR DIE AUSGABE DER OBJEKTNAMEN

Die englische Lib definiert folgende Ausgaberoutinen:

    (The)     Objekt mit bestimmtem Artikel, gro ("The shop assistant")
    (the)     Objekt mit bestimmtem Artikel ("the quick brown fox")
    (a)       Objekt mit unbestimmtem Artikel ("an apple", "some marbles")
    (name)    Objektname ohne Artikel ("red rice-paper lantern")

Diese Routinen stehen auch im deutschen zur Verfgung, sollten aber nicht
benutzt werden. Dazu kommen Ausgaberoutinen fr Verben, wie (ThatOrThose)
oder (TheyreOrThats), die in dieser Lib nicht definiert sind.

In der deutschen Lib muss der Fall der Ausgabe bercksichtigt werden. Es
stehen folgende Routinen zur Ausgabe zur Verfgung:

    (der) o, (des) o, (dem) o, (den) o
        Objekt mit bestimmtem Artikel. Diese Routinen rufen
        DefArt(o, Fall) auf.

    (GDer) o, (GDes) o, (GDem) o, (GDen) o
        Objekt mit bestimmtem Artikel, der erste Buchstabe wird gro
        ausgegeben, ruft DefArt(o, Fall) auf

    (ein) o, (eines) o, (einem) o, (einen) o
        Objekt mit unbestimmtem Artikel, ruft IndefArt(o, Fall) auf

    (kein) o, (keines) o, (keinem) o, (keinen) o
        Negiertes Objekt, umgeleitet zu NegativeArt(o, Fall)

    (er) o, (seiner) o, (ihm) o, (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 mit WithoutArt(o, Fall) in anderen Fllen 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 ("mssen", "muss", noun);

In der Lib kann man nur Objekte mit bestimmtem Artikel gro ausgeben,
da dies wohl am hufigsten 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 schlen ist echt knifflig.";

Natrlich steht es jedem Autoren frei, sich Routinen wie CEin, CEs
usw. zu definieren.


SYNONYME

Um die Kontraktionen aus Prpositionen und Artikeln (ins, zum usw.)
effizient zu behandeln, ohne alle mhselig 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
        'frs'     "fuer das"
        'doch'     ""
        ;

Achtung, der zweite Eintrag in jedem Paar ist ein String in Gnsefchen,
 der natrlich keine Grobuchstaben und Umlaute enthalten darf.

Ein hnliches System, bei dem immer zwei aufeinanderfolgende Wrter ersetzt
werden sind die "Zwillinge", die analog dazu im Feld 'Twins' in Dreier-
gruppen angegeben werden:

    Array Twins table
        'prof' './/'     "prof"
        '10' './/'       "zehnte"
        ;


ENDUNGEN

Der Parser schneidet Endungen ab und bercksichtigt werden den Fall des
Tokens (es gibt nur [noun]) noch den Genus des untersuchten Worts. Dies
ist eine praktikable Vorgehensweise. Im Einzelnen:

(a) Es werden nur folgende Endungen abgeschnitten:

        '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 (den Zwerge-n)

        *)    und Possesiv- und Demonstrativpronomen

    Endungen wie '-ern' werden nicht bercksichtigt, da der deform-Parser
    verlangt, dass Wrter sowohl fr die Eingabe als auch fr die Ausgabe
    im Plural in ihrer kompletten Form angegeben werden. Vokabeln wie
    'haeus' wenn eigentlich 'haeuser' gemeint ist, sind damit hinfllig.

    Verben werden nicht per se beschnitten, sondern auch nur nach den hier
    beschriebenen Regeln. Die meisten Verben haben wie in der offiziellen
    Lib ihr Ende-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 Fllen wie "fuchs, gute nacht"
    oder "setz dich hin. steh auf. leg dich hin" umstndlich sein kann.

(b) Es wird abgeschnitten, wenn dan 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 Wrter gibt, nichts

(c) In jedem Fall hat der Spieler Zugriff auf die Original-Eingabe, die
    in orig_buffer und orig_parse steht. Mit den Routinen OriginalLength(w)
    und OriginalAddress(w) kann man darauf zugreifen. Diese beiden Routinen
    bercksichtigen, dass sich die Wrter durch Synonymbildung verschieben
    knnen: "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) Fllen 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 heit 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 ntztlich fr die Lib,
auch wenn es in einzelnen Fllen, wie etwa Abkrzungen ("Dr. Mller") etwas
rgerlich sein kann. Dies kann man aber mit Synonymen beheben. Der dritte
"word separator" in Inform ist das Gnsefchen (").

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
Mglichkeiten, 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 zu IGNORE_PUNCTUATION verstanden.)

    REPLACE_PUNCTUATION
    Hier werden die Satzzeichen durch Punkte ersetzt. (Was im Fall von
    Frage- und Ausrufezeichen sinnvoll ist, bei den Anfhrungszeichen
    wohl weniger.)

    SEPARATE_PUNCTUATION
    Hier werden die Satzzeichen so von den angrenzenden Wrtern abgerckt,
    dass sie eigene Wrter 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 bercksichtigt auch das Anfhrungszeichen.
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 zurck, je nachdem ob das Zeichen als
Satzzeichen betrachet werden soll oder nicht. Man kann also auch Doppel-
und Strichpunkte besonders behandeln, wenn man mchte.

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 mssen im Imperativ der zweiten Person Singular angegeben werden,
Die Konvention ist hier, dass der Spieler das Spiel duzt. Die regelmigen
Verben lassen hier mist zwei Forme zu, die sich nur durch ein angehngtes
'e' unterscheiden, etwa 'schau' und 'schaue'.

In der offizielle Lib wird das 'e' automatisch vom Parser abgeschnitten,
daher drfen dort Verb-Definitionen kein 'e' am Ende haben. Hier drfen
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 drfen wie alle Vokabeln keine Umlaute enthalten, es mssen 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, entwerden 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 (fr 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 einschrnkenden Tokens [attribute], [noun=Routine] und in gewissem Mae
auch [creature] sollten nur dazu verwendet werden, verschiedene Bedeutungen
gleicher Satzmuster zu unterscheiden, wie im Beispiel oben gezeigt.

Wenn man die Gltigkeit eines Tokens bereits in der Grammatikdefinition
einschrnkt, so kann dies zu ungewollten Fehlermeldungen fhren. Wenn der
Autor zum Beispiel ein neues Verb einfhrt, das nur fr 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 fr das Spielen wrde dann in 'before' der Klasse fr Musikinstru-
mente definiert.




LANGE WRTER

Im Deutschen gibt es viele zusammengesetzte Wrter, die sehr lang sind.
Im z-Code knnen die Vokabeln aber nur neun Zeichen lang sein. (Das heit
in den Versionen fnf und spter. In Version drei ist ein Eintrag ins
Wrterbuch nur sechs Zeichen lang. In Glulx kann man die Lnge der Vokabeln
mit einer Konstante definieren, aber die Voreinstellung ist auch hier neun
Zeichen.)

In vielen Fllen 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 Fllen muss man aber das ganze
Wort parsen. Dazu stehen in deform zwei Methoden zur Verfgung.

(1) Genaue Wortanalyse in parse_name

    In Inform kann man mit der Property 'parse_name' die bliche Analyse
    ber 'name' ersetzen oder erweitern. Um lange Wrter parsen zu knnen,
    steht in deform die Routine WordMatch(s) zur Verfgung. s ist hier
    ein String zwischen Gnsefchen, der so aussehen muss wie eine Vokabel,
    das heit er darf keine Umlaute oder Grobuchstaben besitzen.

    Die Routine untersucht das Wort wn und gibt false zurck, wenn das Wort
    nicht passt oder die Lnge des Strings (die einen wahren Wert hat),
    wenn das Wort bereinstimmt. In diesem Fall wird auch der Wortmarker wn
    um eins weitergerckt. Auf diese Weise sind in parse_name Prfungen wie
    folgende mglich:

        Object -> Hauptsicherung "Sicherungsschalter des Schiffs"
          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 zhlt wn um eins weiter - NextWord() macht dies auch - und
    springt in den Ausfhrungsblock der Schleife. Hier wird n hochgezhlt.
    Es kann also in diesem Schema immer nur *ein* Aufruf den Wortmarker
    vorrcken.

    WordMatch prft nur ber die Lnge des Worts, alles, was danach kommt,
    wird ignoriert. Mit WordMatch(s, true) kann man eine genaue berein-
    stimmung erwzingen.

        Class  -> Streichholz "Streichholz"
          with name 'holz', 'hoelzer//p',
               parse_name [n b;
                   do {
                       b = false;
                       if (WordMatch("streichholz", 1)) b = true;
                       if (WordMatch("streichhoelzer", 1) {
                           b = true;
                           parser_action = ##PluralFound;
                       }
                   } while (b);
                   if (n) return n;
                   return -1;
               ],
               plural "Streichhlzer",
           has neuter;

(2) Abtrennen der Kpfe und Schwnze

    Oben im Quelltext, bevor Parser.h eingebunden wird, kann man ein Feld
    CompundHeads definieren. Es enthlt "Kpfe" von Wrtern die abgetrennt
    werden und dann, mit einem angehngten Bindestrich, eigene Wrter sind.

    Die Streichhlzer oben shen 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 "Streichhlzer",
           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
            ;

    knnte man nun die ganzen Holz-, Eisen-, Stahl-, Gold-, Molybdn-
    und was wei ich nicht noch fr Schlssel unterscheidbar machen, indem
    man berall das Prfix 'eisen-' usw. und das Wort 'schluessel' angibt.
    Hierbei werden die blichen Endungen brcksichtigt, das heit auch
    'landkarten' wrde in 'land- karte' umgewandelt. (Es sei denn, es gibt
    das Wort 'karten' auch, dann wrde es 'land- karten' heien - es wird
    zunchst geprft, ob das Wort inklusive einer der mglichen 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 dafr, dass das zweite Wort auch 'karte' ist.

    Jeder "Kopf" und jeder "Schwanz" in CompoundHeads muss zwei Feldeintrge
    haben. Der zweite ist blicherweise Null, kann aber Eind sein, um
    anzuzeigen, dass kein Bindestrich eingefgt werden soll. Statt 'haus-
    tuer' hiee es dann 'haus tuer'. (Wozu das genau ntzlich 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 Kpfe immer 
    abgeschnitten werden. Wenn man also die Vorsilbe "oel" abtrennt, so 
    kann man nicht 'oelbild' oder 'oelung' oder 'oeler' als Name fr 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 Wort-
    teile sinnvoll ist.

Wer selbst noch nderungen im Textpuffer vornehmen mchte, kann dies mit
den beiden Einmhngern PreInformese und PostInformese tun, die vor und
nach den Informisierungsmechanismen von deform aufgerufen werden.


DESCRIPTORS

Als Descriptors bezeichnet Inform Wrter, die vor einem Objekt stehen
knnen und dies nher beschreiben. Dazu gehren Artikel, Zahlenangaben,
Possessiv- und Demonstrativpronomen und allgemein gltige Adjektive.

In deform werden nur die Artikel und die selten benutzen Demonstrativ-
pronomen '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 Inform
es will. Auf diese Weise sind Possessivpronomen keine Descriptors und knnen
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 blden Sprchen im Bro 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 FR VOKABELN

Normalerweise betrachtet Inform den Genus von Vokabeln nicht. Das ist
rgerlich, wenn manein Objekt anders nennt, dieser andere Name auch erkannt
wird, aber nachfolgende Pronomen nicht:

     > u die jacke
     Der Anorak ist marineblau mit einem Besatz aus knstlichem
     Eisbrenfell. 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 Tr ist zu."
statt nur "Sie ist zu."

In der ofiziellen deutschen Lib gab es hierzu den Mechanismus "changing
gender", der auch in deform implementiert ist, wenn auch etwas einfacher.
Wenn ein Objekt Vokabeln mit verschiedenen Genera hat, muss es die Property
changing_gender definieren. Vokabeln, deren Genus nicht dem des Objekts
entspricht, werden als Attribut hintenangestellt:

    Object -> Beutel "Beutel"
      with name 'beutel' 'tasche' female 'tuete' female,
           changing_gender,
       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.
(Vokalen knnen in name, und nur da, auch in doppelten Anfhrungszeichen
stehen. Diese Praxis ist aber veraltet und sollte nicht verwendet werden.)

Max Kalus' Ansatz, die Warnung aus dem Compiler zu schmeien, war etwas
kurzsichtig. Sie galt nur fr eine Plattform, und neuere Versionen des
Inform-Compilers haben diese Warnung natrlich wieder. 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 Wrter, die niemals erkannt werden, weil sie
Trennzeichen wie Punkt oder Komma enthalten. Die Eingabe "f." wrde vom
Interpreter in die beiden Wrter 'f//' und './/' aufgeteilt.)

Wenn man in parse_name den changing_gender setzen mchte, 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;

Diese Routine setzt im Moment einfach obj.changing_gender = attr. (Die
globale Variable changed_gender gibt es nicht mehr.) Bitte aber trotzdem
die Routine verwenden, da sich vielleicht irgendwann einmal etwas an der
Methode ndert. (Zum Beispiel, dass nicht mehr die Property changing_gender
explizit bei jedem Objekt angegeben werden mus.)

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.



DISAMBIGUISIERUNG

Oft muss der Parser zwischen mehrerer Objekten mit gleichen Namen auswhlen
oder fehlende Objeke erraten. Diese Methode wird in der Original-Lib (und
auch in der offiziellen deutschen Lib) sehr rudimentr vorgenommen und fhrt
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:

    (a) Die Eigenschaft disambig des Objekts wird herangezogen. Sie
        kann eine Prioritt zwischen -3 (niedrig) und 10 (hoch) zurckgeben.

    (b) Sonst wird ChooseObjects(obj, 2) aufgerufen, wie es in Abschnitt 33
        des DM4 beschrieben ist. Bitte beachten: Der Defaultwert fr die
        Prioritt ist drei, das heit wenn man einen Wert kleiner als drei
        zurckgibt, wird das Objekt heruntergestuft!

    (c) Die Routine Disambiguate der Lib macht allgemeine Annahmen ber
        Objekte im Zusammenhang mit den Standard-Verben. Zum Beispiel werden
        beim ffnen Objekte mit den Attributen openable und ~open bevorzugt.
        Diese Routine kann mit Replace ersetzt werden. Objekte mit den
        Attributen scenery und concealed werden leicht benachteiligt (2).

Wenn in (a) oder (b) ein von Null verschiedener Wert zurckgegeben 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 knnte zum
Beispiel ein Lexikon Folgendes definieren:

    disambig [; Consult: return 5; ],

um dem Spieler die Nachfrage nach dem Nachschalgewerk zu ersparen:

    > schlage erinnyen nach
    (in Baxters Kompakter Ezyklopdie der Antiken Mythologie)
    Erinnyen [grch. "die Zrnenden"]: Die drei griechischen Rachegttinnen
    -> Tisiphone, -> Allekto und -> Megaira. Beschnigend auch Eumeniden
    [grch. "die Wohlgesinnten"] genannt.

Eine andere Anwendung ist das Bevorzugen oder Benachteiligen bestimmter
Objekte je nach durchgefhrter 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 Schlge abhlt
               wenn du ihn an deinem Schildarm trgst.",
       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 zustzlich 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 knnen, ob gerade noun oder second betrachtet wird, kann
man die globale Variable parameters benutzen, die 0 fr noun und 1 fr
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 Annehmen nicht verwenden mchte, der kann
die Konstante TRADITIONAL_CHOOSE_OBJECTS definieren. Ein berschreiben der
Annahmen mit disambig funktioniert dann allerdings weiterhin.

Wer ndern mchte, wie sich der Parser bei "nimm alles" verhlt, kann die
Routine DisambiguateAll() ersetzen.


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
Flle sind von null bis drei surchnummeriert und entsprechen den Konstanten
Non, 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 Kse, 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 zustzlich zu RECURSE_BIT gesetzt werden kann oder
nicht) werden Listen nacheinander ausgegeben. Die Inhalte der vorher
erwhnten 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 einen Anorak. In der Flasche ist etwas Apfelschorle. In der
    durchsichtigen Plastikdose ist ein Butterbrot mit Kse, 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 schn, aber ich finde sie in eigenen Stzen
bersichtlicher. Mit der Konstente NO_NESTED_LISTS kann man erwzingen, dass
alle Listen, die ENGLISH_BIT und RECURSE_BIT haben auch das APPEND_BIT
bekommen.

Die angehngten Srze werden mit der neu eingefgten Library Message
(##Look, -1) geschrieben, die natrlich 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 Stze zurck, so dass man Zeilennumbrche 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 Einrckung von Listen mit INDENT_BIT kann man ber die Konstante
INVENTORY_INDENT steuern, Default ist eine Einrckung um zwei Leerzeichen
in jeder Ebene. Mit der Konstante INVENTORY_BULLET kann man jedem Listen-
eintrag ein Aufzhlungszeichen 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
eingerckt und mit Aufzhlungszeichen 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 Dmonen gestartet
oder Objekte ins Inventar des Spielers verschoben. Das ist unbersichtlich,
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 fr die offizielle deutsche Lib
erstellt wurden, auch mit deform kompilieren lassen. Einige Dinge gibt
es jedoch zu beachten:

  * Einige (wenige) Bezeichner haben sich gendert, 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 knnen unter Umstnden im Genitiv abweichen.
    Da deform nicht auf die Endung der Wrter schaut, knnen -es und -s
    schon einmal vertauscht werden. (Habe ich noch nicht beobachtet, ist
    aber denkbar.) In diesem Fall bitte dekl auf Genitiv_s oder Genitiv_es
    setzen.

  * Die offizielle Lib definiert eine LiftSub, die allerdings nur auf
    LookUnder umlenkt.

Diese Punkte kann man umgehen, indem man die Konstante COMPABILITY_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;

    heit 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 mnnlich,
    weiblich und schlich unterschieden, und jedes Objekt sollte nur eins
    der Attribute 'male', 'female', 'neuter' und 'pluralname' haben.)

  * Wer direkt auf die ta_irgandwas-Routinen zugegriffen hat, muss jetzt
    umstricken. Die ta-Routinen sind zusammen mit tgerman.h verschwunden.
    Wie man was am besten macht, kann man sich in den Library Messages
    abgucken. Oder fragen. Gute Orte um nachzuschauen sind die Felder
    LanguageArticles, LanguageSuffixes und PersonalPronouns.