Verschlossene Türen und versteckte Schlüssel gehören zu einem Textadventure wie die Olive zum Martini. Deshalb gibt es auch in Eden eine verschlossene Tür; sie führt vom östlichen Teil des Gartens - EdenE - zu einem Raum, den wir noch nicht gesehen haben und der den schönen Namen EastOfEden trägt. Es handelt sich um eine komplizierte Tür: Sie ist auf beiden Seiten (fast) gleich; dafür steht sie nicht an einer Seite des Raums oder - wie gewöhnlich - an einer Wand, sondern mittendrin ohne eine bestimmte Richtung; außerdem bietet sie eine böse Überraschung, wenn der Spieler sie zum ersten Mal öffnet (zum Trost bekommt er Punkte dafür):
with description "Die Tür ist bis auf das Schlüsselloch mit Blumen
zugewachsen. Sie steht mitten im Raum, trotzdem
kannst du ihre Rückseite nicht sehen.",
name 'tuer' 'blume' 'blumen' 'zugewachsen' 'schluessel' 'loch'
'Raum' ,
each_turn[;
if (location == EastOfEden)
self.&name->6 = 'Garten';
else
self.&name->6 = 'Raum';
],
when_closed "Eine mit Blumen bewachsene Tür steht da.",
when_open [;
if (self in EdenE) "Eine Tür führt aus dem Garten heraus in
einen weiten, offenen Raum."; ! rtrue!
"Die Tür führt zurück in den Garten Eden.";
],
door_to [;
if (self in EdenE) return EastOfEden; ! auch das ist true!
return EdenE;
],
door_dir in_to,
with_key Primel,
before [;
lookUnder: "Du siehst viele Blumen.";
take, lift, transfer: "So kommst du nicht weiter.";
],
react_before [;
insert, puton: if (self == second)
{
if (noun==primel)
<<unlock self primel>>;
else
"So kommst du nicht weiter.";
}
],
after [;
open: if (self hasnt general)
{
achieved(0);
give self general;
move schlange to mitte;
"Du öffnest die Tür nur einen Spalt weit, da wird sie
dir schon aus der Hand gestoßen. Etwas Großes, rot und
schwarz Gefärbtes drückt die Tür auf und dringt in den
Garten ein. Es ist ein Tier, das du noch nicht kennst,
langgestreckt und ohne Gliedmaßen. Es sieht dich kurz
an, zischt, und du fühlst dich mit einem Mal wie eiskalt.
- Dann wendet es sich wieder ab und schlängelt durch
das Gras in westlicher Richtung in den Garten.^^
Das Tier braucht einen Namen. Du beschließt, es
~Schlange~ zu nennen. ^^
Die Tür ist jetzt offen. Du siehst durch die Tür in einen
weiten, offenen Raum.";
}
unlock: remove primel;
give primel general;
"Du hältst die Primel an das Schlüsselloch. Sie schlägt
sofort Wurzeln zwischen den anderen Blumen und ist von
ihnen nicht mehr zu unterscheiden.
^^Die Tür ist nicht mehr versperrt.";
],
found_in EdenE EastOfEden,
short_name "Tür",
dekl 9,
has female static door openable lockable locked;
Zur Tür wird ein Objekt durch das Attribut door. openable legt fest, dass der Spieler sie auf- und zumachen kann; lockable legt fest, dass er sie - mit dem richtigen Schlüssel - auf- oder zusperren kann. Das Attribut locked schließlich bedeutet, dass die Tür zu Anfang zugesperrt ist. Die Aktionen dazu heißen ##Open, ##Close, ##Lock und ##Unlock.
Eine Tür muss gar keine Tür sein. Mit dem eben beschriebenen Instrumentarium kann man auch z.B. eine Brücke oder einen Materietransmitter bauen.
Im klassischen Adventure dreht sich alles darum, durch die Tür und an den Schatz zu kommen. Wie die Tür auf der Rückseite aussieht, ist nicht so wichtig. Unsere Tür aber hat zwei Seiten:
Zunächst ist sie wieder mit found_in als Schiebekulisse implementiert, d.h. sie befindet sich immer in dem Raum, in dem auch die Spielfigur ist. Dies ermöglicht es, entweder mit (location==EdenE) oder mit (self in EdenE) abzufragen, auf welcher Seite wir gerade sind. (Beides führt hier zum gleichen Ergebnis: location ist der augenblickliche Aufenthaltsort der Spielerfigur25; mit in wird abgefragt, ob EdenE der parent von self, d.h. der Tür ist.) Je nach dem Ergebnis ändern wir den Inhalt von door_to und die Beschreibung des Raums, der durch die offene Tür zu sehen ist, in der property when_open. Bei einer ,,normalen'' Tür müssten wir auch noch door_dir ändern.
Hier ist an zwei Stellen (die ich markiert habe) der oben (2.6.3) beschriebene Trick mit (implizitem) return angewendet worden; bei ,,sauberer'' Programmierung müsste da jeweils noch ein else stehen.
Um das Ganze perfekt zu machen, jonglieren wir auch mit dem Namen der Tür. Der Befehl ,,Gehe in den Garten'' soll den Spieler durch die Tür schicken, wenn er auf der anderen Seite steht. Steht er aber schon im Garten, wäre der Befehl sinnlos und der Spieler würde sich zu Recht aufregen, wenn er mit ,,Gehe in den Garten'' aus dem Garten herausgeschickt würde.
Zu Spielbeginn steht die Tür auf der Gartenseite (in EdenE) und der letzte (siebte) Eintrag der name-property lautet: 'Raum'. Auf 'Garten' hört die Tür gar nicht, wohl aber auf ,,Gehe in den Raum''. Geht der Spieler aber durch die Tür, so ändern wir diesen (siebten) Eintrag von 'Raum' in 'Garten' und voilá: ,,Gehe in den Garten'' funktioniert; dafür hört die Tür nicht mehr auf 'Raum', denn das ist überschrieben worden.
Wie macht man das? Ganz einfach: Intern ist das name-property ein array, d.h. ein Feld aus einzeln (mit dem Operator ->) adressierbaren Wörterbucheinträgen. Ein ,,normales'' property der Tür kann z.B. mit tuer.description (innerhalb des für die Tür geschriebenen Codes einfacher mit self.description) aufgerufen werden. Uns interessiert aber nicht die gesamte name-property, sondern nur ein einzelner (der siebte und letzte) Eintrag. Um dies zu kennzeichnen, muss dem name ein & vorangestellt werden, also self.&name.
Nun kann der siebte Eintrag mit self.&name->6 adressiert werden (der erste Eintrag hat den Index 0, der siebte den Index 6).
Wie aber merken wir, ob der Spieler durch die Tür gegangen ist? Wir schauen ganz einfach nach jedem Zug nach, wo er steht und sorgen dafür, dass der Name richtig gesetzt ist. Dafür benutzen wir der Einfachkeit halber die property each_turn , die eine Routine enthalten kann, die bei jedem Zug ausgeführt wird, wenn die Tür im Blickfeld des Spielers ist.
Wenn die Tür zum ersten Mal geöffnet wird, ist das Attribut general noch ungesetzt. Dann lassen wir die Schlange in den Garten einbrechen und setzen anschließend general, damit das nicht noch einmal passiert. Mit der Routine Achieved(0) wird festgehalten, dass der Spieler die erste (bzw. die nullte, auch hier wird beginnend mit Null gezählt) Aufgabe des Spiels gelöst hat und dafür Punkte beanspruchen kann.
Wir betrachten nochmal die react_before-property und dort die Regel für ##Insert und ##PutOn : Hier werden Handlungen des Spielers wie ,,Setze die Primel auf die Tür'' abgefangen (In diesem Befehl wäre die Primel erstes, direktes Objekt (noun) und die Tür zweites Objekt (second).) und abgeändert -- in den Befehl ,,Sperre die Tür mit der Primel auf'' (auf ,,Informese'' <Unlock Tuer Primel>, der zweite Satz spitze Klammern steht wieder für ein implizites return und statt Tuer kann self stehen).