T. A. G. Text-Adventure-Generator (C) 2000 Martin Oehm, Version 2.0 Benutzer- und Referenzhandbuch _____________________________________________________________________________ Inhalt: I. Ein erster Blick auf TAG 1. Einleitung 1.1. Wozu das alles? 1.2. Rechtliches 1.3. Kontakt, Verweise und Danksagungen 1.4. Über dieses Handbuch 2. Grundkonzept eines Adventures 2.1. Wie ist ein Adventure aufgebaut? 2.2. Der Text-Adventure-Generator TAG 2.3. Aufbau der Quelldatei für TAG 2.4. Der Parser II. Definitionen und Anweisungen 3. Räume und Objekte 3.1. Räume und ihre Verbindungen 3.1.1. Richtungen 3.1.2. Raumattribute 3.1.3. Räume 3.1.4. Antworten 3.1.5. Wege 3.2. Objekte 3.2.1. Objektattribute 3.2.2. Zustände 3.2.3. Objekte 3.2.4. Dekorationen 3.3. Klassen von Objekten und Räumen 3.3.1. Objektklassen 3.3.2. Raumklassen 4. Befehle, Aktionen und Variablen 4.1. Befehle 4.2. Flaggen und Variablen 4.2.1. Flaggen und Integer-Variablen 4.2.2. Konstanten 4.2.3. Felder 4.2.4. Raumvariablen 4.2.5. Objektvariablen 4.2.6. Weitere Variablen 4.2.7. Strings 4.3. Aktionen 5. Programmieren der Ausführungsblöcke 5.1. Arten von Aktionen 5.1.1. Textprozeduren 5.1.2. Variablenzuweisungen 5.1.3. Prozeduren für Räume und zur Fortbewegung 5.1.4. Objekte 5.1.5. Allgemeine Spielprozeduren 5.1.6. Prozeduren zur Belegung von Feldern 5.2. Grundprozeduren und -funktionen 5.3. Bedingungen 6. Die verschiedenen Aktionen im Spiel 6.1. Die Aktion Anfang 6.2. Ablauf eines Zuges 6.3. Zeitabhängige Ereignisse 6.4. Wiederkehrende Verhaltensmuster 6.5. Die Ausführungsblöcke der Objekte und Räume 6.5.1. Ausführungen von Räumen 6.5.2. Ausführungen von Objekten 6.6. Neue Befehle einbauen 7. Erstellen der Texte 7.1. Textblöcke 7.2. Anweisungen im Text 8. Allgemeines 8.1. Stilparameter und Formate 8.2. Synonyme 8.3. Funktionstasten 8.4. Punkte III. Beispiele 9. Räume 9.1. Wann werden Wege benutzt? 9.2. Die Raumbeschreibung 9.3. Tag und Nacht 9.4. Eine Menge von Räumen als ein Raum 9.5. Ein Labyrinth 9.6. Verschiedene Antworten als eine 9.7. Spiegelung der Landkarte 10. Verschiedene Arten von Objekten 10.1. Behälter und Ablagen 10.2. Türen und Schlüssel 10.3. Sitze, Liegen und begehbare Objekte 10.4. Fahrzeuge 10.5. Unwichtige Dekorationen 10.6. Ähnliche Objekte an verschiedenen Orten 11. Aufzählungen und Beschreibungen 11.1. Die Beschreibung eines Objekts 11.2. Gruppieren von Objekten 11.3. Ein Objekt als Gruppe von Objekten 12. Andere Personen im Spiel 12.1. Mit anderen reden 12.2. Maschinen mit Spracherkennung 13.3. Ein schleichender Dieb 13. Der Spieler 13.1. Was genau ist der Spieler in TAG? 13.2. Mehrere Leben 13.3. Ein ganzes Team 14. Die Sichtbarkeit und Erreichbarkeit von Objekten 14.1. Was man sehen und was anfassen kann 14.2. Änderungen der Sichtbarkeit und Erreichbarkeit 14.3. Ein Raum, der in der Mitte ein Gitter hat 15. Besonderheiten des Parsers 15.1. Wie arbeitet der Parser? 15.2. Der Vor- und Nach-Parser 15.3. Parsen von Objekten 15.4. Parsen von numerierten Objekten 15.5. Parsen von Objekten mit komplexen Kennungen 15.6. Parsen von Verben 16. Extras 16.1. Ein Rang für Punkte 16.2. Komplette Auflistung der Punkte 16.3. Eine frei definierte Statuszeile 17. Allgemeine Tips und Tricks 17.1. Hilfsvariablen 17.2. Größe eines Spiels Anhang: A. Kurzübersicht B. Bereits vorhandene Definitionen C. Vordefinierte Befehle D. Überblick über die Textoptionen E. Glossar des 'Adventure-Slangs' _____________________________________________________________________________ I. EIN ERSTER BLICK AUF TAG 1. EINLEITUNG 1.1. Wozu das alles? TAG ist ein Generator für Text-Adventures in deutscher Sprache. Text-Adventure heißt dabei: Es können Anweisungen an die Spielerfigur per Tastatur gegeben werden, die Ausgabe des Programms erfolgt nur über Texte auf dem Bildschirm. Meist geht es darum, einen Helden (oder natürlich eine Heldin) mittels kurzen Befehlen durch eine Phantasielandschaft zu geleiten, dabei muß er (oder sie) verschiedene Aufgaben lösen, Hindernisse überwältigen und Gefahren überstehen. Diese Art von Spielen ist eines der ältesten Genres von Computerspielen, Text- Adventures gibt es etwa seit Ende der siebziger Jahre. Der Erfolg eines solchen Adventures liegt an einer guten Spielidee und an packend geschrie- benen Texten. Die Grundstruktur eines Adventures ist nicht sehr kompliziert und es werden wenig Systemressourcen gebraucht. Es können also auch Hobby- Programmierer leicht ein Adventure selbst erstellen. TAG will eine Hilfestellung zum Schreiben von eigenen Adventures sein. Der Parser, der die Eingabe des Spielers analysiert, ist sehr flexibel. Er ver- steht auch komplexere Eingaben, wie z.B. 'Nimm fünf Bälle' oder 'Lege alles außer dem frisch gebackenen Vollkornbrot in die Vitrine'. Bei mehrdeutigen oder unvollständigen Eingaben fragt er nach und kann in manchen Situationen auch Annahmen über fehlende Angaben machen. Trotzdem muß der Autor des Ad- ventures nur wenige, leicht verständliche Angaben zu Verben und Objektnamen machen, um dies zu ermöglichen. Auch das Modell der Räume und Objekte behandelt bereits die meisten gängigen Bestandteile von Text-Adventures, wie z.B. Türen, Personen, Behälter, dunkle Räume, Lampen, Schlüssel, Fahrzeuge uvm. Auch hier sind die Angaben, die der Autor machen muß, für die meisten Fälle relativ unkompliziert. Trotzdem kann man mit etwas Mehraufwand kompliziertere Sachvarhalte darstellen. Die Ausgabetexte können sogenannte Textbefehle enthalten, um grammatikalisch korrekte Sätze auf den Bildschirm zu bringen. Da in einem Text-Adventure die Texte die Hauptrolle spielen, ist es unschön, wenn automatisch generierte Sätze wie 'Der Hofnarr und der Barde ist hier' oder 'Du siehst ein roter Ball' auftauchen. Dies kann mit den Textbefehlen von TAG leicht vermieden werden. Natürlich ist TAG in seiner Flexibilität eingeschränkt, man kann nicht alles beliebige mit dem Programm machen. Aber ich denke, es reicht schon, um ein ordentliches Adventure von ansehnlicher Größe und Komplexität zu kreieren. Ich habe versucht, es für den Anfänger verständlich, aber trotzdem für den Profi nicht langweilig zu machen. 1.2. Rechtliches Das Autorensystem TAG für Text-Adventures ist Freeware. Ihr könnt es also umsonst benutzen. Dabei sollte folgendes beachtet werden: 1. Der Text-Adventure-Generator TAG darf nur kostenlos weitergegeben werden. Dabei sollte sichergestellt sein, daß alle dazugehörigen Dateien enthalten sind und daß sie nicht verändert wurden. 2. Die Text-Adventures, die mit TAG erstellt wurden, sind Eigentum ihrer Autoren. Das heißt allerdings auch, daß die Autoren für deren Inhalt ver- antwortlich sind. Von mit TAG generierten Spielen mit extremistischem oder anstößigem Inhalt distanziere ich mich ausdrücklich. In jedem Fall freue ich mich, wenn Ihr mir Eure fertigen Programme zukommen laßt oder mir sagt, wo ich sie finden kann. Diese Version von TAG läuft nur unter MS-DOS und seinen Emulationen unter MS-Windows. Es wurde mit Borlands Turbo Pascal 5.5 erstellt. Für eventuell auftretende Schäden, die durch die Benutzung von TAG entstehen, kann ich keine Verantwortung übernehmen. Dafür bitte ich um Verständnis. Der Text-Adventure-Generator TAG ist geistiges Eigentum seines Autors, Martin Oehm aus Dreis-Tiefenbach. Das war zum Rechtlichen alles. 1.3. Kontakt, Verweise und Danksagungen Wer Verbesserungsvorschläge hat oder mich auf Fehler im Programm aufmerksam machen möchte, darf dies gerne tun. Das gilt auch für Kommentare über dieses Handbuch. Wem einige Sachen unklar sind oder wer Unterstützung benötigt, darf sich auch mit mir in Verbindung setzen. Meine e-Mail Adresse ist martin.oehm@gmx.de. Es kann aber manchmal einige Zeit dauern, bis Ihr Antwort bekommt. Geduld. Wer Lust hat, den Text-Adventure-Generator oder den Interpreter auf andere Systeme zu portieren, damit TAG nicht auf die PC-(MS-)Welt beschränkt bleibt, setzt sich ebenfalls bitte mit mir in Kontakt, um Unterstützung zu bekommen. TAG hat sich langsam aus meinem ersten PC-Adventure "Das Amulett" entwickelt. Während dieser Zeit haben mir natürlich einige Leute geholfen und mich auf Fehler im Programm aufmerksam gemacht oder Verbesserungsvorschläge gemacht. Wenn das Beta-Stadium einmal verlassen wird, werde ich diese Leute auch namentlich erwähnen, doch im Moment ist die Liste noch *sehr* klein. Wer sich weiter mit TAG beschäftigt, wird feststellen, daß das Konzept der Vor- und Nach-Ausführungen in vielen anderen Autorensystemen angewandt wird. Deshalb bin ich Graham Nelson für die sehr gute Dokumentation von "Inform" zum Dank verpflichtet. Sie war eine wichtige Quelle für Ideen während meiner Arbeit an TAG. Einige Beispiele im dritten Teil sind in leicht abgewandelter Form von den Übungen zu Inform übernommen. Aber auch die Dokumentation von Kent Tessmans "Hugo" und von Oliver Berses "Textopia" sowie die Quelltexte zur TADS-Version von "Colossal Cave Revisited" von David M. Baggett waren eine gute Hilfe bei der Programmierung. Wer sich weiter über (deutsche) Text-Adventures informieren will dem seien folgende Adressen im Internet ans Herz gelegt: http://www.geocities.com/TheTropics/7490/tag.html Das ist die Seite von TAG. Hier gibt es eine kurze Einführung und eine Sammlung der bereits mit TAG geschriebenen Spiele. ftp://ftp.gmd.de/if-archive/ Hier befindet sich das IF- oder "Interactive-Fiction"-Achchiv mit unzähligen Freeware-Text-Adventures, von denen die meisten jedoch englisch sind. Auch Autorensysteme für Adventures, Lösungswege, Karten und ausgewählte Diskussionsbeiträge zum Thema IF finden sich hier. (TAG übrigens auch.) http://private.freepage.de/mo/if/ Im MIFTAZZ ist sehr viel über die deutsche Text-Adventure-Szene zusammengetragen. Obwohl die Sammlung der Spiele nahezu komplett ist, ist die deutsche Schwester des IF-Archivs wesentlich kleiner. http://www.stud.fh-hannover.de/~roehling/Index.htm Bernd Roehling hat auf seinen Seiten "IF.de" viele Informationen und Links für Text-Adventure-Autoren zusammengetragen. Es gibt natürlich noch mehr Seiten über Text-Adventures im Internet. Um diese alle aufzuzählen, ist hier der falsche Platz. Aber gerade die letzten zwei oben genannten Seiten bieten viele weitere Verweise, so daß man sicherlich dort fündig wird. 1.4. Über dieses Handbuch Dieses Handbuch ist in drei Teile aufgeteilt. Der erste Teil ist nur ein Überblick über den Text-Adventure Generator. Im zweiten Teil sind alle Elemente des Text-Adventure-Generators erklärt. Dabei werden zunächst die Raum- und Objektdefinitionen behandelt, dann die Definition der Befehle, die der Spieler eingeben kann und anschließend erst die Ausführungsblöcke und die Textoptionen. Die Beschreibung der Ausführungs- blöcke ist wohl der umfangreichste Teil. Dabei läßt es sich allerdings nicht vermeiden, daß schon vor der eingehenden Erklärung Ausführungsblöcke und Textoptionen in Beispielen auftauchen. Ich habe versucht, Befehle, die unklar sind, an Ort und Stelle, d.h. dort, wo das Beispiel steht, kurz zu erklären. Sie werden aber ausführlich in den Kapiteln 4 bis 6 behandelt. Da der zweite Teil durch die vielen Definitionen manchmal sehr trocken sein kann, werden im dritten Teil konkrete Beispiele angegeben, die mehr oder weniger schwierige Situationen in TAG beschreiben. Diese Beispiele gehen näher auf die im zweiten Teil aufgezählten Optionen ein. Man sollte also zunächst den zweiten Teil lesen oder zumindest überfliegen, bevor man sich daran macht, die Beispiele in Teil III. zu verstehen. 2. GRUNDKONZEPT EINES ADVENTURES 2.1. Wie ist ein Adventure aufgebaut? Ein klassisches Text-Adventure besteht aus einer Anzahl von Räumen, die mit- einander verbunden sind, aus einigen Objekten, die in diesen Räumen herum- liegen, aus Personen, die dort umherwandern und natürlich aus verschiedenen Möglichkeiten, die Objekte und Personen zu manipulieren. Dies sind die sog. Rätsel, von denen man eine ganze Menge lösen muß, um an sein Ziel zu gelangen. Das Ziel kann dabei alles Mögliche sein. Eine Schatzsuche in unwirtlichen Gegenden oder eine rechtzeitige Flucht vor einer Supernova. Je nachdem, was zu tun ist und wo das Adventure spielt, werden dann auch die Objekte und Personen aussehen. Wenn Ihr eine Idee habt, worum es in Eurem Adventure gehen soll, werden langsam immer mehr Sachen in Eurem Kopf zusammengetragen. Ein Blatt Papier oder zwei sind dabei sehr hilfreich. Diese Aufzeichnungen sind hinterher ziemlich wichtig, um den Überblick zu behalten, und ich rate Euch, sie in einer Mappe zu sammeln oder sie zumindest zusammenzuheften. Das erste, was bei einem Adventure festgelegt werden muß, sind die Handlung, die Räume, die Objekte und die Rätsel, die gelöst werden müssen. Schnappt Euch also ein Blatt Papier und beginnt, eine Karte zu malen von der Gegend, in der Euer Adventure spielen soll. Am besten ist eine herkömmliche Karte, in der die Orte mit Kästchen dargestellt werden. Diese Karte wird wahrschein- lich nach und nach erweitert oder verändert werden, wenn Euch noch etwas einfällt oder wenn Ihr auf etwas verzichten wollt. Dann müssen die Objekte auf die Räume verteilt werden. Objekte sind Gegen- stände, die aufgehoben werden können, feste Objekte, wie etwa Möbelstücke, Türen oder Bäume, aber auch Personen sind Objekte im Sinne von TAG. Um die Rätsel lösen zu können, ist es wahrscheinlich erforderlich, daß Ihr neben den Befehlen, die TAG schon mitbringt (z.B. gehen, nehmen, weglegen, untersuchen usw.), Eure eigenen Befehle einführt. Dabei sind Eurer Phantasie keine Grenzen gesetzt, und Ihr könnt verschiedene Synonyme verwenden. 2.2. Der Text-Adventure-Generator TAG TAG ist ein 'Generator' für Text-Adventures. Er liest einen vom Benutzer er- stellten Datensatz, die Quelldatei, und analysiert sie. Wenn keine Fehler ge- funden wurden, wird die Spieldatei erstellt. Diese Datei besteht aus drei großen Blöcken. Diese Blöcke sind: - die Datenbank, die alle Informationen über Objekte, Räume, Befehle und Anweisungen enthält. - das Lexikon mit dem Wortschatz, der vom Programm verstanden wird - die Ausgabetexte des Programms. Dieser Block ist i.A. der größte. Eine weitere Datei, das Logbuch, enthält Informationen zum Generationsvorgang und eine Satistik und kann, wenn gewünscht, herausgeschrieben werden. Die Quelldatei wird in einem beliebigen ASCII-Editor erstellt. Der Standard- Name einer solchen Datei ist .adv. Anschließend werden die Spieldateien generiert: > tag Dabei ist der Name der Quelldatei und der zu erstellenden Dateien. (Eine genauere Aufzählung der Optionen, die mit dem Generator verwendet werden können, wird im nächsten Abschnitt gegeben.) Standardmäßig wird für die Spieldatei die Endung .tag benutzt. Um das so generierte Adventure spielen zu können, benötigt man den Inter- preter für Text-Adventures TAM (Text-Adventure-Maschine): > tam Mit diesem Programm wird dann der Adventure-Datensatz interpretiert und die vom Adventure-Autor gewünschten Handlungen auf den Bildschirm gebracht. 2.3. Aufbau der Quelldatei für TAG Alle Daten, die der Generator zum Erstellen der Spieldatei und damit zum Ausführen des Adventures benötigt, müssen in der Quelldatei .adv ein- gegeben werden. Der Aufbau ist so simpel wie möglich gehalten. Die Eingabe- datei ist in verschiedene Blöcke unterteilt, die in beliebiger Reihenfolge angegeben werden können. Es gibt verschiedene Arten von Blöcken: - Block zur Umgebungsdefinition Hier werden allgemeine Parameter, wie Text- und Hintergrundfarbe, Dateisuffixe und -kennungen u.ä. festgelegt. Dieser Block kann aus- gelassen werden, dann werden die Standardeinstellungen benutzt. - Definitionsblöcke In diesen Blöcken werden alle Räume, Objekte, Flaggen, Aktionen und weiteren Spielvariablen definiert. Diese Blöcke beschreiben das ei- gentliche Adventure. - Textblöcke Hier werden die Ausgabetexte im Programm definiert. Es können bis zu 255 Blöcke mit jeweils 255 Texten definiert werden, darunter ein Block für die Standardantworten des Programms. - Ende-Block Dies ist eigentlich kein richtiger Block, sondern die Anweisung Ende, die den Eingabedatensatz beendet. (Wenn diese Anweisung fehlt, ist der Datensatz mit dem Ende der Eingabedatei beendet.) Die Befehle in den jeweiligen Blöcken sind ebenfalls so einfach wie möglich. Die Befehle müssen zeilenweise eingegeben werden, eine Zeile für jede Anwei- sung. TAG unterteilt alle Zeilen in Worte, die mit Leerzeichen und Kommas voneinender getrennt sind. Dabei gibt es verschiedene Arten von 'Worten': - Schlüsselwörter von TAG Dies sind vordefinierte Wörter, die das Programm erkennt. Hierbei wird nicht zwischen Groß- und Kleinschreibung unterschieden. Einige häufig verwendete Konstanten werden durch ein vorangestelltes Prozent- zeichen gekennzeichnet. - Benutzerdefinierte Schlüsselwörter Diese Schlüsselwörter werden vom Benutzer definiert, um Flaggen, Räume, Objekte u.ä. zu beschreiben. Diese Wörter müssen einmalig sein unter den anderen Schlüsselwörtern, benutzerdefiniert oder von TAG. Auch hier wird nicht zwischen Groß- und Kleinschreibung unterschie- den. - Strings Zeichenketten, die von Hochkommas (Apostrophen) eingeschlossen sind, heißen Strings. Bei Strings werden Groß- und Kleinschreibung unter- schieden. Sie können eigentlich alle Zeichen außer dem Hochkomma ent- halten. Im Falle von Texten und Beschreibungen, die während des Spiels ausgegeben werden sollen, können Strings auch über mehrere Zeilen gehen. An Stelle des Zeilenumbruchs wird dann intern ein Leerzeichen eingesetzt. Diese Ausgabestrings können auch kurze Anweisungen in eckigen Klammern enthalten. Strings, die nur zur Definition des Vokabulars dienen, bestehen nur aus einem Wort. Sie können nur Buchstaben und Zahlen enthalten. - Zahlen können in TAG nur ganzzahlig sein. In den meisten Fällen reicht der Bereich von 0 bis 255 aus. Solche Zahlen belegen genau ein Byte und werden in TAG vorrangig verwendet. Für besondere Fälle können Zahlen definiert werden, die Werte bis zwei Milliarden, positiv oder negativ, annehmen können. Diese Zahlen belegen 4 Bytes. - Bedingungen werden in runde Klammern eingeschlossen, die allerdings nicht inein- ander geschachtelt werden können. Diese Klammerausdrücke enthalten wieder mehrere 'Wörter'. - Verneinte Bedingungen sind Bedingungen, die durch einen vorangestellten Schrägstrich ne- giert werden. Alle Zeichen, die in einer Zeile hinter einem Ausrufezeichen oder einem senkrechten Strich (Pipe) stehen, werden als Kommentar betrachtet und vom Programm ignoriert. Dies gilt natürlich nicht für '!' und '|', die sich innerhalb eines Strings befinden. Kommentarblöcke von mehreren Zeilen können zwischen den Begrenzern /* und */ angegeben werden. Kommentare können also wie folgt aussehen: /* Dies ist ein Kommentarblock, der über mehrere Zeilen geht, in diesem Fall über drei. */ /* Ein Einzeiler. */ ! Auch ein Einzeiler Blockkommentare können nicht innerhalb eines Befehls stehen. Man kann verschiedene Befehlzeilen auf eine Zeile schreiben, indem man die Befehle mit Semikola voneinander trennt. So sind z.B. Text 'Hallo, Welt!' Absatz und Text 'Hallo, Welt!'; Absatz gleichwertig. Ob am Ende einer Zeile ein Semikolon steht oder nicht, ist egal. Diese Zeilentrennung funktioniert natürlich nicht innerhalb eines Strings oder eines Klammerausdrucks. Es gibt noch einige sogenannte Systembefehle, die aus einem Lattenzaun und drei Großbuchstaben bestehen. Dies sind: #DOS Schaltet den MS-DOS-Modus ein. Das heißt, die eingelesenen Zeilen werden mit dem MS-DOS-Zeichensatz gelesen, bei dem die Umlaute durch andere Zeichen dargestellt sind. Sollte also Euer Quelltext unter DOS, z.B. mit edit geschrieben worden sein, muß am Dateianfang dieser Befehl stehen, damit die Umlaute und das Es-Zett richtig interpretiert werden. #WIN Dito, nur für den Windows-Zeichensatz. Diese Einstellung ist Standard und der Befehl dient nur zum Aufheben von #DOS. (Obwohl TAG unter DOS läuft, sind die Texte in der Spieldatei mit dem Zeichensatz ISO-8859-1 geschrieben, der auch von Windows benutzt wird.) #DBG Steht dieser Befehl irgendwo im Quelltext, so wird die Debug- Option aktiviert. Der Befehl sollte also angegeben werden, wenn das Spiel mit dem Debugger TAD geprüft werden soll. (Der Befehl funktioniert zwar, aber da der Debugger nicht fertig ist, ist ein im Moment nutzlos.) #DAT Bindet eine externe Datei in den Quelltext ein (Include). Die Syntax ist #DAT '' und ist eine Datei im ASCII-Format, die weitere An- weisungen im TAG-Format enthält. Ist sie komplett gelesen worden, so wird sie geschlossen und es wird in der Quelldatei an der entsprechenden Stelle nach dem #DAT-Befehl weiterge- lesen. Es können beliebig viele Dateien nacheinander einge- bunden werden, aber eine eingebundene Datei darf keinen #DAT- Befehl enthalten. In der Quelldatei darf der #DAT-Befehl überall zwischen abgeschlossenen Anweisungen stehen. Sinn- vollerweise werden aber immer logische Blöcke in eine externe Datei geschrieben. #STD Erlaubt es, die Standardantworten von einer anderen Datei als TAG.STD zu lesen. Die Syntax ist ähnlich wie bei #DAT #STD ''. Der Aufbau von muß natürlich derselbe wie bei TAG.STD sein. Wer möchte, kann die Standardantworten auch im Textblock 'Standard' im Adventure-Datensatz angeben, dann wird keine externe Datei gelesen. #KUM Schaltet die Fehlerkumulation ein. Das heißt, alle Fehler werden in der LOG-Datei und auf dem Bildschirm ausgegeben, aber übergangen. Zum Schluß wird dann überprüft, ob es Fehler gegeben hat, und dann bricht das Programm erst ab. Das ist ganz nützlich, wenn man längere Passagen neu in die Quelldatei eingefügt hat, da man nicht immer alle Fehler nacheinander abarbeiten muß, sondern sofort einen Überblick über alle Fehler bekommt. (Kann aber auch sehr deprimierend sein. Meist sieht es jedoch schlimmer aus, als es ist, da Fehler Folgefehler erzeugen. So kann z.B. ein weggelassenes Apostroph die ganze Syntax durcheinanderbringen.) #PIN Aktiviert den pingeligen Modus. Das bedeutet, daß TAG auch kleine Dinge mit einer Information meldet, etwa, wenn ein Raum keinen Ausgang hat oder ein Objekt keine Beschreibung. Da dies unter Umständen sehr viel - auf den ersten Blick unbrauchbare - Information erzeugt, die die wichtigen Meldun- gen "überschwemmt", ist dieser Modus zu Beginn inaktiv. #ENG Schreibt enge Fehlermeldungen, die nur eine Zeile benötigen. Das ist besonders nützlich, wenn die Fehlerkumulation oder der pingelige Modus eingeschaltet sind, da so mehr Meldungen auf einen Bildschirm passen. (Die standardmäßigen Meldungen belegen drei Zeilen.) #TXT Schreibt alle Texte auf eine zusätzliche Datei mit dem Namen .out. Die Textbefehle werden dann herausgeschnitten, das Absatz- und Zeilenformat ist wie im Datensatz. Die Texte werden mit dem momentan aktiven Zeichensatz in der Reihen- folge ihres Auftretens geschrieben. Dies dient dazu, um den Ausgabetext mit einer Rechtschreibprüfung auf Tippfehler zu untersuchen. Diese Direktiven können auch als Optionen in der Befehlszeile angegeben werden. Die komplette Syntax für das Aufrufen des Generators ist: tag {-Optionen} Quelldatei{.adv} {Spieldatei{.tag}} Mögliche Optionen sind: -k Fehlerkumulation -p Pingelige Ausgabe -l Schreiben einer Log-Datei -d Schreiben einer Debug-Datei -w Benutzt den Windows-Zeichensatz -t Schreibt alle Ausgabetexte auf .out -b Schreibt die Texte auf Festplatte, nicht in den Buffer -e Benutzt einzeilige (enge) Fehlermeldungen -i Ignoriert die Steueranweisungen im Quelltext Die Definition der Optionen mit #XXX überschreibt natürlich die Optionen, die beim Aufrufen gesetzt wurden. Jenachdem, ob man Optionen immer wirksam haben oder nur gelegentlich von ihnen Gebrauch machen möchte, sollte man sie in der Quelldatei oder auf der Kommandozeile angeben. Die Option -i ignoriert nur die Direktiven, die auch auf der Kommandozeile angegeben werden können. #DAT und #STD funktionieren weiterhin. TAG besitzt ein Fehlersystem mit drei Stufen: *** FEHLER *** führen zum sofortigen Abbruch der Adventure-Generierung. Häufig sind es Eingabefehler, fehlende Angaben u.ä, die schnell repariert sind. Ist die Fehlerkumulation eingeschaltet, so werden Fehler nur aufge- listet, aber nicht beachtet. ** WARNUNG ** bedeutet, daß etwas eingegeben wurde, das evtl. Schwierigkeiten machen kann. Zum Beispiel, wenn ein Behälter kein Volumen hat. Das ist wahrscheinlich nicht beabsichtigt, ist aber kein Fehler, da der Behälter immer noch Objekte aufnehmen könnte, die ebenfalls kein Volumen haben. (Sehr abstrakt, gell?) Der Programmierer soll hier nur auf etwas aufmerksam gemacht werden. * INFORMATION * ist nützlich, kann in ihrer Fülle den Benutzer aber oft erschlagen. Deshalb wird sie nur angezeigt, wenn der Pingelig-Modus mit #PIN akti- viert wurde. Dennoch ist es nicht schlecht, sich gegen Ende des Pro- jekts, oder wenn man einen logischen Fehler suchen will, sich einmal die Informationen anzeigen zu lassen. Alle Meldungen erscheinen auf dem Bildschirm mit Angabe der Zeile im Quell- code und ggf. mit dem Namen der eingefügten Datei. Dieselben Meldungen er- scheinen auch in der LOG-Datei, und zwar am Anfang, in der Rubrik LOGBUCH. 2.4. Der Parser Der Parser ist der Teil des Programms, der die Befehle aufteilt und unter- sucht. Zunächst wird der Befehl in einzelne Worte aufgeteilt. Diese Worte werden dann vom Programm untersucht. Der Befehl wird in folgende Elemente aufgeteilt: aBef Angesprochener Befehl aObj Objekt, das im Befehl angesprochen wurde. aObj2 zweites Objekt aObj3 drittes Objekt (in sehr seltenen Fällen verwendet) aRitg Richtungsangabe im Befehl Diese Werte sind das Ergebnis der Analyse des vom Spieler eingegebenen Satzes. Außerdem ermittelt der Parser noch folgende Informationen (die zur Bestimmung des angesprochenen Befehls dienen, aber eventuell von Nutzen sein können): aVerb benutztes Verb aPräp eine evtl. zusammen mit einem Objekt angegebene Präposition aKlammer ist eine Präposition, die bei trennbaren Verben die Vorsilbe angibt (z.B. 'an' in 'mache ... an') Die Objekte im Satz können durch eine Kette von Eigenschafts- und Hauptworten angegeben werden. Eine solche Kette hat folgendes Aussehen: {Art} {1. Adj./Adverb} {2. Adj.} Substantiv {weitere Substantive} Die Angaben in Klammern sind dabei optional. Der Parser versteht also die folgenden Wortketten als Objekte: DAS BOOT KÜHLES GLAS BIER DER FRISCH GEBACKENE LAIB BROT DER KLEINE SILBERNE HAUSTÜRSCHLÜSSEL Die Bedeutung der oben genannten Elemente wird am deutlichsten mit ein paar Satzbeispielen. Die Zeile in Großbuchstaben nach dem Prompt (>) ist die Ein- gabe des Spielers, die nachfolgenden Zeilen sind das Analyseergebnis des Parsers. Werte, die nicht angegeben werden, sind Null bzw. leer. > GEHE NACH NORDEN aBef = gehen, aRitg = N (= Norden) aVerb = 'gehe' > NIMM DIE MÜNZE aBef = nehmen, aObj = Münze aVerb = 'nimm' > NIMM DIE MÜNZE AUS DER TRUHE aBef = herausnehmen, aObj = Münze, aObj2 = Truhe aVerb = 'nimm', aPräp = 'aus' > LEGE MÜNZE HIN aBef = hinlegen, aObj = Münze aVerb = 'lege', aKlammer = 'hin' > LEGE MÜNZE AUF DEN TISCH aBef = darauflegen, aObj = Münze, aObj2 = Tisch aVerb = 'lege', aPräp = 'auf' > ÖFFNE KLEINES SCHLOSS MIT HAARNADEL aBef = öffnen_mit, aObj = Truhe, aObj2 = Haarnadel aVerb = 'öffne' > MACHE TRUHE MIT BRECHEISEN AUF aBef = öffnen_mit, aObj = Truhe, aObj2 = Brecheisen aVerb = 'mache', aKlammer = 'auf' > GIB DEM AFFEN DEN ZUCKER aBef = geben, aObj = Zucker, aObj2 = Affe aVerb = 'gib' Bei den Beispielen gibt es einige Dinge, die auffallen: - Verschiedene Verben können zum selben Befehl führen, wie bei 'öffne' und 'mache auf'. - Andererseits können Eingaben mit demselben Verb verschiedene Befehle bedeuten. Dies kann an einer Verbklammer liegen, wie bei 'lege' und 'lege hin'. Es kann aber auch an den angegebenen Objekten und der ver- wendeten Präposition liegen, wie bei den beiden Sätzen mit 'nimm'. - Je nach Verwendung können Worte wie 'auf', 'an' usw. als Präposition oder als Klammer definiert werden. Präpositionen stehen vor einem Objekt ('auf den Tisch'), Klammern gehören zum Verb ('mache auf'). - 'mit' ist eine vorgegebene Präposition und wird daher nicht als aPräp definiert. Der Grund ist, daß immer nur ein Objekt mit Präposition je Satz definiert werden kann. 'mit' taucht aber häufig auf und mit dieser Sonderbehandlung kann man auch Sätze eingeben wie 'Grabe mit dem Schäufelchen im Dreck.' - 'nach' ist im Beispiel oben ebenfalls keine Präposition im Sinne von aPräp. Es wird als Bestandteil der Richtung interpretiert. - Dennoch können 'nach' und 'mit' als Klammern auftauchen, z.B. in Sätzen mit 'nimm mit' oder 'schaue nach'.) - Sätze mit drei Objekten sind nicht sehr häufig. aObj3 kann aber in Befehlen wie 'Hole die Münze mit der Zange aus dem Schlitz' vorkommen. Wird ein Befehl an jemand anderen gerichtet, so wird das angesprochene Objekt in der Variable 'Akteur' gespeichert. Dies ist in Sätzen wie > SAGE DEM JUNGEN "FOLGE MIR" > PRINZESSIN, "KÜSS DEN FROSCH" > COMPUTER, KURS AUF GANYMED der Fall. Meistens ist Akteur jedoch Null, d.h. der Spieler soll die Anweisung ausführen. Dieses Kapitel ist nur ein Überblick über die Aufgabe des Parsers. Detaillier- tere Angaben befinden sich in den Kapiteln über die Befehls- und Objektdefini- tionen sowie im Kapitel 15. Anmerkung: Die eingegebene Anweisung wird vom Programm als Kleinbuchstaben behandelt. Dabei werden automatisch 'ß' in 'ss' und 'ae', 'oe' und 'ue' in die entsprechenden Umlaute umgewandelt. Die Worte, die ins Lexikon von TAG geschrieben werden sollen, werden auch erst in diese Form gebracht. _____________________________________________________________________________ II. DEFINITIONEN UND ANWEISUNGEN 3. RÄUME UND OBJEKTE Zunächst müssen alle Räume und Objekte sowie deren Attribute und Zustände definiert werden. Das heißt, sie müssen einen Namen bekommen, damit sie im Programm angesprochen werden können. Außerdem erhalten sie bei der Definition bestimmte Eigenschaften. Wo die Definition im Datensatz steht, ist dabei aber egal. (Ausnahme sind hier die Klassen, die im Datensatz vor den Objekten und Räumen stehen müssen, auf die sie ihre Eigenschaften vererben.) 3.1. Räume und ihre Verbindungen In einem Text-Adventure bewegt sich der Spieler in einer Welt, die eine Landschaft aus einzelnen Räumen ist. Diese sind miteinander durch sog. Ausgänge verbunden, die in einer bestimmten Richtung liegen. Der Spieler bewegt sich durch diese Landschaft, indem er die Richtung angeben möchte, in die er gehen will. So versucht z.B. die Anweisung 'Gehe nach Norden', den Spieler in einen Raum zu bewegen, der vom momentanen Aufenthaltsort aus gesehen im Norden liegt. (In einzelnen Fällen funktionieren auch Angaben wie 'Betrete die Hütte' oder 'Gehe über die Brücke', aber die Regel ist die Fortbewegung per Richtungsangabe, vor allem schon deshalb, weil man für die Richtungen griffige Abkürzungen wie 'n', 'rein' usw. angeben kann.) 3.1.1. Richtungen Als Richtungen bezeichnet TAG die möglichen Ausgänge aus einem Raum. Tradi- tionell sind dies die Himmelsrichtungen und die beiden Richtungen oben und unten. Je nach Zusammenhang sind aber auch andere Richtungen denkbar, z.B. 'Backbord' und 'Steuerbord'. TAG erlaubt bis zu 16 Richtungen. Eine Richtung wird wie folgt definiert: Richtung '' '' {*} Kennzeichnung der Richtung in TAG lange Bezeichnung der Richtung für den Parser (z.B. 'norden') kurze Bezeichnung für den Parser (z.B. 'n') Beispiel: Es soll die Richtung Steuerbord definiert werden: Richtung Steuerbord 'steuerbord' 'sb' Die Kurzbezeichnung ist in der Regel eine Abkürzung, und erlaubt daher einen knappen Eingabestil. Eingebürgert haben sich folgende Richtungen: N (Norden) NO (Nordosten) O (Osten) SO (Südosten) S (Süden) SW (Südwesten) W (Westen) NW (Nordwesten) H (nach oben) R (nach unten) REIN (nach drinnen) RAUS (nach draußen) Diese Richtungen sind in der Datei NORMAL.ADV bereits vordefiniert. Wird der Richtungsdefinition ein Sternchen (*) nachgestellt, so wird diese Richtung als 'Standardrichtung' definiert, um die Eingabe bei der Raumdefinition zu vereinfachen: Richtung N 'norden' 'n' * Näheres siehe dort. Generell sind die acht Windrichtungen Standardrichtungen. 3.1.2. Raumattribute Raumattribute sind Eigenschaften, die ein Raum besitzt oder nicht. Bis zu 64 Raumattribute können definiert werden. Sie werden definiert mit: RaumAttr Kennzeichnung des Attributs in TAG Die Zuweisung der Attribute erfolgt bei der Definition der Räume. Drei Raumattribute sind schon vordefiniert. Es sind Dunkel gibt an, ob ein Raum dunkel ist und wird dazu benutzt, um zu prüfen, ob der Spieler etwas sieht. Aus einem dunklen Raum kann man nur in einen hellen Raum gehen, wenn man versucht, woanders hinzugehen, stolpert man. (Tatsächlich prüft das Programm aber, ob sich an den Orten funktionierende Licht- quellen befinden. Dunkel gibt also nur an, ob ein Raum an sich dunkel ist.) Laby bezeichnet Labyrinthe. In einem Labyrinth kommt immer die lange Raumbeschreibung, ungeachtet des KNAPP-Modus, damit der Spieler nicht an der Raumbeschreibung sehen kann, ob er schon einmal hier war oder nicht. Besucht zeigt an, ob der Spieler schon einmal an diesem Ort war. Dieses Attribut wird automatisch vom Programm bestimmt, um lange oder kurze Raumbeschreibungen auszugeben. 3.1.3. Räume Räume sind einfach zu handhaben. Die wichtigsten Eingaben bei der Raumdefini- tion sind die Verbindungen zu den anderen Räumen. Die Raumdefinition wird eingeleitet durch: Raum TAG-Kennzeichnung des Raums Innerhalb der Raumdefinition werden folgende Anweisungen verstanden: Name '' {()} Name des Raums, der bei der Kurzbeschreibung und in der Statusleiste erscheint, etwa 'Beim Teich' oder 'Eßzimmer' Es kann eine Raumklasse in Klammern angegeben werden, von der der Raum Eigenschaften erbt. Std Vordefinition der Ausgänge in den Standardrichtungen. Diese Definition muß immer vor den anderen Richtungsanwei- sungen stehen, da diese die Standardausgänge überschreiben. Mögliche Ausgänge siehe nächster Absatz. Gültiger Richtungsbezeichner wie mit Richtung definiert. Ausgang in diese Richtung. Es gibt drei verschiedene Arten von Ausgängen: Wenn man in diese Richtung geht, kommt man in diesen Raum. In dieser Richtung ist kein Ausgang. Aber anstelle des normalen Textes 'Ich kann nicht in diese Richtung gehen.', erscheint der Text, der bei definiert ist. Näheres dort. Wege sind komplizierte Gebilde. Wenn man in diese Richtung geht, passiert mehr, als in einen anderen Raum zu gelangen oder nicht. Hier müssen explizite Ausführungen eingegeben werden. Näheres bei Weg- Definitionen. Attr {/} {{/}} {{/}}... Attribut wie bei RaumAttr definiert. Es kann eine beliebig lange Liste von definierten Attributen angegeben werden. Die Attribute können durch vorangestellte Schrägstriche auch wieder weggenommen werden. Das ist nützlich, wenn der Raum Attribute von einer Raum-Klasse geerbt hat, der Raum aber diese geerbten Attribute nicht haben soll. Besch '' Lange Raumbeschreibung, die erscheint, wenn man den Raum zum ersten Mal betritt oder wenn man den 'Lage'-Befehl eingibt. Diese Raumbeschreibung muß in Hochkommas gestellt werden und kann über beliebig viele Zeilen gehen. Siehe Texte. Zu jedem Raum können zwei Ausführungsblöcke angegeben werden. Diese Blöcke sind kleine Routinen, die aus Anweisungen im TAG-Format be- stehen. Wie dieses Format genau aussieht und was man mit den Blöcken machen kann, steht in den Kapiteln 5 und 6. Hier nur eine kurze Beschreibung der beiden Blöcke: VorAusf wird aufgerufen, bevor der vom Spieler eingegebene Befehl ausgeführt wird, wenn sich der Spieler in diesem Raum befindet. Hier kann evtl. das Vorhaben des Spielers unterbunden werden. NachAusf kommt nach dem erfolgreichen AUsführen der vom Spieler eingegebenen Anweisung zum Zuge, wenn sich der Spieler in diesem Raum aufhält und beinhaltet meist eine Raktion auf das Geschehene. 3.1.4. Antworten Antworten sind Texte, die ausgegeben werden, wenn der Spieler nicht in diese Richtung gehen kann, aber nicht der Standardsatz erscheinen soll. Sie werden definiert mit: Antwort Kennzeichnung der Antwort in TAG Die einzige Anweisung bei der Antwort-Definition ist Besch, die analog zur Besch-Anweisung bei der Raumbeschreibung funktioniert. Zum besseren Verständnis hier ein kleines Beispiel: Richtung N 'norden' 'n' * Richtung O 'osten' 'o' * Richtung S 'süden' 's' * Richtung W 'westen' 'w' * Richtung rein 'drinnen' 'rein' Richtung raus 'draussen' 'raus' Raum Vor_dem_Haus Name 'Vor dem kleinen Haus' Std In_Garten O Im_Haus Rein Im_Haus N Lichtung Besch 'Du stehst hier westlich eines kleinen weißen Häuschens. Alle Fenster sind mit Brettern zugenagelt, die Haustür jedoch nicht. Durch einen farbenfrohen Garten führt ein Weg nach Norden auf eine Lichtung.' Antwort In_Garten Besch 'Der Pfad führt nach Norden und der Eingang zum Haus ist im Osten.' Raum Im_Haus Name 'In dem kleinen Häuschen' Std Gegen_Wand W Vor_dem_Haus raus Vor_dem_Haus Attr Dunkel Besch 'Hier im Haus ist offensichtlich schon lange niemand mehr gewesen. Alles ist staubig und die Luft ist muffig. Ein schäbiges Sofa steht in einer Ecke des Raumes. Der einzige Ausgang ist die Tür im Westen, durch die ein schmaler Lichtstrahl fällt.' Antwort Gegen_Wand Besch 'Dort ist leider eine Wand.' Raum Lichtung Name 'Auf einer Lichtung' Std Unterholz S Vor_dem_Haus Besch 'Diese Lichtung ist dünn von Bäumen bestanden, die aus dem dichten Gestrüpp ragen. Ein gut ausgetretener Pfad führt nach Süden.' Antwort Unterholz Besch 'In dieser Richtung ist das Unterholz zu dicht.' Diese Passage definiert einen Garten vor einem kleinen Haus, einen Raum im Haus, in dem es dunkel ist und eine Lichtung. In diesem Beispiel hat jeder Raum seine eigene Antwort. Während die Antwort für den Garten maßgeschneidert ist, können die anderen auch für andere Räume in einem Haus oder in einem Wald benutzt werden. ALs Richtungen wurden hier, wie in Adventures allgemein üblich, die Himmelsrichtungen und die Richtungen rein und raus definiert. Wer will, kann diese Passage in eine leere Textdatei kopieren, sie z.B. 'haus.adv' nennen, mit 'tag haus' ein Adventure generieren und es dann mit 'tam haus' ausprobieren. (Das Beispiel ist allerdings etwas langweilig, da drei Räume ohne besondere Merkmale von denen noch dazu einer stockdunkel ist, schnell ihre Faszination verlieren. Das ändert sich aber im Kapitel über Objekte.) 3.1.5. Wege Wege sind Aktionen, die durchgeführt werden, wenn der Spieler in diese Richtung gehen will. Was passiert, und ob der Spieler im selben Raum bleibt oder in einen anderen Raum geht, wird in dieser Aktion beschrieben. Wege definiert man wie folgt: Weg Ausf [...] EndeAusf Name des Wegs in TAG Die Aktion wird zwischen Ausf und EndeAusf definiert. Wie man das macht, ist in Kapitel 5 beschrieben. Insgesamt können bis zu 253 Räume, Antworten und Wege definiert werden. Es gibt bereits zwei vordefinierte Räume: Nirgendwo ist ein Ort, der sich nicht im sichtbaren Bereich des Spiels befindet. Er wird benutzt, um Gegenstände zu lagern, die noch ins Spiel kommen sollen. Nirwana ist ein Ort, der ähnlich wie Nirgendwo ist. Hier sollen Gegenstände abgelegt werden, wenn sie aus dem sichtbaren Teil des Spiels verschwunden sind. Im Prinzip ist es egal, ob sich ein Gegenstand in Nirgendwo oder im Nirwana befindet. Es hilft dem Programmierer aber, etwas Ordnung zu bewahren. Die Anwendung der Trennung zwischen Nirgendwo oder Nirwana ist daher kein Muß, sondern liegt im Ermessen des Programmierers. Aber Vorsicht: Die beiden Räume sind nicht identisch! 3.2. Die Objekte Mit den Räumen haben wir eine Landschaft definiert, in der sich der Spieler bewegen kann. In einem Adventure, das nur Räume enthält, ist der Spieler dazu verdammt, aktionslos umherzustreifen. Es fehlen noch Objekte, die er manipulieren kann. Ein Objekt in TAG kann alles sein: eine Person, ein Gegenstand, den man aufheben kann, ein Gegenstand, der fest ist oder ein Teil der Landschaft. Ein Objekt kann sogar eine Gruppe von Gegenständen oder Personen sein, die man dann jedoch nur als Gruppe handhaben kann. Zur Handhabung der Objekte kann man folgende Dinge definieren: 3.2.1. Objektattribute Analog zu den Raumattributen können auch Objekte Attribute besitzen. Sie werden mit ObjAttr Attribut-Kennzeichnung von TAG definiert. Zugewiesen werden die Attribute in der Objektdefinition. Es gibt einige vordefinierte Attribute in TAG: Person Das 'Objekt' ist eine Person. Personen können nicht mitge- nommen werden und tauchen in Raumbeschreibungen stets extra auf, z.B. "Lord Helmchen ist hier." (Dies ist zugegebener- maßen eine sehr simple Definition von "Person". Da Personen meist etwas mehr Eigenschaften als die beiden oben genannten besitzen ist der Programmcode für eine Person meist sehr lang. Mehr dazu in Kapitel 12.) Licht Das Objekt ist eine Lichtquelle. Ist eine Lichtquelle in einem dunklen Raum, so kann man dort sehen. Manche Objekte müssen erst angeschaltet oder angezündet werden, um zu leuch- ten, z.B. eine Taschenlampe oder eine Fackel. Sind sie ausge- schaltet, so ist es trotzdem dunkel. Logisch. Das Programm vermutet, daß sich das Anschalten bei Lichtquellen auf eine Leuchtfunktion bezieht. (Wer einen floureszierenden Küchen- mixer in sein Spiel einbauen wollte: Pech gehabt.) Kleidung Man kann das Objekt anziehen. Alles wird der Reihe nach angezogen. Ob die Socken angezogen werden, obwohl man schon die Stiefel anhat, wird nicht überprüft. Es wird aber ange- nommen, daß der Spieler seine Grundbekleidung anhat und daß nur spezielle Kleidungsstücke angezogen werden, etwa magische Ringe, Tarnkappen oder Verkleidungen. Sitz Ein Sitz ist ein Objekt, auf dem man sitzen kann, wie ein Stuhl oder ein Sessel. Sitzt man, so kommt man an die restli- chen Objekte im Raum nicht mehr heran, es sei denn, es wird extra programmiert. Liege Wie ein Sitz, nur daß man auf einer Liege nicht sitzt, sondern liegt. Standfläche Man kann sich auf das Objekt stellen. Zum Beispiel eine Trittleiter oder ein Podest. Häufig kann ein Objekt Sitz, Liege und Standfläche gemeinsam sein. InObj Dies ist ein Hilfsattribut, um das richtige Pronomen für Sitze und Liegen zu benutzen. Hat ein Objekt dieses Attribut so sitzt und liegt man 'in' ihm, ansonsten 'auf' ihm. Deutsche Sprache, schwere Sprache: Wir sitzen AUF dem Stuhl, aber IM Sessel; Wir liegen IM Bett, aber AUF dem Sofa. Behälter sind Objekte, in die man etwas hineinlegen kann. Damit man die Objekte im Innern sehen kann, muss ein Behälter offen sein (d.h. eigentlich weder geschlossen noch abgeschlossen) oder transparent. Ablage Eine Ablage ist ein Objekt, auf das man etwas legen kann. Ein Objekt kann Ablage und Behälter zugleich sein. Transparent sind Objekte, die Behälter sind, deren Inhalt man aber sehen kann, obwohl sie geschlossen sind. Man kann den Inhalt jedoch nur sehen, nichts mit ihm anstellen. Dazu müßte man den Behälter öffnen. Personen können auch transparent sein, nämlich dann, wenn sie zeigen, was sie bei sich tragen. Im Normalfall weiß der Spieler nicht, was eine andere Person bei sich hat. Tür Das Objekt ist eine Tür. Tür bedeutet: Das Objekt verbindet oder trennt zwei Räume und wechselt den Ort, wenn man durch die Tür geht. Eine Tür muß also nicht unbedingt eine Tür im eigentlichen Sinne sein, sondern kann auch eine Brücke oder ein Durchgang sein. Man kann problemlos durch eine Tür von einem Raum zum anderen gehen, wenn sie nicht abgeschlossen ist. Eine Tür benötigt zwei Ortsangaben - für jede Seite eine. Schlüssel sind Objekte, mit denen man verschließbare Objekte auf- und abschließen kann. Verschließbar sind Objekte, die man mit einem Schlüssel auf und ab- schließen kann. Fahrzeug Ein Fahrzeug ist ein Objekt, das sich mit dem Spieler fort- bewegt, wenn er sich auf oder in ihm befindet. Deshalb muß ein Fahrzeug immer zusätzlich auch eine Standfläche, ein Sitz oder eine Liege sein. Boote und Reittiere sind auch Fahrzeuge im Sinne von TAG. Grundsätzlich kann man mit einem Fahrzeug überallhin gelangen. Daß man mit dem Auto nicht durch die Haustür fahren kann und auf dem Esel keine Leiter hochreiten kann, muß extra programmiert werden. Fluid Das Objekt ist flüssig und kann nicht in die Hand genommen werden, sondern nur in Behältern getragen werden. Entf Dieses Attribut bezieht sich auf alle Objekte, die zu weit entfernt sind. Das klingt vielleicht blöd, aber stellt Euch das folgende vor: Ihr steht auf einem Aussichtsturm und ihr seht eine Stadt im Süden und das Meer im Norden. Ihr könnt es natürlich anschauen, aber sobald Ihr etwas konkretes machen wollt, kommt die Antwort "Das Meer ist zu weit weg!". Fest Das Objekt kann nicht aufgehoben werden. Feste Objekte sind z.B. Möbel, Bäume, Felsen, Haken in der Wand und Knöpfe auf Schaltpulten. Diese Objekte werden nicht in der Liste der sichtbaren Objekte in der Raumbeschreibung erwähnt ('Ich sehe hier...'). daher sollten diese Objekte in der Raumbe- schreibung erwähnt werden. Immobil Das Objekt ist 'immobil'. Immobile Objekte sind wie feste Objekte, nur daß sie in der Liste der sichtbaren Objekte auftauchen. Das kann z.B. auch bedeuten, daß ein Namens- schild an einem Schulranzen befestigt ist und nicht gelöst werden kann, aber bei U RANZEN erscheint nach der Beschrei- bung: 'An dem Ranzen ist ein Namensschild befestigt'. Diese Art von Objekten ist eher ungewöhnlich und es ist üblicher, dieser Sachen in der Raum- oder Objektbeschreibung mizuer- wähnen. Bewegt zeigt an, ob der Spieler schon etwas mit dem Objekt ange- stellt hat. Dieses Attribut wird vom Programm aktualisiert. In einigen neu definierten Befehlen kann es vom Programmierer aktualisiert werden. Bekannt bedeutet, daß der Spieler das Objekt schon einmal gesehen hat. Dieses Attribut wird auch vom Programm aktualisiert. Natürlich besitzten alle Objekte, die 'bewegt' worden sind, dieses Attribut. Immer bewirkt, daß der Erst-Text, der in der Raumbeschreibung für Objekte verwendet wird, wenn sie noch nicht bewegt wurden, immer verwendet wird, also auch nachdem sie bewegt worden sind. ansprechbar ist ein Objekt, das keine Person ist, dem der Spieler aber Anweisungen geben kann wie einer Person. Man kann sich hier Computer mit Sprachkontrolle oder eine Sprechanlage vorstellen. 5.2.2. Zustände Objekte können einen speziellen Zustand haben. Standardmäßig sind in TAG die folgenden Zustände definiert: Normal normal, kein besonderer Zustand Kaputt beschädigt Offen geöffnet Geschlossen geschlossen Abgeschlossen mit einem Schlüssel o.ä. abgeschlossen Ein ein- bzw. Aus ausgeschaltet Zusätzlich dazu können noch weitere Zustände definiert werden mit Zust {''} Kennzeichnung des Zustands in TAG Kurzbeschreibung des Zustands, meist ein Adjektiv. Wird angegeben, so erscheint beim Untersuchen eines Gegenstands nach der Objektbeschreibung der Satz 'Er ist .' Zum Beispiel: Zust voll 'randvoll' Anmerkung: Ein Objekt kann immer nur einen Zustand haben. Ein Kühlschrank kann also nicht 'offen' und 'ein' zugleich sein. In einem solchen Fall emp- fiehlt es sich, das Objekt aufzuteilen in Kühlaggregat und Kühlschrank. 3.2.3. Objekte Nun kommen die Objekte dran. Sie sind schon etwas schwieriger zu handhaben als die Räume, da sie einige Merkmale mehr haben. Sie werden definiert mit Obj Kennzeichnung des Objekts in TAG Bei der Objektdefinition werden folgende Anweisungen verstanden: Name '' {} Name des Objekts, wie er im Spiel auftaucht. Der Name wird ohne Artikel angegeben. Enthält der Name Adjektive, so muß an Stelle der Endung ein Dach ('^') angegeben werden. Das ist zwar umständlich, dient aber dazu, daß die Ausgabe in korrektem Deutsch erfolgen kann, da sich die Endung mit dem Fall ändert. Richtige Namen wären also: 'Schwert' 'rot^ Knopf' 'frisch gestrichen^ Bank' Ein weiteres Sonderzeichen, das in Objektnamen angegeben werden kann, ist die Tilde ('~'). Sie gibt an, wenn nach Substantiven im Dativ ein 'n' angehängt werden soll. Das ist in der Regel bei Substantiven im Plural der Fall, die nicht mit 'n' oder 's' aufhören. So gäbe es dann: 'unzählig^ Vögel~ am Himmel' 'Leute~' 'rostig^ Nägel~' 'frisch^ Brötchen' (aber: 'alt^ Semmel~') 'parkend^ Autos' Die Tilde kann auch für männliche Substantive benutzt werden, an die im Akkusativ und Dativ 'n' bzw. 'en' angehängt wird. Das ist bei Worten, die auf 't' oder 'e' enden häufig der Fall, wie z.B.: 'klein^ Junge~' 'Student~ der Chemie' 'des Zaren Bote~' 'alt^ Schwede~' 'Sextant~' Wieso müssen diese Dinge noch angegeben werden, wenn es doch genaue Regeln für diese Unregelmäßigkeiten gibt? Ganz einfach: TAG weiß nicht, welche Worte Adjektive und welche Substantive sind. Außerdem kann man Worte im Namen angeben, die nur Attribute sind und nicht gebeugt werden müssen, wie z.B. 'am Himmel', 'des Zaren' und 'der Chemie' im Beispiel oben. Grammatikalisches Geschlecht des Objekts, das mit einem Buchstaben gekennzeichnet wird: m männlich (maskulin) | f weiblich (feminin) | Einzahl n sächlich (neutrum) | p Mehrzahl (Plural) Spezialausdruck für das Namensformat 0 normale Ausgabe 1 (%eigenname) Das Objekt wird immer ohne Artikel ausgegeben wie z.B. bei Namen oder im obigen Beispiel des Zaren-Boten. 2 Das Objekt hat keinen unbestimmten Artikel 3 (%einige, %etwas) Anstelle des unbestimmten Artikels wird je nach Anzahl 'einige' bzw. 'etwas' benutzt: 'etwas Milch', 'einige Kieselsteine' 4 (%immerBest) Das Objekt hat immer einen bestimmten Artikel. Dies dient dazu, um nach langen Strapazen lapidare Texte wie folgenden zu vermeiden: "Ich sehe hier EINEN Smaragd der Weisheit' 5 (%mein, %dein) Das unbestimmte Objekt wird mit einem besitz- anzeigenden Fürwort ausgegeben: 'meine Trink- flasche', 'dein Teddy'. Welche Person dabei verwendet wird, bestimmt die Flagge #Person. Plural '' {} Hier kann ein Plural angegeben werden. Der Plural wird verwen- det, wenn das Objekt in Wirklichkeit eine Anzahl von Objekten ist und Anz (s.u.) größer als eins ist. Bei Objektklassen be- wirkt der Plural, daß Objekte derselben Klasse in Listen zusammengefaßt werden. Dazu aber mehr in Kapitel 11. Grammatikalisches Geschlecht des Plurals Spezialausdruck im Format wie oben, mit der Ausnahme, daß Null hier bedeutet, daß dem Plural die Anzahl mit einem Zahlwort vorangestellt wird ('sieben Streichhölzer'). lName '' {} Der Listenname, der verwendet wird, wenn das Objekt in einer Liste, z.B. im Inventar oder in der Liste der beweglichen Gegenstände, mit anderen gruppiert wird. Dieser Name ist i.A. kürzer als der eigentliche Name. Wie das genau funktioniert steht in Kapitel 11.2. Plural und lName dürfen nicht beide für ein Objekt definiert sein. Grammatikalisches Geschlecht des Listennamens Spezialausdruck im Format wie beim Namen. Adj '' {'' ...} Liste von Adjektiven, die der Parser im Zusammenhang mit diesem Objekt versteht. "Leere" Adjektive ('') werden nicht akzeptiert. Vor '' {'' ...} Liste von Wörtern, die der Parser als ersten Teil eines zu- sammengesetzten Hauptworts versteht. Einige nähere Erläute- rungen folgen dazu gleich. Subst '' {'' ... } Substantive, die der Parser im Zusammenhang mit diesem Objekt versteht. Genus des vorangehenden Substantivs, gekennzeichnet durch m männlich (maskulin) | f weiblich (feminin) | Einzahl n sächlich (neutrum) | p Mehrzahl (Plural) Es kann eine beliebig lange Liste von Substantiven angegeben werden. Dabei müssen Substantive und der dazu passende Genus immer paarweise stehen. Einige Hinweise zum Vokabular: Der Parser versteht bis zu zwei Adjektive hintereinander, die gebeugt angegeben werden müssen: > NIMM DAS LANGE SCHWERT. > NIMM LANGES SCHARFES SCHWERT. Bei zwei Adjektiven kann das erste auch ein Adverb, d.h. ungebeugt, sein: > SCHRECKLICH HÄSSLICHES ENTLEIN. > DIE FRISCH GESTRICHENE BANK. Die mit Vor definierten ersten Teile des Hauptwortes können in Kombination mit jedem definierten Substantiv stehen. Das Substantiv kann aber immer auch alleine stehen. Beispiele Vor 'haus' 'eingangs' Subst 'tür' f 'eingang' m versteht TÜR, HAUSTÜR, EINGANGSTÜR, EINGANG und HAUSEINGANG, nicht aber HAUS. Dafür wird aber auch EINGANGSEINGANG ver- standen, was nicht ganz korrekt ist. Um mehr Eingabevielfalt zu haben, wird also in Kauf genommen, daß der Spieler "un- sinnige" Wörter eingeben kann. Die Vor-Angabe kann auch mit einem Bindestrich an das Haput- wort angefügt werden: HAUS-TÜR. Es muß mindestens ein Substantiv angegeben werden, Adjektive und Teile von zusammengesetzten Hauptwörtern brauchen nicht angegeben zu werden. Allerdings muß es möglich sein, ein Objekt eindeutig ansprechen zu können. Dies gilt besonders für alle beweglichen Objekte und Objekte im selben Raum. Es gibt Fälle, wo man ein "leeres Substantiv", d.h. zwei direkt aufeianderfolgende Hochkommas mit einem nachfolgenden Genus, angeben kann. Dann muß aber mindestens ein Adjektiv angegeben werden. Dieser Fall ist für substantivierte Adjek- tive gedacht, die sehr häufig im Zusammenhang mit Personen vorkommen, z.B. 'der Alte (Mann)' oder 'die Blinden'. Vielleicht findet man im Verlauf des Spiels mehrere unter- schiedliche Schlüssel. Dann muß der Parser einduetig wissen, welcher Schlüssel in einem Befehl gemeint ist. Also müssen die Schlüssel verschiedenes Vokabular bekommen: 'kleiner Schlüssel', 'Haustürschlüssel', 'Hydrantenschlüssel' usw. Kein einziger darf nur 'Schlüssel' als Substantiv verstehen! Bei festen Objekten, die in verschiedenen Räumen sind, können auch gleiche Namen vorkommen. So kann es sein, daß im Labor ein roter Knopf ist und ein weiterer im Keller hinter dem Weinregal. (Diese Regel gilt nicht für Objekte, die man nicht unter- scheiden kann, wie z.B. eine Anzahl Münzen. Der Parser wählt aus den möglichen Objekten dann irgendeins aus. Es spielt ja sicherlich keine Rolle, welche Münze der Spieler aufhebt.) Manche Bezeichnungen bestehen auch aus zwei oder mehreren Worten, wie 'Glas Wein', 'Blatt Papier' oder 'Herr Dr. Karl Weißenstein'. Deshalb prüft TAG auch nach dem erfolgreichen Finden eines Substantiv die nachfolgenden, ob sie mit den gefundenen Objekten übereinstimmen. Dies kann auch benutzt werden, um Objekte zu unterscheiden. Gibt es zum Beispiel ein Glas Milch und ein Glas Saft, so ist 'Glas' zweideutig, 'Glas Milch' aber eindeutig. Ist das einem Substantiv folgende Wort ein Substantiv, paßt aber nicht zum ersten Wort, so wird die Eingabe als zwei verschiedene Objekte betrachtet: > NIMM GLAS FLEISCH wird also interpretiert als 'Nimm das Glas und das Fleisch.' Hierbei sollte beachtet werden, daß nur Akkusativ-Objekte ohne Präposition mehrfach auftreten können. (Anmerkung: Der Parser prüft zunächst, ob die eingegebenen Adjektive und das zusammengesetzte Substantiv zusammenpassen. Unter Umständen trifft die Parser-Eingabe auf mehrere Objekte zu. Dann wird bei den meisten Verben geprüft, welche dieser Objekte sich im selben Raum wie der Spieler befinden. Der eingegebene Befehl wird nur dann weiterverarbeitet, wenn ein Objekt eindeutig angesprochen wird. Ansonsten kommt die Meldung 'Ich sehe hier kein ' bzw. 'Welches ? oder ?'.) Ort {} Ort des Objekts zu Anfang des Spiels. kann folgende Sachen bedeuten: Das Objekt befindet sich in diesem Raum Das Objekt befindet sich je nach Verhältniswort IN, AUF, BEI, AN, HINTER oder UNTER einem anderen Objekt. BeiMir Ich trage das Objekt bei mir. Angezogen Ich habe das Objekt angezogen. wird nur bei Türen angegeben, um zu sagen, wo die Tür hin- führt. In diesem Fall können und nur Räume sein. (Das Programm prüft, ob die Tür im Raum ist und vertauscht dann ggf. die Räume. So ist es egal, von welcher Seite man die Tür zuerst sieht.) Wird nicht angegeben, so kann man die Tür nur von einer Seite sehen und öffnen. Die Variable .Ort2 dient zum Ansprechen des Zielorts im Programm, es ist eine Raumvariable. Zust Ein definierter Zustand. Wird diese Zeile weggelassen, so ist der Zustand normal, was wohl für die meisten Objekte zutrifft. Ein Objekt kann immer nur einen Zustand haben! Attr {/} {{/}} {{/}}... Attribut wie mit ObjAttr definiert. Die Liste von definierten Attributen kann beliebig lang sein, und es können beliebig viele Attr-Zeilen angegeben werden. Die Attribute können mit einem Schrägstrich versehen werden. So kann dem Objekt das Attribut wieder weggenommen werden, wenn es ihm durch eine Klassendefinition vererbt wurde. Gew Gew gibt im allgemeinen das Gewicht des Objekts in einer frei wählbaren Einheit an. Leider ist diese Einheit nicht ganz so frei wählbar, denn das maximal tragbare Gewicht MaxGew darf 255 nicht überschreiten. Objekte, deren Gewicht größer ist als MaxGew, sind zu schwer für den Spieler. Ein Objekt kann auch ein Gewicht von 0 haben. Damit können Sätze wie 'Ich kann nicht mehr tragen.' vermieden werden, wenn man ein Blatt Papier oder eine Feder aufheben will. Feste Objekte benötigen keine Gewichtsangabe. Es kommt nicht darauf an, das Gewicht auf ein Gramm genau anzugeben. Die Gewichtsangabe ist nur eine grobe Schätzung des Gewichts, damit das Inventar des Spielers nicht nur auf eine Anzahl von Objekten beschränkt ist. Man kann die Gewichtsabhängigkeit auch ganz weglassen, indem man zu keinem Objekt ein Gewicht definiert. Vol gibt den Rauminhalt eines Objektes in einer beliebigen Maßeinheit an. Das größtmögliche Volumen ist 255. ist nur von Bedeutung bei Objekten, die man aufheben kann. wird benutzt um zu verhindern, daß größere Objekte in oder auf kleinere gelegt werden. Es ist natürlich nur eine An- näherung, da die Form des Objekts nicht berücksichtigt werden kann. Bei Behältern gibt Vol das größtmöglich nutzbare Volumen an. Genau wie das Gewicht kann man auch das Volumen außer acht lassen. Öffnet gibt ein verschließbares Objekt an, das mit dem aktuellen Objekt aufgechlossen werden kann. Das aktuelle Objekt muß natürlich das Attribut Schlüssel besitzen. Das Objekt, das mit dem momentanen Objekt geöffnet werden kann, kann im Programm mit .Öffnet angesprochen werden. Anz gibt die Anzahl der gleichen Unterobjekte an, aus denen ein Objekt besteht. Wenn das Objekt etwa eine Ansammlung von sieben Münzen ist, so ist Anz 7. Wenn Anz benutzt wird, sollte auch ein Plural angegeben werden, damit das Objekt korrekt aus- gegeben werden kann. Die Variable zum Ändern der Anzahl heißt .Anz. Besch '' Beschreibung des Objekts, die erscheint, wenn man das Objekt untersucht. Die Objektbeschreibung muß in Hochkommas gestellt werden und kann über beliebig viele Zeilen gehen. Siehe Texte. Wird Besch weggelassen, so erscheint die Standard-Antwort 'Ich finde an nichts Besonderes.' (Es sei denn, das Objekt besitzt einen Text zum Lesen, beinhaltet Objekte oder hat einen Zustand, der beschrieben werden kann. Näheres dazu in Kapitel 11.1.) Text '' Gibt einen Text an, der erscheint, wenn man das Objekt liest. Im allgemeinen ist dieser Text von der Beschreibung verschie- den. Wenn kein Text angegeben wird, erscheint beim Lesen des Objekts der Standardsatz: 'Auf steht nichts.' Erst '' ist ein Text, der anstelle der Liste der Objekte in der Raumbeschreibung ausgegeben wird, wenn das Objekt noch nicht benutzt worden ist, d.h. wenn es das Attribut 'bewegt' noch nicht besitzt. Danach wird das Objekt immer in die Liste der beweglichen Gegenstände in der Raumbeschreibung mit auf- genommen. Bei Personen, die nicht aufgehoben werden können, ist diese Beschreibung immer aktiv. Dabei '' Darin '' Darauf '' Daran '' sind hier Texte, die die Liste der Dinge enthalten, die bei einer Person sind, sich in oder auf dem Objekt befinden oder die an dem Objekt befestigt sind. Dieser Text sollte die Textanweisung [Liste] enthalten (s. Kap. 7). Wird dieser Text nicht angegeben, so werden die Standardantworten be- nutzt, etwa 'Auf dem Tisch siehst du einen Jonagold-Apfel.' InBesch '' ist ein Text, der angegeben wird, wenn das Objekt begehbar (d.h. ein Behälter und ein Sitz, eine Liege oder eine Stand- fläche) ist und sich der Spieler darin befindet. Mehr dazu in Kap 10.3. Var {} ist eine Variable für Objekte. Je Objekt können bis zu acht Variablen definiert werden. Die Variable wird kann dann später mit der Syntax . angesprochen werden. ist der Wert der Variablen, der im Bereich von 0 bis 255 liegen muß. Anmerkungen zu Variablen für Objekte: Insgesamt können 32 Variablen für Objekte definiert werden, wobei verschiedene Objekte dieselben Variablen haben können. Dieselbe Variable kann natürlich für verschiedene Objekte verschiedene Werte annehmen. Besitzt ein Objekt eine Variable nicht, so ist ihr Wert Null. Ob eine Variable für ein Objekt definiert ist oder nicht, kann man mit der Bedingung ( hat ) prüfen. Es empfiehlt sich, die Variablen, die bei mehreren Objekten definiert sind, direkt bei den Objekten zu definieren und Variablen, die nur auf ein oder zwei Objekte zutreffen, als globale Flaggen zu deklarieren. Zum Beispiel ist von den folgenden Möglichkeiten Obj Bär Var gezähmt 0 ... Flagge Bär_gezähmt 0 die zweite glücklicher, es sei denn, das Spiel findet in einem Zoo statt und es gibt eine ganze Menagerie zu zähmen. Eine typische Anwendung für eine Objektvariable wären z.B. Waffen- und Rüstungsattribute, wie sie in Rollenspielen wie 'Das Schwarze Auge' vorkommen. Hier macht es sogar Sinn, Ob- jektklassen wie 'Waffe', 'Schild' usw. zu definieren und die Variablendefinitionen auf die Objekte weiterzuvererben. (Mehr dazu in Kapitel 3.3) Außerdem können noch einige Ausführungsblöcke angegeben werden. Die Syntax von Ausführungsblöcken wird in Kap. 5 beschrieben. Diese Blöcke müssen mit EndeAusf abgeschlossen werden. Es können folgene Ausführungen angegeben werden: VorAusf wird aufgerufen, wenn das Objekt in der Spielereingabe angesprochen wurde. Hier kann definiert werden, was passiert, bevor die eigentliche Befehlsausführung durchgeführt wird. Wenn diese Ausführung negativ ab- geschlossen wird, etwa durch eine Bed- oder Stop- Anweisung oder durch setzen der Flagge NullAkt, so wird die Befehlsausführung nicht weitergeführt. NachAusf wird nach der Befehlsausführung aufgerufen, wenn das Objekt in der Spielereingabe angesprochen wurde, um eventuelle Folgen des Befehls zu beschreiben. VorReakt ist die Reaktion eines Objekts vor einer Aktion des Spielers, auch wenn das Objekt nicht im Befehl ange- sprochen wurde. Um reagieren zu können, muß das Objekt im selben Raum wie der Spieler sein. NachReakt ist die Reaktion, nachdem der Spieler die Aktion er- folgreich beendet hat. BefAusf wird aufgerufen, wenn der Spieler dem Objekt einen Befehl erteilt hat, wie z.B. BERND, "GEHE NACH NORDEN" oder COMPUTER, "ANALYSIERE GESTEIN". Im allgemeinen besitzen nur Personen diese Ausführung, aber sie kann für alle Objekte angegeben werden. Wie man genau mit diesen Aktionen arbeitet und wie man sie geschickt einsetzt, wird in den Kapiteln 5 und 6 beschrieben. Dazu einige Eingabebesipiele: Obj Taschenlampe Name 'Taschenlampe' f Vor 'taschen' Subst 'lampe' f 'funzel' f 'leuchte' f Ort BeiMir Zust Aus Attr Licht Vol 1 Besch 'Die Taschenlampe war sehr billig, aber sie hat dir bis jetzt immer gute Dienste geleistet.' Obj Rucksack Name 'alt^ Wanderrucksack' m Adj 'alt' Vor 'wander' Subst 'rucksack' m Ort BeiMir Attr Behälter Kleidung Vol 20 Zust offen Besch 'Mit diesem alten Wanderrucksack hat mein Großvater schon so manche Tour durch das Sauerland gemacht.' Darin '[Liste 0] [ist 0] im Rucksack.' Obj Haustür Name 'Haustür' f Vor 'haus' 'wohnungs' 'holz' Subst 'tür' f 'eingang' m Ort Vor_dem_Haus Im_Haus Attr Tür Fest verschließbar Zust abgeschlossen Obj Messingschlüssel Name 'Messingschlüssel' m Vor 'messing' Subst 'schlüssel' m Ort Lichtung Öffnet Haustür Attr Schlüssel Besch 'Der Messingschlüssel hat einen simplen Bart, aber einen schön verzierten Griff.' Erst 'Neben dem Pfad glänzt ein Schlüssel im Gras, den hier wohl jemand verloren hat.' Obj Sofa Name 'rot^ Sofa' n Adj 'abgewetzt' 'einstmals' 'rot' 'schäbig' Subst 'sofa' n 'couch' f Attr Fest Liege Sitz Ablage Vol 40 Ort Im_Haus Besch 'Obwohl die (einstmals rote) Couch schon etwas abgewetzt aussieht, könntest du es dir dort bequem machen, um dich von deinen Strapazen auszuruhen.' Darauf 'Irgendjemand hat [liste 1] auf der Couch abgelegt.' Hier werden folgende Gegenstände definiert: - Eine Taschenlampe, die der Spieler bei sich hat und die man ein- und ausschalten kann. Wenn sie eingeschaltet ist, leuchtet sie. - Einen Rucksack, der bis zu 20 Volumeneinheiten aufnehmen kann und den man aufziehen kann. Wenn er offen ist, und sich mindestens ein Objekt in ihm befindet, erscheint 'XXX ist/sind im Rucksack'. - Eine Haustür, die verschlossen ist und die vom Garten ins Haus führt. - Einen Messingschlüssel, der die Haustür aufschließt. Am Anfang liegt er am Wegesrand in der Lichtung, das wird in der 'Erst'-Beschreibung gesagt. - Ein Sofa im Haus, auf das man Gegenstände ablegen kann und auf das sich der Spieler setzen und legen kann. 3.2.4. Dekorationen Eine besondere Art von Objekten sind die Dekorationen. Sie können sich wäh- rend des Spiels nicht verändern und sind immer fest. Sie dienen nur dazu, Sachen, die in Raumbeschreibungen erwähnt werden, mit Leben zu füllen. Sie werden mit Deko definiert: Deko Kennzeichnung der Deko in TAG Bei der Definition der Dekorationen werden folgende Anweisungen verstanden: Name '' Adj '' {'' ...} Vor '' {'' ...} Subst '' {'' ...} Attr Ort { ... } Ort {/} Besch '' Die Syntax ist dabei wie bei den entsprechenden Anweisungen für Objekte. Dekorationen können in bis zu fünf Orten sein. Alternativ kann als Ort ein Raum-Attribut angegeben werden, dann befindet sich die Deko automatisch an einem Ort, wenn dieser das passende Attribut besitzt. Wird das Attribut mit einem Schrägstrich versehen, so befindet sich die Deko in allen Räumen, die dieses Attribut nicht besitzen. (So kann mit 'Ort besucht' eine Dekoration definiert werden, die immer präsent ist, z.B die Luft oder die Nase des Spielers. Dasselbe erreicht man aber mit 'Ort BeiMir' eleganter und im Fall der Nase auch logischer.) Außerdem können Dekos auch Ausführungsblöcke besitzen. Prinzipiell können einer Dekoration alle Attribute gegeben werden, aber das einzige, das hier Sinn macht, ist wahrscheinlich 'entfernt'. Als Objekt-Attribut kann hier von den vordefinierten Attributen nur entfernt angegeben werden. Ein Beispiel: Deko Bäume Name 'Bäume' p Vor 'laub' 'eichen' Subst 'bäume' p 'baum' m 'eichen' p 'eiche' f 'wald' m Subst 'stämme' p 'birke' f 'birken' p Ort Lichtung Vor_dem_Haus Besch 'Der Wald ist hier sehr dicht und besteht zum größten Teil aus Eichen. Ein paar Birken gibt es aber auch.' Deko Gartenflora Name 'Blumen im Garten' p Adj 'exotisch' 'immergrün' 'farbenprächtig' 'bunt' Subst 'garten' m 'blumen' p 'büsche' p 'hyazinthen' p Ort Vor_dem_Haus Besch 'Der farbenprächtige Garten ist voll von exotischen Blumen, die in allen Farben blühen. Zwischen ein paar immergrünen Büschen blühen Hyazinthen.' Zusammen mit den Raumdefinitionen im Abschnitt davor geben diese Objekte und Dekos schon ein kleines Adventure, das nicht ganz so langweilig ist wie die drei Raumdefinitionen alleine. Das wichtigste an Dekorationen ist wahrscheinlich die Beschreibung. Außerdem haben Dekorationen ein großes Vokabular, um mit einem Objekt möglichst viele Sachen aus der Raumbeschreibung 'totschlagen' zu können. Insgesamt können nur 251 Objekte und Dekos definiert werden. Es gibt vier (Hilfs-)Objekte, die schon vordefiniert sind: Ich ist ein Hilfsobjekt, das den Spieler meint. Es kann auch für Anweisungen benutzt werden, die der Spieler an andere richtet, wie in 'Sam, "Mix mir einen Wodka."'. Du meint i.a. auch den Spieler und wird für reflexive Verben benutzt. Wenn andere Personen angesprochen werden, dann wird Du in diese Person umgewandelt. Zahl ist ein Hilfsobjekt, das benutzt wird, wenn der Spieler eine Zahl eingegeben hat. Zitat bedeutet, daß der Spieler anstelle eines Objektes eine wörtliche Rede angegeben hat, die in Anführungszeichen be- grenzt ist. Diese Objekte können aber keine Eigenschaften besitzen, sie werden nur für den Parser verwendet, um zu checken, daß eine Eingabe vorliegt, die keins der definierten Objekte meint. 3.3. Klassen von Objekten und Räumen Um die Handhabung von Räumen und Objekten einfacher und effektiver zu machen, bietet TAG die Möglichkeit, Klassen von Räumen und Objekten zu definieren, von denen Räume und Objekte Eigenschaften erben können. Dieses Konzept wird häufig als Objektorientierung bezeichnet. Die Objekt- orientierung von TAG ist sehr einfach, sie arbeitet nicht mit Konstruktoren und Destruktoren, sondern sucht nur die jeweils passende Eigenschaft für ein Objekt oder einen Raum. 3.3.1. Objektklassen Eine Objektklasse ist wie ein Objekt und wird auch wie eines definiert. Das so definierte Objekt taucht aber nie wirklich im Spiel auf, sondern ist nur die Vorlage für tatsächliche Objekte. Man sagt, Objektklassen vererben ihre Eigenschaften auf Objekte. Es gibt dabei zwei Arten der Vererbung: Ersetzende Vererbung Das bedeutet, daß die jeweilige Eigenschaft zunächst bei einer Objektdefinition vererbt wird. Wird dieselbe Eigenschaft für das Objekt neu definiert, so wird die vererbte Eigenschaft überschrieben, der Raum besitzt nur die neue Eigenschaft. Dies ist der Regelfall. Erweiternde Vererbung Hier werden die Eigenschaften der Objektklasse nicht überschrieben, sondern erweitert. Das heißt die Definitionen aus der Objektklasse existieren zusätzlich zu den neu definierten, wobei die neuen Ei- genschaften jedoch den Vorrang besitzen. Bei Objekten sind alle Ausführungblöcke und das Vokabular erweiternd vererblich. Auch Objektklassen können ihre Eigenschaften wieder von einer anderen Klasse erben. Es kann immer nur von einer Klasse geerbt werden, die bereits definiert worden ist. Auf diese Weise wird auch vermieden, daß sich Klassen gegenseitig auf sich selbst beziehen. Die genaue Syntax zur Definition einer Objektklasse ist: ObjKlasse {()} Bezeichnung der Objektklasse in TAG Hier kann in Klammern eine Objektklasse angegeben werden, von der die Klasse ihre Eigenschaften erbt. Nachfolgend können dieselben Definitionen gemacht werden wie bei der Objekt- definition. Zum Beispiel: ObjKlasse Münze Name 'Münze' f Subst 'münze' f Var Wert 10 Besch '[Der selbst] [ist] ein örtliches Zahlungsmittel in Wert von [num selbst.Wert] Kronen.' VorAusf (kaufen_mit) Bed (aObj hat Preis) 'Das kann ich nicht käuflich erwerben.' Bed /(aObj gekauft) 'Du hast [den aObj] bereits gekauft.' Bed (aObj.Preis = selbst.Wert) '[Der selbst] [ist] [num selbst.Wert] Kronen wert, [der aObj] koste[t] aber [num aObj.Preis] Kronen.' ObjNach selbst Nirwana ObjNach aObj BeiMir Text 'Topp! Du kaufst [den aObj] mit [dem selbst].' EndeAusf Alle Objekte, die von dieser Klasse erben, besitzen die Variable Wert. Diese Variable hat zunächst den Wert 10, kann aber in der jeweiligen Objektdefini- tion geändert werden. Alle Objekte der Klasse Münze verstehen das Vokabular 'münze' und befolgen die VorAusf zum kaufen von anderen Objekten. (Wie diese VorAusf genau funktioniert, steht in Kapitel 6.) Wird bei der Objektdefinition keine Beschreibung angegeben, so erscheint die Beschreibung der Klasse statt- dessen. Eine mögliche Münzen-Definition wäre: Obj Silberling (Münze) Name 'Silberling' m Adj 'silbern' Vor 'silber' Subst 'silberling' m 'münze' f Var Wert 5 Die Beschreibung und die Anweisungen zum Kaufen können hier entfallen, da sie von der Klasse vererbt werden. Das schafft Ordnung im Quelltext, da er durch die knappen Münzen-Definitionen übersichtlicher wird. Bei der Klassendefinition ist darauf zu achten, daß das selbstbezügliche Ob- jekt 'selbst' benutzt wird, da 'Münze' nicht als Objekt verstanden wird - Es ist ja eine Objektklasse. Beim Ausführen der VorAusf oder beim Ausgeben der Beschreibung setzt TAM dann das passende Objekt für selbst ein. 3.3.2. Raumklassen Raumklassen sind Vorlagen für Räume, genau wie Objektklassen Vorlagen für Objekte sind. Auch hier gibt es wieder zwei Arten der Vererbung, wobei aber nur die beiden Ausführungsblöcke erweiternd vererblich sind. Auch Raumklassen können wiederum von einer anderen Klasse erben. Dabei muß aber darauf geachtet werden, daß eine Raumklasse bereits definiert sein muß, damit sie ihre Eigenschaften auf andere Klassen oder auf Räume vererben kann. Raumklassen werden genauso definiert wie ein Raum, nur daß das Kennwort RaumKlasse anstatt von Raum benutzt wird: RaumKlasse {()} Dazu wieder ein Beispiel: RaumKlasse Wald Name 'In einem Wald' Std Unterholz VorAusf (riechen) Text 'Du saugst den reichen, erdigen Geruch tief in deine Lungen ein.' EndeAusf NachAusf (global) Zufall Aux 1 10 Jenach Aux (1) Text '[#]Ein schauriges Heulen ertönt im Gebüsch.' (2) Text '[#]Du hörst etwas rascheln.' (3) Text '[#]Im Laubdach über dir hörst du eigenartige Geräusche.' Ende EndeAusf In jedem Raum der Klasse Wald riecht der Spieler nun den erdigen Geruch und hört in 30% der Züge eigenartige Geräusche. Diese Regeln können selbstver- ständlich durch eigene erweitert oder ersetzt werden. Wird für einen Raum der Klasse Wald kein Name angegeben, so heißt er 'In einem Wald' und die Standardrichtungen werden auch vererbt. Da diese Klasse keine Beschreibung besitzt, muß sie in der Raumdefinition mit angegeben werden. Bei der Definition von Raumklassen muß man sich auf den Raum mit 'daselbst' beziehen, das das Pendant zu 'selbst' bei Objekten ist. Bei Räumen kommt es aber nicht so häufig vor wie bei Objekten und ist meistens gleichwertig mit 'aRaum'. 4. BEFEHLE, AKTIONEN UND VARIABLEN 4.1. Befehle Die Befehle sind Verben, die zu einer Aktion zusammengafaßt werden, und die schließlich irgendetwas bewirken. Sie werden folgendermaßen definiert: Bef {*} Kennzeichnung des Befehls in TAG. Mit dem nachgestellten Sternchen wird der Befehl als Steuerbefehl (oder Meta- Befehl) definiert. Steuerbefehle dienen nur zur Kommunikation mit dem Pro- gramm, der Spielverlauf bleibt davon unberührt. Typische Steuerkommandos sind z.B. SPEICHERN, LADEN oder ENDE. Zu den Befehlen können folgende Anweisungen angegeben werden: Name '' Der Name des Befehls in Infinitivform. Er taucht dann auf, wenn dem Parser Informationen fehlen und er z.B. fragt: 'Was soll ich ?'. Steuerbefehle wie #laden, #ende usw. benötigen keine Namen. Verb '' {'' ...} Liste von Verben, die der Parser dem Befehl zuordnen soll. Verben können einzelne Worte sein wie 'gib' oder 'werfe'. Sie können aber auch - und das kommt im Deutschen häufig vor - aus einem Verb und einer Verbklammer bestehen, wie z.B. 'gib ab' oder 'werfe weg'. Diese beiden Worte müssen dann im String durch Leerzeichen abgetrennt werden. Mehr als zwei Worte sind in einem String nicht erlaubt, außer, wenn das zweite Wort 'dich' oder 'dir' ist. Dann wird ein reflexives Verb definiert, z.B. 'schau dich um' oder 'nimm dir einen Keks'. Der Parser von TAG arbeitet mit der Befehlsform in der 2. Person Singular, also der Du-Form. Die meisten der Verben werden also mit 'e' aufhören. In diesen Fällen versteht der Parser auch die Befehlsform für die 2. Person Plural (ihr) und die 3. Person (Sie). Außerdem versteht der Parser auch die umgangssprachliche, aber oft gebrauchte Form ohne das 'e' am Ende. Das heißt, daß für das Verb 'springe' auch folgende Eingaben verstanden werden: > SPRINGT > SPRINGEN SIE > SPRING Es lohnt sich also immer, bei unregelmäßigen Verben die re- gelmäßige Form auch zu definieren, z.B. 'stiehl', 'stehle'. (Die Ihr- und Sie-Form sind eigentlich nur für die direkte Rede nützlich, damit es keinen Stilbruch gibt, wie in HERR DR. SCHWARZ, FOLGE MIR) Syntax {{} dasObj/demObj {( )} ... {nachRitg} Diese Zeile definiert die Syntax des Befehls, d.h. die Objekte, die der Befehl erfordert und einige zusätzliche Informationen. dasObj definiert ein Objekt, das im Befehl als Akkusativobjekt auf- tritt. Dem Objekt kann eine Präposition vorangehen. demObj definiert ein Objekt, das im Befehl als Dativobjekt vorkommt. Ihm kann eine Präposition oder 'mit' vorangehen. ist eine Angabe, mit der eine Bedingung für den Ort verknüpft wird. In der Syntax-Definition können folgende Orte angegeben werden: Hier Das Objekt muß sich im selben Raum wie der Spieler befinden und darf weder weit entfernt noch in einen transparenten Behälter einge- schlossen sein. Mit anderen Worten: Man muß das Objekt nicht nur sehen, sondern auch an- fassen können. Diese Ortsangabe ist voreinge- stellt, wenn keine Angabe gemacht wird. BeiMir Das Objekt muß sich im Besitz des Spielers befinden. Ist das Objekt in Reichweite, so wird versucht, es zu nehmen. Dabei werden alle Sachen berücksichtigt, die beim normalen 'nehmen'-Befehl auch beachtet werden, auch die neu definierten. Ist also kein Platz mehr beim Spieler oder ist z.B. ein Objekt zu glitschig um aufgehoben werden zu klappt es nicht und der Befehl wird abgebrochen. NichtBeiMir Das Objekt darf sich nicht im Besitz des Spielers befinden. Ähnlich wie bei BeiMir wird versucht, es hinzulegen. inSicht Das Objekt muß sich im selben Raum wie der Spieler befinden, kann aber zu weit entfernt oder in einem transparenten Behälter einge- schlossen sein. Man muß es also nur sehen können. Allg Das Objekt kann ein beliebiges Objekt aus dem Spiel sein. Ist das Objekt nicht eindeu- tig angesprochen, so wählt der Parser das erste Objekt, auf das die Eingabe paßt, aus. Mit dieser Möglichkeit kann man z.B. Personen über Objekte fragen, die sich woanders befin- den. Mobil Das Objekt kann aufgehoben werden und befindet sich nicht beim Spieler. Dies wird bei 'nehmen' benutz. Ob ein Objekt aufgehoben werden kann, hängt nur davon ab, ob es nicht zu schwer ist und ob es keine Person, keine Flüssigkeit und keine Deko ist. Benutzerdefinierte Einschrän- kungen werden hier nicht berücksichtigt, erst später bei der Befehlsausführung. Inhalt Das Objekt muß in einem anderen enthalten sein. Diese Angabe gibt es nur für aObj, sie bezieht sich dann auf aObj2. Das Objekt muß in, auf, unter, hinter, an oder bei aObj2 sein, um berücksichtigt werden zu können. Ist diese Ortsbedingung des Objekts nicht erfüllt, so wird der Befehl vorzeitig mit der passenden Meldung abgebrochen, z.B. 'Ich habe ... nicht bei mir.' ist ein Attribut, das das angesprochene Objekt besitzen soll. Wird dieses Objekt nicht im Befehl angegeben, so versucht der Parser, anhand des Attributs ein passendes zu finden. Ist kein passendes Objekt am Ort oder gibt es gar mehrere, so fragt der Parser nach, ansonsten wird das gefundene Objekt benutzt. Diese Angabe ist keine Bedingung an das Objekt! Es können auch Objekte angesprochen werden, die das Attribut nicht besitzen! Zusätzlich können in der Klammer noch folgende Angaben gemacht werden: Multi bedeutet, daß anstelle eines einzelnen Objekts auch eine Liste von Objekten angegeben werden kann. Alles ist wie Multi, erlaubt aber auch die Eingabe "alles" im Befehl. Worauf sich alles bezieht, wird durch den Ort und das Attribut bestimmt. Alles sollte mit Vorsicht eingesetzt werden, da Eingaben wie SCHAUE ALLES AN sehr viel Text produzieren, ohne den Spieler wirklich weiter- zubringen. evtl bedeutet, daß dieses Objekt nicht unbedingt im Befehl auftauchen muß. Vorsicht: Ob dieses Objekt auftaucht muß im Befehl oder im Ausfüh- rungsblock eines Objekts gegebenenfalls über- prüft werden. Es ist meistens besser zwei ver- schienene Befehle zu definieren, von denen einer das Objekt berücksichtigt, der andere nicht. Diese beiden Optionen funktionieren nur bei reinen Akkusativ- Objekten, also bei dasObj ohne vorangehende Präposition. ist eine Präposition, die mit dem nachfolgenden Objekt benutzt wird. Sie kann zur Verdeutlichung in Hochkommas gesetzt werden, muß aber nicht. Wird ein Wort nicht als Schlüsselwort erkannt und steht nicht in Klammern, so wird es als neue Präposition definiert. Vorsicht bei Tippfehlern also! Weiterhin darf nur eine Präposition je Befehl definiert werden, es sei denn die zweite Präposition ist 'mit', da dieses Wort einen Sondersta- tus besitzt. nachRitg erlaubt die Angabe einer Richtung im Befehl. Präp '' {'' ...} Präposition, die alternativ zu der mit Syntax definierten Präposition benutzt werden kann. Ausf Dies ist der Block, der die Ausführung des Befehls beschreibt. Dieser Block wird ausführlich in Kapitel 6.6. beschrieben. Er wird mit EndeAusf abgeschlossen und muß auf jeden Fall in der Befehlsdefinition enthalten sein. Und wieder ein Beispiel: Bef putzen Name 'putzen' Verb 'putze' 'wasche' 'reinige' 'säubere' 'mache sauber' Syntax dasObj mit demObj (BeiMir evtl) Ausf [...] EndeAusf Es ist schön, wenn Ihr zu jedem Befehl möglichst viele Umschreibungen mit Verben zulaßt. Es gibt nämlich nichts Schlimmeres, als an einem bestimmten Verb zu suchen, wenn man ein Adventure spielt. Außer BINDE sollte der Parser z.B. auch KNOTE und BEFESTIGE verstehen. Außerdem solltet Ihr die Befehle so allgemein wie möglich halten. BEFESTIGE könnte außer festbinden noch andere Aktivitäten bedeuten, vielleicht einen Magneten anheften oder einen Zettel mit einer Nadel an eine Pinnwand stecken. In TAG sind bereits einige Befehle vorgegeben, die die wesentlichen Aktionen durchführen. Dies sind: gehen nehmen herausnehmen herunternehmen hinlegen hineinlegen darauflegen untersuchen lesen lage inventar öffnen schliessen aufschliessen abschliessen anmachen ausmachen anziehen ausziehen sitzen_auf liegen_auf stehen_auf steigen_auf betreten steigen_von aufstehen sagen sagen_zu hineinschauen daraufschauen schauen warten Dies sind nur die allereinfachsten Verben, die am häufigsten verwendet werden. Einige gehen auch in andere über, z.B. steigen_auf wird je nach angesprochenem Objekt zu sitzen_auf, liegen_auf oder stehen_auf. Eine Erläuterung der bereits vorgegebenen Verben findet sich im Anhang C. Außerdem sind die wichtigsten Steuerfunktionen bereits realisiert: #ende #neu #laden #speichern #knapp #ausführlich #meldungen #punkte #manuskript #rückgängig #fussnote Inklusive dieser Befehle können nur 255 Befehle definiert werden. Die von TAG vorgegebenen Befehle können noch erweitert werden. Dazu wird der Befehl angegeben wie ein neuer Befehl: Bef Kennzeichnung des Befehls in TAG. Zu den TAG-Befehlen können folgende Anweisungen angegeben werden: Verb '' {'' ...} Die Liste von Verben, die der Parser dem vorhandenen TAG- Befehl zuordnen soll, kann hier erweitert werden. VorAusf In diesem Block wird eine Aktion definiert, die vor der Aktion des Verbs in TAG durchgeführt wird. Wird diese voraus- gehenden Aktion vorzeitig beendet, so wird die eigentliche Aktion des Verbs nicht ausgeführt. NachAusf ist eine Aktion, die nach der eigentlichen Aktion des Verbs durchgeführt wird, wenn diese nicht vorzeitig beendet wurde. Mit VorAusf unf NachAusf können die bestehenden Befehle also nach Bedarf ergänzt werden. Zu Befehlen, die zwei Objekte benötigen, kann man einen Pseudo-Befehl definieren, der in den Vor- und Nach-Ausführungen der Objekte (Kap. 6.5) benutzt wird: Pseudo Name des Pseudo-Befehls Befehl, auf den sich der Pseudo-Befehl bezieht. Die genaue Bedeutung dieses Pseudo-Befehls wird später bei den Ausführungs- blöcken der Objekte beschrieben. 4.2. Flaggen und Variablen Auch in TAG gibt es natürlich eine Menge von Variablen, um sich im Spielver- lauf Dinge zu merken. Da es in TAG verschiedene Datentypen gibt, gibt es auch verschiedene Arten von Variablen, die im folgenden vorgestellt werden sollen. 4.2.1. Flaggen und Integer-Variablen Flaggen werden benutzt, um sich bestimmte Sachverhalte zu merken. Generell gibt es zwei Arten von Flaggen in TAG: Flaggen, die nur zwischen den zwei Zuständen 'wahr' und 'falsch' unterscheiden und Flaggen, die einen Zahlenwert von 0 bis 255 repräsentieren, um kompliziertere Sachverhalte darzustellen. TAG unterscheidet nicht zwischen diesen beiden Typen. Die Flagge hat einen Zahlenwert und sie ist falsch, wenn ihr Wert 0 ist und wahr, wenn ihr Wert von Null verschieden ist. Wie die Flaggen verwendet werden, liegt auch hier im Ermessen des Programmierers. Definiert werden Flaggen mit: Flagge {} ist die Bezeichnung der Flagge in TAG ist der Wert der Flagge zu Anfang des Spiels. Wenn Wert nicht angegeben wird, so ist der Wert der Flagge zu Beginn des Spiels Null oder Falsch. Manchmal benötigt man negative Zahlen oder Zahlen, die größer sind, als 255. Für diesen Fall gibt es die Integer-Zahlen. Sie entsprechen dem langen Ganz- zahlenformat und können Werte von ca. minus 2 Mrd. bis plus 2 Mrd. annehmen. Sie werden analog zu den Flaggen definiert mit: Integer {} ist die Bezeichnung der Integer-Variable in TAG ist der Wert der Variable zu Anfang des Spiels. Wenn Wert nicht angegeben wird, so ist der Wert der Flagge zu Beginn des Spiels Null. Es können 255 Flaggen und 32 Integer-Zahlen in TAG definiert werden. Es gibt einige Flaggen, die schon von TAG vorgegeben sind: MaxInv beschreibt die maximale Anzahl von Gegenständen, die der Spieler bei sich tragen kann, ohne sie fallenzulassen. MaxGew Dies ist das Gewicht, das der Spieler mit sich tragen kann. MaxVol Wie InvGew, nur auf das Volumen bezogen. Inv Inv ist die Anzahl der Objekte, die der Spieler bei sich hat. Diese Anzahl darf MaxInv nicht überschreiten, sonst fällt ein Gegenstand herunter. Inv bezieht Gegenstände, die in anderen enthalten sind, nicht ein. Mit einer Tasche oder kann der Spieler also das Problem des Fallenlassens von Objekten umgehen. InvGew ist das Gewicht, das der Spieler bei sich tragen könnte. InvVol ist analog dazu das Volumen, das der Spieler bei sich tragen könnte, also MaxVol abzüglich des getragenen Volumens. PktZahl ist die Gesamtpunktzahl, die aus den einzelnen Punktzahlen ermittelt wird und die nicht überschrieben werden kann. PktBasis ist der Grundwert der Punktwertung, mehr dazu in 8.2 Züge ist die Anzahl der bisher gespielten Züge Minuten, Stunden geben die Minuten und Stunden der Zeit im Spiel an, wenn das Spiel eine interne Zeitrechnung besitzt anstatt die Züge mit- zuzählen. Dies ist sehr beliebt bei Kriminal-Adventures. Ein Zug dauert eine Minute der Spielzeit. Andere Zeitänderungen müssen extra programmiert werden. Nummer ist die im Befehl eingegebene Zahl, wenn aObj den Wert 'Zahl' hat ('TIPPE 3 AUF TASTATUR') Nummer2 ist die im Befehl eingegebene Zahl, wenn aObj2 den Wert 'Zahl' hat ('DREHE RÄDCHEN AUF 12') Still ist eine Systemflagge, die veranlaßt, daß keine Bildschirm- ausgabe erfolgt, wenn Still wahr ist. Dies ist praktisch, wenn man Aktionen aufrufen will, um Objekte zu manipulieren, dieses aber dem Spieler nicht gesagt werden soll. NullText ist wahr, wenn der letzte mit Text ausgegebene Text ein leerer Text war. Dies kann nützlich sein, wenn Text zusammen mit Flaggen benutzt wird. NullAkt ist wahr, wenn eine Aktion nicht ausgeführt wurde, weil eine Bed-oder Stop-Anweisung sie vorzeitig abgebrochen haben. Ist dies der Fall, so werden alle nachfolgenden Anweisungen ignoriert NullBef ist wie NullAkt, nur für die vordefinierten TAG-Befehle. Fehler ist die Nummer des aufgetretenen Parser-Fehlers. Ist Fehler Null, so ist der eingegebene Satz OK. Ansonsten steht an der Position Fehler bei den Standardantworten die passende Fehler- meldung. zFehler ist die Nummer des aufgetretenen Parser-Fehlers beim Unter- suchen einer Anweisung an eine Person im Spiel. Nummer, Nummer2, Züge, PktZahl und PktBasis sind Integer-Zahlen, alle anderen Systemflaggen liegen im Bereich von 0 bis 255. 4.2.2. Konstanten Manche Zahlen ändern sich nicht während eines Spiels. Dennoch werden sie häufig benutzt und so ist es sinnvoll sie als Konstanten zu definieren. Das geschieht wie folgt: Konst Bezeichnung der Konstante in TAG Wert der Konstante. Dieser Wert muß angegeben werden, da es keine Möglichkeit gibt, der Konstante währen des Spiels einen Wert zuzuweisen. Konstanten können nur Werte von 0 bis 255 annehmen. Folgende Konstanten sind automatisch von TAG belegt: minObj, maxObj erstes und letztes definiertes Objekt minDeko, maxDeko erste und letzte Deko minRaum, maxRaum erster und letzter Raum minRitg, maxRitg erste und letzte Richtung Diese Konstanten sind sinnvoll für Schleifen über alle Objekte oder über alle Räume. Die Objekte und Räume sind natürlich intern durchlaufend numeriert und zwar in der Reihenfolge ihres Auftretens im ADV-Datensatz. Mit einer Schleife von minObj bis maxObj durchläuft man also alle Objekte. Diese Konstanten sind jeweils vom Typ Objekt, Raum und Richtung. 4.2.3. Felder Für flexibles Programmieren steht dem fortgeschrittenen Text-Adventure-Autor die Möglichkeit zur Verfügung, Felder zu definieren. Insgesamt können folgen- dermaßen 32 Felder definiert werden: Feld ( {} {}) Bezeichner des Feldes in TAG Dimension des Feldes. Es können bis zu drei Dimensionen eines Feldes angegeben werden. (Nicht angegebene Dimen- sionen sind automatisch eins.) Das Produkt der Dimensionen darf nicht größer sein als 256, da in jedem Feld maximal 256 Speicherplätze zur Verfügung stehen. Auch die Werte selbst können nur im Bereich von 0 bis 255 liegen. Der Anfangswert aller Elemente im Feld ist natürlich Null, ein Feld kann nur in einem Anweisungsblock belegt werden. Ein Wert in einem Feld wird angesprochen mit: Feld. oder Feld. Dabei können tatsächlich nur definierte Flaggen oder Zahlen angegeben werden. Zum Arbeiten sollte also eine Hilfsflagge definiert werden, so daß verschach- telte Poistionen auf einem Feld leichter angesprochen werden können. Die Feldbelegungen fangen immer bei 0 an. Das Feld Wald (9) hätte also die Einträge Wald.0, Wald.1, Wald.2, ... Wald.8 Die Einträge Wald.9 und darüber existieren nicht. (Sie können angesprochen werden, aber ihr Wert ist immer Null. Auf keinen Fall können sie mit Werten belegt werden.) Mehrdimensionale Felder haben Feldeinträge von 0 bis Dim1*Dim2*Dim3 - 1. Die Indizes der einzelnen Dimensionen gehen wieder von 0 bis Dim - 1. Das Feld wird intern als eindimensional behandelt und man kann die eindimensionale Position der Position (x, y, z) berechnen aus: Pos = (x*Dim1 + y)*Dim2 + z Da das Arbeiten mit Feldern in TAG nicht besonders leicht ist, gibt es ein paar Anweisungen, die dem Autor das Leben etwas erleichtern. Sie sind in Kap. 5.1.6. beschrieben. 4.2.4. Raumvariablen Um bestimmte Räume abspeichern zu können, bietet TAG die Möglichkeit, Raum- variablen zu definieren. Ähnlich, wie eine Variable einen Zahlenwert hat, so hat eine Raumvariable einen Raum als Wert. Definiert wird eine Raumvariable folgendermaßen: RaumVar {} Bezeichner der Variablen in TAG Hier kann ein Raum angegeben werden, auf den sich die Variable zu Beginn des Spiels bezieht. Wird keiner angegeben, so ist die Variable Null, sie bezieht sich also auf keinen Raum. Es gibt bereits zwei Variablen, die vordefiniert sind: aRaum ist der aktuelle Raum, in dem sich der Spieler befindet. Er wird vom Programm aktualisiert und ist immer einer der im Quelltext definierten Räume. daselbst ist eine selbstbezügliche Raumvariable, die bedeutet: der Raum, der gerade in Betracht gezogen wird. Diese Variable wird häufig bei der Vererbung von Raum-Eigenschaften ver- wendet und wird dort näher beschrieben. Insgesamt können bis zu 63 Raumvariablen definiert werden. 4.2.5. Objektvariablen Für Objekte gib es natürlich auch die Möglichkeit, Variablen zu definieren. Hier können den Variablen nur ein bestehenden Objekt oder der Zahlenwert Null zugewiesen werden. Die Definition einer Objektvariable ist: ObjVar {} Bezeichner der Variablen in TAG Hier kann der Anfangswert der Variable angegeben werden, der natürlich ein definierts Objekt sein muß. Es gibt neun vordefinierte Objektvariablen: aObj, aObj2, aObj3 sind die Objekte, die in der Eingabe des Spielers angesprochen wurden. Näheres dazu im Kapitel über den Parser und im Ab- schnitt über die Befehlsdefinition. Akteur ist derjenige, der einen Befehl ausführen soll. Ist Akteur Null, so ist der Spieler der Akteur, was fast immer der Fall ist. selbst ist die selbstbezügliche Objektvariable, die bedeutet: das Objekt, das gerade bearbeitet wird (welches auch immer). Diese Variable wird häufig bei der Klassen-Definition verwendet. aSitz ist das Objekt, auf dem der Spieler sitzt, steht oder liegt. Ist aSitz = 0, so steht der Spieler mit beiden Füßen im Raum. (Die Variable bSitz gibt an, ob der Spieler auf aSitz steht, liegt oder sitzt.) iObj ist eine allgemeine Objektvariable, die häufig in den TAG- Routinen verwendet wird und die auch häufig in den Standard- Antworten auftaucht. Innenraum ist das Objekt, in dem sich der Spieler befindet und das ein Behälter und ein Sitz, eine Liege oder eine Standfläche ist. Wenn in einem Raum z.B. ein Käfig steht, in den der Spieler geht, so ist Innenraum = Käfig. esObj ist ein Objekt, auf das sich der Sieler mit den Pronomen be- ziehen kann. Es wird vom Programm bestimmt, aber manchmal möchte man es auch verändern. Es können - diese Variablen mitgezählt - 63 Objektvariablen definiert werden. 4.2.6. Weitere Variablen TAG bietet auch die Möglichkeit, Zustände, Richtungen oder Befehle auf Variablen zu legen. Diese Variablen werden weitaus weniger benötigt, sind aber trotzdem hin und wieder sinnvoll. Richtungsvariablen definiert man wie folgt: RitgVar {} Bezeichner der Variablen Eventuell Vorbelegung mit einer Richtung Eine vordefinierte Richtungsvariable in TAG ist: aRitg die Richtung, die im Befehl des Spielers verwendet wurde. Zustandsvariablen werden folgendermaßen definiert: ZustVar {} Bezeichner der Variablen Eventuell Vorbelegung mit einem Zustand Es gibt hier keine vordefinierten Variablen Und die Definition von Befehlsvariablen: BefVar {} Bezeichner der Variablen Vorbelegung mit einem Befehl Vordefiniert ist hier: aBef der Befehl, der als Ergebnis der Textanalyse der Eingabe des Spielers bestimmt wurde. (Siehe Kapitel 2) Es können jeweils 63 Richtungs-, Zustands- und Befehlsvariablen definiert werden. 4.2.7. Strings Strings sind Textvariablen. Intern wird in TAG jeder Text als eine Position auf den Texblöcken dargestellt, und zwar in der Form . Deshalb kann man auch Texte entweder explizit zwischen zwei Apostrophen oder implizit als Block- und Textkennung angeben. Ein String wird folgendermaßen definiert: String {''} Bezeichner in TAG Text in einfachen Anführungszeichen. Wird kein Text angegeben, so ist der String leer (bzw. Block und Nr sind beide Null). Strings sind sehr praktisch zum variablen Definieren von Texten, die normaler- weise statisch sind. In TAG gibt es nicht die Möglichkeit, Objekt- und Raum- beschreibungen oder -Namen als Routinen anzugeben. Deshalb kann man Strings in diese Texte einbetten, um sie variabel zu machen. Ein String ist bereits vordefiniert: Statuszeile kann in der Statuszeile benutzt werden, wenn es in der Umgebung so definiert ist. (Siehe Kap. 8: einer der Parameter von Status muß den Wert 7 haben.) Es können 63 Strings definiert werden. 4.3. Aktionen Aktionen sind Folgen von Anweisungen zum Manipulieren von Objekten, Räumen und dem Spieler. Sie können definiert werden, um häufig wiederkehrende Passagen abzukürzen. Sie können von anderen Aktionen aufgerufen werden. Aktionen werden wie folgt definiert: Aktion {*} Ausf [...] EndeAusf Name der Aktion in TAG Das Sternchen kann angegeben werden, wenn die Aktion in jedem Zug aufgerufen werden soll. Das kann für zeitabhängige Ereignisse sehr nützlich sein. Wenn eine Aktion für jeden Zug, also mit einem Sternchen, definiert wurde, braucht die Aktion keinen Namen zu besitzen. (Der Name dient natürlich zum Aufrufen der Aktion, und da Aktionen, die in jedem Zug aufgerufen werden, in der Regel sowieso nur dort aufgerufen werden und dies vom Programm automatisch bewerk- stelligt wird, kann der Name hier entfallen.) Die Aktion wird zwischen Ausf und EndeAusf definiert. Wie man das macht, ist im nächsten Kapitel beschrieben. Eine genaue Übersicht über den Einsatz von Aktionen und über den Ablauf eines Spielzuges im nächsten Kapitel. 5. PROGRAMMIEREN DER AUSFÜHRUNGSBLÖCKE 5.1. Arten von Aktionen Aktionen sind Folgen von Anweisungen, die Objekte, Räume oder den Spieler verändern. Aktionen können definiert werden als - Bestandteile von Befehlen, - Ergänzungen von bereits in TAG vorhandenen Befehlen, - Ausführungsblöcke von Räumen und Objekten, - Wege und - frei definierte Aktionen Dia Aktionen werden sequentiell abgearbeitet. Dabei steht in jeder Zeile eine Anweisung. Nachfolgend werden die Standardprozeduren erläutert. Für die Variablen in den Beschreibungen gilt: Objekt Dies kann ein benutzerdefiniertes Objekt oder eine Objekt- variable sein. gültiger Raumname. Ortsbezeichnung Dies kann ein Raumname, ein Verhältniswort mit einem nachfol- genden Objekt oder eines der Schlüssselworte 'hier', 'BeiMir' oder 'angezogen' sein. Attribut Je nachdem, worauf sich das Attribut bezieht, kann es ein Objekt- oder ein Raumattribut sein. Zustandsbezeichner Beliebige Flagge Dies kann eine benutzerdefinierte Flagge, eine Systemflagge wie Inv oder NullAkt, oder eine der Objektvariablen Gew, Vol und Spez sein, die dem Objekt mit einem Punkt versehen an- gehängtwerden: aObj.Gew, Lampe.Zust usw. Textblock-ID (Zahl von 0 bis 255) ist ein Text, der in einfache Anführungszeichen eingeschlos- sen ist, und der über mehrere Zeilen gehen kann. Die Regeln, die ein solcher Text erfüllen muß, sind in Kapitel 7 erklärt. Alle anderen Bezeichner sind ganze Zahlen. 5.2. Grundprozeduren und -funktionen Zur Erleichterung des Programmierens sind schon einige Grundprozeduren vor- handen, die hier kurz erklärt werden: 5.2.1. Textprozeduren Das wichtigste Element in einem Text-Adventure sind wohl die Texte, die auf dem Bildschirm ausgegeben werden sollen. Daher sollen die Befehle zur Text- ausgabe hier an erster Stelle stehen. Text '' Gibt den Text zwischen den Apostrophen aus. Dieser Text kann über mehrere Zeilen gehen und Textbefehle enthalten. Dabei werden die Zeilen mitgezählt, damit das Fortsetzungszeichen erscheint, wenn der Bildschirm voll ist. Zum Format von Texten und den darin enthaltenen Textbefehlen siehe Kapitel 7. Text Gibt den Text aus dem Textblock aus. Funktioniert wie die direkte Textangabe mit '', nur, daß der Text auf einem Textblock steht. kann eine Flagge oder eine ganze Zahl sein, weshalb es manchmal besser ist, den Text aus einem Textblock zu lesen. Absatz Beendet einen Textabsatz und beginnt einen neuen. Je nach den im Umgebungs-Block angegebenen Parametern wird dabei eine Leerzeile eingefügt und der neue Absatz eingerückt. Zufallstext Bestimmt zufällig einen Text von bis aus dem Textblock und gibt ihn aus. Hier können keine expliziten Texte ange- geben werden, sondern nur Verweise auf einen Textblock. Puffer '' Schreibt den angegebenen Text nur in den Meldungspuffer, der bei jeder normalen Text-Anweisung gelöscht wird. Der Text im Buffer wird nur dann geschrieben, wenn es in der Nachausführungen der Objekte und des Raums keine Textanweisung gegeben hat oder mit dem Befehl Puffer ohne Text- Angabe. Box '' oder Box Mit diesem Befehl kann ein Zitat, das entweder als String in Hoch- kommas oder durch einen Textblock mit der Stelle angege- ben wird, in einem Kasten in der Mitte des Bildschirms eingeblendet werden. Das ist Graham Nelsons Inform abgeguckt. Die Box in TAG ver- schwindet jedoch nach Tastendruck. Obwohl der Text wie ein normaler Ausgabetext in einem Block definiert wird, gibt es doch ein paar Besonderheiten: - Der Umbruch ist genau wie in der ADV-Datei, jede Zeile dort entspricht einer Zeile in der Box. - Die Zeilen werden nach 60 Zeichen abgeschnitten, es sind nur acht Zeilen erlaubt. - Es können keine Steuerzeichen in eckigen Klammern oder mit Schrägstrichen angegeben werden. Die einzigen Steuerzeichen, die mit der Box benutzt werden sollen, stehen in der ersten Spalte, und können ein '<' für linksbündig, ein '>' für rechtsbündig und ein '.' für zentrierten Text sein. Ist das erste Zeichen einer Zeile keins dieser Zeichen, so wird linksbündig geschrieben. Beispiel: Box '.Gruselett Der Flügelflagel gaustert durchs Wiruwaruwolz, die rote Fingur plaustert und grausig gutzt der Golz. >Chr. Morgenstern' Die Farbe der Textbox ist die Rahmenfarbe. 5.2.2. Variablenzuweisungen Zur Zuweisung von Variablen stehen folgende allgemeinen Prozeduren zur Verfü- gung, die anstelle der in den meisten Programmiersprachen üblichen Zuweisungen der Form x = y verwendet werden können: Sei Weist der Flagge oder der Variable den Wert von zu. kann natürlich auch ein Zahlenwert sein. Inkr Erhöht den Wert der Flagge um den Wert von . Wenn weggelassen wird, wird um 1 erhöht. Dekr Erniedrigt den Wert der Flagge um den Wert von . Wenn weggelassen wird, wird um 1 erniedrigt. Mult Multipliziert den Wert der Flagge mit dem Wert von . Achtung! Da TAG nur mit Bytes arbeitet, sollte sichergestellt sein, daß das Produkt nicht größer als 255 ist. (Es sei denn, es werden Integer-Variablen benutzt.) Div Dividiert den Wert der Flagge durch den Wert von . Es ist eine ganzzahlige Division, bei der der Rest weggelassen wird, z.B. 7 div 3 = 2. Mod Weist der Flagge den Rest der Division von durch zu. Zum Beispiel ist 7 mod 3 = 1. Anmerkung: TAG erlaubt nicht, wie die meisten Programmiersprachen, Ausdrücke wie x = y*8 + z. Stattdessen müssen diese Anweisungen nacheiander durch die obenstehenden ausgedrückt werden. Das entspricht in etwa der Vor- gehensweise, die man beim Eintippen des Ausdrucks in einen Taschen- rechner anwenden würde. Der Ausdruck oben wäre also in TAG: Sei x y Mult x 8 Inkr x z Das ist zwar etwas gewöhnungsbedürftig, funktioniert aber. Setze Weist der Flagge den Wert 1 (und damit 'wahr') zu. Lösche Weist der Flagge den Wert 0 zu (d.h. 'falsch') zu. Zufall Belegt die Flagge mit einer Zufallszahl von bis . Anstelle der Flagge können auch Objekte, Räume usw. angegeben werden. Zufall ( ... ) Weist der Variablen zufällig einen der Werte aus der Klammer zu. Hier können auch Objekte, Räume, Richtungen usw. angegeben werden. Die Werte in der Klammer müssen aber immer vom selben Typ sein wie die Variable. BitUnd Verknüpft die beiden Flaggen und bitweise mit 'und' und weist den Wert der Verknüpfung der Variablen zu. Bei der Und- Verknüpfung werden nur diejenigen Bits gesetzt, die in beiden Flaggen gesetzt sind. Zum Bispiel: 6 und 10 = 2 oder in binärer Schreibweise: #0110 und #1010 = #0010. (0 markiert nicht-gesetzte, 1 gesetzte Bits. Das # bezeichnet eine binäre Zahl.) BitOder Verknüpft die beiden Flaggen und bitweise mit 'oder' und weist den Wert der Verknüpfung der Variablen zu. Bei der Oder- Verknüpfung werden nur die Bits gesetzt, die in mindestens einer der Flaggen gesetzt sind: 6 oder 10 = 14 bzw. #0110 oder #1010 = #1110. (Anmerkung: Die Notation #xxxx wird als binäre Zahl verstanden, wenn dem # nur Einsen und Nullen folgen. Binäre Zahlen können höchstens achtstellig sein, das Doppelkreuz wird dabei nicht mitgezählt. Man kann auch Zahlen in Hex-Notation angeben, wenn man ihnen ein $ vor- anstellt: $ff = 255, $c0 = 192. Hex-Zahlen können auch größer als 255 sein.) 5.2.3. Prozeduren für Räume und zur Fortbewegung Für die Behandlung der Räume gibe es ebenfalls eine Anzahl in TAG vordefinier- ter Funktionen: GeheZu Bewegt den Spieler an den genannten Ort. kann ein Raumname sein oder ein Verhältniswort mit einem Objekt, z.B. 'in Sessel'. SeiRaum Belegt mit dem Ausgang des Raums in Richtung . Ist Null, wenn es in diese Richtung keinen Ausgang gibt. SeiRitg Sucht eine Richtung, in die man von nach gehen kann. Gibt es mehrere Möglichkeiten, so wird die zuerst gefundene benutzt. AttrHin Belegt den Raum mit einem Raumattribut . (Anstatt des Schlüsselworts AttrHin kann auch AttrZu benutzt werden.) AttrWeg Entfernt ein Raumattribut von einem Raum . 5.2.4. Objekte Um die Objekte hin- und herjonglieren zu können, gibt es folgende Anweisungen: ObjNach Bewegt ein Objekt an einen bestimmten Ort. kann ein Raumname sein oder ein Verhältniswort mit einem Objekt, z.B. 'unter Bett'. Tausche Vertauscht die Orte der beiden Objekte und . Das ist nützlich, wenn ein Objekt sich verändert und gegen ein anderes aus- getauscht wird, das sich nirgendwo (d.h. in keinem Raum) befindet, z.B. Tausche Vase Scherben. ObjZust Ändert den Zustand des Objekts in . AttrHin Belegt das Objekt mit einem Objektattribut . (Auch hier darf wieder AttrZu benutzt werden.) AttrWeg Entfernt ein Objektattribut von einem Objekt oder ein Raumattribut von einem Raum . MutterObj Ein Mutterobjekt ist ein Objekt, in dem ein anderes (Tochter-)Objekt enthalten ist. Es kann aber auch auf, unter, bei, an oder hinter dem Mutterobjekt sein. Diese Anweisung weist der Objektvariablen das Mutterobjekt von zu. Ist kein Tochterobjekt oder ist beim Spieler, soist Null. StammObj Weist das Stammobjekt von zu. Das Stammobjekt eines Objekts ist das Objekt, das dieses Objekt auf einer beliebigen Ebene enthält, das aber selbst kein Tochterobjekt ist. Ist kein Tochterobjekt, so ist das Stammobjekt gleich . Das Stammobjekt kann also nicht Null sein, wie beim Mutterobjekt. Da dies sich das etwas kompliziert anhört, hier ein Beispiel: Auf einem Tisch steht eine Schale, darin befindet sich Obst. Das Mutter- objekt des Obstes ist die Schale, das der Schale der Tisch und der Tisch hat kein Mutterobjekt, da er dirket im Raum steht. Das Stamm- objekt aller drei Objekte ist der Tisch. MutterObj bezieht sich also auf die jeweils nächste Ebene, Stammobj immer auf die unterste Ebene, d.h. auf alle Objekte, die direkt in einem Raum sind. StammRaum Weist der Raumvariablen den Raum zu, in dem sich das Objekt auf einer beliebigen Ebene befindet, d.h. ist der Ort des Stammobjekts von . Das Stammobjekt eines Objekts ist immer direkt in einem Raum enthalten. Ist bei mir, so ist der Stammraum Null. ObjListe () Schreibt eine Objektliste aller Objekte, auf die die Bedingung zutrifft, auf die Hilfsvariable Aussage. Dies funktioniert natürlich mit einer Schleife, die als Zählvariable benutzt (Wie Bedingungen genau aussehen, steht im nächsten Kapitel.) Die Anzahl der aufgezählten Objekte liegt auf der Flagge #AnzListe. InhListe Schreibt den Inhalt des Objekts heraus. Je nach wird eine Meldung herausgegeben, wenn leer ist, und es werden darunter- liegende mitbetrachtet (Rekursion). Um Sachen darin zu zeigen, muß das Objekt ein Behälter sein, um Sachen darauf zu zeigen, eine Ablage. ObjInh Belegt die mit der Anzahl der Dinge, die sich in, auf, bei usw. dem Objekt befinden. ObjGew Berechnet das Gewicht von und seiner Unterobjekte und schreibt es auf die Flagge . ZeigeInh Listet den Inhalt des Orts auf. ist ein Raumname oder ein Verhältniswort mit einem nachfolgenden Objekt. ObjGenus Ändert das grammatikalische Geschlecht und/oder das Namensformat eines Objekts. Das ist nur dann nützlich, wenn der Name einen Aktionsaufruf enthält und somit veränderlich ist. und werden wie in der Objektdefinition angegeben. 5.2.5. Allgemeine Spielprozeduren Diese Prozeduren sind für das allgemeine Spielgeschehen: Stop Beendet die Aktion sofort und setzt die Flagge NullAkt. Stop springt aus allen Schleifen und Bedingungen direkt ans Ende der Aktion. Gestorben Wird aufgerufen, wenn der Spieler stirbt. Es erscheint ein Text, stan- dardmäßig: 'Ich bin jetzt leider tot.' Dann werden die Punkte gezeigt und gefragt, ob neu gestartet werden, ein Spielstand geladen werden oder das Programm verlassen werden soll. Gewonnen Ein Text wird angezeigt, standardmäßig: 'Ich habe gewonnen!' Dann wird der Punktestand gezeigt, und das Programm verlassen. Ich nehme an, daß jemand, der soeben gewonnen hat, nicht einen alten Spielstand laden oder sogar von vorne anfangen möchte. Punkte Ändert den Punktestand auf den Wert . ObjPunkte Ändert den Punktestand des Objekts auf den Wert . RaumPunkte Ändert den Punktestand des Raums auf den Wert . Eine genaue Beschreibung des Punktesystems gibt es in Kapitel 8. Ausf Ruft eine Aktion auf und führt sie aus. kann eine benutzerde- finierte Aktion sein, ein Weg oder ein Befehl, benutzerdefiniert oder von TAG. Ist ein Befehl, dann wird natürlich zuerst VorAusf, dann der Hauptausführungsteil und schließlich NachAusf abgearbeitet, wie gehabt. Es können keine Variablen übergeben werden. Ausf {} {} {} {} Führt einen Befehl aus und übergibt die Objekte und die Richtung. Die Objekte müssen dabei in derselben Reihenfolge stehen wie in der Syntax des Befehls definiert. Objekte, die nicht übergeben werden, bleiben wie sie sind. Objekte, die übergeben werden, obwohl sie in der Befehls- syntax definiert sind, bleiben unberücksichtigt. Bei der Ausführung werden alle Vor- und Nachausführungen der Objekte und des Raums be- rücksichtigt. Diese Anweisung ist sehr wichtig, wenn in einem Befehl andere implizit ausgeführt werden sollen oder wenn ein Befehl mit einer VorAusf 'umgelenkt' wird: Ausf untersuchen aObj Ausf gehen N Ausf hineinlegen aObj Truhe SetzeZeit Setzt die Uhrzeit und , die in den Sytemflaggen Stunden und Minuten abgelegt werden. WarteZeit Läßt Stunden und Minuten der Spielzeit verstreichen. Die Uhrzeit wird im 24-Stunden-Format ausgegeben. Wartet man um 23:55 h zwölf Minuten, so ist es danach 0:07 h. Logisch. JaNein Fragt nach der Eingabe von 'J' oder 'N', schreibt je nach Angabe JA oder NEIN mit einem anschließenden Absatz und belegt mit 0, wenn die Antwort 'N' war, mit 1 wenn sie 'J' war. Auswahl '' Fragt nach der Eingabe einer der Tasten, die im String Tasten enthalten sind. wird dann mit der Position der Taste im String belegt. Wird die Abfrage mit Escape abgebrochen, so ist Null. Ist 'String' z.B. 'max', so ist 2, wenn 'a' (oder 'A') gedrückt wurde. 5.2.6. Prozeduren zur Belegung von Feldern Zur leichteren Handhabung der Felder gibt es folgende Prozeduren: Daten ( { ...}) Belegt das Feld ab der Position mit den Werten . Lese ( { }) Liest den Wert des Feldes an der Position , je nach Dimen- sion des Feldes. Belege ( { }) Belegt die Position des Feldes , je nach Dimension des Feldes mit dem Wert . FeldPos ( { }) Berechnet die eindimensionale Position des Feldes nach der Dimension und der (mehrdimensionalen) Positionsangabe. 5.3. Bedingungen Bedingungen sind Abfragen, ob ein Ereignis wahr oder falsch ist. In TAG werden Bedingungen immer in runde Klammern gesetzt. Dabei dürfen keine Klammern ineinandergeschachtelt werden. Ein Schrägstrich vor der Klammer ver- neint die Bedingung. Bedingungen können miteinander verknüpft werden. Gültige Verknüpfungen sind 'und' und 'oder': und ist wahr, wenn beide Bedingungen wahr sind. oder ist wahr, wenn mindestens eine der Bedingungen wahr ist. Achtung! TAG behandelt nicht, wie allgemein üblich, die Und-Verknüpfung vor- rangig vor der Oder-Verknüpfung, sondern arbeitet die Verknüpfungen der Reihe nach ab. TAG versteht keine verschachtelten Klammern, deshalb müssen Bedingungen, die zuerst ausgewertet werden sollen, mit einer SeiBed-Anweisung einer Hilfsflagge zugewiesen werden: SeiBed Weist der Flagge den Wahrheitswert der Bedingung zu, d.h. ist 0, wenn falsch ist und 1, wenn wahr ist. ist eine Kette von Einzelbedingungen, die mit 'und' oder 'oder' ver- knüpft werden können. Die Bedingungen werden nun beschrieben. Da keine verschachtelten Bedingungen verstanden werden, ist es wichtig, zu wissen, wie man verknüpfte Bedingungen ausdrücken kann. So ist z.B.: /(a und b) = /a oder /b /(a oder b) = /a und /b Auf diese Weise kommt man noch einmal um den lästigen Umweg der Hilfsvariablen herum. Die Verneinung einer verneinten Bedingung ist natürlich wieder die Bedingung selber. Doppelte Verneinungen heben sich also auf und werden auch nicht von TAG verstanden. Man kann die Auswertung von links auch auch ausnutzen, um Prioritäten zu setzen: a oder (b und c) -> b und c oder a a oder /(b und c) -> /b oder /c oder a (Dies funktioniert natürlich nur, solange nur eine Verknüpfung vorrangig be- handelt werden soll.) TAG kennt verschiedene Bedingungen: ( ) Vergleicht zwei Flaggen oder Werte miteinander. kann eine Flagge, eine Variable oder einen Zahlenwert bezeichnen. Der Operator kann '=' (gleich), '>' (größer als) und '<' (kleiner als) sein. Weitere Operatoren erhält man durch Negation der Bedingung. Beispiele: (Täter = Opfer) Ist der Täter auch das Opfer? (8 < 5) Ist erlaubt, aber unsinnig, da es immer falsch ist. (aObj = Seil) Wurde im Befehl das Seil angesprochen? (aObj.Gew < 7) Wiegt das Objekt weniger als 7 Gewichtseinheiten? ( ) Prüft, ob sich das Objekt am Ort befindet. kann IN gefolgt von einem Raum sein, oder ein Verhältniswort, gefolgt von einem Objekt, oder eines der Schlüsselwörter 'hier', 'beimir' und 'angez', z.B.: (Mann Hier) Ist der Mann hier? (aObj2 BeiMir) Habe ich das Objekt? (Münze in Keller) Liegt die Münze im Keller? (Stab bei Magier) Hat der Magier den Stab? Anmerkung: IN und BEI prüfen nicht, ob man das Objekt sehen kann. So ist die letzte Bedingung auch wahr, wenn der Magier den Stab hat, ihn aber vor den Augen des Spielers versteckt. ( ) Prüft, ob das Objekt im Zustand ist: (Lampe ein) Ist die Lampe eingeschaltet? (Luftballon kaputt) Hat der Luftballon ein Loch? ( ) Prüft, ob das Objekt ein bestimmtes Attribut besitzt: (iObj Kleidung) Kann man das Objekt anziehen? (xObj Person) Ist das Objekt eine Person? ( ) Prüft, ob der Raum ein bestimmtes Attribut besitzt: (aRaum besucht) war ich hier schon einmal? (Proz ) Ist mit einer Wahrscheinlichkeit von Prozent wahr. kann eine Flagge oder ein fester Zahlenwert sein. () Eine alleinstehende Flagge wird als Boolsche Flagge interpretiert und ist falsch, wenn sie Null ist und und anderen Fällen wahr. Diese Schreibweise ist eine Abkürzung für /( = 0). Diese Bedingung wird häufig im Zusammenhang mit Setze, Lösche und SeiBed verwendet. ( nebenan) Prüft, ob ein Objekt sich im Nachbarraum befindet. (Nachbarräume sind Räume, die mit aRaum durch normale Ausgänge, auch durch Türen ver- sperrt, abgetrennt sind. Wege zählen nicht.) ( hat ) Prüft, ob die Variable bei einem Objekt definiert ist. ( Deko) Prüft, ob das Objekt als Dekoration definiert wurde. ( ) ( ) Prüft, ob ein Raum oder ein Objekt eine Klasse besitzt. ( am_Ort_von ) Prüft, ob sich zwei Objekte am selben Ort befinden. Das bedeutet, sie müssen dasselbe Mutterobjekt besitzten und dasselbe Verhältnis zu ihm. So sind ein Taschentuch im Nachttisch und eine Lampe darauf nicht am selben Ort, genausowenig wie ein Apfel in einer Schale und ein Messer auf dem Tisch, auch wenn die Schale auf dem Tisch steht. ( im_Raum_mit ) Prüft, ob sich zwei Gegenstände im selben Raum befinden. Sie müssen denselben Stammraum besitzen, mehr nicht. Alle oben genannten Gegen- stände sind im selben Raum. (Meta ) Prüft, ob ein Befehl ein Meta-Befehl ist. (Licht_in ) ist wahr, wenn man im Raum sehen kann. Es gibt Licht im Raum, wenn er das Attribut 'dunkel' nicht besitzt oder man mindestens ein Objekt, das eine Lichtquellen ist und das nicht ausgeschaltet ist, sehen kann. Als Abkürzung kann man mehrere Bedingungen des gleichen Typs in einer zusammen- fassen, indem man das letzte Wort wiederholt. Zum Beispiel werden folgende Bedingungen (aObj = Schere Messer Gabel) /(aRaum = Ruine Park) (xObj in Eimer Tasche) /(xObj geschlossen abgeschlossen) von TAG in die folgenden Ketten umgewandelt: (aObj = Schere) oder (aObj = Messer) oder (aObj = Gabel) /(aRaum = Ruine) und /(aRaum = Park) (xObj in Eimer) oder (xObj in Tasche) /(xObj geschlossen) und /(xObj abgeschlossen) Normale Bedingungen werden mit 'oder' verknüpft, verneinte mit 'und'. Diese Abkürzung funktioniert nur bei den Vergleichen mit Operator, bei Ortsangaben, bei Zuständen und bei Attributen. Außerdem muß die Bedingung immer von der selben Art sein. (aObj abgeschlossen in Tasche) funktioniert also nicht. Die folgenden Konstrukte sind jedoch erlaubt: (aObj = akteur Hans) (Nummer > X Y 25) Bedingungen spielen in bestimmten Anweisungen eine Rolle. Dieses sind die Wenn-dann-Anweisungen, die Bed(ingungs)-Anweisungen und ihre Abkürzungen sowie verschiedene Arten von Schleifen. Eine Wenn-dann-Anweisung ermöglicht es, einen oder mehrere Befehle nur dann auszuführen, wenn eine Bedingung erfüllt ist. Die Syntax ist: Wenn () dann [...] Ende Dabei ist eine Bedingung aus beliebig vielen Einzelbedingungen und das Auslassungszeichen [...] steht für beliebige Anweisungen. Jede dieser Anwei- sungen steht dabei in einer eigenen Zeile. Alle Anweisungen bis zum Schlüssel- wort 'Ende' werden nur ausgeführt, wenn wahr ist. Zum Beispiel Wenn (aRaum draußen) und (Sturm = 15) dann Text 'Der Himmel zieht sich langsam zu und ein unangenehmer Wind bläst scharf über das Land.' Ende Wenn-dann-Anweisungen können auch ineinander geschachtelt werden. (Maximal können 12 Wenn-dann-Bedingungen ineinander liegen.) Wenn (Fisch hier) dann Text 'Es riecht hier ziemlich streng.' Wenn (Katze hier) dann Text 'Die Katze stürzt sich auf den Fisch und vertilgt ihn hastig (und nicht gerade manierlich...)' ObjNach Fisch Nirwana Ende Ende Sehr häufig möchte man zusätzlich Anweisungen geben, wenn die Bedingung nicht erfüllt ist. Dazu kann man die Wenn-dann-Anweisung mit Sonst erweitern: Wenn () dann [...] sonst [...] Ende Wenn wahr ist, werden alle Ausführungen bis zum Kennwort 'sonst' durch geführt, die Ausführungen zwischen 'sonst' und 'Ende' werden übersprungen. Ist die Bedingung falsch, so wird der erste Teil bis sonst übersprungen und nur der zweite Teil von 'sonst' bis 'Ende' durchgeführt. Danach geht es weiter. Zum Beispiel: Text 'Der Bauer sagt:' Wenn (Regen) dann Text '"Verdammtes Scheißwetter heute!"' sonst Text '"Ein schöner Tag, nicht wahr?"' Ende Wenn der Bereich der Wenn-dann-Anweisung nur eine Anweisung enthält und es keinen sonst-Bereich gibt, kann man die Anweisung durch Weglassen des Wortes 'dann' abkürzen. So sind die folgenden drei Anweisungen äquivalent: Wenn (x > 15) dann Sei x 0 Ende Wenn (x > 15) Sei x 0 Wenn (x > 15) Sei x 0 Ob die Anweisung dirket hinter der Bedingung oder in der nächsten Zeile steht, ist dabei egal. Die Anweisung kann auch eine weitere Bedingung oder eine Schleife sein. Diese Notation kann praktisch sein, aber man muß auf- passen, daß man 'dann' und das abschließende 'Ende' wegläßt. Im Zweifelsfall empfiehlt es sich immer, die komplette Schleife anzugeben, um Mißverständ- nisse auszuschließen. Sehr häufig werden aber Bedingungen abgefragt, um zu prüfen, ob ein Befehl des Spielers durchführbar ist oder nicht. Ist die Bedingung nicht erfüllt, passiert aber nichts. Dazu dient die Bed-Anweisung. Sie springt sofort zum Ende des Ausführungsblocks und gibt nur einen Text aus. Die Syntax ist: Bed () '' oder Bed () Dabei ist die zu erfüllende Bedingung. Ist sie wahr, geht es weiter im Programm. Ist sie falsch, so wird Text aus oder der nachfolgend in Anführungszeichen angegebene Text ausgegeben und der Ausführungsblock sofort gestoppt. Dies soll in einem Beispiel verdeutlicht werden: Wir möchten den Befehl 'graben' neu einführen. Als Werkzeug (aObj2) akzeptieren wir nur den Spaten. Bef graben [...] Ausf [...] Bed (aObj2 = Spaten) 'Wie soll ich denn mit [dem aObj2] graben? Das mußt Du mir aber erst erklären.' [...] AusfEnde Anmerkung: Da die Bedingungen unter Umständen sehr lang sein können, finde ich es schöner, den Text in die nächste Zeile zu schreiben. Aus diesem Grund kann bei der Bed-Anweisung der Textstring auch in der nächsten Zeile stehen, während er bei anderen Anweisungen wie Text oder String immer auf derselben Zeile wie der Befehl stehen muß. Das hat außer der Optik des Datensatzes keinen besonderen Grund. Aber das Auge programmiert schließlich mit. Zwei Bedingungen sind besonders wichtig, nämlich, ob das Objekt hier ist und ob der Spieler das Objekt bei sich hat. Dafür gibt es besondere Bedingungen: ObjHier Prüft, ob im selben Raum wie der Spieler ist. Ist das der Fall, so geht es weiter, wenn nicht, so wird ein Text ausgebeben. Je nach- dem, ob das Objekt nicht hier ist, zu weit entfernt oder außer Reich- weite ist oder ob es in einem Glasbehälter verschlossen ist und deshalb nichts mit ihm gemacht werden kann. ObjBeiMir Prüft, ob das Objekt beim Spieler ist. Wenn nicht, wird die Aktion abgebrochen und 'Ich habe nicht bei mir.' ausgegeben. Sollen Anweisungen häufiger wiederholt werden, so kann man in TAG einfache Schleifen programmieren, die solange ausgeführt werden, wie eine bestimmte Bedingung wahr ist. Solange () [...] Ende Dabei muß natürlich vom Programmierer sichergestellt werden, daß die Bedingung durch die Anweisungen in der Schleife falsch werden kann, so daß die Schleife zu einem Ende kommt. Ist das nicht der Fall, so hängt sich das Programm auf, da immer und immer wieder die Schleife abarbeitet. So ist zum Beispiel folgendes Solange (1 < 5) [...] Ende eine Endlos-Schleife, da 1 immer kleiner als 5 ist, was immer auch in der Schleife passiert. Ist die Bedingung beim ersten überprüfen falsch, so wird alles, was zwischen Solange und Ende steht, nicht ausgeführt. TAG kennt auch Schleifen, die eine Variable von einem festen Wert zu einem nächsten zählen. Dies entspricht den Do- oder For-Schleifen, die es in den meisten Programmiersprachen gibt: Schleife { } {()} [...] Ende Es muß die Variable angegeben werden, die variiert werden soll. Dies kann eine Flagge, oder eine beliebige Variable sein. Dann werden die Grenzen des Inter- walls angegeben, das durchlaufen soll. Bei Flaggen müssen sie angegeben werden, bei Objekten, Räumen und Befehlen werden implizit alle Objekte, Räume und Befehle durchlaufen, wenn sie nicht angegeben werden. Weitehin kann eine Bedingung angegeben werden, so daß Werte übersprungen werden, die diese Be- dingung nicht erfüllen. Das ist bei Objekten praktisch: Schleife xObj (xObj in Handtasche) [...] Ende Änlich wie die Solange-Schleife arbeitet eine Wiederhole-Schleife. Hier wird die Bedingung nur am Ende der Schleife anbgefragt. Wiederhole [...] bis () Hier werden die Anweisungen zwischen 'Wiederhole' und 'bis' solange ausge- führt, bis eine Bedingung wahr ist. Da die Überprüfung hier am Ende der Schleife erfolgt, werden die Ausführungen [...] auf jeden Fall mindestens einmal ausgeführt. Eine weitere Bedingungsabfrage ist der JeNach-Befehl, der eine Vereinfachung des Wenn-dann-Befehls für einfache Bedingungen des Typs (X = Y) ist. JeNach ist sehr nützlich, wenn eine Variable auf verschiedene Werte hin überprüft werden soll. Die Syntax ist: JeNach () [...] () [...] () [...] ... Ende Dabei steht für eine definierte Flagge, für eine Objektvariable, eine Raumvariable oder einen Befehl. Die sind verschiedene Bereiche. Je nach können sie Zahlen von 0 bis 255, Objekte, Räume oder Befehle enthalten. Gültige Bereiche sind: () einzelnes Element ( ) Liste von Elementen (..) alle Elemente von bis einschließlich ([...]) jede Kombination dieser drei (sonst) Das Schlüsselwort 'sonst' in Klammern Nach den Bereichsdefinitionen in Klammern folgen dann in gewohnter Form TAG-Anweisungen. Die erste Anweisung kann in derselben Zeile wie die Defi- nition des Bereichs stehen. Ist der momentene Wert von in einem Bereich enthalten, so werden die Ausführugen, die nach dem Bereich stehen, ausgeführt, bis ein neuer Bereich definiert wird. Wichtig! Ist in einem Bereich und wurden die dazugehörigen Anweisungen abgearbeitet, so wird automatisch zur Ende-Marke gesprungen. Es können also überschneidende Bereiche angegeben werden, aber es wird nur der erste Bereich, in dem sich die Variable befindet behandelt. Nach der gleichen Logik wird 'sonst' einfach als der komplette Bereich der möglichen Werte betrachtet. Es können weitere Bereiche nach 'sonst' definiert werden, aber sie sind wirkungslos. Also, ein kleines Beispiel: Jenach Monat (2) Sei Tage 28 (4 6 9 11) Sei Tage 30 (sonst) Sei Tage 31 Wenn (Monat = 12) dann Text 'Es weihnachtet sehr!' Ende | (Wenn) Ende | (Jenach) Text 'Der [Ord Monat] hat [Num Tage] Tage.' In diesem Beispiel wird nicht beachtet, daß die Monate nur von 1 bis 12 gehen. So hätten hier auch der 0. oder 13. einunddreißig Tage. 6. DIE VERSCHIEDENEN AKTIONEN IM SPIEL 6.1. Die Aktion Anfang In der Aktion Anfang muß alles programmiert werden, was zu Anfang des Spiels passieren soll. Es soll wahrscheinlich ein Text erscheinen und einige all- gemeine Variablen gesetzt werden: Aktion Anfang Ausf Text 'Mann, da bin ich vielleicht in eine wirre Geschichte verwickelt worden... (Hier unglaubliche Story einfügen.) So war das, und jetzt stehe ich hier mutterseelenallein abends um halb eins auf der Autobahnrastätte Aggertal. [f]T R A M P E R[n] [x]Eine interaktive Reise per Daumen, (C) 1988 Hieronymus Karpinsky ENDE eingeben, um aufzuhören, HILFE für ein paar Tips.' Sei MaxInv 6 Sei MaxGew 80 GeheZu Raststätte EndeAusf Block 10 Hier wird also zunächst ein Anfangstext angegeben, um dem Spieler das Wozu und Warum des Spiels zu erläutern. Die Systemflaggen MaxInv und MaxGew werden gesetzt, um nicht die Defaultwerte zu benutzen. Dann wird der Spieler zu seiner Ausgangsposition befördert. Enthält Anfang keine GeheZu-Anweisung, so beginnt das Spiel im zuerst im Datensatz definierten Raum und es wird eine Raumbeschreibung ausgegeben. 6.2. Ablauf eines Zuges Die Aktionen Vorher und Nachher werden in jedem Spielzug abgefragt. (Ein Spielzug ist hierbei alles, was zwischen zwei eingegebenen Befehlen geschieht, wenn der erste Befehl kein Steuerbefehl ist.) Die Vorgehensweise ist dabei wie folgt: 1. Eingabe des Spielers und Befehlsanalyse. Tritt ein Fehler in der Parser-Routine auf, so ist der Zug hier zu Ende. In der Prozedur NachParser kann das Ergebnis des Parsers modifiziert werden. 2. Die globale Vorher-Aktion wird ausgeführt. 3. Der Ausführungsteil "Vorher" Solange NullAkt falsch ist, werden die folgenden Aktionen nach- einander ausgeführt: a. die VorReakt'en aller anwesenden Objekte b. die VorAusf des momentanen Aufenthaltsorts c. die VorAusf von aObj d. die VorAusf von aObj2, wobei aBef vorübergehend auf den passenden Pseudo-Befehl gesetzt wird. e. bei vordefinierten TAG-Verben die ergänzende VorAusf 4. Die eigentliche Befehlsausführung wird ausgeführt, wenn NullAkt falsch ist, d.h. wenn keine der VorAusf'en mit einer Stop- oder Bed-Anweisung negativ abgebrochen wurde. Diese Aktion wurde im Ausf-Block der Befehlsdefinition angegeben. 5. Der Ausführungsteil "Nachher" Es werden, je nach NullAkt, die folgenden Aktionen ausgeführt: a. die NachAusf eines TAG-Verbs b. die NachAusf von aObj c. die NachAusf von aObj2 (mit Anpassung von aBef) d. die NachAusf von aRaum e. die NachReakt'en aller anwesenden Objekte 6. Die globale Nachher-Ausführung wird - unabhängig von NullAkt - ausgeführt. Hier ist definiert, was in jedem Zug passiert. Es werden auch alle Aktionen ausgeführt, die für jeden Zug definiert wurden. Wenn der eingegebene Befehl ein Steuerbefehl ist, werden nur die Punkte 1. und 3.e. bis 5.a. abgearbeitet. Wird der eingegebene Befehl nicht erkannt, so ist nach Punkt 1. Schluß und der nächste Zug beginnt. (Das heißt, eigentlich wird der Zug wiederholt, da nichts im Spiel passiert ist.) 6.3. Zeitabhängige Ereignsse Viele Ereignisse im Spiel sind zeitabhängig: Die Batterien der Taschenlampe werden schwächer, die Zündschnur einer Dynamitstange brennt herunter, eine Person wartet nur eine bestimmte Zeit lang an einem Ort, der Spieler wird müde, hungrig oder erholt sich von Verwundungen - all das sind typische Dinge, die in einem Adventure passieren. In TAG werden solche Ereignisse mit Aktionen gesteuert, die am Ende jeden Zugs ausgeführt werden. (Sie werden mit einem Stern versehen, wir erinnern uns.) Bleiben wir einmal bei dem Beispiel mit dem Dynamit. Es soll 3 Züge lang brennen, bevor es explodiert. Wenn es angezündet wird, wird die Flagge Brenn- zeit auf 3 gesetzt. In einer Aktion, die in jedem Zug aufgerufen wird, wären dann die Anweisungen: Flagge Brennzeit 0 [...] Aktion * Ausf Wenn (Brennzeit > 0) dann Dekr Brennzeit 1 Wenn (Dynamit hier) und (Brennzeit = 2) dann Text 'Die Zündschnur des Dynamits brennt munter herunter.' Ende Wenn (Dynamit hier) und (Brennzeit = 1) dann Text 'Die Zündschnur ist beinahe abgebrannt.' Ende Wenn (Brennzeit = 0) dann Wenn (Dynamit hier) dann Text 'Die Flamme an der Zündschnur erreicht das Dynamit, welches spontan mit einem lauten Knall explodiert. Der Preis dafür, daß ich dieses Schauspiel mit ansehen durfte, ist, daß ich mit aller Wucht gegen eine Wand geschleudert werde.' Gestorben sonst Text 'In der Ferne höre ich eine Explosion.' | Was passiert, wenn gesprengt wird, hier einfügen Ende Ende Ende AusfEnde Der Zeitzünder wird also stetig heruntergezählt, bei Null wird dann die Ak- tion eingeleitet. Zwischendurch werden Warnsätze über die abbrennende Zünd- schnur losgelassen. Es gibt aber auch Variablen, die hoch- und nicht runterzählen. Z.B. ein Teekessel, der auf den Herd gestellt wird. Nach fünf Zügen soll das Wasser kochen. Voraussetzung ist, daß der Herd an ist und der Kessel mit Wasser gefüllt ist: Flagge Temperatur 0 Zust voll 'mit Wasser gefüllt' Aktion Teekessel * Ausf Wenn (Kessel auf Herd) und (Herd an) und (Kessel voll) dann Inkr Temperatur 1 Wenn (Temperatur = 5) dann Wenn (Kessel hier) dann Text 'Das Wasser kocht und der Kessel pfeift.' sonst Text 'In der Ferne höre ich ein Pfeifen.' Ende Sei Temperatur 0 ObjZust Kessel normal Ende sonst Wenn (Temperatur > 0) dann Dekr Temperatur 1 Ende Ende EndeAusf Immer, wenn der Topf auf dem Herd steht, der Herd an und der Kessel voll Wasser ist, wird die Temperatur hochgezählt. Wenn fünf Züge vergangen sind, pfeift der Kessel, und das Wasser verdampft. (Wahrscheinlich passiert noch mehr, aber es ist hier nicht berücksichtigt.) Immer wenn die Bedingung nicht erfüllt ist, etwa weil jemand den Kessel vom Herd nimmt oder den Herd ab- schaltet, wird die Temperatur langsam wieder auf Null zurückgezählt. Die Variable ist also hier ein Maß für die Kesseltemperatur. 6.4. Wiederkehrende Verhaltensmuster Manche Objekte im Spiel - meistens sind es Personen - folgen immer einem bestimmten Verhaltensschema, das meistens immer wiederkehrt. Um dieses Schema zu beschreiben, bieten sich wieder die Sternchen-Aktionen, die in jedem Zug ausgeführt werden, an. Nehmen wir einmal an, in der Altstadt patroulliert der etwas blöde Nacht- wächter immer auf derselben Route: Vom Marktplatz zum Schuldturm, von dort zur Fleischergasse und weiter zum "Goldenen Becher", dem billigsten (und einzigen) Gasthaus in der Stadt. Dort beginnt seine Tour von vorne. An jedem Ort bleibt er drei bis sieben Züge, je nachdem. Dies wird in der Flagge Verweilen festgelegt: Aktion Nachtwache * Ausf Wenn (Verweildauer = 0) dann Wenn (Wächter hier) dann Text 'Der Wächter schlurft weiter seines Wegs.' Ende Stammraum nRaum Wächter Jenach nRaum (Goldener_B) ObjNach Wächter Marktplatz (Fleischerg) ObjNach Wächter Goldener_B (Schuldturm) ObjNach Wächter Fleischerg (sonst) ObjNach Wächter Schuldturm Ende Zufall Verweildauer 3 7 Wenn (Wächter hier) dann Text 'Der Nachtwächter ist soeben angekommen. Er nickt dir aufmunternd zu, gähnt und lehnt sich auf seine Hellebarde.' Ende Ende Dekr Verweildauer EndeAusf Bei jedem Zug wird Verweildauer heruntergezählt. Ist sie Null, so wird der Ort des Nachtwächters gemäß seiner Route geändert und die Verweildauer mit einem Zufallsgenerator bestimmt. Verweildauer ist also die Anzahl der Züge, bis der Wächter seinen Ort wechselt. In manchen Fällen wird das schematische Verhalten einer anderen Person im Spiel auch durch eine Aktion ausgelöst, so daß in der Aktion eine Kombination aus zeit- und verhaltensgesteurtem Ablauf ist. Es können auch Ereignisse ohne Zeitzünder definiert werden. Zum Beispiel sagt der Papagei in drei von fünf Zügen einen dummen Satz. Dieser Satz wird zu- fällig bestimmt: Aktion * [...] Ausf Wenn (Papagei hier) und (Proz 60) dann Text 22 1 Zufallstext 22 2 4 Zufallstext 22 5 10 end; EndeAusf Block 22 1 'Der Papagei' 2 'krächzt:' 3 'kräht:' 4 'sagt:' 5 '"Beim Klabautermann!"' 6 '"Polly will einen Keks!"' 7 '"Klar zum Entern!"' 8 '"Käpt%n Flint, Sir!"' 9 '"Fünfzehn Mann auf des Totenmanns Kiste..."' 10 '"Rrrum, ich brrrauch% mehr Rrrum!"' Dies ist übrigens ein gutes Beispiel, wo die Textausgabe aus einem Text- block einfacher und klarer ist als die direkte Textangabe als String. Das Geschwätz des Papageis könnte aber genausogut in der Ausführung NachReakt des Papageis stehen, da sie nur ausgeführt wird, wenn der Papagei im selben Raum wie der Spieler ist. Dazu aber im nächsten Abschnitt mehr. 6.5. Die Ausführungsblöcke der Objekte und Räume Die Ausführungsblöcke eines Befehls beschreiben den Regelfall dessen, was ein vom Spieler eingegebener Befehl bewirkt. Zum Beispiel prüft 'nehmen', ob ein Objekt in greifbarer Nähe ist, ob es leicht genug ist und ob es sich nicht um eine Person handelt. Ist dies nicht der Fall, so wird der Befehl schon nach der Textanalyse abgebrochen. Erfüllt das Objekt diese Bedingungen, so wird im Ausführungsblock des Befehls kontrolliert, ob noch Platz beim Spieler ist und ob er das zusätzliche Gewicht noch tragen kann. Wenn ja, dann wird das Objekt vom Aufenthaltsraum in das Inventar des Spielers befördert. Das ist die Vorgehensweise, die die Regeln zum Aufheben von Gegenständen in den meisten Fällen korrekt beschreibt. Aber - wie so oft im Leben - gibt es auch Ausnahmen. Nehmen wir einmal an, es gibt irgendwo eine Eidechse. nun wird jeder, der in seiner Jugend einmal versucht hat, ein solches Tier in die Finger zu kriegen, bestätigen, daß das nicht so einfach ist. Damit dieser Sachverhalt beim Aufheben von Gegenständen nicht in der Ausführung stehen muß, gibt es die Ausführungsblöcke, die spezielle Regeln für Objekte und Räume beschreiben. So können wir für die Eidechse folgende Objektdefinition machen: Obj Eidechse Name 'Eidechse' f Adj 'klein' 'wendig' Vor 'eid' Subst 'echse' f 'reptil' n Gew 2 Besch 'Ein kleines, wendiges Tierchen.' Erst 'Auf dem warmen Steinuntergrund sonnt sich eine Eidechse, ihr Körper ist in der typischen S-Form gekrümmt.' VorAusf (nehmen) Text 'Die Eidechse huscht schnell weiter, um deinen plumpen Fingern zu entwischen. Sie findet einen neuen Sonnenplatz in einer anderen Ecke der Terrasse.' Stop EndeAusf Damit würde es unmöglich, die Eidechse aufzuheben da vor der eigentlichen Ausführung des Befehls dieser Ausführungsblock zum Greifen käme. Das 'Stop' nach der Textausgabe bewirkt, daß der Befehl damit vorzeitig abgeschlossen ist. Würde dieses 'Stop' fehlen, ginge der Befehl weiter wie gewohnt: Du bist hier auf einer steingefliesten Terrasse. Auf dem warmen Steinuntergrund sonnt sich eine Eidechse, ihr Körper ist in der typischen S-Form gekrümmt. > NIMM DIE EIDECHSE Die Eidechse huscht schnell weiter, um deinen plumpen Fingern zu entwischen. Sie findet einen neuen Sonnenplatz in einer anderen Ecke der Terrasse. Du hast nun die Eidechse. Das ist sicherlich widersprüchlich, deshalb sollte auf das 'Stop' geachtet werden. Da eine Txtausgabe mit anschließendem Stop in Vorausführungen sehr häufig vorkommt, kann man den Text nach dem Schlüsselwort 'Stop' angeben. So wird es hoffentlich nicht so oft vergessen: Stop 'Die Eidechse huscht schnell weiter, um deinen plumpen Fingern zu entwischen. Sie findet einen neuen Sonnenplatz in einer anderen Ecke der Terrasse.' Die Ausführungsblöcke der Räume und Objekte haben alle ein implizites 'Jenach aBef' vorgeschaltet, da es hier Sinn macht, die Ausführungen befehlsabhängig zu machen. Möchte man hier eine Ausführung an- geben, die immer, also befehls- unabhängig, geschehen soll, so kann man als letzte Angabe (global) angeben. Dies funktioniert nur bei diesem implizieten Jenach. Dieses (global) bedeutet natürlich nichts anderes als ein Ende der Jenach-Anweisung. Es gibt verschiedene Arten dieser Sonderregeln für Räume und Objekte. In einem komplexen Spiel machen sie den größten Teil der Objektdefinition aus. Nachfolgend sollen die verschiedenen Ausführungsblöcke beschrieben werden. (Der genaue Ablauf eines Spielzuges wird in Kap. 6.2. beschrieben.) 6.5.1. Ausführungen von Räumen Diese Ausführungsblöcke werden durchgeführt, wenn dieser Raum der jeweilige Aufenthaltsort ist. Der Block VorAusf wird dabei vor der eigentlichen Befehls- ausführung aufgeriufen. Hier können also die Standardregeln für Befehle ab- gefangen werden, indem andere Regeln gegeben werden und die Flagge NullAkt explizit oder durch einen 'Bed'- oder 'Stop'-Befehl gesetzt wird: Raum Museum [...] VorAusf (nehmen) Text 'Die Exponate hier sind zum Anschauen, nicht zum Anfassen gedacht.' Stop (legen) Text 'Nur Kulturbanausen schmeißen Gegenstände in Museen auf den Boden.' Stop (springen singen) Text 'Die anderen Besucher würden sich bedanken.' Stop EndeAusf Der Block NachAusf wird nach der eigentlichen Befehlsausführung aufgerufen. Er dient hauptsächlich dazu, um die Standardantworten zu einem Befehl nach erfolgreicher Ausführung zu ändern: Raum Moor [...] NachAusf | | Jenach aBef | (springen) Puffer Text '(Gar nicht so einfach in diesem Morast)[#]' (singen) Text 'Es schallt hohl über das Moor.' (global) Schleife xObj (xObj in daselbst) Text 'Du schaust zu, wie [der xObj] langsam im knietiefen Schlamm versink[t].[#]' ObjNach xObj Nirwana Ende EndeAusf Die Ausführungen nach (global) werden in jedem Zug, also unabhängig vom an- gegebenen Befehl, behandelt. Hier wird überprüft, welche Gegenstände im Moor versinken. Die Puffer-Anweisung ohne Text bedeutet, daß die Standardantwort für 'springen' erst ausgegeben wird und dann erst der angegebene Text. Würde der Befehl fehlen, So würde die Standardantwort vom nächsten Text überschrie- ben. 6.5.2. Ausführungen von Objekten Häufiger benutzt man die Vor- und Nach-Ausführungen in Objektdefinitionen. Diese werden vor bzw. nach der Befehlsausführung aufgerufen, wenn das Objekt als erstes Objekt im Befehl angesprochen wurde. Mit anderen Worten: Es werden die Vor-/Nachausführungen von aObj aufgerufen. Das Beispiel oben mit der Eid- echse gehört in diese Kategorie. Hier ein anderes: Obj Seil Name 'Hanfseil' n Vor 'hanf' Subst 'seil' n 'strick' m 'tau' n Gew 2 Vol 2 Attr bindbar Besch 'Das Hanfseil macht einen recht zuverlässigen Eindruck.' Erst 'Ein Seil liegt aufgerollt zwischen den Kisten und Fässern.' VorAusf (klettern) MutterObj xObj Seil Bed (Seil an xObj) 'Du solltest das Seil irgendwo anbinden, bevor du daran kletterst. (Es sei denn, du bist Experte für den indischen Seiltrick.)' Wenn (xObj = Haken) dann Text 'Du kletterst an dem Seil in den Schacht.[#]' GeheZu Im_Schacht sonst Text 'Wagemutig kletterst du über die Schlucht. Tief unter dir rauscht das Wasser und deine Knie sind ganz schön weich, als du auf der anderen Seite ankommst.' GeheZu Andere_Seite Ende Stop (werfen) Wenn (aObj2 = Felsnase) dann Text 'Du wirfst das Seil über die Felsnase. Mit etwas Mut und Glück kannst du wahrscheinlich auf die andere Seite klettern.' ObjNach selbst an Felsnase Stop Ende EndeAusf NachAusf (nehmen) Wenn /(selbst bewegt) Text 'Das Seil fühlt sich klamm und plump an, als du es aufhebst.' (binden) Wenn (Selbst an Haken) dann Puffer Text 'Ein Ende des Seils baumelt jetzt in den dunklen Schacht hinunter...' Ende EndeAusf Die VorAusf wird hier benutzt, um Befehle abzufangen: Man kann an dem Seil klettern und es über die Felsnase werfen, Aktionen, die im Regelfall wahr- scheinlich nur eine dumme Antwort parat haben. ("Du kannst doch nicht auf ein Seil klettern!") Die NachAusf ändert die Antworten ein wenig ab: Beim ersten Aufheben wird gesagt, daß das Seil klamm ist und beim Binden des Seils an den Haken wird der Spieler mit der Nase auf die Möglichkeit gestoßen, in den Schacht zu klettern. (Das Beispiel nimmt an, daß es einen Befehl binden gibt, der das Objektattribut 'bindbar' benutzt.) Es gibt eine Besonderheit bei den Objekt-Ausführungen: Die Pseudo-Befehle. Bleiben wir einmal bei dem Beispiel mit dem Werfen. OK, ein Gegenstand wird geworfen. Mit einer VorAusf kann dan das Flugverhalten (oder was auch immer) dieses Gegenstands verändert werden. Was aber ist mit dem Ziel, dem Objekt, das den Gegenstand abbekommt? Gleiches Recht für alle: Auch er sollte die Möglichkeit bekommen, vor der Befehlsausführung dazwischenzufunken. Deshalb gibt es die Möglichkeit, zu Befehlen, die zwei Objekte verlangen, einen Pseudo-Befehl zu generieren. Im Beispiel werfen z.B. Bef werfen Name 'werfen' [...] Pseudo getroffen werfen Wenn ein solcher Pseudo-Befehl zum jetzigen Befehl existiert, dann wird auch die Vor- bzw. Nach-Ausführung des zweiten Objekts, also von aObj2, aufgerufen. Um zu unterscheiden, ob es sich um aObj oder um aObj2 handelt, wird beim Aufruf der Ausführungen von aObj2 aBef vorübergehend auf den Pseudo-Befehl gesetzt. So könnte man für eine Dartscheibe definieren: Obj Dartscheibe [...] VorAusf (getroffen) Wenn /(aObj = Dart) dann '[Der aObj] prall[t] von der Dartscheibe ab, ohne irgendwelche Punkte zu erzielen.' ObjNach aObj aRaum sonst Text 'Der Dartpfeil segelt elegant auf die Scheibe:' Wenn (Proz 2) dann Sei Dart_Pkt 50 Text 'Bulls Eye!' sonst Zufall Fakt 1 3 Jenach Fakt (2) Text 'Doppelte' (3) Text 'Dreifache' Ende Zufall Dart_Pkt Text '[Zahl Dart_Pkt]!' Mult Dart_Pkt Fakt Ende ObjNach Dart auf selbst Ende EndeAusf Die Vor- und NachAusf der Objekte sind der einzige Ort, wo aBef den Wert eines Pseudobefehls haben kann. (Außer es wird extra spezifiziert. Das ist aber gefährlich, also: Finger weg!) 6.6. Neue Befehle einbauen Am besten wird das Vorgehen beim Einbinden von eigenen Befehlen an einem Bei- spiel deutlich. Wir wollen den Befehl 'essen' einführen, so daß eßbare Objekte komplett vertilgt werden können und sie dann aus den Spiel verschwinden. Dazu führen wir zunächst ein Attribut 'eßbar' ein, das Lebensmittel kennzeichnet. ObjAttr eßbar Dann müssen wir uns überlegen, wie die Syntax des Befehls aussieht. Es wird ein Objekt geben, das aufgegessen werden soll, mehr nicht. Dieses Objekt muß der Spieler in der Hand halten, um es zu essen. Niemand ißt einen Apfel, der noch an einem Baum hängt oder einen Schokoriegel direkt aus der Handtasche. Zusammen mit einer Liste plausibler Verben könnte der Kopf der Befehlsdefini- tion dann so aussehen: Bef essen Name 'essen' Verb 'iß' 'esse' 'verspeise' 'verzehre' 'iß auf' 'esse auf' Verb 'vertilge' 'friß' 'fresse' 'verleibe dir ein' 'probiere' Verb 'versuche' Syntax das Obj (BeiMir eßbar) Mit dieser Definition haben wir zum Zeitpunkt, wo die mit diesem Befehl ver- bundene Ausführung aufgerufen wird, ein Objekt, das der Spieler bei sich hat. Ist das angesprochene Objekt nicht beim Spieler, so wird versucht es aufzu- heben, und wenn das nicht klappt, endet der Parser mit einem Fehler und die Ausführung wird nie erreicht. Im Gegensatz zu dieser Ortsangabe wird das Attribut 'eßbar' nicht überprüft. Der Parser läßt also den Befehl 'Vorschlaghammer essen' zu. Das Attribut muß in der Ausführung überprüft werden. Die passende Ausführung könnte folgende sein: Ausf Bed (aObj eßbar) '[Der aObj] schein[t] mir nicht besonders zum Verzehr geeignet zu sein.' Puffer 'Du ißt [den aObj] ratzeputz auf.' ObjNach aObj Nirwana EndeAusf Somit haben wir eine allgemeingültige Regel für das Essen von Gegenständen geschaffen: Wenn es ein Lebensmittel ist, so iß es und laß es von der Bild- fläche des Spiels verschwinden. Wenn nicht, so breche den Befehl ab. (Die Anweisung Puffer bedeutet, daß der Text erst ausgegeben wird, wenn kein ande- rer Text in einer der Nachausführungen ausgegeben wurde. So ist es möglich, den Standard-Text in einer NachAusf zu ändern.) Diese Regel gilt zwar für alle Lebensmittel, aber für einige sollen spezielle Regeln gelten. Diese werden dann am besten in den Objekt-Ausführungen direkt behandelt. Einige Beispiele: Obj Erdnußriegel [...] NachAusf (essen) Text '[Der aObj] gibt dir wieder Kraft.' Inkr Power 5 EndeAusf Obj Obsttörtchen [...] NachAusf (essen) Puffer Text '(Hat gut geschmeckt!)' EndeAusf Obj Giftpilz [...] VorAusf (essen) Text 'Du knabberst an dem Pilz.' Wenn (Proz 50) dann Text 'Beim Kauen denkst du an einen Rat deiner Großmutter: keine unbekannten Pilze essen! Ein sehr, sehr unruhiges Gefühl in der Magen/ gegend gibt deiner Großmutter Sekunden später Recht.' Gestorben sonst Text 'Er hat einen eigenartigen Geschmack.' Ende Stop EndeAusf In unserem neuen Befehl passiert tatsächlich etwas, das Objekt wird verändert. Es verschwindet nämlich, wenn es eßbar ist. Sehr viele Befehle produzieren aber nur eine Antwort, ohne irgendetwas zu bewirken. Das beste Beispiel hier- für sind wohl die Befehle 'untersuchen' und 'Lage'. Solche Befehle sind sehr einfach zu realisieren, da alle besonderen Regeln direkt bei den Objekten oder bei den Räumen definiert werden: Bef putzen Verb 'putze' 'säubere' 'wasche' 'mache sauber' 'staube ab' Syntax dasObj Ausf Puffer 'Du hast wohl einen Putzfimmel.' EndeAusf Obj Teekessel VorAusf (putzen) Text 'Hey! Der alte Kessel war in Wirklichkeit Aladins längst vergessene Wunderlampe!' Tausche selbst Wunderlampe Stop EndeAusf Das Einfügen von eigenen Befehlen erfolgt also ganz schematisch. Der Befehl selbst ist nur eine Regel, die für möglichst viele Objekte oder Räume gilt. Sonderregelungen werden bei den Objekten getroffen. Wenn man einmal ein paar Befehle geschrieben hat oder bestehende Befehle äbgeändert hat, wird man schnell hinter das System schauen. Zu TAG gibt es den Datensatz NORMAL.ADV, der die häufigsten Befehle enthält, die nicht standardmäßig zu TAG gehören. Wer diese benutzen möchte, kann diese Datei am Anfang seines Adventures mit #DAT 'normal.adv' einbinden. Die meisten Befehle in dieser Datei sind einfache Befehle, die nur eine Antwort produzieren. Diese Datei kann natürlich nach Belieben abgeändert werden und auf das jeweilige Projekt angepaßt werden. Die Benutzung dieser Datei empfeiehlt sich besonders für Einsteiger. 7. ERSTELLEN DER TEXTE 7.1. Textblöcke Neben der Möglichkeit, Ausgabetexte direkt in einem Anweisungsblock mit dem Text-Befehl anzugeben, kann man Texte auch auf gesonderten Blöcken definieren. Sie können dann mit der Angabe ihres Blocks und der Position im Block ange- sprochen werden. Dies ist noch ein Überbleibsel aus den frühen Tagen von TAG. Diese Möglichkeit wurde trotzdem nicht abgeschafft, da sie in manchen Situa- tionen nützlich ist, da man sich auf die Texte aus einem Textblock auch mit Variablen beziehen kann. Die Texte werden am Schluß der Adventure-Datei gespeichert, genau wie die Texte der Raum- und Objektbeschreibungen und die Standardantworten. Die Texte werden in Blöcke unterteilt. Es können bis zu 251 Textblöcke ange- geben werden. Jeder Block kann 255 Texte enthalten. Die Definition eines Textblocks sieht folgendermaßen aus: Block '' '' ... '' Hierbei sind: Blockkennziffer von 0 bis 255. Textblöcke können in beliebi- ger Reihenfolge definiert werden. Nummer des Texts. Textnummern müssen innerhalb eines Blocks in aufsteigender Reihenfolge aufgegeben werden, da sie se- quentiell abgespeichert werden. Dabei müssen die Nummern nicht unbedingt aufeinanderfolgen. Man kann z.B. Text 7 nach Text 2 definieren, die Datei wird dann mit 4 leeren Strings anstelle der Texte 3-6 aufgefüllt. Der zur Nummer gehörende Text wird in einfache Anführungs- striche eingeschlossen und beginnt hinter der Nummer. Er kann über beliebig viele Zeilen gehen und außer Steuerzeichen und dem Hochkomma beliebige Zeichen enthalten. Ein Textblock endet mit dem Beginn des nächsten Blocks (der nicht unbedingt ein Textblock sein muß). Es gibt zwei Textblöcke, die eine besondere Bedeutung haben: Standard (Block 0) Auf diesem Block werden die Standardantworten abgelegt, die vom Parser und den bereits definierten Befehlen verwendet werden. Wird dieser Block nicht angegeben, so werden diese Texte von der Datei TAG.STD bzw. der bei #STD angegebenen Datei gelesen. Mit Text 0 kann also der Standardtext ausgegeben werden. Fußnoten (Block 255) Wenn im Spiel Fußnoten benutzt werden, dann müssen sie in diesem Block abgelegt werden. Der Programmierer muß darauf achten, daß der Text zu einer Fußnote auch angegeben wird. Diese Blöcke können mit der Notation 'Block x' oder mit den Schlüsselwörtern 'Standard' und 'Fußnoten' angegeben werden. 7.2. Anweisungen im Text Für alle Texte, egal ob gesondert in Textblöcken oder direkt im Ausführungs- block definbiert, gelten die folgenden Regeln: - Die Texte werden nacheinander geschrieben. Ein Text fängt dort an, wo der letzte aufgehört hat. Hört ein Text nicht mit einem Leerzeichen auf, so wird automatisch ein Leerzeichen gesetzt (außer nach einem Absatz). - Ein Zeilenumbruch innerhalb des Textes wird wie ein Leerzeichen betrach- tet. Leerzeichen, die sich vor oder nach dem Text befinden, werden nicht beachtet. Der signifikante Bereich einer Zeile darf nicht länger als 80 Zeichen sein. - Ist das letzte Zeichen einer Zeile ein Schrägstrich, so wird die nächste Zeile direkt ohne Leerzeichen an die vorhergehende angefügt. Das geht auch am Ende eines Textes: Der nächste Text, der ausgegeben wird 'klebt' dann ohne trennendes Leerzeichen am vorherigen. - Ein doppelter Zeilenumbruch innerhalb eines Textes, d.h. eine leere Zeile zwischen zwei Textabschnitten, bewirkt einen Absatz zwischen diesen beiden Abschnitten. Dasselbe kann mit der Sequenz '[#]' im Text erreicht werden. - Da das Hochkomma zum Abtrennen der Strings benötigt wird, können Apo- strophe durch das Prozentzeichen oder durch die Textbefehle '/"' oder '/,' ersetzt werden: 'Thomas% Buch' Thomas' Buch '/,s ist gar schaurig.' 's ist gar schaurig. '"Die Parole ist /"Rot/"."' "Die Parole ist 'Rot'." - Es gibt verschiedene Sonderbefehle, die in eckige Klammern eingeschlossen werden. Diese Befehle werden intern als Sequenzen, die mit einem Schräg- strich beginnen, gehandhabt. Einige Befehle können auch als /-Sequenz an- gegeben werden. Die Textbefehle sind: [Absatz] oder [#] bewirkt einen formatierten Zeilenumbruch, d.h. ein neuer Ab- satz beginnt. Das Format des Umbruchs kann mit dem Befehl Absatz in der Umgebungsdefinition festgelegt werden. (Dies entspricht /#) [/] schreibt einen Schrägstrich. (Entspricht //) [%] schreibt ein Prozentzeichen. (Entspricht /%) [,], ["] schreiben ein Apostroph. (Dies entspricht /" oder /,) [[, ]] schreiben die eckigen Klammern. (Entspricht /( und /) ) [-] ist ein bedingter Trennstrich. Wenn dort umgebrochen wird, wird ein Bindestrich geschrieben, ansonsten gar nichts. (/-) [_], [] schreiben ein geschütztes Leerzeichen. Das bedeutet, daß an dieser Stelle nicht umgebrochen werden darf. (/_) [^] schreibt die Endung eines Adjektivs. Das ist nur möglich, wenn es in einem Objektnamen auftaucht, z.B., wenn der Objektname mit einer Aktion ausgegeben wird. Im Objektnamen ist es das- selbe wie ein Dach. (Entspricht /^) [~] schreibt 'n' oder 'en' bei Plural-Objekten im Dativ und bei maskulinen Objekten im Akkusativ und Dativ. Das ist wie bei [^] auch nur für die Objektausgabe möglich. (Entspricht /~) [Umbr] oder [x] bewirkt einen unformatierten Zeilenumbruch, d.h. der Cursor geht an den Anfang der nächsten Zeile, es gibt weder Leer- zeile noch Einrückung. (Entspricht /x) [Aufz] oder [:] schreibt das Aufzählungszeichen, wie es z.B. bei der Inven- tarliste verwendet wird. [Fett] oder [f] Fettdruck ein. (Fett bedeutet, daß eine andere Farbe benutzt wird.) (/f) [Norm] oder [n] Fettdruck aus, die normale Textfarbe wird verwendet. (/f) [Tab] oder [->] schreibt einen Tab, d.h. rückt zur nächsten Tabstop-Position (ganzzahliges Vielfaches der Tabulatorweite) vor. [TTab] oder [-->] schreibt einen Tab mit doppelter Tabulatorweite. [@] wird häufig in den Standard-Aussagen in TAG.STD verwendet. Es ist ein Überbleibsel aus den Zeiten von 'Das Amulett', wo komplizierte Texte in die Puffervariable 'Aussage' geschrie- ben wurden. Dieser Befehl schreibt diesen Puffer. Er wird aber nur noch sehr selten benutzt. In der Datei TAG.STD wird die Bedeutung der Puffervariable kurz beschrieben, falls man die Datei ändern möchte. [: ] bewegt den Cursor in die Spalte , wenn er nicht bereits über diese Position hinaus ist. [+ ] bewegt den Cursor an die Stelle , wenn er nicht schon über diese Stelle hinaus ist und setzt den Einzug am linken Rand für den momentanen Textabsatz auf . Der Absatz wird also hängend geschrieben. [- ] setzt den Einzug am rechten Textrand auf . Das heißt, es wird nun Zeichen früher umgebrochen. [= ] setzt den Einzug auf beiden Rändern auf . Dies entspricht den beiden Anweisungen [+ ] und [- ] nacheinander. - Die Zeichen, die nicht im 7-Bit-ASCII-Zeichensatz enthalten sind, d.h. die Zeichen mit Akzenten und Umlauten, können durch zwei andere Zeichen in eckigen Klammern ausgedrückt werden: [.a] Accent aigu auf a, e, i, o, u, y [`a] Accent grave auf a, e, i, o, u [^a] Zirkumflex (Dach) auf a, e, i, o, u ["a] Umlaut auf a, e, i, o, u, y [~a] Tilde auf a, n, o [,c] Cedille an c [/o] skaninavisches durchgestrichenes o [oa] schwedisches a mit Ring [ae] skandinavische ae-Ligatur [sz] scharfes s (Es-Zett) [dt] isländisches Eth [th] isländisches Thorn [my] griechisches My [CO] Copyright [RO] Registriertes Warenzeichen [SS] Paragraph [=L] Pfund Sterling [c/] Cent [xo] Währungs-Zeichen [xx] Multiplikationszeichen [oo] Grad-Zeichen [<<],[>>] französische Anführungszeichen [!!],[??] spanische Ausrufe- und Fragezeichen (auf dem Kopf) [=>],[<=] Größergleich und Kleinergleich [+-] Plusminus [_o],[_a] spanische/italienische Ordinalzeichen [12],[14],[34] ein halb, ein Viertel bzw. drei Viertel [^1],[^2],[^3] hochgestellte Eins, Zwei bzw. Drei [||] gebrochener Strich Die Buchstaben nach den Akzenten können auch groß sein, dann wird der Ak- zent natürlich auf den Großbuchstaben gesetzt. In welcher Reihenfolge die beiden Zeichen angegeben werden, spielt keine Rolle. So sind z.B. [^e] und [e^] dasselbe, aber verschieden von [^E]. Diese Option ist nur nützlich, wenn diese Zeichen nicht auf der Tastatur sind. Dieselben Zeichen können auch wie üblich generiert werden, da sie von TAG automatisch in den Zeichensatz nach ISO-8859-1 übertragen werden. - Weiterhin gibt es Befehle, die zur Ausgabe von variablen Objekten in Textstrings dienen. Auch diese Befehle stehen in eckigen Klammern: [dasObj ] gibt das Objekt mit bestimmtem Artikel im grammatikalischen Fall aus. ('der Ball') Da dieser Befehl sehr häufig vorkommt, kann man ihn abkürzen mit den folgenden Befehlen: [der ], = 0 (%Nom, Nominativ) [den ], = 1 (%Akk, Akkusativ) [dem ], = 2 (%Dat, Dativ) Der Fall wird hier aus dem Artikel bestimmt. Der Artikel muß hier männlich sein, da dies der einzige Genus ist, bei dem die Arikel für die drei Fälle verschieden sind. (Am besten man denkt dann nicht an ein 'Objekt' sondern an einen 'Gegenstand'.) [einObj ] gibt das Objekt mit unbestimmtem Artikel im Fall aus ('ein Ball'). Auch hier gibt es die Abkürzungen: [ein ], [einen ], [einem ] [keinObj ] gibt das Objekt verneint im Fall aus ('kein Ball'). Die Abkürzungen sind: [kein ], [keinen ], [keinem ] [obj ] gibt das Objekt ohne Artikel im Fall aus. ('Ball') [] gibt das Objekt ohne Artikel im Nominativ aus. [es ] gibt das passende Pronomen (Fürwort) für im Fall aus. [präp] oder [p] gibt die Präposition aus dem eingegebenen Befehl aus. [ist ] gibt das Verb 'sein' an das Objekt angepaßt aus, d.h. gibt 'ist' aus, wenn im Singular ist, und 'sind', wenn im Plural steht. Dies dient dazu, Aussagen wie 'Die Zwerge ist müde.' zu umgehen. [hat ] gibt das Verb 'haben' an angepaßt aus, d.h. je nachdem, ob im Singular oder Plural steht, wird 'hat' oder 'haben' ausgegeben. [wird ] gibt das Verb 'werden' an angepaßt aus, d.h. je nachdem, ob im Singular oder Plural steht, wird 'wird' oder 'werden' ausgegeben. [t ] gibt die Endung eines schwachen Verbs an ange- paßt aus, d.h. 't' oder 'en'. Für die meisten Verben gilt diese Beugung. Zum Beispiel gibt 'komm[t ]' je nach Anzahl 'kommt' oder 'kommen'. [/ ] gibt das komplette gebeugte Verb an. Steht das Objekt in der Einzahl, so wird ausgegeben, andern- falls , z.B. '[muß/müssen xObj]'. Die gesamte Sequenz muß dabei in einer Zeile stehen! Diese Option kann auch für verschiedene Zeiten benutzt werden, z.B. '[ging/gingen xObj]'. [liste ] gibt die zuvor mit 'ObjListe' erstellte Liste im Fall aus. Für den Nominativ, d.h. den Fall 0, kann dann das Verb mit der Objektangabe 0 benutzt werden: 'Hier [ist 0] [liste 0].' [sitz] Gibt abhängig von bSitz den Stamm des passenden Ruheverbs aus: 'sitz', 'steh' oder 'lieg'. Es wird nur der Stamm ausgegeben, damit das Verb angepaßt werden kann, wenn der Spieler in verschiedenen Per- sonen agesprochen wird. Zum Beispiel: 'Ich [sitz]e...', 'Du [sitz]st...' oder 'Sie [sitz]en...' (Die 'zs'- Kombination wird dabei erkannt und in ein 's' umge- wandelt.) [setz] Gibt abhängig von bSitz den Stamm des passenden Bewegungsverbs aus: 'setz', 'stell' oder 'leg'. So können auch allgemeine Satzkombinationen wie 'Ich habe mich hinge[setz]t.' verwirklicht werden. (Zum Glück sind es schwache Verben.) [in] Befindet sich der Spieler in einem InObjekt, so wird 'in' ausgegeben, ansonsten 'auf'. Die letzten drei Befehle funktionieren natürlich nur, wenn der Spieler auf einem anderen Objekt sitzt, steht oder liegt. Das sollte vom Programmierer zuerst überprüft werden. Sie werden auch häufig bei den Standardantworten benutzt. [] gibt den Zahlenwert einer Flagge aus. [num ] gibt den Zahlenwert einer Flagge aus, aber benutzt (kardinale) Zahlwörter für die Zahlen bis hundert. [ord ] gibt den Zahlenwert einer Flagge aus, aber benutzt ordinale Zahlwörter (erste, zweite, ...) für die Zahlen bis hundert und schreibt sonst einen Punkt hinter die Zahl (145.). [rom ] gibt den Zahlenwert einer Flagge als römische Zahl aus. Achtung! Die Zahl kann nur im Bereich von 1 bis 3999 liegen. [Buchst ] gibt den Buchstaben aus, der im Alphabet an der Stelle steht. Ist kleiner als 1 oder größer als 26, so wird ein Fragezeichen ausgegeben. [] gibt den Zustand aus (wenn er angegeben wurde). [Zust ] gibt den Zustand des Objekts als Satz aus, wenn der Zustand einen Namen hat ('Sie ist offen.'). Ansonsten wird nichts ausgegeben. [] gibt den Namen des Befehls aus. [Befsatz] gibt den aktuellen Befehlssatz aus, wie er vom Parser erkannt wurde, z.B. 'den Zwerg mit dem Hämmerchen erschlagen.' oder 'nach Süden gehen.' [Zeit] gibt die Uhrzeit im Spiel (Stunden:Minuten) aus. [] gibt den String aus. Dieser String kann natür- lich wieder Textbefehle in eckigen Klammern enthalten. Man sollte nur aufpassen, daß sich ein String nicht selbst 'aufruft'. [Text ] gibt den Text aus dem Textblock aus. Auch hier sollte aufgepaßt werden, daß der Text sich nicht selbst aufruft. [] setzt die Fußnote . ist dabei die in- terne Nummer, extern werden die Fußnoten nach der Reihenfolge ihres Auftretens numeriert. Die externe Fußnotennummer erscheint dann in der Form [x] im Text. Mit der Eingabe 'FUSSNOTE x' oder 'FN x' kann der Spieler dann die Fußnote lesen. Der Fußnotentext ist der Text mit der Nummer im Block 255. Es sollte sichergestellt sein, daß es ihn gibt. Es können die Fußnoten 1 bis 255 definiert werden. [] ruft die Aktion auf, die der Textausgabe dienen soll. (Mit diesem Befehl kann man reine Textgrößen wie z.B. Raum- und Objektbeschreibungen und -namen variabel machen.) Die Argumente der Textbefehle sind: ist ein Objekt oder ein Platzhalter für ein Objekt. Die Objektangabe kann auch weggelassen werden, dann wird das Objekt aus dem letzten Textbefehl benutzt. So sind etwa '[Der aObj] [ist aObj] dagegen und [er aObj] streik[t aObj].' und '[Der aObj] [ist] dagegen und [er] streik[t].' gleichwertig, wobei die zweite Variante besser zu lesen ist. Vorsicht bei Sätzen, die nicht mit einem Subjekt anfangen! Dort muß die Objektangabe beim Verb stehen: 'Langsam [wird aObj] [der] von den Flammen verzehrt.' kann folgende Werte annehmen: 0, %Nom Nominativ (1. Fall) 1, %Akk Akkusativ (4. Fall) 2, %Dat Dativ (3. Fall) Es empfiehlt sich, die Abkürzungen mit impliziter Faller- kennung zu benutzen. Wenn der erste Buchstabe eines Textbefehls zur Textausgabe ein Groß- buchstabe ist, so wird die auszugebende Zeichenkette mit einem großen Buchstaben am Anfang ausgegeben, ansonsten bleibt der String unver- ändert. Mit dieser Ausnahme können Textbefehle - genau wie die anderen Anweisungen in TAG - in Groß- oder Kleinbuchstaben angegeben werden. So sind [der aObj] und [Der aObj] verschieden, [DER AOBJ], [Der aObj] und [ Der aObj ] aber nicht. (Es gilt das erste signifikante Zeichen.) Mit dieser Ausnahme können Textbefehle - genau wie die sonstigen Anweisungen in TAG - in Groß- oder Kleinbuchstaben angegeben werden. Wenn die TAG-Datei erstellt ist, könnt Ihr Euch diese Datei ja einmal im Editor ansehen. Es erscheinen lauter eigenartige Zeichen. Um zu vermeiden, daß irgendwelche Leute die Texte lesen, bevor sie das Spiel spielen und so Hinweise auf die Lösung der Rätsel bekommen, habe ich die Texte chiffriert. Der Code ist simpel, aber erfüllt hoffentlich seinen Zweck. 8. ALLGEMEINES 8.1. Stilparameter und Formate Im Block Umgebung werden allgeimeine Angaben über das Adventure und über die Text- und Absatzformate gemacht. Folgende Anweisungen werden in diesem Block verstanden: Name '' Name für das Adventure. Wird nur intern für Systemmeldungen benutzt. Default ist . Kennung '' Kurze Kennung, die an den Anfang von abgespeicherten Spiel- ständen geschrieben wird, um zu überprüfen, ob es sich um einen Spielstand dieses Spiels handelt oder nicht. Ob die Daten im Spielstand manipuliert sind, wird hinterher extra überprüft. Default ist . Text Definiert die Textfarbe, Default ist hellgrau auf schwarz. Fett Definiert die Farbe für fetten Text, Default ist weiß auf schwarz. Zeile Definiert die Farbe für die Statuszeile. Diese Farbe wird auch für ausgewählte Elemente im Dateifenster benutzt. Default ist Weiß auf Blau. Rahmen Definiert die Farbe für den Rahmen der Datei-Dialogbox. Default ist schwarz auf hellgrau. Vordergrund, d.h. Textfarbe. Mögliche Angaben sind: 0 %Schwarz 8 %Dunkelgrau 1 %Blau 9 %Hellblau 2 %Grün 10 %Hellgrün 3 %Türkis 11 %Aquamarin 4 %Rot 12 %Hellrot 5 %Violett 13 %Pink 6 %Braun 14 %Gelb 7 %Hellgrau 15 %Weiß Hintergrund für den Text. Hier können nur die 'dunklen' Farben von 0 bis 7 angegeben werden. Obwohl theoretisch 128 Farbkombinationen möglich sind, denkt bitte daran, daß Spieler u.U. stundenlang mit Eurer Farbwahl konfrontiert sind. Blau- und Grautöne sind also Pink und Türkis vorzuziehen! Einige Stilparameter können während des Spiels geändert werden. Sie sind auf folgenden Systemflaggen abgelegt, die alle mit einem Doppel- kreuz beginnen: #Absatz Format eines Absatzes: 0 keine Einrückung, keine Leerzeile zwischen Absätzen 1 Leerzeile zwischen Absätzen 2 Einrückung (eine Tabulatorweite) 3 Einrückung und Leerzeile. Default-Absatzformat ist eine Leerzeile zwischen Absätzen ohne Einrückung (1). #Eingabe Format der Eingabezeile: 0 Eingabe in Großbuchstaben, d.h. alle Buch- staben werden als Großbuchstaben ausgegeben. 1 fettgedruckte Eingabe in Großbuchstaben 2 Eingabe in Klein- und Großbuchstaben, d.h. die Zeichen erscheinen wie eingegeben. 3 fettgedruckte Eingabe mit gemischten Buch- staben. Default ist hier Fettdruck in Großbuchstaben (1). Dieser Wert beeinfußt nur das Ausgabeformat. Unabhängig davon wird die gesamte Eingabe als Kleinbuchstaben betrachtet. #Raumname Format für lange Raumbeschreibungen: 0 Kurze Raumbeschreibung vor der ausführlichen Beschreibung mit anschließendem unformatiertem Zeilenumbruch 1 Kurze Raumbeschreibung vorher in Fettdruck 2 Kurze Raumbeschreibung vorher mit formatiertem Zeilenumbruch (Absatz) 3 Kurzbeschreibung fett und als Absatz 4 keine kurze Raumbeschreibung vor der langen Default ist hier keine Kurzbeschreibung (4). #Leiste Flagge für Leistendarstellung: 0 keine Statusleiste am obenren Bidschirmrand 1 Darstellen der Statusleiste (Default) #Meldung Meldungen bei Punktstandänderung: 0 keine Meldung 1 Punktestandsänderung wird angezeigt (Default) #Links Anzeige im linken Teil der Statuszeile #Mitte Anzeige in der Mitte der Statuszeile #Rechts Anzeige im rechten Teil der Statuszeile Für die Statuszeile können folgende Angaben gemacht werden: 0 keine Anzeige 1 Raumname des momentanen Aufenthaltsraums, inkl. Angabe von möglichen Sitzen, Liegen und Standflächen. ("Hotelzimmer, im Bett") 2 Anzahl der Züge 3 Anzahl der Punkte 4 Anzahl der Punkte und Züge (z.B.: "4/55") 5 Uhrzeit im Spiel (z.B.: "12:45") 6 Mögliche Ausgänge im Raum als Liste der Richtungsabkürzungen (z.B.: "nw, s, rein") 7 Anzeige des Strings Statuszeile. Der String muß natürlich während des Spiels definiert werden. #Besch Flagge für Raumbeschreibungen 0 Knappe Raumbeschreibungen (Default) 1 Ausführliche Raumbeschreibungen (Bei jedem Betreten eines Raums wird die ausführliche Raumbeschreibung ausgegeben.) 2 Superknappe Beschreibungen (Es wird immer nur der kurze Raumname ausgegeben.) #Tab Tabulatorweite in Leerzeichen, Default ist acht. #Liste Format für Objekt-Listen (bei ObjListe interessant) +1 bestimmte Artikel +2 Verbindungswort 'oder' +4 Aufzählung in Kommas statt Klammern (Das + bedeutet, daß die Stile beliebig summiert werden können, z.B. 'oder' und in Klammern = 6) #Inv Flagge für das Format der Inventarliste: 0 Hochformat (Liste mit Gedankenstrichen) 1 Querformat (als vollständiger Satz) #Person Flagge, die die grammatikalische Person des Spielers angibt. Momentan kann sie folgende Werte annehmen: 0 zweite Person Singular (%du) 1 erste Person (%ich) 2 Höflichkeitsform in der dritten Person Plural (%Sie, wird immer groß geschrieben.) Diese Flagge wird für die Ausgabe der reflexiven Verben und der Objekte mit Possesivpromomen verwendet. Die Werte entsprechen dabei den oben angegebenen. Der Benutzer muß dafür sorgen, daß keine unsinnigen Werte eingegeben werden. 8.2. Synonyme Zu guter letzt kann man dem Parser noch Synonyme mitteilen. Dies geht mit diesem Befehl, der überall außerhalb eines Blocks stehen kann: Synonym '' '' ist ein Ausdruck aus einem oder zwei Wörtern, der ersetzt werden soll. ist ein Ausdruck aus einem oder zwei Wörtern, der für im Befehl eingesetzt wird. Die Ersetzung erfolgt dabei direkt nach der Eingabe des Befehls, d.h. der Parser arbeitet schon mit den ersetzten Ausdrücken. Das kann natürlich zu Überraschungen führen, wenn der Parser einen Fehler findet, und dann andere Worte anmeckert, als der Spieler eingegeben hat. Aber im allgemeinen wird so die Eingabevielfalt erhöht. Es gibt vier Arten von Synonymen: - Wort gegen Wort Das ist z.B. bei Richtungen denkbar. Zu jeder Richtung können eine lange Beschreibung und eine Abkürzung angebenen werden, mehr nicht. Das reicht auch in den meisten Fällen aus. Manchmal ist es aber schön, andere Worte benutzen zu können: Richtung H 'unten' 'r' Synonym 'runter' 'r' Synonym 'abwärts' 'r' - Wort gegen zwei Wörter Dies ist häufig notwendig bei Wörtern, die aus einer Präposition und 'das' oder 'dem' zusammengezogen wurden. Da der Parser diese Wörter wie 'ins', 'am' usw. nicht versteht, sollten sie als Synonyme ange- geben werden: Synonym 'ums' 'um das' Die Synonyme für die schon in TAG eingebauten Präpositionen sind bereits angegeben. - Zwei Wörter gegen ein Wort Denkbar ist hier der Fall, daß der Befehl 'hallo' geschrieben werden soll. Als Synonyme sollen 'Guten Tag' oder 'Guten Morgen' zugelassen werden. Verben können immer nur aus einem Wort bestehen. Wenn man hier nicht die Präpositionen 'tag' und 'morgen' einbauen will, was eine ziemliche Vergewaltigung der Sprache wäre, aber formal korrekt ist, kann man angeben: Synonym 'guten morgen' 'hallo' Synonym 'guten tag' 'hallo' - Ein Wort gegen nichts Ein bestimmtes Wort soll vom Parser einfach ignoriert werden. Dies wird im Moment nur mit 'und' und 'dann' gemacht. Man könnte hier vielleicht Adverbien angeben, damit man die Tür 'leise' aufmachen kann und 'vorsichtig' nach Norden gehen kann. (Das wäre sogar ziemlich ungefährlich, da die Adjektive der Objekte meist gebeugt sind und sich so vom Adverb unterscheiden.) Man kann also angeben: Synonym 'vorsichtig' '' Synonym 'bitte' (Die leeren Anführungszeichen können weggelassen werden.) Die Synonyme sind nur eine Notlösung, um manche Satzkonstrukte zu ermöglichen. Wenn es geht, sollten die Vokabellisten der Befehle, Objekte usw. direkt benutzt werden. 8.3. Funktionstasten Die Funktionstasten F1 bis F10 können mit häufig gebrauchten Befehlen belegt werden. Der Befehl dazu, der außerhalb eines Blocks stehen muß, heißt: Funkt '' Nummer der Funktionstaste von 1 bis 10 Befehlstext der beim Drücken der Funktionstaste ausgegeben werden soll. Der Text sollte vom Spiel als Eingabe verstanden werden, und möglichst allgemeingültig sein. Ob der Parser den Befehl erkennt, wird hier nicht überprüft. Beim Drücken der Funktionstaste wird der Text nach dem Prompt ausgegeben und direkt analysiert. Der Spieler hat also keine Möglichkeit, Wörter vor oder nach dem Text einzugeben. Ab- kürzungen für 'nimm', 'untersuche' usw. machen hier also keinen Sinn. Folgende Belegungen für die Funktionstasten sind bereits voreingestellt: F1 Ende F2 Neu F3 Laden F4 Speichern F5 Knapp F6 Ausführlich F7 Meldung F8 Punkte F9 Zurück F10 Manuskript Diese Meta-Befehle sind sicher für die meisten Spiele nützlich. Wird als Text ein leerer String '' angegeben, so hat die Taste keine Belegung. Wer will, kann also die voreingestellten Belegungen löschen. 8.4. Punkte Für einige Handlungen im Spiel soll es Punkte geben. In TAG können für 255 Aktionen Punkte verteilt werden. Alle Aktionen, für die es Punkte geben soll, werden am besten aufgeschrieben und durchnumeriert, etwa: 1. Schlüssel unter der Fußmatte finden (2 Punkte) 2. Dem Mädchen die Sprechpuppe wiedergeben (5) 3. Holzkiste mit Brecheisen aufstemmen (4) ... ... Wenn dann im Spiel die Punkte vergeben werden sollen, verwendet man die Anweisung Punkte ist die laufende Nummer des Punktbeitrags, die vergebene Punktzahl. Je nachdem, ob die Meldung ein- oder ausgeschaltet wurde, erscheint sie dann auf dem Bildschirm. Um die Gesamtpunktzahl zu erhalten, kann man die vordefiniere Variable Punkte verwenden. Um also den Punktestand beim Finden des Schlüssels zu ändern, sind die An- weisungen: Ausf [...] Text 'Unter der Fußmatte finde ich einen kleinen Schlüssel. Bingo!' Punkte 1 2 [...] Ende Achtung! Es können keine negativen Punktzahlen angegeben werden. Wir denken positiv. Es können aber wieder Punkte abgenommen werden, wie z.B. bei der klassischen Schatzsuche. Der Spieler findet nach langen Strapazen eine Perlenkette und bekommt zwei Punkte: Punkte 10 2 Dann schleppt er sie ins Trophäenzimmer und legt sie in die Vitrine und bekommt dafür weitere 8 Punkte. Man beachte, daß sich Punkte, die in einem Handlungsstrang befinden, summieren können. Dies funktioniert nur, weil Ihr die Kette erst nehmen müßt, bevor Ihr sie in die Vitrine legen könnt. Ihr habt also jetzt zusammen mit dem ersten Auffinden zehn Punkte erhalten: Punkte 10 10 Wird nun die Kette wieder aus der Vitrine genommen, so werden wieder zwei Punkte vergeben: Punkte 10 2 Da der Punktestand Nr. 10 aber vorher zehn war, gehen eigentlich acht Punkte verloren. Die Meldungen zur Punktestandsänderung geben immer die Veränderung zum vorherigen Stand an, in diesem Fall also 'Du hast soeben 8 Punkte ver- loren.'. Anstatt die beiden Handlungen in eine Punktrechnung zu packen, kann man für das Ablegen auch eine zweite Aktion definieren, etwa: Punkte 10 2 | fürs Finden [...] Punkte 11 8 | fürs in die Vitrine legen Viele Punktzahlen sind nicht mit bestimmten Aktionen, sondern eng mit Objekten oder Räumen verbunden. Für diese Fälle gibt es die Befehle ObjPunkte und RaumPunkte So kann man die Punktevergabe bequem in Klassendefinitionen vornehmen, und spart sich so eine umständliche Listenführung. So könnte die Perlenkette oben von der Objektklasse Schatz sein: ObjKlasse Schatz ... Var Nimm_Wert 2 Var Pack_Wert 10 NachAusf (nehmen) ObjPunkte selbst Nimm_Wert (hineinlegen) Wenn (aObj2 = Vitrine) dann Text 'Du legst [den selbst] vorsichtig in die Glasvitrine.' ObjPunkte selbst Pack_Wert sonst ObjPunkte selbst 0 Ende (hinlegen) ObjPunkte selbst 0 EndeAusf Ein weiteres Beispiel sind markante Räume, die beim Besuch Punkte geben: RaumKlasse PunktRaum NachAusf (gehen) RaumPunkte daselbst 5 EndeAusf Die Werte der einzelnen Punktzahlen können folgendermaßen als Variable ange- sprochen werden: Pkt., Pkt. ObjPkt., ObjPkt. RaumPkt., RaumPkt. Einzelne Aktionen können immer nur bis zu 255 Punkte geben. Die Summe der Einzelpunkte kann jedoch größer sein. Außerdem können immer nur positive Punktzahlen vergeben werden. Dennoch ist es mit einem Trick möglich, nega- tive Punktzahlen zu erreichen: Die Variable Pktbasis enthält eine Integer-Zahl, die immer zum Punktestand addiert wird. Wird Punktbasis am Anfang auf sagen wir mal 60 gesetzt, so ist der Anfangspunktestand 60, obwohl noch kein Rätsel gelöst wurde. Dieser Wert kann auch negativ sein, wir können den Spieler sich auch aus den Miesen hocharbeiten lassen. Nehmen wir einmal an, der Spieler würde mit Minuspunkten bestraft, wenn er einen Spiegel zerbricht. Er soll aber mit Null Punkten starten. Dann lautet die Anfangsanweisung: Aktion Anfang Ausf [...] Sei Pktbasis -49 Sei Pkt.1 49 EndeAusf So bekommt der Spieler (lautlos) 49 Punkte, aber er merkt es nicht, weil er über die Variable Punktbasis 49 Punkte abgezogen bekommt, und so wieder bei Null steht. Zerbricht er nun den Spiegel, so passiert das folgende: [...] ObjZust Spiegel Kaputt Punkte 1 0 Die Einzelpunktzahl 1 wird also auf Null zurückgesetzt, eine Meldung besagt, daß der Pechvogel 7x7 Strafpunkte bekommt und die Punktzahl fällt um 49 Punkte. Das Ändern der Variable Punktbasis geschieht immer lautlos, es sei denn, es wird extra programmiert. PktBasis kann während des Spielverlaufs verändert werden. Zum Beispiel könnte sie alle hundert Züge um einen Punkt herabgesetzt werden, damit der Spieler zügig vorangeht und nicht lange Zeit verliert. Die Gesamtpunktzahl ergibt sich also immer aus der Summe aller mit 'Punkte' definierten Einzelpunktzahlen plus der Summe der Objekt- und Raumpunktzahlen plus der globalen Variable PktBasis. Wem das System der ereignis-, raum- und objektbezogenen Punktvergabe nicht gefällt, kann also nur PktBasis für den Punktestand verwenden. _____________________________________________________________________________ III. BEISPIELE 9. RÄUME 9.1. Wann werden Wege benutzt? Wozu genau ist die Weg-Definition gut? Das ist eine gute Frage. Das Konzept der Wege kommt aus den Anfangstagen von TAG. Es soll Situationen abfangen, in denen es eine besondere Regel für die Fortbewegung gibt. Die gewöhnliche Definition der Landkarte, bei der nur Räume und Antworten benutzt werden, deckt die meisten Situationen ab, selbst wenn Türen Räume voneinander trennen (s. Kap. 10.2). Manchmal gibt es aber besondere Regeln, wenn zum Beispiel ein Tunnel in zwei verschiedene Räume führen kann, jeweils mit einer Wahrscheinlichkeit von 50%: Weg Zufallsweg Ausf Wenn (Proz 50) dann GeheZu Schweizer_Käse_Raum sonst GeheZu Orientalischer_Raum Ende EndeAusf Und das sieht doch übersichtlicher aus als dies hier: Raum Dreckiger_Raum [...] VorAusf (gehen) Wenn (aRitg = W) dann Wenn (Proz 50) dann GeheZu Schweizer_Käse_Raum sonst GeheZu Orientalischer_Raum Ende Stop Ende EndeAusf Prinzipiell sind aber beide Methoden gleich. 9.2. Die Raumbeschreibung Raumbeschreibungen sind ein wichtiger Bestandteil von Adventures. Sie tauchen häufig auf und geben dem Spieler einen ersten Eindruck von einem Ort. Deshalb hier eine Aufzählung dessen, was der Befehl Lage macht: 1. Die eigentliche Raumbeschreibung: a. Die kurze Raumbeschreibung, d.h. der Name des Raums, wird aus- gegeben. Das passiert immer, wenn knappe Beschreibungen aktiv sind und der Spieler den Raum bereits kennt oder wenn #Besch kleiner als vier ist. Das Format wird von #Besch bestimmt. Wenn der Spieler irgendwo sitzt, liegt oder steht, dann wird aSitz in Klammern angegeben. b. Bei ausführlichen Beschreibungen, wenn der Spieler einen Raum zum ersten Mal betritt oder bei einem Lage-Befehl wird die Beschreibung ausgegeben, die mit Besch zu diesem Raum definiert wurde. c. Wenn sich der Spieler in einem Behältnis befindet, wie z.B. einem Käfig (s. Kap. 10.3), dann wird die 'InBesch' dieses Objekts ausgegeben. 2. Liste der Objekte im Raum: a. Alle beweglichen Objekte im Raum, ausgenommen Personen, die eine Erst-Beschreibung haben und die entweder noch nicht bewegt wurden oder das Immer-Attribut besitzen, werden mit dem Erst- Text erwähnt. Bei Behältern oder Ablagen wird dirket im Anschluß der Inhalt aufgelistet. Jedes dieser Objekte bekommt einen eigenen Absatz. b. Alle beweglichen Objekte, die noch nicht erwähnt wurden und die sich direkt im Raum befinden, werden extra aufgezählt: "Du siehst hier (außerdem) ..." c. Der Inhalt aller beweglichen Objekte im Raum (mit Ausnahme von Personen) wird im selben Absatz wie die Liste der Objekte ausgegeben. d. In einem gesonderten Absatz wird der Inhalt aller unbeweg- lichen Objekte im Raum angezeigt. 3. Angabe des Sitzes, wenn der Spieler irgendwo sitzt, steht oder liegt und wenn der Sitz nicht schon unter 1. genannt wurde. 4. Liste der Personen im Raum: Alle Personen werden in einem eigenen Absatz erwähnt. Dabei wird "Hier ist..." oder die Erst-Beschreibung verwendet, wenn vorhanden. Direkt im Anschluß werden die Dinge, die diese Person bei sich hat, aufgezählt, wenn diese Person 'trans- parent' ist. Eine übertriebene Raumbeschreibung, die alle Punkte oben benutzt, wäre: Labor (auf dem Seziertisch) Dies hier ist offensichtlich das geheime Labor des Doktor Wassilij Saratow. Elektrische Apparate, deren Funktion du nicht annähernd erraten kannst, Chemikalien in allen Farben und mit absolut unverständ- lichen Formeln vollgekritzelte Zettel bilden ein malerisches, wenn auch etwas beunruhigendes Chaos. Der einzige Ausgang ist eine graue Stahltür im Norden, die momentan geschlossen ist. Du befindest dich in einem Metallkäfig mit sehr stabilen Gitterstäben, der in der Mitte des Raumes steht. Ein kleiner Labortisch mit Rollen steht hier. Auf dem Labortisch siehst du eine Codekarte, eine Obstschale und eine Spritze. In der Schale sind drei Apfelsinen und eine Mango. Auf einem Tischchen in der Nähe der Tür liegt ein Schlüsselbund. Außerdem siehst du hier einen braunen Karton und einen Plastikschlauch. In dem Karton sind Papierschnitzel. In dem Käfig siehst du ein Skalpell und einen Seziertisch. Du liegst auf dem Seziertisch. Ein Gorilla turnt im Labor herum. Er jongliert mit einer Banane und einem Tennisball. Tatjana Perpetrowa, Dr. Saratows Assistentin, ist hier und notiert ab und zu Werte, die sie von den verschiedenen Apparaturen abliest, in ein Schulheft. Dies ist eine Raumbeschreibung, wie man sie ohne große Probleme mit den einfachen TAG-definitionen erhalten kann, ohne Ausführungsblöcke definieren zu müssen. Manchmal ändern sich aber Räume auch. Dann sollte man diese Änderungen in der Raumbeschreibung mitteilen. Dies geht entweder mit einer Aktion, die in Besch aufgerufen wird, oder eleganter mit einer NachAusf des Lage-Befehls: Raum Korridor Name 'Felskorridor' [...] Besch 'Du befindest dich hier in einem Felskorridor, der von Südosten nach Norden läuft.' NachAusf (Lage) Wenn (Fels_gesprengt) dann Absatz Text 'Ein kleiner Kriechgang führt über loses Geröll hoch nach Westen. Blasses Tageslicht kommt aus dieser Richtung.' Ende EndeAusf Diese Erweiterung steht natürlich nach der Liste der Objekte im Raum, was eventuell unschön ist. Mit einer Aktion, die aus dem Besch-Text des Raums heraus aufgerufen wird, kann man das vermeiden. 9.3. Tag und Nacht Nehmen wir einmal an, ein Spiel geht über einen Tag oder länger. Dann sollen sich Tag und Nacht abwechseln. Natürlich wirkt sich das auf die Lichtverhält- nisse aus. (Vielleicht bleibt auch der ein oder andere Troll oder Vampir auf der Strecke.) Dazu definiert man ein Raumattribut, das alle Räume besitzen, die durch Tageslicht erhellt werden. Wenn es dämmert, werden alle Räume, die außen sind mit Licht versehen, das am Abend wieder weggenommen wird. Flagge Tageszeit RaumAttr Tageslicht RaumVar xRaum Aktion Tag_und_Nacht * Ausf | Morgengrauen Wenn (Stunden = 5) und (Minuten = 30) dann Schleife xRaum Wenn (xRaum Tageslicht) dann AttrWeg xRaum dunkel Ende Ende Wenn (aRaum Tageslicht) dann Text '[#]Die ersten Strahlen der Morgensonne erhellen das Land.' Ende Ende | Morgen Wenn (Stunden = 5) und (Minuten = 45) und (aRaum Tageslicht) dann Text '[#]Die Sonne ist jetzt vollständig aufgegangen und taucht das Land in ein warmes goldenes Licht.' Ende | Abend Wenn (Stunden = 7) und (Minuten = 45) und (aRaum Tageslicht) dann Text '[#]Die Sonne beginnt, langsam hinter dem Horizont zu verschwinden' Ende | Abenddämmerung Wenn (Stunden = 8) und (Minuten = 00) dann Schleife xRaum Wenn (xRaum Tageslicht) dann AttrHin xRaum dunkel Ende Ende Wenn (aRaum Tageslicht) dann Text '[#]Die letzten Strahlen der Sonne verschwinden und das Land versinkt im Dunkel.' Ende Ende EndeAusf Die Texte um 5:45 Uhr und 8:45 Uhr sind natürlich nur schmückendes Beiwerk. Die Lichtverteilung in allen Räumen, die nicht vom Tageslicht erhellt werden, wird wie gehabt geregelt: Dunkle Räume sind immer dunkel, wie z.B. eine Höhle, und alle anderen sind immer hell, etwa ein unterirdisches Labor, das mit Neonröhren beleuchtet wird. 9.4. Eine Menge von Räumen als ein Raum Man kann eine Menge von Räumen als einen Raum in TAG programmieren. So könnte man ein riesiges Schachbrett programmieren, so daß der Spieler immer genau in einem Feld ist: Flagge Pos_X 1 Flagge Pos_Y 1 Flagge Pos_XX 1 Flagge Pos_YY 1 Flagge Aux Raum Schachbrett Name 'Riesen-Schachbrett ([Buchst Pos_X][Pos_Y])' Std Schachzug Attr Laby Besch 'Du stehst auf einem riesigen Schachbrett. Im Moment befindest du dich auf dem [Feld_Farbe]en Feld [Buchst Pos_X][Pos_Y].[Schach_Ausgang]' Aktion Feld_Farbe Ausf Sei Aux Pos_X Inkr Aux Pos_Y Mod Aux 2 Wenn (Aux) dann Text 'schwarz/' sonst Text 'weiß/' Ende EndeAusf Aktion Schach_Ausgang Ausf Wenn (Pos_X = 1) und (Pos_Y = 1) dann Text ' Im Südwesten kannst du das große Schachbrett verlassen.' Ende Wenn (Pos_X = 8) und (Pos_Y = 8) dann Text ' Im Nordosten führt ein schmaler Pfad vom Schachbrett.' Ende EndeAusf Weg Schachzug Ausf Sei Aux 0 Schleife iObj Wenn (iObj in Schachbrett) und /(iObj Figur) dann Inkr Aux Ende Ende Bed /(Aux) 'Du solltest keine Sachen auf dem Schachbrett liegenlassen. Nimm bitte alles mit, bevor du weitergehst.' Sei Pos_XX Pos_X Sei Pos_YY Pos_Y Jenach aRitg (N) Inkr Pos_YY (NO) Inkr Pos_YY Inkr Pos_XX (O) Inkr Pos_XX (NO) Dekr Pos_YY Inkr Pos_XX (S) Dekr Pos_YY (SW) Dekr Pos_YY Dekr Pos_XX (W) Dekr Pos_XX (NW) Inkr Pos_YY Dekr Pos_XX Ende Wenn (Pos_XX = 0) und (Pos_YY = 0) dann Text 'Du verläßt das Schachbrett nach Südwesten.[#]' GeheZu SW_Eingang Stop Ende Wenn (Pos_XX = 9) und (Pos_YY = 9) dann Text 'Du verläßt das Schachbrett nach Nordosten.[#]' GeheZu NO_Eingang Stop Ende Bed /(Pos_YY = 0 9) und /(Pos_XX = 0 9) 'In diese Richtung kannst du das riesige Schachbrett nicht verlassen. Es hat nur Ausgänge im südwestlichen und im nordöstlichen Ende.' Sei Pos_X Pos_XX Sei Pos_Y Pos_YY Ausf Figuren_setzen Ausf Lage EndeAusf ObjKlasse Figur Adj 'gross' 'riesig' Vor 'schach' Subst 'figur' f Subst 'figur' f Besch 'Es ist [ein selbst], mehr als vier Meter hoch.' Var X Var Y Aktion Figuren_setzen Ausf Schleife iObj Wenn (iObj Figur) dann Wenn (iObj.x = Pos_X) und (iObj.y = Pos_Y) dann ObjNach iObj Schachbrett sonst ObjNach iObj nirgendwo Ende Ende Ende EndeAusf Obj weisser_Läufer (Figur) Name 'riesig^ weiß^ Läufer' m Adj 'weiss' Subst 'läufer' m Var X 5 Var Y 4 Obj schwarze_Dame (Figur) Name 'riesig^ schwarz^ Dame' f Adj 'schwarz' Subst 'dame' f Var X 7 Var Y 1 Auf diese Weise kann der Spieler auf den einzelnen Feldern hin- und hergehen. Die einzige Einschränkung ist, daß man keine Gegenstände liegenlassen kann, da diese auf jedem Feld zu sehen wären. Dazu gibt es die Abfrage beim Gehen, die schaut, ob sich irgendwelche Gegenstände auf dem Brett befinden. Die Ausnahme sind hier die riesigen Figuren, die jedesmal beim Betreten eines neuen Feldes berücksichtigt werden. (Man könnte dies auch auf alle Gegenstände ausweiten, indem man jedem Objekt die Positionsvariablen Pos_X und Pos_Y gäbe. Aber das wäre doch wohl ein wenig zuviel des Guten.) 9.5. Ein Labyrinth So könnte man z.B. auch ein großes Labyrinth mit bis zu 256 Räumen als einen einzigen Raum definieren. Das Labyrinth soll, sagen wir mal, 6x6 Felder besitzen. Auf einem Feld wird dann die Information, ob man von einem Feld aus in eine bestimme Richtung gehen kann, gespeichert. Dazu eignet sich das Bit-Format. Von jedem Fald des Labyrinths aus kann es Gänge in jede der vier Hauptrichtungen geben. Dabei werden die Richtungen Norden, Osten, Süden und Westen durch die Bits 0, 1, 2 und 3 bzw. den Zahlen 1, 2, 4 und 8 repräsentiert. Sind diese Bits gesetzt, so kann man in die entsprechende Richtung gehen. Das Labyrinth soll folgendermaßen aussehen: +---+---+---+---+---+---+ | | | +---+ + +---+---+ + | | | | + + + +---+ + + | | | | | +---+---+---+ +---+ + | | + +---+ + +---+ + | | | | | + + +---+---+ + + | | | | | +---+---+---+---+ +---+ Um die Gänge im Labyrinth zu beschreiben, definiert man nun ein Feld und eine Aktion zum Belegen des Feldes, die am besten aus der Aktion Anfang heraus aufgerufen wird: Feld LabyFeld (6 6) Aktion LabyInit Ausf Daten LabyFeld 0 (2 12 6 10 10 12) Daten LabyFeld 6 (12 5 5 2 14 13) Daten LabyFeld 12 (3 11 13 4 2 5) Daten LabyFeld 18 (6 10 15 15 10 13) Daten LabyFeld 24 (5 6 9 3 12 5) Daten LabyFeld 30 (1 3 10 8 5 1) EndeAusf Vom oberen linken Fald aus kann man nur nach Osten = 2 gehen. Vom Feld rechts daneben kann man nach Westen und Süden = 8 + 4 gehen. Von den beiden 15er Feldern in der Mitte aus führen Gänge in alle vier Richtungen. Bei der Definition sollte man darauf achten, daß die Gänge auch wieder zurückführen. Außerdem sollten die Felder am Rand keine Bewegungsmöglichkeit aus dem 6x6-Feld heraus bieten. So spart man sich eine lästiga Abfrage später. Die beiden Öffnungen nach außen oben links und unten rechts sind die Ein- bzw. Ausgänge des Labyrinths. Die Definition des Raums sieht dann so aus: Raum Labyrinth Name 'Im Labyrinth' Std Nur_diagonal N im_Labyrinth O im_Labyrinth S im_Labyrinth W im_Labyrinth Besch 'Du bist in einem Labyrinth. [LabyrinthBesch].' Attr Laby Antwort Nur_diagonal Besch 'Hier führt kein Gang nach [ARitg].' Um den Spieler innerhalb des Raums zu bewegen definieren wir die Variablen X und Y, um seine Position zu bestimmen und den Weg Im_Labyrinth, um diese Position zu verändern. Flagge X 4 Flagge Y 5 Flagge FeldXY Flagge BitRitg Weg im_Labyrinth Ausf | Ausgänge abfangen Wenn (X = 4) und (Y = 5) und (aRitg = S) dann GeheZu Eingang Stop Ende Wenn (X = 0) und (Y = 1) und (aRitg = W) dann GeheZu Versteck Stop Ende | Bit-Äquivalent der Richtung definieren Jenach aRitg (N) Sei BitRitg 1 (O) Sei BitRitg 2 (S) Sei BitRitg 4 (W) Sei BitRitg 8 Ende | Weg in diese Richtung? Lese FeldXY LabyFeld (X Y) BitUnd FeldXY BitRitg Bed (FeldXY) 'Hier führt kein Gang nach [ARitg].' | Spieler im Labyrinth bewegen Jenach aRitg (N) Dekr Y (O) Inkr X (S) Inkr Y (W) Dekr X Ende Ausf Lage EndeAusf Obwohl diese Weg-Definition relativ lang ist, ist sie doch recht einfach: Zu- nächst werden die beiden Ausgänge abgefangen, da sie nicht mit dem Binär- Schema funktionieren. Dann wird geprüft, ob in die Richtung ein Gang führt. Wenn ja, so werden die Positionen X und Y verändert, aRaum bleibt Labyrinth. Es fehlt nur noch eine Routine, um die möglichen Gänge aufzulisten: Flagge AnzGänge Aktion LabyrinthBesch Ausf Lösche AnzGänge Sei BitRitg 1 | Anzahl der Gänge bestimmen Wiederhole Lese FeldXY LabyFeld (X Y) BitUnd FeldXY BitRitg Wenn (FeldXY) dann Inkr AnzGänge Ende Mult BitRitg 2 bis (BitRitg = 16) Wenn (AnzGänge = 1) dann Text 'Der einzige Gang führt' sonst Text 'Gänge führen' Ende Lösche Aux Sei BitRitg 1 | Richtungen auflisten Wiederhole Lese FeldXY LabyFeld (X Y) BitUnd FeldXY BitRitg Wenn (FeldXY) dann Inkr Aux Jenach BitRitg (1) Sei xRitg N (2) Sei xRitg O (4) Sei xRitg S (8) Sei xRitg W Ende Wenn (Aux = 1) dann Text 'nach [XRitg]/' sonst Wenn (Aux = AnzGänge) dann Text ' und nach [XRitg]/' sonst Text ', nach [XRitg]/' Ende Ende Ende Mult BitRitg 2 bis (BitRitg = 16) EndeAusf Auch diese Routine ist wieder lang, aber nicht kompliziert. In einer ersten Schleife wird die Anzahl der möglichen Ausgänge bestimmt. Dies dient nur dazu, um die Liste im richtigen Format auszugeben. In einer zweiten Schleife wird dann die Liste geschrieben. Eine Sache, die noch abgefangen werden muß, ist das Ablegen von Gegenständen. Im Labyrinth dürfen keine Objekte liegen, da sie in allen Feldern gleichzeitig sein würden. Das macht man an besten mit einer VorAusf des Raums: VorAusf (hinlegen) Stop 'Du behältst [den aObj] besser bei dir, in diesen verwinkelten Gängen würdest du ihn nie wiederfinden und zum Wegwerfen [ist] [er] zu schade.' EndeAusf Das ist zwar eine blöde Antwort, aber beser, als in jedem Feld auf dasselbe Objekt zu stoßen. Außerdem wird so die Möglichkeit, sich im Labyrinth mit abgelegten Gegenständen zu orientieren, unterbunden. 9.6. Verschiedene Antworten als eine Wenn die Anzahl der Räume, Raumklassen, Wege und Antworten sich der maximalen Anzahl von 255 nähert, kann es hilfreich sein, mehrere Antworten zu einer zusammenzufassen, um weitere Räume einfügen zu können: Antwort geht_nicht Besch '[allg_Antw]' Aktion allg_Antw Ausf Jenach (aRaum) (Klippe) Text 'Dort geht es hundert Meter tief hinunter - das würde dir bestimmt nicht guttun.' (Ufer) Text 'In dieser Richtung ist zuviel Wasser.' (Garten) Text 'Du solltest lieber nicht durch die Beete trampeln.' [...] Ende EndeAusf Hier wird der auszugebende Text einfach über eine Aktion gesteuert, die passend zum Raum eine Antwort gibt. 9.7. Spiegelung der Landkarte Ein kleiner Trick: Der Spieler schnippt mit den Fingern und plötzlich ist die Landschaft ost-west-verkehrt gespiegelt. Das Beispiel ist zugegebenermaßen etwas akademisch, aber es funktioniert: Flagge gespiegelt String west 'west' String ost 'ost' Bef schnippen Name 'schnippen' Verb 'schnippe' Ausf Wenn (gespiegelt) dann Lösche gespiegelt Sei west 'west' Sei ost 'ost' sonst Setze gespiegelt Sei west 'ost' Sei ost 'west' Ende Text 'Schnipp! Es scheint sich etwas verändert zu haben...' EndeAusf Aktion NachParser Ausf Wenn (gespiegelt) dann Jenach aRitg (NO) Sei aRitg NW (O) Sei aRitg W (SO) Sei aRitg SW (NW) Sei aRitg NO (W) Sei aRitg O (SW) Sei aRitg SO Ende Ende EndeAusf Raum Kreuzung Name 'Kreuzung mehrerer Wege' O Straße_Ost W Straße_West N Straße_Nord S Straße_Süd Besch 'Hier kreuzen sich mehrere Wege: Im Norden geht es zur wunderschönen Stadt Alamant, im Süden in die dunklen Regionen des Königreichs. Im [West]en sehe ich ein weites Feld voller Sonnenblumen und im [Ost]en erhebt sich das Schattengebirge.' [...] Das ist zumindest das Prinzip: Die Strings werden in die Raumbeschreibungen eingesetzt, damit diese immer angepaßt werden. Die Umwandlung eines 'W' in ein 'O' erfolgt in der Routine Postparser, die nach dem abgeschlossenen Parsen des Satzes aufgerufen wird. (Die Spiegelung könnte auch in Vorher erfolgen.) Die Strings sollten nur Kleinbuchstaben besitzen, damit Sie auch in Kombinationen wie Süd[osten] verwendet werden können. Außerden sollte man noch zwei zusätzliche Strings für 'westlich' und 'östlich' einführen. 10. VERSCHIEDENE ARTEN VON OBJEKTEN 10.1. Behälter und Ablagen Objekte liegen selten direkt auf dem Fußboden, meist befinden sie sich auf oder in anderen Objekten. Damit ein Objekt andere aufnehmen kann, muß es das Attri- but Ablage oder Behälter besitzen. Ablagen sind, wie man vermuten möchte, Objekte, die eine ebene Oberfläche haben, auf denen etwas abgelegt werden kann. Typische Ablagen sind Tische, Regale und Tabletts. Objekte, die darauf liegen, bekommen z.B. die Angabe 'Ort auf Tablett' bei ihrer Definition. Behälter sind Objekte, in die etwas hineingelegt werden kann. Die Objekte in einem Behälter können manipuliert werden, wenn der Behälter weder geschlossen noch abgeschlossen ist, d.h. wenn er offen ist oder einen anderen Zustand besitzt. (Es gibt auch Behälter, die nicht verschließbar sind, wie etwa ein Wassereimer.) Im Allgemeinen kann man in geschlossene Behälter nicht hineinschauen. Gibt man einem Behälter jedoch das Attribut Transparent, so kann man die Dinge in diesem Behälter sehen, jedoch nicht berühren: Obj Vitrine Name 'Glasvitrine' f Adj 'gläsern' Vor 'glas' 'schau' Subst 'vitrine' f 'kasten' m Zust abgeschlossen verschließbar Attr Behälter Transparent Darin 'In dem gläsernen Schaukasten [ist 0] [liste 0] ausgestellt.' Um nicht ständig den Standard-Text 'In/Auf dem x siehst du y.' zu benutzen, kann man bei Behältern die Texte Darin und Darauf definieren, die dann statt- dessen angezeigt werden. Dabei muß der Befehl [liste x] auftauchen, jenachdem, in welchem Fall die Liste stehen soll mit x = 0, 1 oder 2. Ist x = 0, d.h. wird die Liste im Nominativ geschrieben, so muß das Verb je nach Anzahl der Dinge in der Liste nach Singular und Plural veränderlich sein. Dazu gibt man bei den Verben oder den Endungen anstelle eines Objekts 0 an. Mit [ist 0] wird dann 'sind' geschrieben, wenn die Liste mehr als ein Objekt enthält oder das einzige Objekt im Plural steht, und 'ist' sonst. (Bißchen umständlich vielleicht, aber es lohnt sich, wenn dann der Satzbau stimmt.) Es können beliebig viele Gegenstände in einen Behälter oder auf eine Ablage gelegt werden, solange iht Volumen zusammen nicht größer ist als das Volumen des Behälters oder der Ablage. Wer also zu keinem Objekt ein Volumen definiert, kann unbeschränkt Dinge dort lagern. Mit Hilfe der Volumendefinition kann aber verhindert werden, daß unsinnige Dinge ineinandergestapelt werden, wie z.B. eine Spitzhacke in einen Brotkorb. Das Konzept des Volumens ist bei Ablagen sicherlich nicht ganz richtig, denn was ist das Volumen eines Tabletts? Aber auch hier dient das Volumen von Gegenständen nur als grobes Maß für seine Größe. Anders als die meisten anderen Autorensysteme unterscheidet TAG zwischen Behältern und Ablagen, und ein Objekt kann auch Ablage und Behälter zugleich sein: Obj Kommode Name 'Kommode "Linköping"' f Subst 'kommode' f 'Linköping' f 'schublade' f Zust geschlossen Attr Ablage Behälter Besch 'Ein Designer-Stück aus Buche aus der Serie "Kirkegaard". Sie hat eine schwarz abgesetze Schublade.' Darauf '[Liste 0] lieg[en 0] auf der Kommode.' Darin 'In der geöffneten Schublade der Kommode kannst du [liste 1] sehen.' Mit dieser Definition funktioniert das folgende: > u Kommode Ein Designer-Stück aus Buche aus der Serie "Kirkegaard". Sie hat eine schwarz abgesetze Schublade. Das Telefonbuch von Stockholm liegt auf der Kommode. > öffne Schublade Die Kommode ist nun offen. In der geöffneten Schublade der Kommode kannst du einige Taschentücher, eine Krawattennadel und ein Paar Handschuhe sehen. > u Kommode Ein Designer-Stück aus Buche aus der Serie "Kirkegaard". Sie hat eine schwarz abgesetze Schublade. In der geöffneten Schublade der Kommode kannst du einige Taschentücher, eine Krawattennadel und ein Paar Handschuhe sehen. Das Telefonbuch von Stockholm liegt auf der Kommode. Behälter können natürlich auch abgeschlossen sein. Zu abgeschlossenen Objekten und deren passenden Schlüsseln gibt es im nächsten Kapitel mehr. Ein Behälter oder eine Ablage können mit dem Pseudo-Befehl 'empfangen' auf Objekte reagieren, die in oder auf sie gestellt werden und mit 'freigeben' regelt das Heraus- und Herunternehmen von Ablagen und Behältern: Obj Decke Name 'Picknick-Decke' f vor 'picknick' 'patchwork' Subst 'decke' f 'tuch' n 'plane' f Besch 'Es ist die alte Patchwork-Decke, die Tante Gisela vor zwanzig Jahren in liebevoller Handarbeit angefertigt hat. (Du verfluchst den Herausgeber der Handarbeitszeitschriften immer noch, aber im Gegensatz zu den zahllosen Makramee-Eulen kann man diese Decke gut zum Picknicken benutzen.)' VorAusf (empfangen) MutterObj iObj selbst Bed (iObj = 0) 'Dazu solltest Du die Decke erst hinlegen.' (nehmen) Sei #Liste 1 ObjListe iObj (iObj auf Decke) Bed /(AnzListe) 'Solange [liste 0] noch auf der Decke [ist], kannst du sie nicht nehmen.' EndeAusf NachAusf (hinlegen) Text 'Du breitest die Decke auf dem Boden aus.' (freigeben) Wenn (Proz 60) dann Text 'Die Decke wirft Falten, als du [den aObj] herunternimmst.' Ende EndeAusf 10.2. Türen und Schlüssel Türen sind wohl die beliebteste Art von Hindernissen in Adventures. Deshalb gibt es das vorgefertigte Attribut 'Tür' in TAG. Türen haben in der Regel zwei Ortsangaben. Das Betreten des dahinterliegenden Raumes ist nur möglich, wenn die Tür nicht abgeschlossen ist. Ist sie nur zu, so wird sie automatisch geöffnet, wenn der Spieler hindurchgeht. Eine einfache Tür wäre: Obj Haustür Name 'blaue Haustür' f adj 'blau' vor 'eingangs' 'haus' subst 'tür' f Ort Vor_Haus Diele Zust geschlossen Attr Fest Tür Besch 'Die schlichte, blau gestrichene Tür ist [Haustür.Zust].' Damit haben wir eine Tür, die von vor dem Haus in die Diele führt. Geht der Spieler von einem der beiden Räume in den anderen, so wird die Tür 'mit- genommen' und die beiden Räume vertauscht. Das geschieht automatisch, es spielt auch keine Rolle von welcher Seite der Spieler die Tür zuerst zu sehen bekommt. Einen kleinen Haken gibt es allerdings bei Türen: Beim Gehen von einem Raum in den anderen wird geprüft, ob sich eine Tür dazwischen befindet, die abgeschlossen ist und deren beide Raumangaben mit dem Start- und Zielräumen übereinstimmen. Ist das der Fall, so wird das gesagt, und der Spieler bleibt wo er ist. Diese Bedingung greift auch dann, wenn es z.B. zwei Türen zum selben Raum gibt, eine offen, die anderen verschlossen. Die verschlossene Türe ist immer dominant. Auch wenn es eine normale Verbindung zu einem Raum gibt und eine, die mit einer Tür verschlossen ist. In dem Fall müsste man sich mit einer Weg-Definition behelfen: Raum Diele N Wohnzimmer O durch_Tür S Bad W Vor_Haus Besch 'Von dieser geschmackvoll eingerichteten Diele aus gibt es zwei Wege ins Wohnzimmer, ein Tür im Osten, und einen offenen Durchgang im Norden.' Weg durch_Tür Ausf Bed (Dielentür offen) 'Die Dielentür ist aber noch zu.' Wenn (aRaum Diele) dann GeheZu Wohnzimmer ObjNach Dielentür Wohnzimmer sonst GeheZu Diele ObjNach Dielentür Diele Ende Wenn (Mistelzweig in nirgendwo) dann ObjNach Mistelzweig aRaum Text 'Als ich durch die Tür gehe, stoße ich mit dem Kopf an einen alten Mistelzweig, der wohl noch seit der letzten Weihnachtsfeier dort hängt. Er fällt auf den Boden.' Ende EndeAusf Obj Dielentür Name 'Dielentür' f Subst 'dielentür' f 'tür' f Ort Diele Attr Fest Zust offen Das ist ungefähr die Art und Weise, wie TAG Türen behandelt. Die Geschichte mit dem Mistelzweig ist nur ein Zusatz: Es muß ja schliesslich einen Grund geben, um durch die Tür zu wollen. Diese "von Hand" eingabaute Tür darf natürlich nicht das Tür-Attribut besitzen. (Die Theorie hinter den Türen von TAG ist, daß sie immer zwei Räume verbinden bzw. voneinander trennen, die ansonsten keine weitere Verbindung haben. Ich denke, für die meisten Türen gilt das. Deswegen kann man bei außergewöhn- lichen Türen ruhig etwas Mehraufwand in Kauf nehmen.) Der Zielraum einer Tür kann mit .Ort2 angesprochen und auch geändert werden. Der Zielraum ist immer der Raum, in dem man gerade nicht ist. So kann man zum Beispiel eine magische Tür erschaffen: Aktion Tür_Zeichen Ausf Wenn (aRaum = großer_Saal) dann Text 'In der Mitte der Tür prangt das Zeichen' jenach Zaubertür.Ort2 (See) Text 'des Wassers.' (Berg) Text 'der Luft.' (Mine) Text 'der Erde.' (Vulkan) Text 'des Feuers.' Ende Ende EndeAusf Obj Zaubertür Name 'eigenartig^ Tür' f adj 'eigenartig' subst 'tür' f Ort großer_Saal See Besch 'Es ist eine geheimnisvolle Tür. [Tür_Zeichen]' Weg durch_Tür Ausf Bed (Zaubertür offen) dann 'Die eigenartige Tür ist noch geschlossen.' GeheZu Zaubertür.Ort2 EndeAusf Bef ignis Name '"IGNIS" sagen' Verb 'ignis' Ausf Bed (aRaum = großer_Saal) und /(Zaubertür.Ort2 = Vulkan) 'Nichs passiert...' Sei Zaubertür.Ort2 Vulkan Text 'Du hörst ein dumpfes Grollen aus den Tiefen der Erde, als das Zeichen des Feuers auf der Tür erscheint.' EndeAusf Das Gehen durch die Tür muß mit einer Weg-Definition gemacht werden, weil die Tür nicht weiß, in welcher Richtung sie sich befindet. Sie weiß nur, welche Räume sie verbindet. (Beim Gehen in einen anderen Raum, prüft das Programm bei der Ausführung nur, ob es eine Tür gibt, deren Ort2 der Zielraum ist.) Türen in Adventures sind selten sperrangelweit auf. Obwohl es High-Tech und Magie gibt, die Türen verschlossen halten, ist das übliche Mittel dazu doch noch ein Schlüssel. Der passende Schlüssel zur Haustür oben wäre: Obj Haustürschl Name 'Stahlschlüssel' m vor 'haus' 'haustür' 'stahl' subst 'schlüssel' m Attr Schlüssel Ort unter Fußmatte Öffnet Haustür Besch 'Paßt bestimmt auf die Haustür...' Die Öffnet-Definition beschreibt also das Objekt, auf den der Schlüssel paßt. Auch hier ist wieder der denkbar einfachste Fall angenommen: Jeder Schlüssel paßt auf eine Tür. Fehlt die Öffnet-Angabe, so paßt der Schlüssel nirgendwo im Spiel. Aber auch hier kann man abhelfen: .Öffnet enthält das Objekt, das der Schlüssel momentan aufschließt: Obj General Name 'Generalschlüssel' m [...] VorAusf (aufschl_mit) Sei selbst.öffnet aObj EndeAusf Und schon sind Türen kein Hindernis mehr. Schlüssel können übrigens nicht nur Türen, sondern auch andere Objekte als 'öffnet'-Objekt besitzen, etwa Behälter und Vorhängeschlösser. Achtung: Der Speicherplatz für 'öffnet' und 'Ort2' ist derselbe. Ein Ob jekt kann also nicht gleichzeiteig Schlüssel und Tür sein, was mir logisch erscheint. Auf dem selben Platz liegt auch die Information 'Anz', die die Anzahl der Objekte angibt, wenn es einen Plural besitzt. Auch hier denke ich, daß eine Tür und ein (klar von allen anderen unterscheidbarer) Schlüssel nicht mehrfach auftreten. Es gibt aber ein paar Stolperstricke: 'öffnet' ist ein Objekt, 'Ort2' ein Raum und 'Anz' eine Zahl. Belegt man z.B. Anz von einer Tür, so landet man sonstwo. Dies nur als Information und als Warnung, die Attribute Tür und Schlüssel erst abzuchecken, bevor Ihr diese Variablen bei einem allgemeinen Objekt verändert. 10.3. Sitze, Liegen und begehbare Objekte Genau wie Objekte auf anderen liegen können, kann sich auch der Spieler in oder auf anderen Objekten befinden. Solche Objekte müssen das Attribut Sitz, Liege oder Standfläche besitzen: Obj Sessel Name 'Ledersessel' m Vor 'leder' Subst 'sessel' m Ort Stube Attr Fest Sitz In_Obj Ablage Besch 'Der Sessel ist ein wahres Monstrum. Vom Standpunkt des Designers ist er sicher verbesserungswürdig, an Bequemlichkeit allerdings kaum zu überbieten.' Dieser Sessel ist ein Sitz, sobald sich der Spieler daraufsetzt, wird aSitz mit dem Sessel belegt. Da der Sessel ein In_Obj ist, sitzt man im Sessel, nicht auf ihm. Der Spieler kann sich allerdings weder auf den Sessel legen noch darauf stellen. Dazu wären die Attribute Liege und Standfläche nötig. TAG unterscheidet, ob der Spieler auf einem Gegenstand sitzt, steht oder liegt. Das wird in der Flagge bSitz festgehalten, die die Werte %sitzen (1), %stellen (2) und %legen (3) haben kann. Ist aSitz = 0, so hat diese Flagge keine Bedeutung, es wird einfach angenommen, daß der Spieler steht, oder - noch einfacher - daß es keine Rolle spielt, in welcher Haltung er sich in einem Raum befindet. Um sich von einem Sitz auf einen anderen zu setzen, muß der Spieler erst auf- stehen. Dasselbe gilt für das Verlassen des Raums. Wenn der Spieler auf dem selben Objekt bleibt und nur seine Haltung ändert, kann das ohne weiteres geschehen. wenn er auf einem Sofa liegt, muß er nicht erst aufstehen, um sich darauf zu legen. Sitze, Standflächen und Liegen können auch Behälter und Ablagen sein. Was aber passiert, wenn sich der Spieler auf eine Ablage setzt, auf der viele Sachen liegen, das muß der Autor des Adventures selbst programmieren. Eines oder mehrere der Attribute Sitz, Liege oder Standfläche zusammen mit dem Behälter-Attribut machen ein Objekt begehbar. Wenn das Objekt nicht transparent ist und geschlossen wird, wenn sich der Spieler darin befindet, so ist es in diesem Objekt dunkel (es sei denn, das Objekt selbst ist eine Lichtquelle, dann ist es darin immer hell) und der Spieler kann nur die Sachen in diesem Objekt sehen. Das Objekt ist dann quasi wie ein Raum im Raum. Für eine Hütte ist eine solche Definition nicht besonders klug, aber für einen Kleiderschrank oder etwas ähnliches ist es sicherlich angebracht, ihn als Objekt zu definieren, da der Spieler auch Sachen daraus nehmen kann, ohne hineinzugehen. Auf diese Weise kann man auch einen Käfig implementieren, den der Spieler betreten kann oder in dem er gefangen ist. Obj Käfig Name 'groß^ Käfig' m Adj 'gross' 'käfig' 'eisen' Subst 'käfig' m 'stangen' p 'stange' f Attr Immobil Behälter Standfläche Transparent InObj Zust geschlossen Besch 'Es ist ein großer, quadratischer Käfig, dessen dicke Eisenstangen bis an die Decke reichen.' Erst 'In der Mitte des Raumes steht ein großer Käfig, dessen Tür [selbst.Zust] ist.' InBesch 'Du stehst in einem Käfig und schaust durch die dicken Gitterstäbe hinaus.' Und damit ist der Käfig fertig. Wichtig ist, daß der Käfig transparent ist. Wenn nicht, dann könnte der Spieler den Raum, in dem der Käfig steht und die anderen Sachen darin nicht sehen. 10.4. Fahrzeuge In TAG können Sitze, Liegen und Standflächen als Fahrzeuge definiert werden. Das heißt, diese Objekte bewegen sich mit dem Spieler, wenn er sich in oder auf ihnen befindet. Das ist zwar schon ganz bequem, aber dennoch gibt es einige Einschränkungen, denn man kann ja z.B. nicht mit einem Auto einen Steilhang hochfahren. Als Beispiel soll hier (in Anlehnung an Zork I) ein Boot definiert werden, mit dem man natürlich nur auf dem Wasser fahren kann. RaumAttr Wasser RaumVar xRaum Obj Boot Name 'Ruderboot' n vor 'ruder' 'paddel' Subst 'boot' n 'bötchen' n Besch 'Dieses Boot ist aus Holz und hat zwei Riemen.' VorAusf (gehen) SeiRaum xRaum aRaum aRitg Wenn /(xRaum = 0) dann Bed (xRaum Wasser) oder (aRaum Wasser) 'In diese Richtung kannst du schlecht rudern - dort ist kein Wasser.' Wenn /(aRaum Wasser) dann Text 'Du ruderst nach [ARitg], wo Du wieder festen Boden unter den Füßen hast.' sonst Text 'Du ruderst nach [ARitg].[#]' Ende Absatz Ende EndeAusf Bef gehen VorAusf SeiRaum xRaum aRaum aRitg Bed /(xRaum Wasser) oder (aSitz Fahrzeug) 'In dieser Richtung ist für meinen Geschmack zuviel Wasser.' NachAusf Bef rudern Name 'rudern' Verb 'rudere' 'fahre' 'paddle' Syntax nachRitg Ausf Bed /(aSitz = 0) und (aSitz Fahrzeug) 'Dazu bräuchtest du wohl ein Boot...' Ausf gehen aSitz aRitg NachAusf Mit dem Raumattribut beschreibt man, ob ein Raum 'Wasser' ist oder nicht. Ein Strand wäre kein Wasser, ein Ort auf einem See oder in einem Fluß schon. Die Bedingung zum Paddeln ist nun, daß der Zielraum, der momentane Raum oder beide Wasser sind. Mit der Erweiterung des Befehls 'gehen' wird verhindert, daß man auch zu Fuß übers Wasser gehen kann. Wenn man beim Befehl 'gehen' auf einem Fahrzeug sitzt, so ist aObj das Fahr- zeug, damit man es in der Vorausführung berücksichtigen kann. 10.5. Unwichtige Dekorationen Manche Spiele benutzen Dekorationen, die zu nichts benutzt werden können. Man kann sie zwar untersuchen, aber wenn man eine konkrete Handlung ausführen will, so kommt ein Satz wie "Das ist nicht wichtig." Eine solche Dekoration kann man wie folgt definieren: ObjKlasse unwichtig VorAusf (untersuchen) (sonst) Stop 'Ein flüchtiger Blick auf [den selbst] sagt dir, daß [er] total unwichtig [ist].' EndeAusf Und damit braucht man sich keine Sorgen mehr darüber zu machen, daß es bei den Dekorationen Stolpersteine gibt, wie es oft der Fall ist, wenn der Spieler wirklich *alles* versuchen muß. Die leere Anweisung bei (untersuchen) bewirkt, daß dieser Befehl nicht unter die Klausel (sonst) fällt. Nur beim Untersuchen geht es also weiter wie gewohnt, alle anderen Befehle führen zum Abbruch. Dabei ist es egal, ob die Deko aObj oder aObj2 im Befehl ist, da mit (sonst) auch Pseudo-Aktionen berücksichtigt werden. 10.6. Ähnliche Objekte an verschiedenen Orten Um Objekte zu sparen, kann man eine Klasse von ähnlichen Objekten, die sich an verschiedenen Orten befinden, als ein Objekt definieren. Nehmen wir an, es gäbe verschiedene Torbögen, durch die man gehen könnte und die einen dann magisch zu einem anderen Ort teleportieren. RaumAttr Teleporter RaumVar ZielRaum Flagge TorNr Obj Torbogen Name 'steinern^ Torbogen' m Adj 'steinern' Vor 'tor' 'stein' Subst 'bogen' m 'tor' n Attr Fest Besch 'Oben auf dem Torbogen ist auf einem vorstehenden Stein die Zahl [Rom TorNr] eingemeißelt.' VorAusf (betreten) Bed /(Münzen.Anz < TorNr) und (Münzen BeiMir) 'Du willst durch den Bogen gehen, aber du prallst wie an einer unsichtbaren Wand ab.' Text 'Du trittst durch den Bogen. Die Luft scheint sich zu verwirbeln, es kommt Dir vor wie ein Schleier. Als sich der Dunst gelegt hat, schaust Du dich genauer um. Du befindest dich...' GeheZu ZielRaum (schauen) Bed (Münzen.Anz < TorNr) oder /(Münzen BeiMir) dann 'Wenn du ganz genau hinschaust, siehst du durch den Torbogen ganz schwach einen anderen Raum. Du kannst aber nichts Genaues erkennen.' EndeAusf Aktion * Ausf Wenn (aRaum Teleporter) und /(Torbogen hier) Jenach (aRaum) (Brunnen) Sei ZielRaum Stille_Bucht Sei TorNr 1 (Klostergarten) Sei ZielRaum Alte_Heide Sei TorNr 2 (Friedhof) Sei ZielRaum Hades Sei TorNr 7 [...] Ende ObjNach Torbogen aRaum Ende EndeAusf Raum Friedhof Name 'Friedhof' W Vor_Kapelle SO Gruft Attr Teleporter Besch 'Dies ist der etwas trostlos wirkende Friedhof der St.-Gabriel-Kapelle, die sich im Westen düster gegen den Himmel abzeichnet. Ein paar Holzkreuze verraten, wer in den ungepflegten Gräbern vermodert. Im Südosten steht der wuchtige Bau einer Familiengruft. Ein steinerner Torbogen steht hier, ein gotisches Monstrum auf zwei Säulen, halb mit Efeu bewachsen. Die römische Ziffer VII ist auf dem obersten Stein eingemeißelt.' Ende Der Torbogen wird in einer Aktion, die nach jedem Zug aufgerufen wird, in den momentanen Aufenthaltsort geholt, wenn dieser das Attribut Teleporter besitzt. Je nach aRaum werden dann der Zielraum und die römische Ziffer über dem Torbogen gesetzt. (Ganz genauso funktionieren übrigens die Dekorationen, die in der Ortsdefinition ein Raumattribut benutzen, nur daß sie keine weiteren Variablen setzen.) Man hätte dasselbe auch mit der Objektklasse Torbogen bewerkstelligen können. Aber diese Lösung würde soviele Objekte benötigen, wie es Torbögen gibt plus eine Objektklasse. Die Lösung oben benötigt ein Objekt und eine Aktion, was dann recht praktisch ist, wenn das Spiel groß ist und man die gesparten Objekte anderweitig verwenden kann. 11. AUFZÄHLUNGEN UND BESCHREIBUNGEN 11.1. Die Beschreibung eines Objekts Die Beschreibung eines Objekts folgt ähnlich den Raumbeschreibungen einem bestimmten Schema: 1. Der Besch-Text des Objekts wird ausgegeben. Besitzt das Objekt keinen Besch-Text, sondern nur einen Text zum Lesen, so wird dieser ausgegeben. 2. Wenn das Objekt ein offener oder transparenter Behälter, eine Ablage oder eine transparente Person ist, dann wird der Inhalt des Objekts ausgegeben. 3. Wenn bislang noch nichts ausgegeben wurde, und sich das Objekt in einem Zustand befindet, der beschrieben werden kann, so wird "Das Objekt ist [Zust]" ausgegeben. 4. Wenn immer noch nichts ausgegeben wurde, erscheint der Satz: "Ich kann an dem Objekt nichts Besonderes finden." Zusätzliche Beschreibungen sollten in einer NachAusf angefügt werden, wobei man beachten sollte, daß die Punkte 3. und 4. nur in den Puffer geschrieben werden: Obj Amulett Name 'Amulett' n [...] Besch 'Es ist ein Bronze-Amulett, das ich von meinem Meister Sha-Yan zur bestandenen Beschwörerprüfung bekommen habe.' NachAusf (untersuchen) Wenn (Drache hier) oder (Ork hier) dann Text 'Das Amulett strahlt einen starken roten Glanz aus.' sonst Wenn (Drache nebenan) oder (Ork nebenan) dann Text 'Das Amulett leuchtet schwach rötlich.' Ende Ende EndeAusf Grundsätzliche Änderungen der Beschreibung sollten in der VorAusf abgefangen in gewohnter Weise werden: Obj Pflanze Name 'fleischfressend^ Pflanze' f [...] Besch 'Diese Venus-Fliegenfalle hat mit meine Kusine einmal geschenkt, sie ist aus dem Botanischen Garten von Neustadt. Trotz ihrer Reißzähnchen sieht sie irgendwie putzig aus und ist außerdem praktisch, weil sie das Ungeziefer fernhält.' VorAusf (untersuchen) Bed /(Pflanze_gewachsen) 'Oh weh! Das putzige kleine Pflänzchen hat sich durch meinen vielleicht allzu grünen Daumen in ein wahres Monstrum verwandelt. In unregelmäßigen Abständen schnappt sie nach mir!' EndeAusf Natürlich gibt es auch die Möglichkeit, Aktionen aus Besch heraus aufzurufen oder bestimmte Zustände bereits im Besch-Text zu beschreiben. 11.2. Gruppieren von Objekten Mit einer Plural-Angabe bei Objektklassen können Objekte in Listen, wie sie zum Beispiel im Inventar oder bei der Liste der Objekte in einem Raum auf- treten, gruppiert werden. Zum Beispiel ein Stapel Tarot-Karten: ObjKlasse Karte Plural 'Tarotkarten' p vor 'tarot' subst 'karte' f 'karten' p Ort auf Salontisch Besch 'Diese Karte zeigt [den selbst].' Obj As (Karte) Name 'As der Münzen' n 4 subst 'as' n 'münzen' n Obj Narr (Karte) Name 'Narr~' m 4 subst 'narr' m 'narren' m Obj Mäßigkeit (Karte) Name 'Mäßigkeit' f 4 subst 'mässigkeit' f Synonym 'der münzen' 'münzen' Mit dieser Definition werden drei Karten definiert, die alle einzeln mit ihrem Namen angesprochen werden künnen. In der Raumbeschreibung werden sie aber gruppiert und mit dem Plural der Klasse versehen: Auf dem Salontisch siehst du drei Tarotkarten (das As der Münzen, den Narren und die Mäßigkeit) und einen Brieföffner. Wenn der Spieler nun zwei Karten wegnimmt, so bleibt nur noch eine übrig, die dann nicht mehr gruppiert wird: Auf dem Salontisch siehst du das As der Münzen und einen Brieföffner. (Das Synonym wurde hier nur definiert, damit der Parser von dem zusätzlichen Artikel nicht verwirrt wird. Ein Artikel bedeutet für ihn den Anfang eines neuen Objekts. Mit dem Synonym wird der Artikel elegant entfernt. Da TAG keinen Genitiv kennt, macht es keine Probleme, da 'der Münzen' sowieso in keinem anderen Zusammenhang auftreten kann.) Der Plural muß übrigens nicht immer im Plural stehen, wie im folgenden Beispiel: ObjKlasse Nahrung Plural 'Wegzehrung' f 3 vor 'weg' Subst 'zehrung' f 'verpflegung' f Obj Sandwich (Nahrung) Name 'Käse-Thunfisch-Sandwich' n Vor 'käse' 'thunfisch' 'käse-thunfisch' Subst 'sandwich' n 'brot' n 'käse' m 'thunfisch' m Ort BeiMir Besch 'Ein Spezial-Sandwich "nach Art des Hauses".' Obj Banane (Nahrung) Name 'Banane' f Subst 'banane' f Ort BeiMir Besch 'Gelb und krumm.' Dann gibt die Inventarliste folgendes aus: Du hast etwas Wegzehrung (ein Käse-Thunfisch-Sandwich und eine Banane). Eine weitere Besonderheit von Listen ist, daß die einzelnen Objekte einen Listennamen haben können, der in der Definition mit lName angegeben wird. Dieser Name ist ein kurzer Name, der sich meist auf den Plural der Klasse bezieht: ObjKlasse Ball Plural 'kleine Bälle' p 4 Subst 'ball' m 'bälle' p [...] Obj grün_Ball (Ball) Name 'klein^ grün^ Ball' m lName 'grün^' m Adj 'grün' [...] Obj schwarzer_Ball (Ball) Name 'klein^ schwarz^ Ball' m lName 'schwarz^' m [...] Obj weisser_Ball (Ball) Name 'klein^ weiß^ Ball' m lName 'weiß^' m [...] Die Objektklasse Ball hat einen Plural, also werden die Bälle in Listen als eine Gruppe in Klammern ausgegeben. Damit es nicht zu unschönen Wieder- holungen kommt, wird in der Klammer der kurze Listenname verwendet: Hier sind drei kleine Bälle (ein grüner, ein schwarzer und ein weißer). Hätten die Objekte keinen Listennamen, so würde diese Liste so aussehen: Hier sind drei kleine Bälle (ein kleiner grüner Ball, ein kleiner schwarzer Ball und ein kleiner weißer Ball). Es lohnt sich also, bei Objekten, die gruppiert werden, einen Listennamen anzugeben. Dieser Listenname wird übrigens auch in der Nachfrage des Parsers verwendet: Welche Tür? Die gläserne, die aus Mahagoni, die blaue Holztür oder das große Portal? 11.3. Ein Objekt als Gruppe von Objekten Manchmal möchte man eine Gruppe von Objekten als ein Objekt darstellen. Diese Objekte sind alle gleich und können untereinander nicht unterschieden werden. Zum Beispiel eine Streichholzschachtel, die eine Anzahl von Streich- hölzern enthält. Dabei sollen die Streichhölzer nur ein Objekt sein: Flagge Holz_an 0 Obj Schachtel Name 'Streichholzschachtel' f Vor 'streichholz' 'zündholz' Subst 'schachtel' f Attr Behälter Zust geschlossen Ort BeiMir VorAusf (öffnen) Bed (Streichholz in Nirgendwo) 'Du solltest erst das einzelne Streichholz abbrennen lassen.' EndeAusf Obj Streichhölzer Name 'Streichholz' n Plural 'Streichhölzer' p Vor 'streich' 'zünd' Subst 'holz' n 'hölzer' p Anz 5 Ort in Schachtel Besch 'In der Schachtel [ist selbst] [ein].' VorAusf (nehmen anmachen) Bed /(Streichholz BeiMir) 'Das Streichholz brennt doch schon.' Bed (Streichhölzer.Anz > 0) 'Die Schachtel ist leider leer, du Feuerteufel.' Sei Holz_an 3 ObjZust Streichholz ein ObjZust Schachtel geschlossen ObjNach Streichholz beiMir Dekr selbst.Anz Wenn (selbst.Anz = 0) dann Text 'Du nimmst das letzte Streichholz,' sonst Text 'Du nimmst ein Streichholz,' Ende Stop 'schließt die Schachtel und reißt es an der rauhen Fläche an.' EndeAusf Obj Streichholz Name 'brennend^ Streichholz' n Adj 'brennend' 'einzeln' Vor 'streich' 'zünd' Subst 'holz' n Attr Licht Besch 'Langsam flackernd brennt das Streichholz ab..' VorAusf (untersuchen) Bed (Streichhölzer.Anz > 0) 'Es ist das letzte Streichholz, das langsam herunterbrennt.' (anmachen) Stop 'Das Streichholz brennt bereits.' (hinlegen ausmachen) ObjNach selbst nirgendwo Stop 'Du wedelst das Streichholz aus und wirfst den glimmenden Rest weg.' EndeAusf Aktion * Ausf Wenn (Streichholz BeiMir) dann Wenn (Holz_an) dann Dekr Holz_An Bed (Holz_An) 'Das Streichholz ist bald abgebrannt.' sonst Text 'Das Streichholz flackert langsam aus.' Text 'Du wirfst den schwach glimmenden Rest weg.' ObjNach Streichholz Nirgendwo Ende Ende EndeAusf Mit dieser Definition kann immer nur ein Streichholz aus der Schachtel geholt und angezündet werden. Die Schachtel wird automatisch zugemacht, damit der Spieler das brennende Streichholz als Streichholz eindeutig ansprechen kann, aber trotzdem 'nimm Streichholz' verstanden wird, wenn das einzelne Hölzchen gerade nicht vor Ort ist. Diese Definition ist relativ lang, da man verschiedene Situationen abfangen muß: Es darf immer nur ein Streichholz und in Sicht sein, ist das Streichholz aus, wird es sofort weggeworfen, damit das nächste Streichholz genommen werden kann usw. Eine solche Vorgehensweise bietet sich nur an, wenn man die Objekte immer nur als Gruppe benutzt, wie z.B. Münzen als Zahlungsmittel oder Streichhölzer. 11.4. Objekte, die gleich sind Manche Objekte ähneln einander wie ein Ei dem anderen, befinden sich aber unter Umständen an verschiedenen Orten und können einzeln angesprochen werden. Die Definition aus dem vorigen Abschnitt funktioniert also hier nicht. In einem solchen Fall kann man in TAG eine Objektklasse definieren, die einen Plural und ein Vokabular besitzt. Um die Objekte in dieser Klasse nicht unter- scheidbar zu machen, darf man kein eigenes Vokabular bei ihnen definieren, so daß sie nur das von der Klasse geerbte Vokabular benutzen: ObjKlasse Münze Name 'Münze' f Plural 'Münzen' p Besch 'Eine Münze wie jede andere.' Obj M1 (Münze) Ort BeiMir Obj M2 (Münze) Ort in Beutel Obj M3 (Münze) Ort in Beutel Diese Definition bewirkt, daß die Münzen bei Aufzählungen immer zusammengefaßt werden: 'Der Lederbeutel enthält zwei Münzen.' Wenn der Spieler nun 'nimm die Münze aus dem Beutel' eingibt, so wählt der Parser eine beliebige der beiden aus. Die einzelnen Münzen müssen verschiedene Bezeichner besitzen, auch wenn sie vielleicht nie benutzt werden. Für das Programm sind sie schon verschieden, und vielleicht sollen sie sich ja auch im Verlauf des Spiels ändern: Obj Flüssigkeit Name 'grün^ Flüssigkeit' [...] Besch 'Diese grüne Flüssigkeit brodelt etwas verdächtig in einem Glaskolben.' Darin 'Unten in der Flüssigkeit, durch die Blasen und milchigen Schlieren kaum zu erkennen, befinde[t 0] sich [liste 0].' VorAusf (empfangen) Bed /(aObj Zaubermünze) '[Der aObj] [ist] doch schon verwandelt.' Bed (aObj Münze) 'Besser nicht!.' (freigeben) Bed (Zange Beimir) 'Mit bloßen Händen solltest du nicht in diese dermatologisch recht bedenkliche Flüssigkeit greifen.' EndeAusf NachAusf (empfangen) Jenach aObj (M1) Sei iObj Kupfermünze (M2) Sei iObj Silbermünze (M3) Sei iObj Goldmünze (M4) Sei iObj Bleimünze (M5) Sei iObj Ebenholzmünze [...] Ende Tausche aObj iObj Text 'Die Flüssigkeit brodelt heftig als die Münze darin versinkt. Als der Dampf etwas verflogen ist, siehtst du, daß die Münze in [ein iObj] umgewandelt wurde.' EndeAusf Dabei muß das Objekt umgetauscht werden, es kann nicht bloß verändert werden, da ein unveränderliches Objekt während des ganzen Spiels unverändert bleibt. (Das Vokabular eines Objekts kann sich normalerweise nicht ändern, und die Parserroutinen werden bei der Unveränderlichkeit nicht berücksichtigt.) Obwohl die Münzen nicht unterscheidbar sind, so sind sie doch verschieden und im Beispiel wird eine normale Münze immer in dieselbe einzigartige Münze um- gewandelt. Wenn man also eine Münze im Gartenhäuschen findet, so ist es immer die noch nicht verwandelte Bleimünze, der Spieler hat keine Chance, daß es zufällig doch die goldene ist. 12. ANDERE PERSONEN IM SPIEL 12.1. Reden mit anderen Eine Sache, die sicherlich etwas Übung verlangt, die aber wesentlich zur Spielatmosphäre beiträgt, ist das Reden mit anderen Personen (oder auch mit anderen Objekten) im Spiel. Dazu gibt es in TAG die Möglichkeit, Sätze zu anderen Personen zu sagen: > RITTER, TÖTE DEN DRACHEN > RITTER, "TÖTE DEN DRACHEN" > SAGE ZU DEM RITTER "TÖTE DEN DRACHEN" Die Reaktion eines Objekts (das nicht notwendigerweise eine Person sein muß) auf einen ihm gegebenen Befehl wird in der Aktion BefAusf des Objekts ange- geben. Wenn in diesem Ausführungsblock nichts angegeben wird, so wird einfach ein platter Standardsatz gedruckt: "Das scheint nicht besonders an einem Gespräch interessiert zu sein." oder so. Am einfachsten sind wohl einsilbige Zeitgenossen zu programmieren. Zum Beispiel ein Troll an einer Brücke, der seinen Tribut verlangt, aber sonst mit dem Spieler nicht viel zu tun haben will: Obj Troll Name 'Troll' m vor 'brücken' subst 'troll' m 'wächter' m Attr Person Besch 'Der Troll ist ein ziemlich häßlicher Kerl, der vor Muskeln strotzt. Er beobachtet jeden deiner Schritte.' Erst 'Ein stämmiger Troll steht hier vor der Brücke und versperrt den Weg nach Norden.' VorReakt (gehen) Bed /(aRitg = N) oder (Troll_bezahlt) '"Halt, Freundchen, nicht so schnell!" brummt der Troll. "Wenn du über meine Brücke willst mußt du mir einen Schatz geben."' (geben) Bed (aObj2 Schatz) '"Das will ich nicht!", schnarrt der Troll."' ObjNach aObj2 Nirwana Setze Troll_bezahlt Stop '"Danke, Freund!", sagt der Troll. Seine Augen glänzen, als er [den aObj2] schnell einsteckt und einen Schritt zur Seite macht.' EndeAusf BefAusf (nicht_verst) Text 'Der Troll grunzt abfällig und zieht seine Augenbrauen zusammen.' (sonst) Text 'Der Troll grunzt etwas unverständlich.' Absatz Wenn /(Troll_bezahlt) dann Text '"Zahl deinen Zoll oder laß mich in Ruhe." sonst Text '"Du darfst meine Brücke benutzen, aber laß mich bitte in Frieden."' Ende EndeAusf NachReakt (gehen) Wenn (Troll_bezahlt) dann Text '"Hallo, Freund!" Der Troll versucht, seinem Gesicht mit einer Fratze ein gefälliges Aussehen zu verleihen.' sonst Text 'Der Troll grunzt: "Wenn du über die Brücke willst, mußt du mir einen Schatz geben."' Ende EndeAusf In der Anweisung bedeutet (nicht_verst), daß es einen Fehler in der Anweisung an den Troll gab. Diese Fehler werden nicht vom Parser angezeigt, sondern müssen in der BefAusf ausgegeben werden, wenn es gewünscht ist. Obwohl der Troll nicht gerade gesprächig ist, so ist der Code für sein Verhalten doch schon ziemlich lang. Noch einsilbigere Zeitgenossen kämen mit folgenden Zeilen zurecht: Obj Katze Name 'schwarz^ Katze' f Adj 'schwarz' subst 'katze' f 'mieze' f 'kätzchen' n Besch 'Ziemlich aggressiv, die Kleine.' BefAusf (global) Text 'Die Katze faucht dich an.' EndeAusf VorAusf (untersuchen) (sonst) Stop 'Die Katze faucht dich an.' EndeAusf Die leere Zeile nach (untersuchen) bewirkt, daß dieser Befehl als einziger funktioniert wie gehabt, da alle anderen Befehle durch die (sonst)-Klausel zu einem vorzeitigen Ende kommen: Die Katze faucht den Spieler an. 12.2. Maschinen mit Spracherkennung Das ist Stoff für Science Fiction: Der Bordcomputer versteht Anweisungen der Mannschaft: Zum Beispiel kann man den Kurs des Raumgleiters ändern, wenn man dem Computer sagt: "Kurs auf XXX", wobei XXX eine der Mondbasen ist, die der Computer kennt: Obj Computer Name 'Bordcomputer' vor 'bord' 'kontroll' 'steuer' subst 'computer' m 'rechner' m 'panel' n 'lautsprecher' m subst 'mikrofon' n 'mikro' n 'gerät' n 'hans' m Besch 'Dieses Wunderwerk der Technik steuert das Raumschiff. Es ist eines der ersten vollkommen sprachgesteuerten Geräte, die 2070 von der Sirius, Inc. ausgeliefert wurden und ist immer noch so zuverlässig wie am ersten Tag. Ein Mikrofon, ein Lautsprecher und ein kleiner Bildschirm sind die Hauptmerkkmale des schwarzen Kontrollpanels. Auf einer kleinen Plakette rechts unten steht "HANS" [1].' BefAusf (nicht_verst) Text '"Nicht verstanden. Bitte wiederholen."' (kurs_auf) Bed (aObj Raumstation) '"Das ist keine der Raumstationen, die ich kenne."' Bed /(Ziel = aObj) 'Kurs bereits auf [Ziel] gesetzt.' Sei Ziel aObj Text '"O.K., neuer Kurs auf [Ziel]". Der Gleiter macht eine kleine, unscheinbare Korrekturbewegung, als er sein neues Ziel ansteuert.' (sonst) Text '"Das steht außerhalb meiner Möglichkeiten."' EndeAusf ObjVar Ziel Magellan ObjAttr Raumstation Bef kurs_auf Name 'Kurs nehmen' Verb 'kurs' Syntax auf dasObj (Allg) Ausf Text 'Sag es nicht mir, sag%s deinem Computer.' EndeAusf Deko Magellan Name 'Magellan' m 1 ObjAttr Raumstation subst 'magellan' Deko Thyle_ii name 'Thyle II' m 1 ObjAttr Raumstation subst 'thyle' m 'ii' m Deko Schiaparelli name 'Schiaparelli' m 1 ObjAttr Raumstation subst 'schiaparelli' m Fußnoten 1 'HANS - Heuristisch-Algorithmisches Navigations-System.' Die Dekorationen dienen nur als Referenz für den Bordcomputer. Sie befinden sich in keinem Raum, müssen aber dennoch definiert werden, damit das Programm die Vokabeln kennt. Der Befehl kurs_auf muss natürlich auch definiert werden, obwohl er nur etwas Sinnvolles macht, wenn ihn der Computer ausführt. Wer Lust hat, kann dem Computer ja noch zusätzliche Kompetenzen verabreichen: halbe Kraft, volle Kraft, Schilde aktivieren usw. 12.3. Ein schleichender Dieb Manche Zeitgenossen reden nicht, sondern begnügen sich damit, umherzuschleichen und auf ihre Chance zu warten, dem Spieler Unheil zuzufügen. Der Dieb in Zork und der Pirat und die Zwerge aus Adventure sind Beispiele für ein solches Verhalten. Im Gegensatz zum Nachtwächter aus Kapitel 6 sollen sich diese Geschöpfe aber mehr oder wenig zufällig bewegen. Ein einfacher Algorithmus dazu sähe so aus: Obj Dieb Name 'Herr~ in Schwarz' m Adj 'schwarz' 'dunkel' 'verdächtig' Subst 'herr' m 'herrn' m 'dieb' m 'mann' m Attr Person Erst 'Ein Herr in Schwarz ist hier und schaut sich verstohlen um.' Besch 'Dieser Herr sieht in der Tat sehr verdächtig aus.' RaumAttr Nicht_für_Dieb Aktion Dieb_Schleicht * Ausf Wenn (Proz 30) dann | Prüfen, ob es gültige Richtungen gibt Lösche Aux Schleife xRitg SeiRaum xRaum aRaum xRitg Wenn /(xRaum = 0) und /(xRaum Nicht_für_Dieb) dann Inkr Aux Ende Ende | Wenn ja, dann bewege den Dieb in eine davon Wenn (Aux) dann Wiederhole Zufall xRitg MinRitg MaxRitg SeiRaum xRaum aRaum xRitg bis /(xRaum = 0) und /(xRaum Nicht_für_Dieb) Wenn (Dieb hier) dann Text '[#]Der Herr verläßt den Raum.' Ende ObjNach Dieb xRaum Wenn (Dieb hier) dann Text '[#]Ein Herr in Schwarz hat soeben den Raum betreten.' Ende Ende Ende EndeAusf Dieser simple Algorithmus berücksichtigt allerdings keine Wege und keine mit Türen versperrten Ausgänge. (Vielleicht kann man ja annehmen, daß der Dieb sich gut genug auskennt, und weiß, wie man die Türen öffnet.) Immerhin kann man mit dem Raum-Attribut Nicht_für_Dieb bestimmte Räume für ihn sperren. 13. DER SPIELER 13.1. Was genau ist der Spieler in TAG? Der Spieler ist natürlich ein wichtiges Objekt, obwohl er kein Objekt im Sinne von TAG ist. Der Spieler wird nur mittels einiger Flaggen beschrieben. Für Objekte, die beim Spieler sind, gelten 'BeiMir' und 'angezogen' und sein Aufenthaltsort wird mit aRaum und aSitz beschrieben. Die Variable bSitz beschreibt, ob er auf aSitz sitzt, steht oder liegt mit den Werten %sitzen, %stehen und %liegen. Es gibt kein Objekt 'Spieler' in TAG. Daher müssen alle Besonderheiten, die den Spieler betreffen, im jeweiligen Befehl abgefangen werden, z.B.: Bef drehen [...] Ausf Bed /(aObj = du) 'Du drehst dich zu deinem Vergnügen ein wenig im Kreis herum.' Bed /(aObj fest immobil) '[Der aObj] [läßt/lassen] sich nicht drehen.' Text 'Du drehst [den aObj].' EndeAusf Besondere Regeln, die vielleicht nur in bestimmten Situationen gelten, können in der Aktion Vorher abgefangen werden: Aktion Vorher Ausf Wenn (Gasmaske angezogen) dann Bed /(aBef = sagen fragen erzählen) und (Akteur = 0) 'Man hört nur ein undeutliches Genuschel, wenn du durch die Gasmaske sprichst.' Ende Ende Wenn sich ein Objekt beim Spieler oder in oder auf einem der Objekte, die beim Spieler sind, befindet, so ist der Stammraum dieses Objekts Null. Dies ist etwas allgemeiner als die Angaben 'BeiMir' und 'angezogen', die eine konkrete Situation beschreiben. Anmerkung: In der Eingabe des Spielers wird 'du' und 'ich' als gleichwertig betrachtet. Also bewirkt 'untersuche mich' und 'untersuche dich' dasselbe. Wendet sich der Befehl an einen Akteur, so bezeichnet 'du' den Akteur und 'ich' wird in die Hilfsvariable Du umgewandelt, da ja damit der Spieler gemeint ist. Ein Sonderfall ist, wenn es sich um ein reflexives Verb handelt. Dann wird 'dich' als Bestandteil des Verbs gewertet. 13.2. Mehrere Leben Manche Spiele (darunter auch Adventure und Zork) geben dem Spieler drei Leben. Meistens wurde der Spieler bei seinen ersten beiden Toden wiederbelebt und an seinen Ausgangspunkt zurückgesetzt. Seine Besitztümer jedoch wurden über alle ihm bereits bekannten Räume verstreut. In TAG stirbt der Spieler durch den Befehl 'Gestorben'. Wird dieser Befehl eingegeben, so ist der Spieler tot, es erscheint die passende Meldung und sein fleischliches Gegenstück an der Tastatur wird gefragt, ob er aufhören, von vorne beginnen oder einen Spielstand laden möchte. Um dem Spieler mehrere Leben zu geben, könnte man folgende Routine benutzen: Flagge Leben 3 Raumvar xRaum Aktion Tod Ausf Dekr Leben Wenn (Leben) dann Absatz Text '*** Du bist jetzt leider tot. ***' Absatz Wenn (Leben > 1) dann Text 'Von irgendwo hörst Du eine Stimme: "Aha, schon wieder ein Möchtegern-Abenteurer. Ihr lauft immer so unbetrübt durch die Unterwelt, und ich muß euch dann wieder zusammenflicken. Also, an die Arbeit."' sonst Text '"Du schon wieder!" hörst du die bekannte Stimme. "Hast du schon wieder nicht aufgepaßt? Na schön, einmal kann ich dich gewiß noch in Ordnung bringen."' Ende Absatz Text 'Eine orangefarbene Wolke senkt sich auf dich herab. Du fühlst dich schwer und bleiern und sinkst in einen tiefen Schlaf. Als du aufwachst, befindest Du dich...[#]' | Objekte verteilen Schleife iObj Wenn (iObj beiMir) dann wiederhole Zufall xRaum MinRaum MaxRaum bis (xRaum besucht) Objnach xRaum Ende Ende | Zurück zum Anfang GeheZu Unterwelt_Eingang sonst Text 'Eine Stimme sagt: "Tut mir leid, aber jetzt kann ich nichts mehr für dich tun. Ich konnte ja nicht wissen, daß du *so* ungeschickt bist."' Gestorben Ende EndeAusf Anstelle des Befehls 'gestorben' setzt man dann 'Ausf Tod'. In dieser Aktion wird geprüft, ob man den Spieler noch einmal wiederbeleben kann, und wenn nicht, wird die übliche Ablebensroutine 'gestorben' aufgerufen. Nach dem Aufruf von Tod sollte eine Stop-Anweisung stehen. 13.3. Ein ganzes Team Man kann sich auch vorstellen, daß der Spieler nicht nur eine Figur steuert, sondern eine ganze Mannschaft. Das ist bei Rollenspielen immer sehr beliebt: Ein Kämpfer, ein Zauberer, eine Diebin - jeder Charakter hat seine eigenen Fähigkeiten. Dazu kann der Spieler von einer Person zur anderen schalten. ObjVar Spieler Natalia ObjAttr Teammitglied Bef wechseln Name 'wechseln' Verb 'wechsle' Syntax zu demObj (allg) Ausf Bed (aObj Teammitglied) '[Der aObj] [ist] ganz sicher kein Mitglied unseres Archäologen-Teams.' Bed /(aObj = Spieler) 'Du spielst im Moment [den aObj].' Bed /(aObj tot) 'Es tut mir leid, aber [der aObj] leb[t] nicht mehr.' | Alle Objekte übertragen Schleife iObj Wenn (iObj BeiMir) dann ObjNach iObj bei Spieler sonst Wenn (iObj bei aObj) dann ObjNach iObj BeiMir Ende Ende Ende | Den Raum wechseln Wenn /(aSitz = 0) dann ObjNach Spieler in aSitz sonst ObjNach Spieler aRaum Ende Stammraum aRaum aObj MutterObj aSitz aObj | Spieler wechseln Sei Spieler aObj Objnach Spieler nirgendwo Sei maxInv Spieler.Last Sei maxGew Spieler.Gew Sei maxVol Spieler.Vol Text 'O.K. Du wechselst zu [dem aObj].' Ausf Lage EndeAusf Obj Natalia Name 'Natalia' f 1 subst 'natalia' f 'nat' f Besch 'Dott.ssa Natalia Antonelli arbeitet an der ägyptologischen Fakultät der Universität Turin. In unserem Team ist sie die Spezialistin für Schriftzeichen und die Kultur und Religion des zweiten Königreichs. Sie ist eine braungebrannte Endzwanzigerin mit dunkelbraunen Haaren und einer etwas unattraktiven Hornbrille.' Erst 'Deine Kollegin Natalia ist hier.' Dabei 'Ihre Ausrüstung besteht im Moment aus [liste 2].' Attr Person Teammitglied Transparent Vol 60 Gew 60 Var last 4 [...] So könnte man ein Archäologen-Team in eine Pyramide senden. Der Spieler spielt immer eine Person, kann aber zu jeder beliebigen umschalten, auch wenn sie nicht am selben Ort ist. (Diese Bedingung könnte man einfügen, indem man das 'Allg' in der Syntax-Zeile wegließe.) In einer Schleife über alle Objekte werden dem Spieler alle Objekte der Zielperson gegeben und der jetzigen Spielperson alle Besitztümer des Spielers. (Bei der hier vorgestellten Version werden Sachen, die der Spieler angezogen hat, nicht brücksichtigt.) Der momentan aktive Spieler ist als Objekt nicht im Spiel, da alle Funktionen vom Spieler übernommen werden. Deshalb muß auch der Spieler ins Spiel zurück- geholt werden, bevor der Spieler zur Person aObj wechselt. Diese wird dann ins 'nirgendwo' befördert, damit es sie nicht zweimal gibt: als Spieler und als Person im Spiel. 14. DIE SICHTBARKEIT UND ERREICHBARKEIT VON OBJEKTEN 14.1. Was man sehen und was anfassen kann Welche Sachen kann der Spieler sehen? Welche anfassen? Wenn sich der Spieler in einem Raum befindet kann er folgende Sachen sehen: - alle Sachen, die sich im Raum befinden - alle Sachen, die er bei sich hat - alle Sachen, die sich auf einer Ablage befinden - alles, was in einem Behälter ist, der nicht geschlossen ist oder der transparent ist - alles, was eine 'transparente' Person bei sich hat - alles, was sich an einem anderen sichtbaren Objekt befindet Er kann allerdings von den Sachen, die er sehen kann, nicht alles erreichen und damit auch nicht benutzen. Folgende Sachen kann er nicht benutzen: - das, was in einem transparenten Behälter eingeschlossen ist - das, was eine transparente Person bei sich hat - alles, was das Attribut 'entfernt' besitzt - alles, was das Attribut 'unerreichbar' besitzt. - alles, was in, auf oder an einem dieser Objekte ist. Wenn der Spieler versucht, etwas von diesen Sachen zu benutzen, so wird die passende Antwort bereits vom Parser gegeben. Was aber ist der Unterschied zwischen 'entfernt' und 'unerreichbar'? Dieser Unterschied wird gemacht, um das Sitzen, Liegen und Stehen auf anderen Gegenständen zu erleichtern. Wenn man sich auf oder in einem anderen Gegenstand befindet, so bekommen alle Gegenstände, die sich nicht auf dem Objekt aSitz befinden, das Attribut 'unerreichbar'. Somit kann der Spieler, wenn er auf einem Sofa sitzt, zwar alle Sachen sehen wie üblich, aber nur die Sachen bewegen, die sich auch auf dem Sofa befinden. Wenn der Spieler aufsteht, so bekommen alle Objekte das Attribut 'unerreich- bar' wieder abgenommen, und der Spieler kann alles berühren und manipulieren wie zuvor. Das hätte man natürlich auch mit dem Attribut 'entfernt' bewerkstelligen können. Wenn im selben Raum aber ein Kronleuchter hängt, der 'entfernt' ist, so wäre dieser erreichbar, wenn man sich auf das Sofa setzt und wieder aufsteht. Daher gibt es das Attribut 'unerreichbar'. In der Objektdefinition sollte es aber nicht verwendet werden. Weiterhin angenommen, daß im Kronleuchter ein Schlüssel hängt. (Wie der dahingekommen ist, ist im Moment einmal egal.) Außerdem gibt es einen Tisch, auf den natürlich jeder klettern wird, um an den Schlüssel zu kommen. Dann muß dem Kronleuchter von Hand das Attribut 'entfernt' abgenommen werden: Obj Tisch Name 'Biedermeier-Tischchen' n vor 'biedermeier' subst 'tisch' m 'tischchen' n Besch 'Sehr schöne Schreinerarbeit.' Attr Ablage Standfläche Sitz Gew 200 NachAusf (steigen_auf) AttrWeg Kronleuchter entfernt AttrWeg Kronleuchter unerreichbar (steigen_von) AttrHin Kronleuchter entfernt EndeAusf Das Attribut 'unerreichbar' muß natürlich auch wegenommen werden, da es dem Kronleuchter in der Ausführung von 'steigen_auf' gegeben wurde, weil der Kronleuchter natürlich nicht auf dem Tisch liegt. (Es werden nicht alle Objekte 'unerreichbar' gemacht. Lediglich die Stamm- objekte (außer aSitz) und alle Objekte über aSitz sind unerreichbar. Alle darunterliegenden Objekte sind damit automatisch nicht erreichbar, auch wenn sie das Attribut 'unerreichbar' nicht besitzen. Auf diese Weise kann sich der Spieler auf einen Stuhl an einen Tisch setzen. Der Tisch ist dann 'uner- reichbar'. Wenn man ihm das Attribut wieder wegnimmt, kann der Spieler nun bequem alles auf dem Tisch manipulieren. Das erspart eine Schleife.) Wenn ein Objekt das Attribut 'unerreichbar' besitzt, so schreibt der Parser "Du kannst [den iObj] von [dem aSitz] aus nicht erreichen." Ansonsten wird nur ausgegeben "Du kommst nicht an [den iObj] heran." Eine Ausnahme sind hier Dekorationen, bei denen es heißt "[Der iObj] [ist] zu weit entfernt." Das ist zum Beispiel der Fall, wenn in unserem Raum auch ein großes Panoramafenster ist mit Blick auf das Meer. Man kann das Meer anschauen, aber nichts mit ihm machen. 14.2. Änderungen der Sichtbarkeit und Erreichbarkeit Ob ein Objekt sichtbar oder erreichbar ist, wird durch die Regeln im vorigen Abschnitt für die meisten Fälle gut beschrieben. In manchen Fällen möchte man diese Regeln aber ändern, und das meist nur in bestimmten Situationen. Denk- bare Fälle sind: - Der Spieler kann Dinge in einem dunklen Raum nicht sehen. Macht er zum Beispiel seine Lampe dort aus und legt sie ab, dann kann er sie nicht wieder aufnehmen, da er sie nach den normalen Regeln nicht sieht. Man könnte nun eine Regel definieren, nach der der Spieler Dinge in dunklen Räumen nehmen kann, wenn er sie bereits kennt. - Um mit einer Person reden zu können, muß man sie sehen können. Das ist natürlich eine Annäherung. Wenn der Spieler in einer dunklen Zelle gefangen ist, dann kommt er vielleicht nur durch Hilfe seines Zellengenossen heraus, dem er Anweisungen geben muß. Dazu müßte man zulassen, daß der Spieler mit ihm reden kann. - Ähnlich ist es bei anderen Sinnen als der Sicht: Im dunkeln kann man sich nur auf Dinge beziehen, die man sieht. Wie ist es aber mit Dingen, die man riechen kann? Oder hören? Oder betasten? (Die Regeln von TAG definieren ja Erreichbarkeit, also die Möglichkeit, ein Objekt anzufassen, als einen Sonderfall der Sichtbarkeit.) - Manchmal kann man von einem Ort aus Dinge sehen, die sich an einem anderen Ort des Adventures befinden, z.B. wenn man von einem Balkon im ersten Stock auf einen Hof oder auf die Straße schaut. Für solche Sonderfälle gibt es die Aktion SichtUndRW, das RW steht hier für Reichweite. Sie wird bei der Ortsüberprüfung der Objekte aufgerufen und gibt dem Autor die Möglichkeit, Objekte in oder außer Sicht- und Reichweite zu plazieren. Dies geschieht mit den Befehlen ObjInSicht ObjAußerSicht ObjInRW ObjAußerRW wobei beliebige Objekte sein können. Diese Definition der Reich- und der Sichtweite gilt genau einen Zug lang, am Ende des Zuges wird die Sonder- behandlung der Objekte wieder zurückgesetzt. Wenn SichtUndRW aufgerufen wird, ist iObj das momentan betrachtete Objekt. Eine weitere Variable, #obj, gibt an, ob dieses Objekt als aObj, als aObj2 oder als aObj3 im eingegebenen Befehl stand, was den Werten von 1, 2 und 3 entspricht. Wird der Ort für den Akteur untersucht, so ist #obj = 0. Da zum Zeitpunkt der Ortsanalyse der Befehl bereits feststeht, kann auch aBef abgefragt werden, um das Objekt nur bei bestimmten Befehlen freizuschalten. (Der genaue Ablauf der Parserroutine steht in Kap. 15.1.) Als Beispiel soll hier die Regel aufgehoben werden, daß man einmal im dunkeln abgelegte Objekte nicht wieder aufheben kann: Aktion SichtUndRw Ausf Wenn /(Licht_in aRaum) und (iObj bewegt) und (aBef = nehmen) dann ObjInSicht iObj Ende EndeAusf Alle Sonderregelungen zur Erweiterung der Sicht und Reichweite müssen in dieser Aktion definiert werden. Da es aber in der Regel nicht sehr viele sind, ist die Aktion SichtUndRw dennoch recht übersichtlich. Da diese Aktion unter Umständen mehrfach aufgerufen wird, nämlich für jedes Objekt mindestens einmal, sollten hier keine Texte ausgegeben werden. Zum vorzeitigen Abbruch kann man die Flagge Fehler setzen. Ist ihr Wert kleiner als 40, so wird einer der Standard-Texte als fehlöermeldung ausgegeben. 14.3. Ein Raum, der in der Mitte ein Gitter hat Wie kann man nun einen Raum implementieren, der in der Mitte ein Gitter hat, durch das man alle Gegenstände auf der anderen Seite sehen kann, aber sie nicht bewegen kann? RaumVar Andere_Seite Raum Korridor Name 'Korridor' W Wests O Osts Besch 'Dieser Korridor läuft von Westen nach Osten.' Weg Wests Ausf Sei Andere_Seite Ostseite GeheZu Westseite EndeAusf Weg Osts Ausf Sei Andere_Seite Westseite GeheZu Ostseite EndeAusf Aktion SichtUndRW Ausf Wenn (aRaum Geteilter_Raum) und /(aBef = lage gehen) und (iObj in Andere_Seite) dann | Objekt sichtbar ObjInSicht iObj | aber nicht erreichbar ObjAusserRw iObj Ende EndeAusf RaumKlasse Geteilter_Raum NachAusf (Lage) Wenn (Licht_In aRaum) dann Text 'In der Mitte ist der Raum durch ein massives Gitter geteilt, das vom Boden bis zur Decke reicht.' Ende Wenn /(Licht_In Andere_Seite) dann Text 'Die andere Seite des Raums liegt in tiefer Dunkelheit.' sonst Wenn /(Licht_In aRaum) dann Text 'Durch ein Gitter, das vom Boden bis zur Decke reicht und das diesen Raum offensichtlich in zwei Hälften teilt, kommt jedoch etwas Licht hinein.' Ende ObjListe xObj (xObj in Andere_Seite) Wenn (AnzListe) dann Text 'Auf der anderen Seite des Raums siehst du [liste 1].' Schleife xObj Wenn (xObj in Andere_Seite) dann InhListe xObj Ende Ende Ende Ende EndeAusf Raum Westseite (Geteilter_Raum) Name 'Westseite des geteilten Raums' N Korridor O durch_Gitter Besch 'Du bist hier im westlichen Teil eines großen Raums.' Raum Ostseite (Geteilter_Raum) Name 'Ostseite des geteilten Raums' N Korridor W durch_Gitter Attr Dunkel Besch 'Du bist hier im östlichen Teil eines großen Raums.' Antwort Durch_Gitter Besch 'Nein. Gehe doch bitte im Norden um das Gitter herum.' Das wäre eine typische Anwendung von Sonderregelungen zur Sichtweite, wie sie im vorherigen Abschnitt beschrieben wurden. Hier muß man nur aufpassen, daß die Objekte auch außer Reichweite gelegt werden. Wenn ein Objekt nämlich in Sicht ist (was ja hier durch ObjInSicht der Fall ist), wird zur Überprüfung der Reichweite nur gecheckt, ob das Objekt in einem geschlossenen Behälter, entfernt oder unerreichbar ist. Da die Objekte im anderen Raum frei zugäng- lich sind, muß der Check mit ObjAußerRw korrigiert werden. 15. BESONDERHEITEN DES PARSERS 15.1. Wie arbeitet der Parser? Der Reihe nach macht der Parser folgendes: 1. Die Eingabe des Spielers wird in einzelne Worte aufgeteilt. Dabei werden Synonyme bereits ersetzt. 2. Grammatikalische Satzanalyse: a. Die Aktion VorParser wird aufgerufen b. Der Parser untersucht den eingegebenen Satz auf seine grammatikalischen Bestandteile hin. Am Ende dieses Vorgangs sind das Verb mit Klammer, die verschiedenen Objekte (Akkusativ und Dativ mit und ohne Präposition, Mittelobjekt), die Richtung und die Präposition bekannt. c. Der Parser versucht nun, aus den gegebenen Objekten einen Befehl zu bestimmen. Sind falsche oder zuviele Objekte in einem Satz, wird ein Fehler ausgegeben, fehlen Objekte, so wird nachgefragt. 3. Ortsüberprüfung der gefundenen Objekte a. Zum Schluß wird der Ort eines jeden Objekts überprüft. Gibt es mehrere Objekte, auf die die Eingabe zutrifft und die am richtigen Ort sind, so wird nachgefragt. Mit Ort ist hier gemeint, ob das Objekt beim Spieler, nicht beim Spieler, für ihn erreichbar oder nur in Sicht sein muß. b. Die Aktion NachParser wird aufgerufen, in der nachträglich einiges geändert werden kann. Tritt in einem der Blöcke ein Fehler auf, so wird die Analyse abgebrochen. Wird die Textanalyse fehlerfrei abgeschlossen, dann wird der Befehl ausgeführt. Beim Durchlaufen des Parsers können natürlich Fehler aufteten. Die Variable 'Fehler' enthält die Fehlerkennung und gibt Aufschluß über eventuell aufge- tretene Fehler: - Ist Fehler Null, so wurde der Parser fehlerfrei durchlaufen und der Spielzug wird ausgeführt. - Eine Fehlernummer von 1 bis 19 bedeutet, daß ein grammatikalischer Fehler aufgetreten ist: Ein Wort ist unbekannt, der Satz wurde nicht verstanden oder ähnliches. Dann bricht die Textanalyse im Punkt 2. vorzeitig ab. - Eine Fehlernummer von 20 bis 39 bedeutet, daß ein angesprochener Gegenstand nicht am richtigen Ort ist, daß die Eingabe mehrdeutig oder unvollständig ist. Die Textanalyse bricht im Punkt 3. ab. - Höhere Fehlercodes können vom Spieler generiert werden. Die Fehler- meldung muß dann gesondert mit einer Text-Anweisung ausgegeben werden. Eine Ausnahme ist der Fehler 42, der bereits für eine mehrdeutige Eingabe reserviert ist. Die ausgegebene Fehlermeldung ist der Standardtext mit der Fehlernummer. Eine Besonderheit gibt es beim Reden mit anderen Personen. Dort wird ein eventuell auftretender Fehler auf der Flagge zFehler abgelegt. Ist einmal ein Akteur angesprochen, so wird Fehler auf zFehler umgeleitet, so daß der Spielzug auf jeden Fall ausgeführt wird. In BefAusf des Akteurs sollte dann berücksichtigt werden, ob der Befehl an den Akteur korrekt und durchführbar war. Es gilt: - Wenn zFehler = 0 ist, dann war der befehl an den Akteur korrekt. - Ein Fehler von 1 bis 19 zeigt nicht erkannte Anweisung an. In diesem Fall ist aBef = nicht_verst. - Ein größerer Fehler gibt Probleme mit der Sichtbarkeit oder Erreich- barkeit eines angegebenen Objekts an. (Ob der Akteur ein Objekt sehen oder anfassen kann, wird natürlich genau wie beim Spieler mit den- selben Regeln geprüft.) Dann ist aBef gleich dem erkannten Befehl. Soll ein Akteur einen Befehl tatsächlich ausführen, dann sollte der zFehler erst geprüft werden, damit z.B. der Akteur nicht ein Objekt aufheben kann, das nicht im Raum ist. Da der Parser den Spieler in der Ich-Form anredet, könnte man den Akteur mit der Anweisung [Text 0 zFehler] die passende Fehlermeldung auch sagen lassen. 15.2. Der Vor- und Nach-Parser Die Aktionen Vorparser und Nachparser dienen dazu, dem Autor die Möglichkeit zu geben, in die Textanalyse einzugreifen. Im Vorparser ist noch kein Ergebnis der Textanalyse bekannt. Hier können globale Veränderungen der Sichtbarkeit und Erreichbarkeit definiert werden, damit sie nicht ständig in SichtUndRw abgefragt werden müssen. Im Nachparser können die soeben gefundenen Ergebnisse nachträglich modifiziert werden. Automatisch werden im Postparser von TAG z.B. nehmen in herausnehmen umgewandelt, wenn sich das Objekt in einem anderen befindet oder aObj auf das benutze Fahrzeug gesetzt, wenn der Befehl gehen ist. Ähnliche Modifikationen sind hier denkbar, ein Beispiel ist Kap. 9.5, wo die Richtungen nachträglich angepaßt werden, wenn die Landschaft gespiegelt ist. (Eigentlich könnten die Änderungen des Nachparsers auch in der Aktion Vorher vorgenommen werden, aber es ist schöner, die Trennung von Parser und Spielzug auch in diesen Änderungen zu beachten.) 15.3. Spezielle Anweisungen zum Parsen von Objekten Die normale Parser-Routine von TAG versucht, eine Wortkette anhand des zu jedem Objekt angegebenen Vokabulars zu finden. Diese Methode reicht für die meisten Fälle aus. Manchmal möchte man aber spezielle Dinge beim Parsen berücksichtigen. Nehmen wir einmal an, es gibt eine Schalttafel, an der sich viele Knöpfe be- finden. Diese Knöpfe haben verschiedene Farben. Das einfachste wäre nun, eine Objektklasse 'Knopf' einzuführen, zu dem dann die Knöpfe gehören. Das erzeugt aber sehr viele Objekte, wenn es viele Knöpfe gibt. Man kann die Knöpfe aber als ein einziges Objekt betrachten: Flagge Knopffarbe Konst rot Konst gelb Konst grün Obj Knöpfe Name 'Schalttafel mit vielen Knöpfen' p 0 Vor 'schalt' 'elektro' Subst 'knöpfe' p 'knopf' m 'tafel' f 'pult' n Ort Zentrale Attr Fest Besch 'Auf der Schalttafel befinden sich Knöpfe in allen Farben, deren Bedeutung dir verborgen bleibt. Ein grüner, ein gelber und ein roter Knopf stechen aus dem Gewirr von Knöpfen hervor.' VorAusf (untersuchen) Jenach Knopffarbe (rot) Stop 'Auf dem roten Knopf steht eine große Null.' (gelb) Stop 'Der gelben Knopf ist mit dem Symbol eines Bitzes gekennzeichnet.' (grün) Stop 'Auf dem grünen Knopf steht eine große Eins.' Ende (drücken) Jenach Knopffarbe (rot) Bed (Motor an) 'Klick!' ObjZust Motor aus Stop 'Das brummende Geräusch verstummt.' (gelb) Bed (Motor an) 'Klick!' Stop 'Ein greller Blitz zuckt draußen.' (grün) Bed (Motor aus) 'Klick!' ObjZust Motor an Stop 'Klick! Ein brummendes Geräusch setzt ein, aber du kannst nicht genau sagen, woher es kommt.' (sonst) Stop 'Du drückst ein wenig auf den Knöpfen herum, aber es passiert (zum Glück) nichts aufregendes.' Ende EndeAusf In den meisten Fällen werden die Knöpfe als ein Block behandelt. Nur in seltenen Fällen wird zwischen dem roten, grünen und gelben unterschieden, nämlich dann, wenn es konkrete Handlungen ausgeführt werden sollen. Die Farbe des Knopfes steht auf der Flagge 'Knopffarbe'. Wo aber kommt dieser Wert her? Es gibt eine Routine, die 'ObjParser' heißt und die aufgerufen wird, bevor die übliche Parserroutine zum Zuge kommt. Normal ist sie nicht definiert, aber für den Fall der Knöpfe könnte man folgendes programmieren: Flagge Aux Aktion ObjParser Ausf | Knöpfe? LeseArt m Aux LeseAdj 'rot' m Aux Wenn (Aux) dann Sei Knopffarbe rot Sei aObj Knöpfe sonst LeseAdj 'gelb' m Aux Wenn (Aux) dann Sei Knopffarbe gelb Sei aObj Knöpfe sonst LeseAdj 'grün' m Aux Wenn (Aux) dann Sei Knopffarbe grün Sei aObj Knöpfe Ende Ende Ende Wenn (aObj = Knöpfe) dann Wenn /(Wort = 'knopf') dann Sei aObj 0 sonst NächstesWort Ende Ende EndeAusf In dieser Routine tauchen viele unbekannte Variablen und Anweisungen auf. Wort ist das momentan untersuchte Wort. Nehmen wir einmal an, daß der eigegebene Satz lautet "Drücke den roten Knopf". Dann teilt der Parser den Satz auf in die vier Wörter "drücke" "den" "roten" "knopf" Er stellt das Verb 'drücke' fest und versucht dann, ab dem zweiten Wort ein Objekt zu lesen. Die Variable Wort steht also auf dem Wert 'den', wenn die Aktion 'ObjParser' aufgerufen wird. In dieser Aktion wird dann zunächst versucht, einen männlichen Artikel zu lesen. Das momentane Wort ist 'den', und wenn die Aktion aufgerufen wurde, um einen Akkusativ zu lesen, so wird Aux gesetzt und der Wortzähler ein Wort weiter gesetzt. Er steht jetzt auf 'roten'. Wäre das zweite Wort ein Artikel mit einem anderen Geschlecht oder in einem falschen Fall gewesen, so wäre Aux Null, und der Wortzähler wäre immer noch auf dem zweiten Wort. (Anmerkung: die allgemeine Aktion zum Parsen von Substantiven und damit auch die Aktion ObjParser werden unter Umständen mehrmals für verschiedene Fälle aufgerufen. Der Fall wird immer intern mitberücksichtigt, ohne daß er für den Spieler sichtbar ist. Die Anweisungen LeseAdj und LeseArt benutzen ihn dann. Ob mit LeseArt ein bestimmter, ein unbestimmter oder gar kein Artikel gefunden wurde, bestimmt auch die Endung in nachfolgenden Adjektiven: (ein) groß-es Glas, das groß-e Glas.) So, Wort ist jetzt 'roten'. Mit der Anweisung LeseAdj, wird jetzt versucht, ein Adjektiv mit dem Stamm 'rot' zu lesen. Das Wort ist 'roten', also das passende Adjektiv für 'rot' mit der Endung für Akkusative mit bestimmtem Artikel (der ja bereits gelesen wurde). Aux wird gesetzt, und das Wort wird eins weiter gerückt, es ist jetzt 'knopf'. Wenn Aux gesetzt ist, so wird jetzt eine Flagge Knopffarbe auf eins gesetzt, um zu signalisieren, daß der rote Knopf konkret angesprochen wurde, was sich in den Befehlen 'untersuchen' und 'drücken' auswirkt. Die Ergebnisvariable des ObjParsers, aObj, wird auf das Knopf-Objekt gesetzt. Die anderen Adjektive werden nicht mehr überprüft, da 'rot' bereits gefunden wurde. Zum Schluß wird, wenn ein Adjektiv gefunden wurde, überprüft, ob das nächste Wort 'knopf' ist, um sicherzugehen, daß es sich nicht um ein anderes rotes Objekt handelt, etwa um 'den roten Ball'. Ist auch 'knopf' gefunden, so wird der Wortzähler eins weitergerückt, in unserem Fall auf ein leeres Wort. Damit sind wir am Ende der ObjParser-Routine. aObj ist mit den Knöpfen belegt, es ist also ein Objekt gefunden worden. Zusätzlich ist aber auch noch die Infor- mation, um welchen Knopf es sich genau handelt, auf der Flagge Knopffarbe abgelegt worden. Wäre jetzt das letzte Wort nicht 'knöpfe' gewesen, so wäre aObj wieder ge- löscht worden. ObjParser wäre ohne Ergebnis beendet worde, und der Parser hätte auf herkömmliche Weise versucht, das Objekt zu bestimmen. Wobei kann es passieren, daß 'gelb' z.B. nicht als Adjektiv verstanden wird, wenn es kein weiteres gelbes Objekt im Spiel gibt. Um diesen unschönen Patzer zu umgehen, fügen wir die Zeile Adj 'rot' 'gelb' 'grün' zu unserer Objektdefinition hinzu. Auf diese Weise wird auch 'gelber roter Knopf' vom Parser abgefangen: der Knopf wird erkannt, die Farbe nicht. Wem das jetzt alles zu kompliziert ist, der geht am besten die Routine einmal mit verschiedenen Wortkombinationen durch: 'roten knopf', 'roten apfel', 'den gelben knopf' usw. Es funktioniert eigentlich ganz schematisch. 15.4. Parsen von Objekten, die Zahlen enthalten Manchmal unterscheiden sich aber Objekte nicht durch verschiedene Attribute wie die Farben im vorherigen Beispiel, sondern sind durchnumeriert. Denken wir zum Beispiel an die Schließfächer in der Bahnhofshalle: Integer Fach_nr Obj Schließfächer Name 'Schließfächer' p vor 'schließ' subst 'fächer' p Ort Bahnhofshalle Zust geschlossen Attr Fest Behälter Besch 'Die Schließfächer sind in schier unendlichen Reihen übereinander und nebeneinander angeordnet. Die Fächer 1000 bis 1499 sind links, die Fächer 1500 bis 1999 rechts.' VorAusf (öffnen) Bed /(Fach_nr = 0) 'Sage mir genau, welches der Fächer ich öffnen soll.' (...) (global) Bed (Fach_nr > 999) und (Fach_nr < 2000) oder (Fach_nr = 0) 'Die Fächer sind von 1000 bis 1999 durch[-]/ numeriert. Ein Fach [Fach_nr] gibt es nicht.' EndeAusf Auch hier benutzt man wieder die Routine Objparser: Flagge Aux Aktion Objparser Ausf | Schließfach? LeseArt n Aux Wenn (Wort = 'fach') oder (Wort = 'schliessfach') dann NächstesWort Wenn (Wort = 'nummer') oder (Wort = 'nr') dann NächstesWort Ende Sei aObj Schließfächer LeseZahl Fach_nr Aux Ende EndeAusf Diese Routine sieht etwas übersichtlicher aus. Zunächst wird wieder ein Artikel gelesen, damit man das Objekt auch mit Artikel eingeben kann. Er kann aber auch weggelassen werden. Aux wird hier nicht benutzt, der Aufruf soll nur den Wortzähler weiterbewegen. Dann wird geprüft, ob das momentane Wort 'fach' oder 'schließfach' ist. Wenn ja, dann kann als Zusatz 'nr' oder 'nummer' angegeben werden, in dem Fall wird das nächste Wort betrachtet. Dann wird mit der Anweisung LeseZahl eine Zahl aus dem momentanen Wort gelesen. Diese Zahl ist vom Typ Integer. Zahlen bis zwanzig können auch als Zahlwörter angegeben werden. Wie gehabt wird der Wort- zähler weitergezählt, wenn eine Zahl gefunden wurde. Die Flagge Aux gibt an, ob eine Zahl gefunden wurde. Diese Flagge wird aber hier nicht betrachtet, da es das Fach Nummer 0 nicht gibt. (Vereinfachend wird bei 'fach 0' die Zahl als nicht angegeben betrachtet.) Ein weiterer Schwachpunkt ist, daß 'fach nummer' ohne Zahlenangabe verstanden wird. Das könnte man umgehen, indem man die Aktion abändert: Flagge Aux Flagge Nr_definiert Aktion Objparser Ausf | Schließfach? Lösche Nr_definiert LeseArt n Aux Wenn (Wort = 'fach') oder (Wort = 'schliessfach') dann NächstesWort Wenn (Wort = 'nummer') oder (Wort = 'nr') dann NächstesWort Setze Nr_definiert Ende LeseZahl Fach_nr Aux Wenn (aux) und (nr_definiert) dann Sei Fehler 50 Text 'Du mußt mir schon sagen, welche Nummer das gesuchte Schließfach hat!' sonst Sei aObj Schließfächer Ende Ende ErstesWort EndeAusf In dem Fall wird ein benutzerdefinierter Fehler ausgegeben. Die Fehlernummer muß höher als 40 sein, da die Nummern bis vierzig für Fehler schon vergeben sind. Die fehlermeldung muß dann natürlich auch vor Ort ausgegeben werden. Man hätte hier aber auch einfach den Fehler auf eine bereits benutzte Zahl setzen können, dann wäre die passende Meldung automatisch ausgegeben worden. Im Allgemeinen sollte man aber in ObjParser keinen Text ausgeben. Neben LeseZahl gibt es eine weitere Routine zum Lesen von Nummern, LeseNummer. Eine Nummer ist eine Zahlenkette, die z.B. mit Binde- oder Schrägstrichen ge- trennt sein können und die sich über mehrere Würter erstrecken kann. Diese Routine wird auch vom Parser automatisch aufgerufen. So werden folgende Ein- gaben ohne Definition von ObjParser vom Parser verstanden: > WÄHLE 089/99-43-21 Nummer = 89994321, Nullen = 1 > WÄHLE 1-1-0 Nummer = 110, Nullen = 0 Nullen ist dabei eine Angabe darüber, wieviele Nullen vor der eigentlichen Zahl kommen. Ähnlich wie bei den Schließfächern könnte man dann auch > LIES AKTE 99-2431/1 Nummer = 9924311, Nullen = 0 mit ObjParser bewerkstelligen. Man muß nur aufpassen, daß die Zahl nicht größer als 2^31 wird, das sind ca. 2 Millarden. Telefonnummern bleiben also besser neunstellig. Diese Zahlen können auch negativ werden. Die Routine ObjParser wird zum Abfangen aller Objekte mit Sonderregelungen benutzt. Die Abfragen werden dann hintereinander durchgeführt. Ist in einem Block kein Objekt gefunden worden (aber z.B. ein Artikel), so muß der Anfangs- zustand wiederhergestellt werden. Dies passiert mit ErstesWort. (Dieses Zurück- setzen des Wortzählers geschieht automatisch, wenn ObjParser mit aObj = 0 verlassen wird.) 15.5. Parsen von Objekten, die komplizierte Kennungen enthalten Neben den Objekten, die numeriert sind, kann man sich auch Objekte vorstellen, die eine andere Kennung haben. Zum Beispiel ein Schachbrett mit den 64 Feldern A1 bis H8. Wenn man die Figuren versetzen will, will man die Felder mit ihrem Namen ansprechen: Flagge Feld_nr Flagge Aux Aktion ObjParser Ausf | Schachfelder? LeseArt n Aux Wenn (Wort = 'feld') dann NächstesWort Sei aObj Schachbrett Ende Wenn (Wortlänge = 2) dann Lösche Feld_Nr Wenn /(Wort.1 < "a") und /(Wort.1 > "h") dann Wenn /(Wort.2 < "1") und /(Wort.2 > "8") dann Sei Feld_nr Wort.1 Dekr Feld_nr "a" Mult Feld_nr 8 Sei Aux Wort.2 Dekr Aux "0" Inkr Feld_nr Aux Sei aObj Schachbrett Ende Ende Ende EndeAusf In diesem Fall werden also die Buchstaben bzw. Zeichen des Wortes einzeln angesprochen. dazu werden die folgenden Notationen benutzt: "x" ein Zeichen in doppelten Anführungszeichen stellt den ASCII- Wert dieses Zeichens dar. Es wird wie eine Konstante behandelt, die nur gelesen, aber nicht geändert werden kann. Da z.B. "a" identisch ist mit der Zahl 97, kann man mit den Zeichen auch Rechenoperationen durchführen. Die doppelten Anführungszeichen unterscheiden einzelne Zeichen von Verben mit nur einem Buchstaben, wie z.B. "i" von 'i'. Wort.1 gibt das erste Zeichen des momentan betrachteten Wortes an. Dabei muß beachtet werden, daß ein Wort maximal 12 Zeichen besitzen kann. Die Länge des Worts steht auf der Flagge Wortlänge. Wort.x gibt das x-te Zeichen an, wobei x eine Flagge sein muß. Ist der Wert der Flagge 0 oder größer als 12, dann hat das Zeichen den Wert Null. In unserem Beispiel werden alle zweistelligen Angaben, deren erstes Zeichen von "a" bis "h" und deren zweites von "1" bis "8" geht als Koordinate des Schach- bretts interpretiert und als Feldnummer von 1 bis 64 auf die Flagge Feld_nr gelegt. (Das Feld fängt hier bei eins an, damit (Feld_nr = 0) bedeutet, daß kein Feld im speziellen angegeben wurde.) 15.6. Spezielle Anweisungen zum Parsen von Verben Es gibt auch eine Aktion VerbParser, mit der man der normalen Verbbestimmung mit den zu jedem Befehl bestimmten Befehlen vorgreifen kann. Dies ist nur in seltenen Fällen nötig, aber wenn z.B. ein Verb von einer bestimmten Person oder, was wahrscheinlicher ist, von einer Maschine verstanden werden soll, vom Spieler aber nicht, dann kann man diese Aktion dazu benutzen. Als einfaches Beispiel können wir einen Befehl zum begrüßen definieren, der aber nur verstanden werden soll, wenn er zu einer anderen Person gesagt wird: Aktion VerbParser Ausf Wenn /(akteur = 0) dann Wenn (Wort = 'guten') dann NächstesWort Wenn (Wort = 'tag' 'abend' 'morgen') dann Sei aVerb 'hallo.' sonst ErstesWort Ende Ende Wenn (Wort = 'hallo' 'hi' 'servus') Sei aVerb 'hallo.' Ende Ende EndeAusf Bef hallo Name 'Hallo!' Verb 'hallo.' ObjAttr begrüßt Obj Verkäufer [...] BefAusf (hallo) Wenn (selbst begrüßt) dann Text '"Genug geplänkelt!" sagt der Verkäufer, "Reden wir übers Geschäft."' sonst Text '"Einen wunderschönen Tag! Was darf es sein?" Der Verkäufer setzt ein verbindliches Grinsen auf.' AttrZu begrüßt Ende EndeAusf Wenn der Befehl zu einer anderen Person gesagt wird, dann werden die bekannten Begrüßungsformeln in das Verb 'hallo.' umgewandelt. Der Spieler selbst kann diesen Befehl nie ausführen, da die einzige Vokabel nicht vom Parser inter- pretiert werden kann, da der Punkt bei der Aufteilung der Worte verschwindet. Mit dem Trick, dieses vom Parser nicht lesbare Verb in der Aktion VerbParser zuzuweisen, kann aVerb trotzdem Punkte enthalten. Da der Spieler 'hallo' nicht ausführen kann, braucht dieser Befehl auch keinen Ausführungsblock. 16. EXTRAS 16.1. Ein Rang für Punkte In Text-Adventures ist es üblich, dem Spieler je nach erreichter Punktzahl einen Rang zu geben. TAG macht das nicht, es sagt nur, wieviele Punkte in wievielen Zügen erreicht wurden. Um eine Rangskala einzuführen, müssten wir den TAG-Befehl #punkte erweitern: Integer Aux Bef #punkte NachAusf Text 'Das gibt dir den Rang eines' Sei Aux Pktzahl Div Aux 5 Jenach Aux (0) Text 'blutigen Anfängers.' (1) Text 'Stubenhockers.' (2) Text 'Möchtegern-Abenteurers.' (3) Text 'Abenteurer-Gehilfen.' (4) Text 'Amateurs' (5) Text 'hartnäckigen Kämpfers.' (6) Text 'Abenteurers.' (7) Text 'Abenteurer-Großmeisters.' Ende EndeAusf Hier wird dem Spieler gesagt, wie er auf der Punkteskala von 0 bis 350 steht. Alle 50 Punkte erreicht er einen neuen Rang. Achtung: Die Zahlen in der Jenach-Anweisung können nur von 0 bis 255 gehen. Deshalb der Umweg über die Hilfsvariable Aux. 16.2. Komplette Auflistung der Punkte Graham Nelson hat in seinem Inform die Möglichkeit gegeben, sich eine genaue Auflistung der Punkte geben zu lassen. Mit 'full' wird geasgt, wieviel Punkte es wofür gab. Das könnte man auch in TAG machen: Flagge i Flagge j Integer Aux ObjVar xObj RaumVar xRaum Bef komplett * Name 'Auflistung der Punkte' verb 'komplett' 'k' Ausf Text 'Du hast dir deine Punkte folgendermaßen verdient:' Absatz | Ereignisse Schleife i 0 25 Wenn (Pkt.i > 0) dann Text ' [Pkt.i]:[tab]/' Text 99 i Text '/x' Ende Ende | Objekte Lösche Aux Schleife iObj Inkr Aux ObjPkt.iObj Ende Wenn (Aux > 0) dann Text ' [aux]:[tab]verschiedene Gegenstände erlangen' Ende | Räume Lösche Aux Schleife iRaum Inkr Aux RaumPkt.iRaum Ende Wenn (Aux > 0) dann Text ' [aux]:[tab]wichtige Räume erreichen' Ende Text '[x]' EndeAusf Block 99 1 'dir die Hände auf der Herrentoilette waschen' 2 'den Vampir-Vertreter exorzieren' 3 'das "Troll"-Drei-Sterne-Starkbier in einem Zug trinken' [...] 25 'den Apokalypse-Zauber auf den dunklen Thron anwenden' Hier werden die Ereignisse einzeln aufgelistet, und bei den Objekten und Räumen nur die Summe der Punkte. Diese Auflistung funktioniert natürlich nur, wenn PktBasis Null ist und es immer nur positive Teilpunktzahlen gibt. 16.3. Eine frei definierte Statuszeile TAG bietet einige vorgefertigte Angaben für die Statuszeile an, die wohl die gängigen Fälle abdecken. Der Standard ist der Raumname links und die Anzahl der Züge und der Punkte rechts. Für manche Spiele kann es aber interessant sein, eine eigene Statuszeile zu entwerfen. Dazu gibt es den String Statuszeile, der genau wie alle anderen Strings Steuerbefehle in eckigen Klammern enthalten kann. Diese Befehle werden in jedem Zug neu ausgewertet und aktualisiert, so daß man nur zu beginn das Format der Statuszeile festlegen muß, damit sie in jedem Zug angepaßt wird. Zusätzlich muß man #links (oder natürlich #rechts oder #mitte) auf den Wert 7 setzen, damit der String Statuszeile aktiviert wird. Von diesem String werden allerdings nur die ersten 78 Zeichen (bei einer Bildschirmbreite von 80 Zeichen) genommen. Der Autor muß also aufpassen, daß der Text in der Zeile diese Länge nicht überschreitet. Der Rest wird dann abgeschnitten. Die Statuszeile ist immer nur eine Zeile hoch. Mögliche Anwendungen für Statuszeile wären: Sei Statuszeile '[aRaum] ([Planet])[:60][Datum], [Zeit]' Sei Statuszeile '[Name][:40]HP: [HP][:52]Mana: [MP][:64]Gold:[Gold]' Sei Statuszeile 'Temperatur: [Temp] K[:40]Außendruck [p_ext] bar' Die Tabulatoren mit festen Werten ([:x]) bieten sich hierfür an. 17. ALLGEMEINE TIPS UND TRICKS 17.1. Hilfsvariablen TAG ermöglicht keine lokalen Variablen bei den Aktionen und Ausführungen. Das erfordert einiges Umdenken beim Programmieren mit TAG, wenn man an das Programmieren mit prozeduralen Sprachen gewöhnt ist. Dies ist zugegebenermaßen ein Manko von TAG, das noch dadurch schlimmer wird, daß man Bedingungen nicht ineinander schachteln kann und daß man keine arith- methischen Ausdrücke angeben kann, sondern den Umweg über die "Taschenrechner- methode" gehen muß, bei der man jede Operation in eine eigene Befehlszeile schreibt und Klammerausdrücke sogar auf Hilfsvariablen zwischenlagern muß. (Dieser große Nachteil wird vielleicht in einer der späteren Versionen behoben werden. Das ursprüngliche Konzept von TAG war jedoch, die Behandlung und Definition der Objekte und Räume so einfach wie möglich zu machen. Daraus entstanden die etwas an BASIC erinnernden Anweisungen. Bei komplizierteren Adventures wird dann aber leider der Code unschön.) Ich definiere zu Beginn daher in paar Hilfsvariablen, die nie eine Bedeutung für den Spielverlauf haben und die daher gut als lokale Variablen benutzt werden können: Flagge Aux1 Flagge Aux2 Flagge Aux3 ObjVar xObj ObjVar yObj [...] Diese kommen dann während des Spiels als Zählvariablen für Schleifen oder als Marker für Klammerausdrücke oder Bedingungen zum Zuge. Dies ist natürlich vom Blickwinkel eines Informatikers aus gesehen nicht sehr elegant, aber wenn man sich an diese Vorgehensweise gewöhnt hat, kommt man gut zurecht. (Ich bin übrigens kein Informatiker.) 17.2. Größe eines Spiels Adventures, die mit TAG geschrieben werden, sind in ihrer Größe begrenzt. Die wichtigste Einschränkung ist sicherlich der Arbeitsspeicher. Insbesondere bei der Anzahl der möglichen Definitionen gelten in TAG aber die folgenden Beschränkungen: Objekte: Es können maximal 250 Objekte, Dekorationen und Objektklassen definiert werden. (TAG benötigt weitere 4 Variablen für die Hilfsobjekte ich, du, Zitat und Zahl.) Die Anzahl der Vokabeln für ein Objekt ist unbeschränkt. Räume: Es können insgesamt maximal 255 Räume, Raumklassen, Antworten und Wege definiert werden. Befehle: Es können bis zu 255 Befehle und Befehlsvariablen definiert werden. Meta-Befehle, Pseudo-Befehle, und Befehle, die keinen eigenen Aus- führungsblock besitzen, zählen dazu. Die Anzahl der Verben, die zu einem Befehl angegeben werden können, ist unbeschränkt. Etwa vierzig Verben sind schon vordefiniert. Variablen: Es können 255 Flaggen, je 64 Objektvariablen und Raumvariablen, sowie je 32 Integer-, Richtungs- und Zustandsvariablen definiert werden. Außerdem können 32 Felder mit maximal je 256 Elementen und 32 Strings definiert werden. Texte: Es können bis zu 255 Textblöcke mit je 255 Texten definiert werden. Die Länge der einzelnen Texte ist unbegrenzt, aber alle Texte eines Blocks dürfen zusammen höchstens 32 Kilobytes belegen. (Bei der automatischen Belegung ohne Blockangeben wird das berücksichtigt.) Ausführungsblöcke Jeder Ausführungsblock kann maximal 8 Kilobytes belegen. Texte zählen nicht zu den Ausführungsblöcken. Sonstiges: Es können 32 Richtungen, 32 Zustände und je 64 Objekt- und Raum- attribute definiert werden. Die Anzahl der Synonyme ist unbegrenzt. Das hört sich nicht nach besonders viel an, und man hat sich an ganz andere Datenmengen gewöhnt. Ich denke aber nicht, daß diese Beschränkungen bei einem Spiel von normaler Größe zum Tragen kommen. Die Text-Adventures von Infocom, die in der 80ern sehr populär waren und bereits einen sehr hohen Standard hatten, mußten mit insgesamt 255 Objekten auskommen, wozu auch Räume und Richtungen zählten. Durch geschickte Pro- grammierung und durch den Sparzwang bei den Objekten waren die Spiele aber sehr gut organisiert und vermieden dadurch langweilige Passagen, in denen nichts passierte, und nutzlose Objekte. (Ein Spiel mit den Ausmaßen und der Komplexität von Graham Nelsons "Curses" wäre allerdings mit TAG wahr- scheinlich nicht möglich.) Sollten dennoch die Ressourcen einmal knapp werden, so gibt es veschiedene Möglichkeiten, dies in den Griff zu bekommen: - Dekorationen können an bis zu drei Orten sein. Gibt man anstatt des Orts ein Raum-Attribut an, so befindet sich diese Dekoration in allen Räumen, die dieses Attribut besitzen. Wenn man die Beschreibung der Dekos allgemein hält, kann man auch mehere Dekorationen zusammenfassen. So könnten ein Garten, die Bienen, die darin dekorativ herumsummen, die Blumen und die Büsche eine einzige Dekoration sein. - Viele ähnliche Räume, etwa in einem Labyrinth, können zu als ein Raum programmiert werden (s. 10.1.3/4), wenn man Felder benutzt. - Man kann verschiedene Antworten zu einer zusammenfassen, indem man sie über eine Aktion steuert (10.1.5). - Verschiedene Objekte können auch als ein einzelnes Programmiert werden, wenn man den Parser mit ObjParser anpaßt. Feste Gegenstände, die ähnlich sind und sich alle in verschiedenen Räumen befinden, kann man auch ohne Anpassung des Parsers als ein Objekt implementieren. - Ausführungsblöcke können gesplittet werden: Eine Hauptaktion ruft weitere mit der Ausf-Anweisung auf. - Wenn die globalen Flaggen knapp werden, kann man oft auf Variablen für Objekte oder ein Hilfsfeld umsteigen. Die beste Lösung ist aber wahrscheinlich, das Spiel noch einmal anzuschauen und 'auszumisten': Es gibt bestimmt den ein oder anderen Raum, der überflüssig ist oder ein paar Dekos, die nicht unbedingt notwendig sind. _____________________________________________________________________________ Anhang A: Kurzübersicht Diese Kurzübersicht dient als Referenz für die Syntax der Definitionen in TAG. Die jeweiligen Kapitel des Handbuchs sollten aber bereits bekannt sein. Die Landschaft: Räume, Richtungen und Wege Richtung '' '' {*} RaumAttr Raum Name '' {()} Std / Attr {/} {{/}} {{/}}... Besch '' VorAusf [...] EndeAusf NachAusf [...] EndeAusf Antw Besch '' Weg Ausf [...] EndeAusf Die Gegenstände: Objekte, ihre Attribute und Zustände ObjAttr Zust {''} Obj Name '' {} m männlich (Maskulinum) f weiblich (Feminimum) n sächlich (Neutrum) p Mehrzahl (Plural) 0 normale Ausgabe 1 ohne Artikel (Namen) 2 kein unbestimmter Artikel 3 'einige' bzw. 'etwas' 4 immer bestimmter Artikel 5 'mein' Objekt 6 'dein' Objekt Plural '' {} Adj '' {'' ...} Vor '' {'' ...} Subst '' {'' ... } Ort {} Zust Gew Vol Öffnet Anz Besch '' Text '' Erst '' Darbei '' Darin '' Darauf '' Daran '' InBesch '' Var {} VorAusf [...] EndeAusf NachAusf [...] EndeAusf VorReakt [...] EndeAusf NachReak [...] EndeAusf BefAusf [...] EndeAusf Deko Name '' Adj '' {'' ...} Vor '' {'' ...} Subst '' {'' ...} Attr Ort { } Besch '' VorAusf NachAusf VorReakt NachReak BefAusf Neue Befehle oder Erweiterung der alten Bef {*} Name '' Verb '' {'' ...} Syntax {{} dasObj/demObj {( )} ... {nachRitg} Hier vom Spieler erreichbar BeiMir direkt beim Spieler NichtBeiMir erreichbar, aber nicht beim Spieler inSicht für den Spieler sichtbar Allg beliebiges Objekt im Spiel Inhalt für aObj, muß in/auf aObj2 sein Präp '' {'' ...} Ausf Dies ist der Block, der die Ausführung des Befehls beschreibt. Dieser Block wird ausführlich in Kapitel 5 beschrieben. Er wird mit EndeAusf abgeschlossen und muß auf jeden Fall in der Befehlsdefinition enthalten sein. Pseudo Globale Variablen für alle Typen, Strings, Aktionen Flagge {} Integer {} Konst Feld ( {} {}) RaumVar {} ObjVar {} RitgVar {} ZustVar {} BefVar {} String {''} Aktion {*} Ausf [...] EndeAusf Anweisungen für Ausführungsblöcke: Text '' Text Absatz Zufallstext Puffer '' Box '' oder Box Sei Inkr Dekr Mult Div Mod Setze Lösche Zufall Zufall ( ... ) GeheZu SeiRaum SeiRitg AttrHin AttrWeg ObjNach Tausche ObjZust AttrDazu AttrWeg MutterObj StammObj StammRaum ObjListe () InhListe ObjInh ObjGew Stop Gestorben Gewonnen Punkte ObjPunkte RaumPunkte Ausf Ausf {} {} {} {} SetzeZeit WarteZeit JaNein Auswahl '' Daten ( { ...}) Lese ( { }) Belege ( { }) FeldPos ( { }) _____________________________________________________________________________ Anhang B: Bereits vorhandene Definitionen Räume: Raumattribute: Dunkel Laby Besucht Räume: Nirgendwo Nirwana Raumvariablen: aRaum daselbst Objekte: Objektattribute: Person Licht Kleidung Sitz Liege Standfläche InObj Behälter Ablage Transp Tür Schlüssel Verschließbar Fahrzeug Fluid Entf Fest Immobil Bewegt Bekannt Immer ansprechbar Zustände von Objekten: Normal Kaputt Offen Geschlossen Abgeschlossen Ein Aus Objektvariablen: Akteur selbst aSitz iObj Innenraum esObj Flaggen und allg. Variablen Flaggen und Integer-Variablen (*) MaxInv MaxGew MaxVol Inv InvGew InvVol LichtHier PktZahl (*) PktBasis (*) Züge (*) Minuten Stunden Nummer (*) Nummer2 (*) Still NullText NullAkt NullBef Fehler zFehler minObj maxObj minDeko maxDeko minRaum maxRaum Strings (Zeichenketten): Statuszeile Aktionen: Anfang Vorher Nachher Ergebnis des Parsers: aBef aObj, aObj2, aObj3 aRitg aVerb, aKlammer, aPräp _____________________________________________________________________________ Anhang C: Vordefinierte Befehle Hier werden kurz die bereits in TAG definierten Befehle mit ihrer Syntax und ihrer Wirkungsweise beschrieben. Auch die Verben, die zu jedem Befehl ver- standen werden, sind angegeben, falls man das Vokabular erweitern möchte. gehen ['gehe' 'laufe' 'wandere' 'bewege dich'] [nachRitg] Standardbefehl zur Fortbewegung des Spielers, behandelt Antworten und Wege. Prüft, ob eine verschlossene Tür im Weg ist und öffnet diese automatisch, wenn sie nicht abge- schlossen ist. Beinhaltet auch Fortbewegung in der Dunkel- heit. Der Spieler kann von einem hellen Raum aus überall hin, von einem dunklen Raum aus nur in helle Räume gehen. (Oder anders gesagt: einer der beiden Räume muß hell sein.) Wenn der Spieler auf einem Fahrzeug sitzt, so wird dies mitbewegt. nehmen ['nimm' 'nehme' 'nimm mit' 'nehme mit' 'hebe auf' 'hole'] [dasObj (Mobil)] Standardbefehl zum Aufheben von Gegenständen. Es können Objekte aufgehoben werden, wenn sie nicht schwerer sind als die max. Tragekapazität des Spielers, wenn sie keine Personen und keine Flüssigkeiten sind, wenn die verfügbare Kapazität des Spielers nicht kleiner ist als das Gewicht des Spielers und wenn der Gegenstand nicht zu sperrig ist. Befindet sich aObj in oder auf einem anderen Gegenstand, so wird 'nehmen' in 'herausnehmen' umgewandelt, um die Reaktion des Behälters bzw. der Ablage zu berücksichtigen. herausnehmen ['nimm' 'nehme' 'hole'] [dasObj (Inhalt) aus demObj (Behälter)] Behandelt das Nehmen von Gegenständen aus Behältern und von Ablagen und ggf. von Personen. Dieser Befehl prüft, ob aObj2 ein Behälter oder eine Ablage ist und ruft 'nehmen'. Der Pseudo-Befehl zu 'herausnehmen' lautet 'freigeben'. herunternehmen ['nimm' 'nehme' 'hole'] [dasObj (Inhalt) von demObj (Ablage)] Wird umgewandelt in 'herausnehmen'. hinlegen ['lege hin/ab/weg' 'stelle hin/ab/weg' 'setze hin/ab'] [dasObj (beiMir)] Legt ein Objekt aus dem Inventar einfach in den Raum. hineinlegen ['lege' 'setze' 'stelle' 'tue'] [dasObj (beiMir) in dasObj (Behälter)] Legt ein Objekt aus dem Inventar in den Behälter oder auf die Ablage, vorausgesetzt, daß dort Platz ist und daß der Behälter nicht geschlossen ist. Berechnet das Volumen im Behälter automatisch. Ruft zuvor hinlegen, um sicherzugehen, daß der Spieler aObj aus der Hand legen kann. darauflegen ['lege' 'setze' 'stelle' 'tue'] [dasObj (beiMir) auf dasObj (Ablage)] Wird umgewandelt in 'hineinlegen'. untersuchen ['u' 'untersuche' 'inspiziere' 'schaue (dir) an' 'sieh (dir) an' 'betrachte'] [dasObj (inSicht)] Ruft die Standard-Objektbeschreibung auf: Die Besch-Angabe des Objekts (oder einer vererbenden Klasse) wird ausgegeben. Wenn es ein Behälter ist, so wird die Standard-Inhaltsangabe geschrieben. Besitzt das Objekt einen Zustand mit Namen, so wird dieser ausgegeben. Gibt es keine Ausgabe, so wird die Standardantwort "Du siehst nichts Besonderes an [dem aObj].' ausgegeben, außer wenn das Objekt einen Text zum Lesen besitzt, der in diesem Fall ausgegeben wird. lesen ['lese' 'lies'] [dasObj (inSicht)] Gibt die Text-Angabe aus. Wenn es keine gibt, so wird die Standardantwort 'Auf [dem aObj] steht nichts.' ausgegeben. lage ['l' 'lage' 'schaue/sieh/sehe dich um'] Ruft die Standard-Raumbeschreibung auf: Evtl. Name des Raums, Besch-Angabe, Liste der Gegenstände und Personen, Angabe des Sitzplatzes, Inhaltsangabe der Objekte. inventar ['i' 'inv' 'inventar' 'liste'] Schreibt eine Liste der Gegenstände, die der Spieler bei sich trägt oder angezogen hat, und ihrer Tochterobjekte, d.h. der Objekte, die sich darin, darauf oder daran befinden. Je nach #inv wird die Liste als Aufzählung oder als kompletter Satz (evtl. mit Gruppierungen) ausgegeben. öffnen ['öffne' 'mache auf'] [dasObj] Zum Öffnen von Gegenständen. Ist ein undurchsichtiger Behälter geöffnet worden, so wird dessen Inhalt ausgegeben. schließen ['schließe' 'mache zu'] [dasObj] Zum Schließen von Gegenständen. aufschließen ['schließe auf' 'sperre auf'] [dasObj mit demObj (Schlüssel)] Zum Aufschließen von Gegenständen mit einem Schlüssel. Wenn der Schlüssel definiert ist und er paßt, wird das Objekt aufgeschlossen, sonst wird eine passende Meldung Der Pseudo-Befehl zu 'aufchließen' ist 'aufschl_mit' abschließen ['schließe ab/zu' 'sperre ab/zu' 'verschließe'] [dasObj mit demObj (Schlüssel)] Zum Abschließen von Gegenständen mit einem Schlüssel. Wenn der Schlüssel definiert ist und er paßt, wird das Objekt ab- geschlossen, sonst wird eine passende Meldung ausgegeben. Der Pseudo-Befehl zu 'abchließen' ist 'abschl_mit' öffnen_mit ['öffne''mache auf'] [dasObj mit demObj (Schlüssel)] Versucht, ein Objekt aufzuschließen und öffnet es dann, wenn es erfolgreich aufgeschlossen wurde. Ruft 'aufschließen' und 'öffnen'. anmachen ['mache an' 'schalte an/ein' 'zünde an'] [dasObj] Schaltet ein Objekt ein, sofern dies möglich ist. (Man kann Objekte ein- und ausschalten, wenn sie entweder an oder aus sind.) ausmachen ['mache aus' 'schalte aus/ab' 'lösche'] [dasObj] Schaltet ein Objekt aus, sofern dies möglich ist. anziehen ['ziehe (dir) an/auf/um/über' 'lege an' 'trage'] [dasObj (BeiMir Kleidung)] Zieht das Kleidungsstück an. ausziehen ['ziehe (dir) aus' 'ziehe ab' 'nehme ab' 'nimm ab'] [dasObj (BeiMir Kleidung)] Zieht das Kleidungsstück aus. sitzen_auf ['setze dich' 'sitze'] [auf/in demObj (NichtBeiMir Sitz)] Setzt den Spieler auf einen Sitz. liegen_auf ['lege dich' 'liege'] [auf/in demObj (NichtBeiMir Liege)] Legt den Spieler auf eine Liege. stehen_auf ['stell dich' 'stehe'] [auf/in demObj (NichtBeiMir Standfläche)] Stellt den Spieler auf eine Standfläche. steigen_auf ['steige'] [auf/in dasObj] Setzt, stellt oder legt den Spieler auf das Objekt, ja nach Objektattribut. Ruft 'setzen_auf', 'legen_auf' oder 'stehen_auf' betreten ['betrete'] [dasObj (NichtBeiMir)] Wenn aObj eine Tür ist, so geht der Spieler in die passende Richtung. Wenn aObj eine Liege, ein Sitz oder eine Standfläche ist, so steigen_von ['steige' 'stehe auf'] [von/aus demObj] Stellt den Spieler hin, wenn er auf dem Objekt sitzt. aufstehen ['stelle dich hin' 'stelle dich' 'stehe auf' 'steige ab'] Wird umgewandelt in 'steigen_von', wenn aSitz nicht Null ist. sagen [demObj (ansprechbar)] [dasObj] sagen_zu [zu demObj (ansprechbar)] [dasObj] ['sage'] Werden umgewandelt in "aObj, aObj2", wenn aObj2 eine wört- liche Rede in Anführungszeichen ist. hineinschauen ['sieh' 'schaue' 'sehe'] [in dasObj (Behälter)] Gibt den Inhalt von Behältern an oder 'Dort ist nichts', wenn das Objekt kein behälter oder leer ist. daraufschauen ['sieh' 'schaue' 'sehe'] [auf dasObj (Ablagen)] dito für Ablagen schauen ['sieh' 'schaue' 'sehe'] [unter/hinter dasObj] versucht, Dinge zu finden, die unter oder hinter dem Objekt versteckt sind. warten ['warte' 'z'] läßt einen Zug unngenutzt verstreichen. Folgende Steuerbefehle sind implementiert: #ende Beendet das Programm #neu Beginnt das Spiel von Neuem, d.h. der Anfangszustand wird wiederhergestellt. #laden Lädt einen Spielstand von einer Datei, die zuvor aus dem Datei-Menü ausgewählt wurde. #speichern speichert einen Spielstand auf eine Datei, um das Spiel später an derselben Stelle weiterführen zu können. Spielstände haben die Dateierweiterung '.sav'. #knapp Schaltet den Knapp-Modus ein, bei dem die ausführlichen Raumbeschreibungen nur beim ersten Betreten des Raumes oder mit dem 'lage'-Befehl ausgegeben werden. Bei jedem weiteren betreten wird lediglich der Raumname und die im Raum befindlichen Gegenstände angezeigt. #ausführlich Schaltet den Ausführlich-Modus ein, der bei jedem Betreten eines Raumes die ganze Raumbeschreibung ausgibt, auch wenn der Spieler dort schon einmal war. #meldungen Schaltet die Meldungen bei Änderung des Punktestands aus oder wieder an. Diese Meldungen erscheinen immer, wenn Punkte mit den Anweisungen Punkte, ObjPunkte oder RaumPunkte ver- geben werden. #punkte gibt den Punktestand des Spielers aus. #manuskript öffnet ein manuskript, d.h. eine Textdatei, die die Ein- gabe des Spielers und die Ausgabe des Programms mitproto- kolliert. In TAG haben Manuskripte die Endung '.skr' #rückgängig macht einen Zug rückgängig. Es können auch mehrere Züge hintereinander rückgängig gemacht werden. #fussnote [dasObj (Zahl)] Gibt die Fußnote mit der angegebenen Nummer aus, wenn diese im Spiel bereits aufgetaucht ist. (Kann mit 'fn' abgekürzt werden.) _____________________________________________________________________________ Anhang D: Überblick über die Textoptionen Einzelne Zeichen: [/] // Schrägstrich [%] /% Prozentzeichen [,] ["] % /" /, Apostroph [[ ]] /( /) eckige Klammern [-] /- bedingter Trennstrich [_] [] (/_) geschütztes Leerzeichen [^] /^ Endung eines Adjektivs [~] /~ Anpassung der Endung im Plural [Aufz] [:] /: Aufzählungszeichen Formatierung des Textes: [Absatz] [#] /# Absatz [Umbr] oder [x] /x unformatierter Zeilenumbruch [Fett] [f] /f Fettdruck [Norm] [n] /n normaler Text [Tab] [->] /t Tabulator [TTab] [-->] /T Tabulator mit doppelter Weite [: ] Vorschub bis zur Spalte x [+ ] Einzug links [- ] Einzug rechts [= ] Einzug links und rechts [* ] x geschützte Leerzeichen Optionen zur Objektausgabe [dasObj ] Objekt mit bestimmtem Artikel [der ], [den ], [dem ] [einObj ] Objekt mit unbestimmtem Artikel [ein ], [einen ], [einem ] [keinObj ] verneintes Objekt [kein ], [keinen ], [keinem ] [obj ] Objekt ohne Artikel [] Objekt ohne Artikel im Nominativ [es ] Personalpronomen [er ], [ihn ], [ihm ] [liste ] Liste von Objekten (s. ObjListe) Verben, die an die grammatikalische Person eines Objekts angepaßt sind [ist ] Verb 'sein' [hat ] Verb 'haben' [wird ] Verb 'werden' [t ] Endung für schwache Verben [/ ] Unregelmäßiges Verb Hilfsoptionen für das Objekt aSitz [sitz] Ruheverb 'sitzen'/'stehen'/'liegen' [setz] Bewegungsverb 'setzen'/'stellen'/'legen' [in] Allgemeine Angaben [] Zahlenwert [num ] Wert als kardinales Zahlwort [ord ] Wert als ordinales Zahlwort [rom ] Wert als römische Zahl [Buchst ] Wert als Buchstabenkennung (1=A, 2=B usw.) [] Zustand [Zust ] Zustand als Satz [] Name des Befehls [Befsatz] Kompletter Satz [präp] oder [p] Präposition aus dem Befehl [Zeit] Uhrzeit im Spiel (hh:mm) [] String [Text ] Text aus einem Textblock [] Aufruf einer Aktion [] Fußnote (aus Block 255) _____________________________________________________________________________ Anhang E: Glossar des 'Adventure-Slangs' In diesem Glossar sind die wichtigsten Begriffe rund um Text-Adventures, die mit TAG erstellt werden, kurz erklärt. Adventure: Adventures sind Computerspiele, in denen eine Geschichte erzählt wird, in die der Spieler als Protagonist eingreift und versucht, sie zu einem guten Ende zu bringen. Die Kommunika- tion mit diesem Helden kann auf verschiedene Weise erfolgen. Im Falle der Text-Adventures, wie sie z.B. mit TAG erstellt werden können, werden der Spielfigur Anweisungen in kurzen Imperativsätzen gegeben. Die Bezeichnung stammt vom ersten Spiel dieses Genres, "Adventure" von W. Crowther und D. Woods. Der Einfluß dieses Spiels ist noch in heutigen Adventures spürbar. Akteur: Das ansprechbare Objekt - meistens eine Person -, an die der Spieler einen Befehl gerichtet hat: Dr. Watson, Geben Sie mir das Fläschchen. Aktion: Eine Aktion ist eine Routine, die entweder nach jedem Zug ausgeführt wird oder die aus anderen Ausführungblöcken aufgerufen werden kann. Ausführungsblock: Ein Ausführungsblock ist eine Routine, die sich aus TAG-Anweisungen zusammensetzt und die die Objekte und Räume verändern kann. Ausführungsblöcke sind die Hauptbestandteile von Befehlen und Aktionen, sie können aber auch bei den Objekt- und Raumdefinitionen auftreten. Befehl: Ein Befehl ist eine bestimmte Aktion, die der Spieler ausführen soll, und die der Parser mittels eines vorgegebenen Syntax-Musters aus dem Verb und den eingegebenen Objekten bestimmt. Feld: Ein Feld ist ein Zusammenschluß von Daten in einer gemeinsamen Datenstruktur. Flagge: Eine Flagge ist eine Variable, die die beiden Zusatände ein und aus bzw. gesetzt und nicht gesetzt haben kann. In TAG sind Flaggen Variablen für Zahlen von 0 bis 255. Eine Flagge gilt als gesetzt, wenn ihr Wert von 0 verschieden ist. Fußnoten: Fußnoten sind Referenzen im Text, die laufend durchnumeriert sind. Man kann sie sich mit dem Befehl 'Fußnote x' anschauen, wobei x die Nummer der Fußnote ist. IF oder Interactive Fiction: Dieses Wortmonstrum, das im englischen Sprachraum verbreitet ist, beschreibt das Genre der text- basierten Abenteuerspiele. Es gibt leider keine passende Über- setzung ins Deutsche. Mir persönlich gefällt der Begriff nicht und ich verwende lieber "Text-Adventures". Inventar: Das Inventar sind alle Sachen, die der Spieler mit sich trägt. Der Name des Befehls kommt aus dem Englischen, wo sich der Spieler seine Besitztümer mit 'inventory' anzeigen lassen kann. (Srenggenommen müßte es 'mache Inventur' heißen, aber die meisten werden wohl schlicht das Kürzel 'i' verwenden.) Lage: Mit dem Befehl Lage kann sich der Spieler die Beschreibung seines Aufenthaltsorts ausgeben lassen. Das etwas holprige 'Lage' habe ich ausgewählt, um die von englischen Adventures bekannte Abkürzung 'l' wie 'look' benutzen zu können. Wer will darf aber auch sagen: Schau dich um. Landschaft: Die Räume und ihre Verbindungen bilden die Landschaft des Spiels. In ihr bewegt sich der Spieler durch Angabe von Richtungen. Die Landschaft kann auch kartographiert werden, um sich besser darin zurechtzufinden. Dazu wird traditionell jeder Raum durch ein Kästchen dargestellt, die Verbindungen durch Linien in die jeweilige Richtung. Lexikon: Das Lexikon enthält alle Wörter, die der Spieler eingeben kann und die vom Spiel verstanden werden. Im Lexikon wird zwischen Verben, Substantiven, Adjektiven und Präpositionen unterschieden. Objekt: Ein Objekt ist eine Instanz im Adventure, die der Spieler bewegen kann. Objekte können kleine bewegliche Dinge sein, wie Korkenzieher, Münzen oder Schlüssel, aber auch große, unbewegliche Möbelstücke. Auch Personen und Tiere sind in TAG Objekte. Objektklasse: Eine Objektklasse ist ein Prototyp für mehrere Objekte, die die Eigenschaften des Objekts "erben" können. Anders aus- gedrückt: eine Objektklasse ist ein Objekt, das nirgendwo im Spiel auftaucht, sondern nur Eigenschaften und Ausführungs- blöcke bereitstellt, die dann von anderen Objekten übernommen werden können. Parser: Der Parser ist der Teil des Programms, der den eingegebenen Befehl analysiert. In TAG werden zunächst die Synonyme aus- gewertet. Anschließend wird versucht, die Struktur des Satzes mit Verb, Verbklammer, Präpositionen und den Objekten zu er- kennen und daraus einen Befehl eindeutig zu bestimmen. Zum Schluß wird überprüft, ob der Spieler das Objekt sehen können, erreichen können oder gar bei sich tragen muß. Der Parser versucht manchmal auch, fehlende oder mehrdeutige Objekte automatisch zu bestimmen. Person: Eine Person ist ein Objekt, das etwas aus der Menge der anderen Objekte heraussticht: Man kann mit ihr reden, ihr Anweisungen geben und sie wehrt sich dagegen, aufgehoben zu werden. Punkte: Traditionell wird der Erfolg des Spielers in Punkten gemessen. Das ist den frühen Text-Adventures entlehnt, obwohl es heute heftige Diskussionen darüber gibt, on Punkte in ein Adventure gehören. Punkte zu erzielen ist nicht die Aufgabe in Text- Adventures, aber als Anhaltspunkt dafür, wo der Spieler gerade ist, können Punkte schon sinnvoll sein. Raum: Ein Raum beschreibt einen Ort im Adventure, der nicht unbedingt ein Raum sein muß, sondern auch einen geometrisch nicht ganz klar umrissenen Platz darstellen kann, und der verschiedene Objekte enthalten kann - und in dem sich der Spieler aufhalten kann. Raumklasse: Eine Raumklasse ist ein Raum, der nicht im Spiel vorkommt, der aber für andere Räume als Prototyp gilt. Richtung: Eine Richtung ist eine mögliche Verbindung zweier Räume. Meistens sind diese Richtungen die Himmelsrichtungen, wobei angenommen wird, daß der Spieler sich stets hervorragend orientieren kann. Sieg: Der Sieg ist das erfolgreiche Beenden des Spiels und damit auch das Ende des Programms. Der Befehl 'gewonnen' führt zum Sieg. Spieler: Im engeren Sinne ist der Spieler derjenige, der das Adventure geladen hat und der vor seiner Tastatur sitzt. Im weiteren Sinne ist der Spieler die imaginäre Figur, die er durch die Landschaft des Spiels steuert und der er seine Anweisungen übermittelt. Das setzt natürlich voraus, daß sich der Spieler mit seinem Helden identifiziert. Spielwelt: s. Landschaft Standardantworten: Diese Texte liegen auf dem Block 0 und werden für die Meldungen des Parsers und die bereits implementierten Befehle von TAG benutzt. Sie werden üblicherweise von der Datei 'tag.std' gelesen und können an das jeweilige Spiel angepaßt werden. Tod: Der Tod ist ein vorzeitiges Ende des Spiels. Er muß übrigens nicht unbedingt den Tod der Spielfigur bedeuten, sondern kann auch eine andere Art des Mißerfolgs sein. Der Tod des Spielers wird mit dem Befehl 'gestorben' eingeleitet. Variable: Variablen sind Merker für bestimmte Sachverhalte. In TAG kann man sich Zahlen, Räume, Objekte, Zustände und Richtungen merken. Verb: Ein Verb in TAG ist fast immer ein Verb im Imperativ der zweiten Person Singular, wie z.B. 'gehe' oder 'nimm'. Ein Verb kann aber auch ein Schlüsselwort sein, das eigentlich kein Verb ist, das aber als Verb dient: 'Inventar', 'Lage', 'Knapp' usw. Verbklammer: Eine Verbklammer ist eine Präposition, die immer zu einem trennbaren Verb gehört. 'an' könnte die Verbklammer in den Verben 'mache an', 'ziehe an', 'hebe an' oder 'rufe an' sein. Manchmal kann man auch Wörter, die keine Präpositionen sind, als Verbklammern definieren: 'mache kaputt', 'mache sauber'. Vererbung: Bei der Übertragung von Eigenschaften einer Klasse auf ihre Elemente spricht man von Vererbung. Es gibt ersetzende und ergänzende Verebung, je nachdem, ob die Definition der Eigenschaft eines Elements die Eigenschaft, die es von der Klasse übernommen hat, ersetzt oder ob es beide Eigen- scahften, die soeben definierte und die vererbte, besitzt. Wörterbuch: s. Lexikon _____________________________________________________________________________ Martin Oehm e-Mail: martin.oehm@gmx.de URL zum Download: http://www.geocities.com/TheTropics/7490/tag.html