Floyd: Quelltext

So sieht der Quelltext des kleinen Jade-Adventures in Floyd aus. Wenn man mit der Maus über die rot markierten Details fährt, oder sich mit der Tabulatortaste durch den Quelltext bewegt, werden nährere Informationen angezeigt.

Alles, was zwischen /* und */ steht, ist ein Kommentar und wird von Floyd nicht beachtet. Außerdem ignoriert Floyd alles, was nach // auf einer Zeile steht. (Das ist der C++/Java-Kommentarstil)

Mit #include werden andere Floyd-Dateien eingebunden.

Die Standard-Bibliothek besteht aus acht Dateien, die zu Beginn des Quelltexts eingebunden werden sollten.

Eine Klasse ist eine Instanz eines Objekts im Spiel, ob es ein Gegenstand, ein Raum, eine Person oder vielleicht nur ein Konzept ist.

Der Spieler ist nicht vordefiniert. Man muss eine stdcreature definieren, die man dann in main der Variable player zuweist. Auch die Pronomen »mich«, »mir« müssen explizit bei der Spielerklasse angegeben werden.

Nach dem Namen einer Klasse kann man eine Über- oder Superklase angeben, von der die Klase alle Eigenschaften "erbt". Personen im Spiel, also auch der Spieler selbst, sind Instanzen der Superklasse stdcreature oder deren Unterklassen.

Das Schlüsselwort void kennzeichnet eine Funktion, die keinen Wert zurückgibt.

Die Funktion main wird als erstes aufgerufen. Hier können Dinge, zum Beispiel der Spieler, initialisiert werden. Außerdem kann man hier einen Einleitungstext angeben.

Mit write kann man einen Text ausgeben.

Texte stehen in Floyd in doppelten Anführungszeichen.

Ein Zeilenumbruch wird in Floyd mit einem Dach gekennzeichnet. Zwei Dächer kennzeichnen einen Absatz mit nachfolgender Leerzeile.

Die Variable player bezeichnet das Spielerobkejt. Sie kann mit setPlayer gesetzt werden.

Jede Klasse, die ein Objekt im Spiel repräsentiert, sollte dessen Anfangsort mit der Methode moveto definieren.

Nach dem Namen einer Klasse kann man eine Über- oder Superklase angeben, von der die Klase alle Eigenschaften "erbt". Räume im Spiel sind Instanzen der Superklasse stdroom oder deren Unterklassen.

Mit setShort definiert man den Namen des Objekts im Spiel und das Vokabular, mit dem man das Objekt ansprechen kann. Räume haben kein Vokabular.

Die Methode description eines Raums gibt die Raumbeschreibung aus. Besonderheiten wie Objekte, die zu Beginn eine andere Beschreibung haben oder Behälter müssen hier explizit behandelt werden. Außerdem muss in main die Beschreibung des ersten Raums ausdrücklich ausgegeben werden.

Der Datentyp string kennzeichnet eine Text, der dann mit write ausgegeben werden kann.

Mit der Methode has kann man prüfen, ob ein Objekt ein Attribut besitzt oder nicht.

Texte können mit + verkettet werden. Außerdem kennt Floyd die Notation +=, die einen Text an einen anderen anhängt: s += x ist dasselbe wie s = s + x.

Die lange Beschreibung wird in der Raum- oder Objektbeschreibung description verwendet.

Mit der Methode super erhält man die Superklasse einer Klasse. In Methoden m, die nicht ersetzt, sondern nur erweitert werden, muss super.m() explizit ausfgerufen werden.

Die Methode init wird für jede Klasse zu Beginn des Spiels aufgerufen.

Mit addExit kann man in init (oder später) Verbindungen zu anderen Räumen definieren, die von stdexit abgeleitet werden. Solche Verbindungen sind symmetrisch: Geht's von A Richtung Norden nach B, so geht es automatisch von B Richtung Süden wieder nach A.

Die Richtungen in Floyd werden durch Konstanten angegeben.

Die Methode goto eines Raumes wird aufgerufen, wenn der Spieler aus diesem Raum in die angegebene Richtung geht.

Der Datentyp int (integer) bezeichnet eine ganze Zahl.

Ein Objekt ist eine Variable, die entweder eine Klasse beschreibt oder den Wert NULL hat.

Zwei Gleichzeichen == prüfen werte auf Gleichheit - nicht zu ferwechseln mit dem Zuweisungsoperator =, der nur aus ein Gleichzeichen besteht.

Die Methode in prüft, ob eine Klasse in einer anderen ist, ob sie also mit moveto in diese Klasse bewegt wurde.

Die Anweisung quit bericht das Spiel ab. Der Ausgang des Spiels muss explizit angegeben werden.

Mit dem Schglüsselwort with setzt man ein Attribut.

Das Attribut linefeed bewirkt in Räumne, dass zwiachen Beschreibung und Liste der Gegenstände eine Leerzeile eingefügt wird.

Klassen mit dem Attribut hidden werden nicht in Listen angezeigt.

Gegenstände im Spiel haben die Superklasse stditem.

Die kurze Beschreibung kennzeichnet den Namen eines Gegenstand und die Wörter, die der Spieler eingeben kann, um sich auf diesen Gegenstand zu beziehen. Der Genus wird durch ein vorangestelltes Sonderzeichen festgelegt: Plus bedeutet männlich, minus weiblich und ein Und-Zeichen kennzeichnet den Plural. Namen ohne Sonderzeichen sind sächlich.

In Namen kennzeichnet ein Stern die Endung für Adjektive, die dann gebeugt ausgegeben wird.

Das Attribut takeable kennzeichnet Klassen, die aufgehoben werden können.

Die Variable action zeigt an, welche Aktion der Spieler ausführt. Die Aktionen sind Konstanten, die mit A_ beginnen.

Zwei Und-Zeichen verknüpfen zwei Bedigungen so, dass das Ergebnis nur wahr ist, wenn beide Bedingungen wahr sind. Eine Oder-Veknüpfung wird mit zwei senkrechten Strichen || angegeben.

In with können mit vorangestellter Tilde Attribite gelöscht werden.

In Namen können mehrere Synonyme durch Kommas getrennt angegeben werden.

Mit objectsInside kann man prüfen, wieviele Objekte in einem Raum oder Behälter sind.

Die Funktion strLongList erzeugt einen Text (string), der eine Liste der Objekte in einem Raum oder Behälter anzeigt.

Die Liste wird in einem der vier Fälle ausgegeben, hier im Akkusativ (C_ACC).

Mit der Methode onAction kann man in jeder Klasse das übliche Verhalten überschreiben.

Mit switch und case kann eine Variable auf viele Werte geprüft werden.

Die momentan betrachtete Klasse kann über das Schlüsselwort this angesprochen werden. Wenn es eindeutig ist, kann this weggelassen werden: in(a) ist äquivalent zu this.in(a).

/*
===========================================================
    Die Jadestatue
    Eine interaktives Exempel, Martin Oehm, 22.06.2003

    Die Floyd-Version des Jadestatuen-Beispiels.
===========================================================
*/

#include <stdconst.floyd>
#include <stdlist.floyd>
#include <stdobject.floyd>
#include <stdcreature.floyd>
#include <stdroom.floyd>
#include <stditem.floyd>
#include <stdexit.floyd>
#include <stderror.floyd>

class spieler:stdcreature {
    setShort("mich,mir,dich,dir");
    setLong("Abenteuerlustig und gutaussehend.^");
}

void main() {
    write("Endlich! Nach tagelangem Suchen im Dschungel
        stößt du auf eine Lichtung. Und auf etwas mehr.
        Vielleicht ist dies der Ort, an dem sich die
        Jadestatue befindet?^^");
    write("DIE JADESTATUE^");
    write("Ein interaktives Exempel von Martin Oehm^^");

    setPlayer(spieler);
    spieler.moveto(Lichtung);
    Lichtung.description();
}

class Lichtung:stdroom {
    setShort("Lichtung im Dschungel");
    void description() {
        string desc = "Du stehst auf einer Lichtung im
            dichten Dschungel. Im Norden steht ein alter,
            von Ranken überzogener Schrein. Im Süden
            führt ein schmaler Pfad zurück in die
            Zivilisation.^";
        if (Stein.has(hidden)) {
            desc += "^In der Nähe des Schreins liegt ein
                glatter, runder Stein im Gras.^";
        }
        setLong(desc);
        super.description();
    }
    void init() {
        addExit(D_NORTH, Im_Schrein, Lichtung_Schrein);
    }
    void goto(int dir, object item) {
        if (dir==D_SOUTH) {
            if (Jadestatue.in(spieler)) {
                write("Du schaffst es, mit der Statue
                    wieder zurück in die Zivilisation zu
                    gelangen.^^");
                write("*** Du hast gewonnen ***^^");
                quit;
            } else {
                write("Nicht ohne die Statue!^");
            }
        } else {
            if (exits[dir]==NULL) {
                write("Dort ist der Dschungel zu dicht, es
                    gibt keinen Pfad in diese Richtung.^");
            } else {
                super.goto(dir, item);
            }
        }
    }
    with(linefeed);
}

class Lichtung_Schrein: stdexit {
    with(hidden);
}

class Stein:stditem {
    setShort("+faustgroß* Stein");
    setLong("Der Stein ist so groß wie eine Faust
        und außergewöhnlich glatt und rund.^");
    moveto(Lichtung);
    with(hidden, takeable);
    int onAction(int action) {
        int r = super.onAction(action);
        if (action == A_TAKE && this.in(player)) {
            this.with(~hidden);
        }
        return(r);
    }
}

class Schrein:stditem {
    setShort("+alt Schrein,+Toltekenschrein,+Efeu,&Ranken");
    setLong("Der alte Toltekenschrein ist fast komplett
        mit Efeu überwuchert.^");
}

class Im_Schrein:stdroom {
    setShort("Im Schrein");
    void description() {
        string s = "In dem kleinen Schrein ist es dunkel,
            nur wenig Licht fällt durch das halb
            verfallene Dach. Ein großer Lichtstrahl fällt
            auf eine Steinsäule in der Mitte des Schreins.^
            ^Die Lichtung liegt im Süden.^";
        int n = objectsInside(Saeule);
        if (n > 0) {
            s += "^Auf der Säule siehst du "; 
            s += strLongList(Saeule, C_ACC);
            s += "^";
        }
        setLong(s);
        super.description();
    }
    with(linefeed);
}

class Saeule:stditem {
    setShort("-Steinsäule,-Säule,Podest");
    setLong("Die Säule ist aus glattem Stein
        gehauen, etwas mehr als einen Meter hoch und oben
        flach, wie ein Podest.^");
    moveto(Im_Schrein);
    with(hidden, supporter, transparent, open);
}

class Jadestatue:stditem {
    setShort("-Jadestatue,-Jadefigur,-Figur,-Statue");
    setLong("Es ist die Statue einer toltekischen
        Gottheit, komplett aus grüner Jade geschnitzt. Sie
        glänzt und sieht sehr wertvoll aus.^");
    int onAction(int action) {
        switch (action) {
            case(A_TAKE);
            if (in(Saeule) && !(Stein.in(Saeule))) {
                write("Als du das Gewicht der Statue von
                    der Säule nimmst, hörst Du ein
                    klickendes Geräusch. Kurz darauf wirst
                    du von Giftpfeilen durchbohrt.^^");
                write("*** Du bist jetzt tot. ***^^");
                quit;
            }
        }
        return(super.onAction(action));
    }
    moveto(Saeule);
    with(takeable);
}