Construction Set Morrowind-Scriptkurs - Lektion 1

Killfetzer

Super-Moderator
Teammitglied
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.

Scriptkurs_Globals.jpg


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 ;)

  1. Verändert das "Hallo, Welt"-Script aus der Einführung so, dass ihr die Beispiele zur MessageBox-Funktion ausprobieren könnt.
  2. Probiert das zweite Beispielscript aus.
  3. 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.
  4. 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.
  5. 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:
Hier ist schonmal meine Lösung für 3

(Hab,aber nicht getestet da ich momentan CSlos bin)

Code:
begin md_what_is_your_gender_script

short state
short button

if ( OnActivate == 1 )
    set state to 1
    MessageBox, "Was seid ihr,Mann oder Frau?", "Mann", "Frau"
else
  set button to GetButtonPressed
  if ( button == 0 )
    set state 0
    MessageBox, "Hallo Herr ^PCName!"
  elseif ( button == 1 )
    set state 0
    MessageBox, "Hallo Frau ^PCName!"
  endif
endif

end
 
Zuletzt bearbeitet:
Danke,hab den Code jetzt eingerückt.


EDIT

Hier ist meine Lösung für 4.

Code:
begin md_what_time_is_it_script

short state
short button

if ( OnActivate == 1 ) 
  set state to 1
  Messagebox, "Hallo ^PCName!Es ist %.2f Uhr am %.0f. %.0f. im Jahr 3Ä %.0f.",GameHour, Day, Mouth, Year,"OK"
endif
else
  set button to GetButtonPressed
  if ( button == 0 )
  set state to 0
  endif
end
 
Zuletzt bearbeitet:
Dann will ich hier mal für die erste Lektion meine Lösungen ab Aufgabe 3 präsentieren, es sei denn ihr wollt auch noch für das Rumexperimentieren in 1 und 2 die Lösungen?

Aufgabe 3:

Code:
begin merc_hello_world

short state
short button

if (state==0)
    if (onActivate==1)
        set state to 1
        MessageBox, "Welchen Geschlechts seid Ihr?", "Mann", "Frau"
    endif
else
    set button to GetButtonPressed
    if (button ==0)
        [COLOR=Red]set state to 0[/COLOR]
        MessageBox, "Hallo Herr ^PCName."
    elseif (button==1)
        [COLOR=Red]set state to 0[/COLOR]
        MessageBox, "Hallo Frau ^PCName."
    endif
endif

end

Und gleich mal ne Frage dazu:
Die von mir rot markierten Zeilen im Script, sollen diese dafür sorgen, dass nach Auswahl der Antwortmöglichkeiten das Script wieder in den Ursprungszustand geht, sprich, wieder auf 0 gesetzt wird? Oder hat dies einen etwas anderen Grund?

Aufgabe 4:

Mal das vorläufige Ergebnis, ich feile noch an der genauen Ausgabe der Minuten statt Stundenbruchteilen.

Code:
begin merc_greetin_with_clock


if (OnActivate==1)
    MessageBox, "Hallo ^PCName, es ist jetzt [COLOR=Red]%.2f.[/COLOR] am %.0f. %.0f. in 3Ä %.0f", gamehour day month year, "OK"
endif
end

Aufgabe 5:

Code:
begin Merc_Journal_Door

if(OnActivate==1)
    if(GetJournalIndex, "blades_rithleen"<1)
    Messagebox, "Euch fehlt der Tagebucheintrag für Rithleen."
else
    Activate
    Journal,"A1_Sleepers_Assi", 1
    endif
endif

end

Sehr schöne Aufgaben zur Einführung, klar machbar und doch zum Nachdenken gefordert. So solls sein :)
 
Zuletzt bearbeitet:
  1. Wie ist das deklarieren von state zu verstehen, was nützt es? Wenn state die ganze Zeit auf 0 ist, müsste das Script dann nicht genauso laufen? Da state am Ende wieder zurückgesetzt wird (u.A. im Beispielscript) denke ich dass da keine Endlosschleife entstehen kann.
  2. Ist die Deklaration von Button überhaupt notwendig? kann ich nicht gleich Anstelle von "set Button to GetButtonPressed" nur GetButtonPressed abfragen?

Danke für die Mühe, das Ganze sieht nach einem Haufen Arbeit für dich aus, ich schätze das wirklich :)
 
Hab mich auch mal daran versucht.

Aufgabe 3:

Code:
begin ctg_hallo_welt_script

short state
short button

if ( state == 0 )
    if ( OnActivate == 1  )
        set state to 1
        MessageBox, "Hallo, bist du ein Mann oder eine Frau?", "Mann", "Frau"
    endif
else
    set button to GetButtonPressed
    if ( button == 0 )
        set state to 0
        MessageBox, "Hallo Herr ^PCName."
    elseif ( button == 1 )
        set state to 0
        MessageBox, "Hallo Frau ^PCName."
    endif
endif

end

Aufgabe 4:


Code:
begin ctg_digitaluhr_script

if ( OnActivate == 1 )
    MessageBox, "Hallo ^PCName, beim nächsten Signalton ist es %.2f Uhr. Es ist der %.0f. %.0f. des Jahres 3Ä %.0f.", GameHour, Day, Month, Year, "OK"
endif

end
Was mich hier stört, ist die Tatsache, dass die beiden Nachkommastellen bei der Zeit bis 100 zählen. Lässt sich das irgendwie auf 60 absenken oder hab ich da was überlesen? :?

Aufgabe 5:

Code:
begin ctg_locked_door_script

short journal

if ( OnActivate == 1 )
    if ( GetJournalIndex, Journal "test_locked_door" == 50 )
        Journal, "test_locked_door", 100
        unlock
        PlaySound, "Open Lock"
    elseif ( GetJournalIndex, Journal "test_locked_door" == 100 )
        activate
    else
        MessageBox, "Du kommst hier net rein!"
        PlaySound, "LockedDoor"
    endif
endif

end

Das hab ich aber noch nicht in der Praxis ausprobiert^^ Öhm, muss eigentlich die Tür vorher auch noch wie der Alkoholschrank in der Eisfalter-Festung per Script verschlossen werden?

//EDIT: So alle Probleme an der Tür gefixt, klappt wunderbar.
 
Zuletzt bearbeitet:
@Crashtestgoblin:

Soweit ich das verstanden habe, braucht bei Aufgabe 5 die Türe nicht extra verschlossen zu werden, da dies durch nicht erfüllte Bedingungen von ganz allein geschieht. Ich hab meine Lösung ingame getestet und sie hat auf jeden Fall so funktioniert, wie es sein sollte.
 
  • Like
Reaktionen: Crashtestgoblin
Dann will ich hier mal für die erste Lektion meine Lösungen ab Aufgabe 3 präsentieren, es sei denn ihr wollt auch noch für das Rumexperimentieren in 1 und 2 die Lösungen?

Wir wollen gar nichts. Ihr wollt üben. Aber ich denke den Code der Aufgaben 1 und 2 müsst ihr nicht vergleichen ;)

Und gleich mal ne Frage dazu:
Die von mir rot markierten Zeilen im Script, sollen diese dafür sorgen, dass nach Auswahl der Antwortmöglichkeiten das Script wieder in den Ursprungszustand geht, sprich, wieder auf 0 gesetzt wird? Oder hat dies einen etwas anderen Grund?

Genau, das ist der Sinn dieser Zeilen. Durch diese Zeile kann der Activator seine Nachricht immer wieder abspielen. Außerdem verhindert es, dass die GetButtonPressed-Abfrageimmer wieder neu durchlaufen wird.

Aufgabe 5:

Code:
begin Merc_Journal_Door

if(OnActivate==1)
    if(GetJournalIndex, "blades_rithleen"<1)
    Messagebox, "Euch fehlt der Tagebucheintrag für Rithleen."
else
    Activate
    Journal,"A1_Sleepers_Assi", 1
    endif
endif

end

Das erfüllt aber nicht die Anforderungen (und ist auch nicht sehr schön gesetzt). Der Tagebucheintrag sollte ja nur einmal erscheinen und nicht immer.

  1. Wie ist das deklarieren von state zu verstehen, was nützt es? Wenn state die ganze Zeit auf 0 ist, müsste das Script dann nicht genauso laufen? Da state am Ende wieder zurückgesetzt wird (u.A. im Beispielscript) denke ich dass da keine Endlosschleife entstehen kann.
  2. Ist die Deklaration von Button überhaupt notwendig? kann ich nicht gleich Anstelle von "set Button to GetButtonPressed" nur GetButtonPressed abfragen?

Deine Fragen musst du nicht in Spoiler setzen ;)

  1. Normalerweise lässt du ein Script ja etwas mehr machen als eine Messagebox ausgeben. In meinem Beispielscript würde es wahrscheinlich auch ohne state laufen. Aber ich bin mir relativ sicher, dass es zu ungewollten Nebenwirkungen mit anderen Scripten kommen könnte und sowas will man natürlich vermeiden.
    Allgemein empfehle ich dir, es einfach auszuprobieren. Dafür ist der Kurs ja da. Lass es einfach mal weg und schaue was passiert.
  2. Ja, kannst du. Allerdings ist es programmiertechnisch üblich, dass man eine Funktion nur einmal aufruft und das Ergebnis zwischenspeichert. Die Funktion benötigt nämlich mehr Rechenzeit als das Abrufen einer gespeicherten Variable und man ist immer bemüht, die Rechenzeit zu optimieren.

Was mich hier stört, ist die Tatsache, dass die beiden Nachkommastellen bei der Zeit bis 100 zählen. Lässt sich das irgendwie auf 60 absenken oder hab ich da was überlesen? :?

Genau das ist ja der Knackpunkt an der Aufgabe. Dafür muss man schon ein bisschen rätseln. ;)
 
Code:
begin md_sesam_open_you_script

short state
short journal                           

if ( state == 0 )
   if ( OnActivate == 1 )
      if ( GetJournalIndex, Journal "test_locked_door" < 50 )
      Messagebox "Der Weg ist euch verwehrt!Habt ihr etwas vergessen?"
      elseif ( GetJournalIndex, Journal "test_locked_door ==50 )
             Activate
             Journal, "test_locked_door", 100
             set state to 1
      endif
    endif
endif

end


Was mich stört ist die 3. Aufgabe
OK,wenn man die Stundenbruchteile weg haben will muss man den Platzhalter in %.0f ändern.Trotzdem fehlen noch die Minuten...
 
Gibt es irgendwie eine Möglichkeit lediglich die Nachkommastellen auf 0 zu setzen? Ich bau andauernd Zeitmaschinen, die die Uhrzeit auf 0.00 zurücksetzen...
Oder kann ich GetSecondsPassed irgendwie als Variable verwenden? Es ist zum Verzweifeln...
 
Du suchst Funktionen wie ABS(x), DIV(x) und MOD(x)... zu schade, dass es sowas nicht gibt :-D

Wie heißt es so schön, bei Morrowind Script kann man vieles nur über Umwege machen. Nur wie könnte man dann von einer Dezimalzahl (float) die Dezimalen wegschneiden und nur den ganzzahligen Teil, also einen Integer (Short/Long) behalten... ;)

Denk ein wenig nach, vielleicht kommst du drauf... es ist nicht so schwer.
 
Du suchst Funktionen wie ABS(x), DIV(x) und MOD(x)... zu schade, dass es sowas nicht gibt :-D

Und man kann nicht mal eine math.h einbinden :lol:

Aber man kann sich alle diese Funktionen sehr einfach selbst basteln. Wartet mal bis wir trigonometrische Funktionen als Reihenentwicklung in Morrowind Script basteln, das wird dann ein bisschen komplizierter ;)
 
Mit strenger Logik würde man kaum darauf kommen, dass eine Zuweisung Gleitkomma -> ganzzahlig sowas wie eine Floor-funktion impliziert oder? Aber für alle die noch nie programmiert haben, speichert einfach mal die Uhrzeit als short ab.

Und als Zusatzaufgabe: Wie würde man eine Gleitkommazahl dann normal runden?
 
Ich war fleißig und habe meine Hausaufgaben gemacht:

Code:
begin teri_geschlecht_script

short Tomate
short Zucchini

if ( Tomate == 0 )
    if ( OnActivate == 1 )
        set Tomate to 1
        MessageBox "Wer ist's, der vor mir steht? Eine holde Weiblichkeit oder ein Edelmann?", "Frau", "Mann"
    endif
else
    set Zucchini to GetButtonPressed
    if ( Zucchini == 0 )
        set Tomate to 0
        MessageBox "Guten Tag, edle Dame."
    elseif ( Zucchini == 1 )
        set Tomate to 0
        MessageBox "Guten Tag, edler Herr"
    endif
endif

end teri_geschlecht_script
;Ich wollte es mal unbedingt mit völlig abstrusen Variblen funktionieren und es funktioniert tadellos. ;)

Code:
begin Teri_Zeitanzeige_Script

if ( OnActivate == 1 )
    MessageBox, "Guten Tag, ^PCName. Es ist %.2f, am %.0f.%.0f. im Jahr 3Ä %.0f.", Gamehour, Day, Month, Year, "OK"
endif

end
;siehe Frage b)

Code:
begin Teri_RavirrTuer_Script

if ( OnActivate == 1 )
    if ( GetJournalIndex, "Teri_ZugangRavirr" < 10 )
        PlaySound, "LockedDoor"
        MessageBox, "Ihr habt nicht die Erlaubnis, das Geschäft von Ra'Virr zu betreten.", "OK"
    elseif ( GetJournalIndex, "Teri_ZugangRavirr" >= 10 )
        Activate
    endif
endif

end Teri_RavirrTuer_Script
;Alles bestens

Ein Haufen Fragen, die wohl ziemlich dümmlich wirken:

a) Ich muss das mit dem Else und dem Elseif jetzt ganz genau wissen: Elseif fragt eine festgelegte, also bestimmte Alternative zu If ab, richtig? Und Else dagegen ist die Verneinung zu If und allen Elseifs, also eine unbestimmte Negierung?
b) Bei Aufgabe 4. zeigt er mir beim Aktivieren die Uhrzeit 15.85, anstatt 15.51 Uhr. Das ist auf eine Art ja auch logisch, die Uhren gehen nicht nach dem Dezimalsystem, welches wiederum Morrowind als einziges kennt. Aber kann man das nicht anders regeln?
c)
[...]
if ( state == 0 )
if ( OnActivate == 1 )
set state to 1
[...]
Wenn ich das richtig verstehe, dann bedeutet dieser Block doch nur, dass das Script nicht die ganze Zeit aktiv ist, sondern nur ab dem Moment, in dem der Spieler das Item mit der Leertaste aktiviert. Nachdem alles ausgeführt wurde, wird State ja wieder auf 0 gesetzt, also das Script deaktiviert. Ist mein Gedankengang richtig?
 
  • Like
Reaktionen: J2W
Antwort b) Das ist doch grade der Witz an der Aufgabe das rauszufinden

Antwort c) state wird auf 1 gesetzt, ansonsten ist dein Gedankengang richtig,
wenn ich alles richtig verstanden habe.


EDIT

@IvanDaVile

Meinst du das Runden jetzt im Script oder in der Messagebox?
Wenn du die Messagebox meinst müsste das doch mit %.0f funktionieren...

EDIT2

Code:
begin md_what_time_is_it_script

short state
short time
short button

if ( OnActivate == 1 ) 
  set state to 1
  set GameHour to time
  Messagebox, "Hallo ^PCName!Es ist %.0f Uhr am %.0f. %.0f. im Jahr 3Ä %.0f.",time, Day, Mouth, Year,"OK"
endif
else
  set button to GetButtonPressed
  if ( button == 0 )
  set state to 0
  endif
end
 
Zuletzt bearbeitet:
natürlich in Scripts, in den Message Boxen kanns ja schon jeder :)
alternativ könnt ihr euch auch für das metrische System für die Zeit einsetzten, das einem 8 stunden Tag eine ganz andere Bedeutung verleihen könnte :oops:
 
Wenn du die Messagebox meinst müsste das doch mit %.0f funktionieren...
um das Runden gehts ja ... also wenn es erst 11:30 ist zeigt deine Uhr schon 12 Uhr, was nicht unbedingt gewollt sein muss - glaub zumindest, dass IvanDaVile darauf hinaus wollte

da das mit den Minuten angefragt wurde: hier eine mögliche Variante, die zwar etwas länglich geraten ist, dafür aber hoffentlich von der Abfolge leicht verständlich ist - Spoiler nur lesen wenn man selber nicht drauf kommt:

Code:
float time
short hours
short minutes

; Zeit holen
set time to GameHour

; Stunden zählen
while ( time >= 1 )
   set hours to ( hours + 1 )
   set time to ( time - 1 )
endwhile

; Minuten berechnen
set time to ( 60 * time )

; Minuten zählen
while ( time >= 1 )
   set minutes to ( minutes + 1 )
   set time to ( time - 1 )
endwhile

; Zeit ausgeben
if ( minutes < 10 )
   MessageBox, "Zeit: %.0f:0%.0f", hours, minutes
else
   MessageBox, "Zeit: %.0f:%.0f", hours, minutes
endif
 
a) Ich muss das mit dem Else und dem Elseif jetzt ganz genau wissen: Elseif fragt eine festgelegte, also bestimmte Alternative zu If ab, richtig? Und Else dagegen ist die Verneinung zu If und allen Elseifs, also eine unbestimmte Negierung?

Da komm ich jetzt nicht ganz mit, hört sich aber eigentlich richtig an :huh:
Ich formuliere es noch mal anders. elseif wird immer abgefragt, wenn das vorangegangene if falsch war. Aber es muss selber richtig sein, damit es ausgeführt wird. Else wird immer ausgeführt, wenn die vorangegangenen ifs falsch sind.

b) Bei Aufgabe 4. zeigt er mir beim Aktivieren die Uhrzeit 15.85, anstatt 15.51 Uhr. Das ist auf eine Art ja auch logisch, die Uhren gehen nicht nach dem Dezimalsystem, welches wiederum Morrowind als einziges kennt. Aber kann man das nicht anders regeln?

Ich hätte nicht erwartet, dass diese Aufgabe solch große Probleme bereitet. Also noch mal ein Tipp: Der Befehl ist kein Einzeiler. Ihr müsst schon mehrere Zeilen verwenden, um die Minuten darzustellen.

c) Wenn ich das richtig verstehe, dann bedeutet dieser Block doch nur, dass das Script nicht die ganze Zeit aktiv ist, sondern nur ab dem Moment, in dem der Spieler das Item mit der Leertaste aktiviert. Nachdem alles ausgeführt wurde, wird State ja wieder auf 0 gesetzt, also das Script deaktiviert. Ist mein Gedankengang richtig?

Nicht ganz. State kontrolliert nur, ob man das Objekt aktivieren kann. Nur wenn state gleich 0 ist, wird die Aktivierung mit der Leertaste registriert. Das soll verhindern, dass ein Script durch eine erneute Aktivierung während der Laufzeit auf einen falschen Wert gesetzt wird. Wenn der Status also 0 ist, wird geprüft, ob das Objekt aktiviert wird. In dem Moment wird der Status auf 1 gesetzt und das Script kann, solange es will, seine Arbeit machen (OnActivate wird ja wieder auf 0 gesetzt nach der Aktivierung). Erst wenn die Arbeit fertig ist, wird der Status wieder auf 0 gesetzt und das Script für einen neuen Start wieder freigegeben.
Im Beispiel ist es relativ egal, da der Effekt des Scripts in einem Durchlauf abgearbeitet ist, bei längeren Scripts wird es aber wichtig, dass man solch eine Fehlbedienung verhindert.

/EDIT:
@Tommy: Nette Version, die funktioniert auf jeden Fall und ist formal korrekt. Ich hab ein wenig gecasted. Das funktioniert auch reibungslos und ist nur 3 Zeilen lang ;)
 
Zuletzt bearbeitet:
Ich hab mir jetzt nochmal Aufgabe 5 genau durchgelesen.

Wenn ich die bisherige Reihenfolge der Abfrage in meinem Script einhielt, um die genauen Vorgaben einzuhalten, bekam ich einen Decompression(?)-Fehler im Spiel selbst, sobald ich das Script testen wollte.
Also die Reihenfolge dann umgestrickt, nur hat es dann noch immer nicht so richtig geklappt. Ich habe mal dann mit den Lösungswegen der anderen verglichen, das von Crashtestgoblin kam meinem sehr nahe.

Mir ist allerdings bei seiner Lösung auch ein kleiner Fehler aufgefallen:
Bei seiner jetzigen Reihenfolge wird immer das Tagebuch aktualisiert, sobald der notwendige Eintrag vorhanden ist. Darum müssen die ersten beiden Bedingungen in seinem Script vertauscht werden, dann wird nur beim ersten Betreten mit notwendigem Journal-Eintrag selbiges aktualisiert, danach nicht mehr.

Und hier dann meine Lösung, aufbauend auf Crashtestsgoblins Script:

Code:
begin Merc_Journal_Door



short journal

if ( OnActivate == 1 )
    if ( GetJournalIndex, Journal "A1_Sleepers_Assi" == 1 )
        activate
    elseif ( GetJournalIndex, Journal "blades_rithleen" == 1 )
        Journal, "A1_Sleepers_Assi", 1
        Activate
        PlaySound, "Open Lock"
    else
        MessageBox, "Euch fehlt der Tagebucheintrag für Rithleen!"
        PlaySound, "LockedDoor"
    endif
endif

end

Das Problem mit Aufgabe 4 und den blöden Minuten werd ich mich am Sonntag widmen.