The Elder Scrolls III: Morrowind - Scriptkurs
1. Einfache Spielerinteraktion über Messageboxen und das Tagebuch
In der Einführung wurde euch ein Script vorgestellt:
Code:
begin kf_hello_world_script
if ( OnActivate == 1 )
MessageBox, "Hallo, Welt!"
endif
end
Dieses Script veranlasste den Activator, sobald er aktiviert wurde, eine Messagebox mit dem Text "Hallo, Welt!" zu öffnen. Das hat immer wieder funktioniert. Wie genau funktioniert dieses Script nun?
Bedingungen abfragen: if-Blöcke
In diesem Script wird zuerst eine if-Bedingung abgefragt. Das if ist einer der grundlegenden Befehle in Morrowind Script. Seine Wirkung ist dabei so zu formulieren: Wenn eine Bedingung erfüllt ist, dann mache irgendwas. Wenn die Bedingung nicht erfüllt ist, überspringe diesen Teil. Im Beispielscript ist die einfachste Variante eines if zu sehen. Es gibt auch noch kompliziertere. Die allgemeinste Form eines if-Blocks ist:
Code:
if ( a == 1 )
;mache irgendwas
elseif ( a == 2 )
;mache irgendwas anderes
else
;mache nochmal was anderes
endif
Diesen Block kann man in etwas so lesen:
Wenn a gleich 1 ist, führe alles aus bis zum elseif aus. Wenn a nicht 1 ist, aber a gleich 2 ist, führe alles bis zum else aus. Wenn a weder 1 noch 2 ist, führe alles bis zum endif aus.
Jeder if-Block muss genau ein if und genau ein endif enhalten. Zusätzlich kann jeder Block beliebig viele elseif, aber nur ein else enhalten. Das else steht dabei immer als letzter Teil vor dem endif.
Hinter jedem if und elseif steht eine Bedingung beziehungsweise ein Vergleich in Klammern. Ist dieser Vergleich wahr, wird ausgeführt, was sich unter dem Vergleich befindet. Wenn der Vergleich falsch ist, wird zum nächsten Vorkommen eines else(if) oder endif gesprungen.
Vergleiche bestehen aus zwei Zahlen (ob diese Zahlen nun als tatsächliche Zahen, als Variablen oder als Rückgabewert einer Funktion dort stehen, ist ersteinmal egal) und einem Vergleichsoperator. Einige Beispiele dazu:
Code:
if ( a == 1 ) ;wenn a gleich 1
if ( a > 1 ) ;wenn a größer als 1
if ( a < 1 ) ;wenn a kleiner als 1
if ( a >= 1 ) ;wenn a größer oder gleich 1
if ( a <= 1 ) ;wenn a kleiner oder gleich 1
if ( a != 1 ) ;wenn a ungleich 1
Statt der Variablen a könnte man hier auch viele Funktionen hinschreiben, zum Beispiel OnActivate.
Eine vereinfachte Form der if-Abfrage ist es den Vergleich einfach wegzulassen:
Code:
if ( OnActivate )
;mache irgendwas
endif
Bei diesem Beispiel wird ausgenutzt, dass das Script normalerweise erst den Vergleich auswertet. Ist er wahr ersetzt das Script ihn mit einer 1, ist er falsch ersetzt er ihn mit einer 0. Das Script führt den Teil nach dem if immer aus, wenn in der Klammer letztendlich keine 0 steht (0 steht in der Informatik normalerweise für falsch).
if ( OnActivate ) wird vom Script genauso verstanden wie if ( OnActivate != 0 ).
Viele verwenden diese Kurzformen, wenn eine Variable oder Funktion normalerweise nur die Werte 0 und 1 annimmt. Ich persönlich mag sie nicht besonders, aber das ist größtenteils Geschmackssache. Mein Argument gegen diese Schreibweise ist, dass zumindest Variablen vielleicht doch mal einen anderen Wert als 0 oder 1 haben könnten. In diesem Fall ist mir eine Gleichheit lieber, als eine Ungleichheit.
Scriptfunktionen
Neben den wenigen Befehlen (begin, end, if, while, ...) verfügt Morrowind Script über eine Vielzahl von Funktionen. Diese Funktionen machen die verschiedensten Dinge. Grundsätzlich kann man die Funktionen in zwei Arten einteilen. Einmal gibt es die Funktionen, die irgendeinen Wert des Spiels abfragen (und dabei nichts am Spiel verändern) und es gibt die Funktionen, die irgendwas am Spiel ändern. In dem Beispielscript gab es von jeder Sorte eine dieser Funktionen.
OnActivate
Diese Funktion ist eine Funktion die einen Wert abfragt. Sie liefert normalerweise eine 0 (beziehungsweise falsch). Nur in dem Moment, in dem jemand (normalerweise der Spieler) das Objakt auf dem dieses Script liegt, aktiviert, liefert die Funktion eine 1 (also wahr).
So kann man mit dieser Funktion herausbekommen, wenn der Spieler versucht ein Objekt zu aktivieren. Versucht deshalb, weil das Objekt sich nicht aktivieren lässt, wenn auf ihm ein Script mit OnActivate liegt. Das ist eigentlich eine sehr interessante Möglichkeite für Scripte. Man kann nun (mit Hilfe weiterer ifs) verhindern, dass der Spieler bestimmte Objekte zu einem bestimmten Zeitpunkt aktivieren kann. Ein Beispiel:
Code:
if ( OnActivate == 1 )
PlaySound, "LockedDoor"
endif
Legt man dieses Script auf eine Tür, wird sie dem Spieler so vorkommen, als wäre sie verschlossen (Sie spielt beim Aktivieren den Sound einer verschlossenen Tür ab.). Aber das Schloss kann er niemals knacken, da die Tür eigentlich gar kein Schloss besitzt.
Natürlich gibt es auch Situationen, in denen man zwar ein Aktivieren feststellen möchte, der Spieler das Objekt aber trotzdem Aktivieren können soll. Dazu kann man folgende Konstruktion verwenden:
Code:
if ( OnActivate == 1 )
;mache irgendwas
Activate
endif
Das Activate sorgt dafür, dass ein Objekt trotzdem aktiviert wird. Activate hat zwar noch mehr Einsatzmöglichkeiten, aber dies ist die wichtigste.
Noch eine kleine Randbemerkung zu OnActivate: Versucht man eine Aktivierung bei einem Activator (der Objektklasse) festzustellen, muss dieser einen Namen besitzen!
MessageBox
Die andere im Beispielscript verwendete Funktion ist MessageBox. Diese Funktion gibt, wie wir ja schon wissen, eine Nachricht im Spiel aus. Aber die Funktion kann noch viel mehr. Tatsächlich ist dies eine der vielseitigsten Funktionen in Morrowind Script.
Damit die Funktion ihre komplette Funktionalität entfaltet, müssen der Funktion gewisse Parameter übergeben werden. Parameter heißen bestimmte Zahlen, Objekt-IDs oder Variablen, die hinter einem Funktionsnamen geschrieben werden müssen. Die gesamte MessageBox-Funktion sieht so aus:
Code:
MessageBox, "Anzuzeigender Text"[, var1, var2, ...][, "Antwort 1", ..., "Antwort 9"]
Die Messagebox blendet eine Nachricht ein und kann zusätzlich bis zu 9 Buttons erzeugen (Antwort 1 – Antwort 9). Wenn Antwortmöglichkeiten gegeben sind, schließt sich das Fenster erst nach klicken auf eine der Antworten. Welche Antwort geklickt wurde lässt sich mit GetButtonPressed ausgeben. Ist keine Antwortmöglichkeit gegeben, bleibt das Fenster abhängig von der Zeichenanzahl der Nachricht eingeblendet. Die Dauer pro Zeichen wird im GameSetting fMessageTimePerChar festgelegt und ist standardmäßig auf 0,1 Sekunden gestellt.
Es ist auch möglich Werte von Variablen im Text anzuzeigen. Im Text muss dafür ein Platzhalter verwendet werden: %f oder %.yf. In der ersten Version wird jede Zahl mit 6 Nachkommastellen angegeben. In der zweiten Version wird die Zahl mit der in y festgelegten Anzahl von Nachkommastellen ausgegeben. Somit sollte für Variablen vom Typ short oder long der Platzhalter %.0f verwendet werden. In Messageboxen lassen sich auch einige Stringkonstanten ausgeben. Diese müssen mit einem ^ (Zirkumflex) angeführt
werden.
Wird eine Messagebox während eines Dialoges aufgerufen, wird der Inhalt der Messagebox als weiße Schrift in einen neuen Absatz geschrieben. Dies funktioniert allerdings nur mit Messageboxen ohne Antworten.
Hier einige Beispiele, die die verschiedenen Möglichkeiten der Messagebox zeigen:
Code:
MessageBox, "Ganz einfache Messagebox."
---
MessageBox, "Der Name des Spielers ist ^PCName."
---
long gold
set gold to "Player"->GetItemCount, "Gold_001"
MessageBox, "Ihr besitzt %.0f Draken.", gold
---
MessageBox, "Es ist der %.0f. %.0f. im Jahr 3Ä %.0f.", Day, Month, Year
---
MessageBox, "Diese Nachricht verschwindet erst, wenn Ihr OK anklickt.", "OK"
---
MessageBox, "Es ist schon nach %.0f Uhr. Ihr solltet schlafen gehen.", GameHour, "OK"
GameHour, Day, Month und Year in den obigen Beispielen sind globale Variablen. Das sind Variablen, die von jedem Script aufgerufen oder verändert werden können. Man muss sie nicht im Script deklarieren, sondern kann dies im Construction Set unter Gameplay->Globals tun.
Verwaltung der globalen Variablen
In der Beschreibung zur Messagebox habe ich auch verschiedene Antworten erwähnt und dass man über GetButtonPressed heraus bekommt, welcher Button gedrückt wurde:
GetButtonPressed
Die Funktion liefert die Nummer des Messagebox-Buttons zurück, den der Spieler angeklickt hat. Der erste Button liefert eine 0, der zweite eine 1 und so weiter. Hat der Spieler noch keinen Button geklickt, liefert die Funktion -1 zurück. Eine Konstruktion kann zum Beispiel so aussehen:
Code:
begin kf_beispiel2_script
short state
short button
if ( state == 0 )
if ( OnActivate == 1 )
set state to 1
MessageBox, "Was ist eure Lieblingszahl?", "1", "2", "3"
endif
else
set button to GetButtonPressed
if ( button == 0 )
set state 0
MessageBox, "Eure Lieblingszahl ist 1."
elseif ( button == 1 )
set state 0
MessageBox, "Eure Lieblingszahl ist 2."
elseif ( button == 2 )
set state 0
MessageBox, "Eure Lieblingszahl ist 3."
endif
endif
end
In diesem Script wird auch zum ersten Mal einer Variable ein Wert zugewiesen. Mit dem Befehl set ... to ... lässt sich das erreichen. Zwischen set und to muss der Name der zu verändernden Variable stehen. Hinter dem to kann eine Zahl, eine andere Variable, eine Funktion oder eine Rechnung stehen. Einige Beispiele:
Code:
short test1
short test2
set test1 to 3
set test2 to test1
set test1 to GetButtonPressed
set test2 to test1 - 5
set test2 to ( test1 - 5 ) * 6
Damit wären die beiden Funktionen aus dem Beispielscript erklärt. Um nun noch etwas Neues einzuführen, werde ich noch die Funktion des Tagebuchs erklären:
Das Tagebuch
Das Tagebuch des Spielers ist ein einfacher Weg die Fortschritte von Quests festzuhalten. Man kann Tagebucheinträge genauso wie normale Dialoge erstellen. Allerdings gibt es die Besonderheit, dass als einzige Bedingung einen Index angeben kann. Zusammen mit dem Namen des Tagebuchthemas bildet der Index die Möglichkeit jeden Tagebucheintrag eindeutig anzugeben.
Ihr habt nun also ein Tagebuchthema mit verschiedenen Indizes erstellt. Wie könnt ihr diese nun in das Tagebuch des Spielers eintragen oder (noch wichtiger) wie bekommt ihr heraus, ob sich ein bestimmter Eintrag schon im Tagebuch des Spielers befindet?
Dafür gibt es zwei Funktionen:
Journal
Diese Funktion kann in Scripten aufgerufen werden, wird aber auch sehr oft in Dialogresultboxen verwendet (und in der Konsole ist sie natürlich auch sehr praktisch um Quests abzukürzen ).
Code:
Journal, "JournalTopic_ID", index
Journal, "C3_DestroyDagoth", 50
Diese Funktion fügt dem Tagebuch des Spielers einfach den mit Journalthema und Journalindex bestimmten Eintrag hinzu.
GetJournalIndex
Mit dieser Funktion ist es möglich den Wert des höchsten vorhandenen Indexs zu einem bestimmten Thema, der sich bereits im Tagebuch des Spielers befindet, zu bekommen.
Code:
GetJournalIndex, "JournalTopic_ID"
Eine übliche Anwendung ist es, den Wert eines Tagebucheintrags abzufragen und nur bei einem bestimmten vorhandenen Eintrag eine Aktion auszuführen. Ein Beispiel ist folgendes Script, dass beim Aktivieren eines Activators dem Spieler eine Nachricht ins Tagebuch einfügt. Aber nur wenn dieser Eintrag nicht schon vorhanden ist (Wer braucht schon doppelte Tagebucheinträge?):
Code:
if ( OnActivate == 1 )
if ( GetJournalIndex, "C3_DestroyDagoth" < 50 )
Journal, "C3_DestroyDagoth", 50
endif
endif
Aufgaben
Wie angekündigt, stellen wir am Ende jedes Teils einige Aufgaben, die ihr versuchen sollt zu lösen. Eure Lösungen könnt ihr dann vor Beginn des nächsten Teils hier vorstellen. Präsentiert eure Lösungen aber bitte im Spoiler, damit ihr anderen die Möglichkeit gebt, die Lösung noch selbst herauszufinden.
Natürlich dürft ihr unter einander über die Aufgaben diskutieren. Hier ist ja keine Schule und ihr müsst nicht still sitzen
- Verändert das "Hallo, Welt"-Script aus der Einführung so, dass ihr die Beispiele zur MessageBox-Funktion ausprobieren könnt.
- Probiert das zweite Beispielscript aus.
- Verändert das "Hallo, Welt"-Script so, dass es zunächst fragt, ob der Spieler ein Mann oder eine Frau ist und danach mit "Hallo Herr y" oder "Hallo Frau x" begrüßt.
- Erschafft einen Activator, der sich wie eine Digitaluhr verhält. Sie soll euch mit Namen begrüßen und euch die Zeit (in Stunden und Minuten, nicht nur in Stundenbruchteilen) und das Datum angeben. Ihr sollt die Anzeige bestätigen müssen, bevor ihr weiterspielen könnt.
- Erschafft eine Tür, die sich erst öffnet, wenn der Spieler einen bestimmten Tagebucheintrag hat. Hat er ihn noch nicht, soll er eine entsprechende Nachricht bekommen, hat er ihn, soll die Tür beim ersten Betreten einen neuen Tagebucheintrag hinzufügen.
Lösungen
Aufgaben - Teil 2
Zuletzt bearbeitet: