________________________________________________________________________
| ||
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 RaumbeschreibungRaumbeschreibungen 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:
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ändlichen 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 NachtNehmen 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. 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 RaumMan 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 LabyrinthSo 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ästige 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 eineWenn 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 LandkarteEin 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. | ||
|