Construction Set Morrowind-Scriptkurs - Lektion 1

ich hätte noch das hier im Angebot besonders das mit den Reiserouten finde ich sehr intressant, hat jemand das mal ausprobiert?

Mal wieder zurück zum eigentlichen Thema. Kann ich mit der nächsten Lektion anfangen oder liegt euch noch was zu den ersten beiden auf dem Herzen?
 
Lösungen

Ich poste nun einmal meine Lösungen zu den von mir gestellten Aufgaben. Die Lösungen sind in Spoilern, in diesen erkläre ich den genauen Ablauf jedes Scripts. In einem weiteren Spoiler ist dann der Quellcode der Scripte.

  • 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.

    Hier lag die Aufgabe darin, zwei Messageboxen nacheinander darzustellen. Die erste sollte dem Spieler eine Auswahl von zwei Antwortmöglichkeiten bieten und der Inhalt der zweiten sollte von der Antwort abhängen. Das hier gewählte Beispiel ist zwar eher sinnlos, aber die Problemstellung mit anderen Texten ist recht häufig.

    Code:
    begin kf_sk_act_geschlecht_script
    
    short state
    short button
    
    if ( state == 0 )
    	if ( OnActivate == 1 )
    		set state to 1
    		MessageBox, "Seid Ihr ein Mann oder eine Frau?", "Mann", "Frau"
    	endif
    else
    	set button to GetButtonPressed
    
    	if ( button == 0 )
    		set state to 0
    		MessageBox, "Seid gegrüßt, Herr ^PCName"
    	elseif ( button == 1 )
    		set state to 0
    		MessageBox, "Seid gegrüßt, Frau ^PCName"
    	endif
    endif
    
    end

    In Zeile 1 starte ich das Script. In Zeile 3 und 4 definiere ich die beiden short-Variablen state und button. Erstere steuert, dass man das Script immer wieder neu aktivieren kann. Die zweite speichert die Entscheidung des Spielers.

    In Zeile 6 überprüfe ich, ob sich das Script im Ausgangszustand (state == 0) befindet. Wenn dem so ist, wird in die nächste Ebene (Zeile 7) gegangen. Hier wird überprüft, ob der Spieler das Objekt, auf dem das Script liegt, aktiviert. Sobald er dies tut, ist die Bedingung erfüllt und das Script kann auch an dieser if-Bedingung vorbei.

    In Zeile 8 setze ich, für den Fall, dass das Script im Ausgangszustand ist und der Spieler das Objekt aktiviert, den Status des Scripts auf 1. Somit kann dieser Teil des Scripts nun nicht noch einmal durchlaufen werden, bis man ihm wieder sagt, dass es okay ist.

    In Zeile 9 wird die erste Messagebox mit den beiden Antwortmöglichkeiten des Spielers ausgegeben.

    Danach gelangt das Script zu einem endif und springt weiter. Beim else springt das Script ebenfalls weiter, da die Bedingung zu Beginn des Scriptes ja erfüllt war. So gelangt das Script zum abschließenden endif (Zeile 21) und zum end (Zeile 23).

    Nun läuft das Script wieder von vorne los. Die Variablen sind bereits deklariert, also geht es direkt zu Zeile 6. Diesmal ist state aber 1, somit ist die Bedingung nicht erfüllt und das Script springt zum else in Zeile 11. Hier kann das Script nun weiterarbeiten.

    In Zeile 12 wird der Variable button die Nummer des Buttons zugewiesen, den der Spieler gedrückt hat. Am Anfang hat der Spieler noch keinen Button gedrückt (er hat ja eine gewisse Reaktionszeit). Deswegen nimmt button den Wert -1 an. Die folgende if-Abfrage (Zeile 14) ist also nicht erfüllt (-1 = 0 -> falsch). Also springt das Script zum elseif in Zeile 17. Auch dieses ist nicht erfüllt (-1 = 1 -> falsch). Somit springt das Script zum endif in Zeile 20 und von dort aus über das letzte endif zum end.

    Das Script startet wieder von vorne und läuft bis Zeile 12 wieder genauso ab. Jetzt hat der Spieler aber einen der beiden Buttons gedrückt. Sagen wir er hat den ersten Button ("Mann") gedrückt. In dem Fall bekommt button nun den Wert 0. Somit ist die if-Abfrage in Zeile 14 nun wahr und das Script läuft in Zeile 15 weiter. Zuerst wird state wieder auf 0 gesetzt. Das heißt, dass das Script nach diesem Durchlauf wieder neu gestartet werden kann. In Zeile 16 wird dann die zweite Messagebox ausgegeben.

    In Zeile 17 kommt erneut das elseif. Da bereits das if erfüllt war, springt das Script zum endif. Dann erneut endif und end. Jetzt ist das Script komplett durchgelaufen und man kann den Text wieder von vorne anfangen zu lesen.
  • 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.

    Die Schwierigkeit dieses Scripts lag darin, die Uhrzeit, die man nur als Kommazahl der Stundenbruchteile abrufen kann, in das uns bekannte Stunden-Minuten-Format zu konvertieren. Dazu war es nötig mit Variablen zu rechnen.

    Code:
    begin kf_sk_act_uhr_script
    
    short hour
    short min
    float time
    
    if ( OnActivate == 1 )
    	
    	set time to GameHour
    	set hour to time
    	set min to ( time - hour ) * 60
    
    	if ( min < 10 )
    		MessageBox, "Seid gegrüßt, ^PCName. Es ist %.0f:0%.0f Uhr am %.0f. Tag des %.0f. Monats im %.0f. Jahr der 3. Ära.", hour, min, Day, Month, Year, "OK"
    	else
    		MessageBox, "Seid gegrüßt, ^PCName. Es ist %.0f:%.0f Uhr am %.0f. Tag des %.0f. Monats im %.0f. Jahr der 3. Ära.", hour, min, Day, Month, Year, "OK"
    	endif
    
    endif
    
    end

    • Zeile 7: Hier warte ich darauf, dass der Spieler den Gegenstand aktiviert.
    • Zeile 9: Nachdem der Gegenstand aktiviert wurde, setze ich meine lokale float-Variable time auf den Wert der globalen float-Variablen GameHour. In der wird dann zum Beispiel der Wert 16.123456 gespeichert.
    • Zeile 10: Ich weise meiner lokalen short-Variable den Wert meiner float-Variable zu. Dabei werden einfach die Nachkommastellen abgeschnitten. Die Variabel hat dann also den Inhalt 16.
    • Zeile 13: Hier berechne ich die Minuten. Die Nachkommastellen geben den Bruchteil einer ganzen Stunde an, die bereits vergangen ist, also nehme ich den mit 60 mal, damit ich den Wert der Minuten bekomme. Dazu muss ich natürlich ersteinmal die Nachkommastellen herausbekommen. Dazu ziehe ich die vollen Stunden von der aktuellen Zeit ab:

      set min to ( time - hour ) * 60
      set min to ( 16.123456 - 16 ) * 60
      set min to 0.123456 * 60
      set min to 7.40736

      Da min wieder einer short-Variable ist, werden die Nachkommastellen wieder abgeschnitten und die Zahl 7 in min gespeichert.
    • Notiz 5: Hier prüfe ich, ob die Minuten einstellig sind. In dem Fall muss ich noch eine führende Null in der MessageBox einfügen, sonst würde die Zeit nicht als 16:07 sondern als 16:7 dargestellt.
  • 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.

    Hier musste man eine Aktivierung mit einer Abfrage nach einem Tagebucheintrag kombinieren und in einem der beiden Fälle noch eine weitere optionale Funktion einbauen. Normalerweise könnte man ein solches Script natürlich noch toll gestalten mit Sounds und so weiter, aber diese Funktionen hatten wir noch nicht, deswegen kommen sie in meiner Lösung auch nicht vor.

    Code:
    begin kf_sk_door_journalblock_script
    
    if ( OnActivate == 1 )
    	if ( GetJournalIndex, "kf_testthema" >= 10 )
    		if ( GetJournalIndex, "kf_testthema" < 20 )
    			Journal, "kf_testthema", 20
    		endif
    		Activate
    	endif
    endif
    
    end

    Dieses Script kommt ohne Variablen aus. Zunächst wird wieder darauf gewartet, dass der Spieler die Tür aktiviert. Sobald er dies tut, wird überprüft, ob er einen bestimmten Tagebucheintrag schon besitzt. Hier wird explizit überprüft, ob der Spieler einen bestimmten Tagebucheintrag oder einen höheren Eintrag dieses Themas besitzt. Dies ist normalerweise gewollt, da sich die Tür ja auch noch öffnen soll, wenn der Spieler einen weiteren Tagebucheintrag erhält. Soll sich die Tür nur einmal öffnen und danach nicht mehr aktivieren lassen, sollte hier statt dem >= ein == gewählt werden.

    Danach wird in Zeile 5 überprüft, ob der Spieler noch keinen Tagebucheintrag besitzt der größer oder gleich dem 20er Eintrag ist. Wenn das wahr ist, wird dem Spieler ein neuer Tagebucheintrag (eben der Index 20) hinzugefügt. Danach wird die Tür aktiviert (sie öffnet sich also oder teleportiert den Spieler).

    Hat der Spieler noch nicht den Tagebucheintrag mit Index 10 (oder einen höheren), läuft das Script bis zum Ende durch ohne irgendetwas zu machen. Aber mit der Tür passiert auch nichts. Für den Spieler ist es so, als hätte er die Tür überhaupt nicht aktiviert.

    Wenn der Spieler die Tür nach dem ersten erfolgreichen Betreten erneut aktiviert, ist die zweite if-Abfrage falsch (er hat ja den 20er Eintrag bereits beim ersten Durchgehen bekommen). Somit wird dieser Teil nicht ausgeführt und die Tür öffnet sich einfach. Würde diese zweite if-Abfrage weggelassen, würde der Spieler bei jedem Benutzen der Tür den 20er Tagebucheintrag erneut in sein Tagebuch geschrieben bekommen.
 
  • Like
Reaktionen: Teridan und Zeitgeist
So, da ihr eine Übersicht zu den Befehlen haben wolltet, habe ich hier eine erstellt.

Ich habe versucht, die Befehle neu zu erklären, vielleicht wird es dadurch verständlicher.

Dazu gibt es jetzt natürlich auch neue Aufgaben ;)

Aufgaben - Teil 2

  1. Versucht einen Scriptteil zu schreiben, der die Rechenoperation div für die short-Variablen a und b ausführt. Div bezeichnet die Rechnung, die angibt, wie viele Vielfache einer Zahl in einer anderen stecken und dabei den Rest vernachlässigt.
    10 div 5 = 2
    11 div 5 = 2
  2. Schreibt einen Scriptteil, der die Modulo-Operation für die short-Variablen a und b durchführt. Modulo bezeichnet den Rest einer Division.
    6 mod 3 = 0
    5 mod 3 = 2
    4 mod 3 = 1
  3. Versucht euch an einem Scriptteil, der nur ausgeführt wird, wenn zwei Vergleiche wahr sind (könnte man auch als Bool'sches AND bezeichnen).
  4. Schreibt einen Scriptteil, der ausgeführt wird, wenn mindestens einer von zwei Vergleichen wahr ist (könnte man auch als Bool'sches OR bezeichnen).
  5. Schreibt ein Quiz mit drei Fragen (mit Messageboxen). Der Spieler soll jeweils mehrere Antwortmöglichkeiten haben, von denen nur eine richtig ist. Der Spieler soll sich eine falsche Antwort erlauben können. Beantwortet er eine zweite Frage falsch, soll er verlieren.

Für die ersten beiden Aufgaben benötigt ihr jeweils set ... to Befehle mit Rechnungen. Für die letzten drei Aufgabe benötigt ihr verschachtelte if-Abfragen. Außerdem benötigt ihr für die letzte Variablen um die Antworten des Spielers zu speichern.

Wenn ihr die fünfte Aufgabe hinbekommt (ihr könnt sie ja jederzeit im Spiel testen!), solltet ihr verschachtelte if-Konstrukte wirklich verstanden haben.

Lösungen
 
Zuletzt bearbeitet:
ich hab mich mal dran versucht ... manches hab ich wahrscheinlich komplizierter gemacht, als nötig gewesen wäre ... aber naja was solls ;)
Code:
begin calculate

short a
short b
short div
short mod

set mod to a
set div to 0

while ( mod >= b )
  set div to ( div + 1 )
  set mod to ( mod - b )
endwhile 

messagebox "a: %.0f, b: %.0f, div: %.0f, mod: %.0f", a, b, div, mod
stopscript calculate

end

externe Variablensetzung und Start:
Code:
set calculate.a to 11
set calculate.b to 5
startscript calculate
Code:
if ( a == 1)
  if ( b == 1)
    ;do something
  endif
endif
Code:
if ( a == 0 )
  if ( b == 0 )
    return
  endif
endif
;do something
Code:
begin quiz

short question
short answer
short state
short button
short errors

if ( state == 0)
  set state to 1
  if ( question == 0 )
    messagebox "Der Name Killfetzer beginnt mit...?", "X", "K", "G", "Hä?!"
    set answer to 1
  elseif ( question == 1 )
    messagebox, "Killfetzer leitet...?", "den Scriptkurs", "den Yogakurs", "Timbuktu", "Wer?!"
    set answer to 0
[COLOR="Red"]  elseif ( question == 2 )
    messagebox, "Killfetzer ist...?", "Gott", "der Teufel", "Super-Moderator", "Was?!"
    set answer to 2[/COLOR]
  else
    messagebox "Ihr habt bestanden!"
    set state to -1
  endif
elseif ( state == 1 )
  set button to GetButtonPressed
  if ( button == -1 )
    return
  elseif ( button == answer )
    messagebox "Richtig!"
  else
    messagebox "Falsch!"
    set errors to ( errors + 1 )
  endif
  set state to 0
  set question to ( question + 1 )
  if ( errors > 1 )
    messagebox "Zuviele Fehler!"
    set state to -1
  endif
else
  set state to 0
  set errors to 0
  set question to 0
  stopscript quiz
endif

end

etwas kompliziert ... ist aber leicht erweiterbar, da für jede neue Frage nur ein elseif-Zweig mit MessageBox und Antwortdefinition eingefügt werden muss (siehe Markierung)
 
  • Like
Reaktionen: Killfetzer
Schöne Lösungen, Thommy :)

Ja, 1,2 und 4 hätte ich anders gelöst ;)
Du scheinst ja ein großer Fan von while-Schleifen zu sein. Ich bin eher rechnerisch rangegangen und habe den netten Integercast verwendet. Aber deine Lösung für die 4 ist wirklich elegant, auf die Lösung bin ich noch nie gekommen. Ich hätte jetzt ein else eingebaut. Nachteil deiner Lösung ist natürlich, dass du die Ausführung des gesamten Scripts verhinderst und ich mit meiner Variante auch nur einen kleinen Teil aus dem Script ausschließen kann.



Falls ihr es noch nicht bemerkt haben solltet:

Der Scriptkurs wurde in mehrere Themen aufgeteilt. Hier hat IvanDaVile die nächste Lektion gepostet. Es geht um Inventarscripte.
 
Lösungen - Teil 2

Hier nun noch die Lösungen zum zweiten Aufgabenblock:

  • Versucht einen Scriptteil zu schreiben, der die Rechenoperation div für die short-Variablen a und b ausführt.

    Code:
    short div
    
    set div to a / b

    Hier mache ich mir die Eigenschaft von Morrowind Script zu Nutze, dass Kommazahlen einfach abgeschnitten werden, wenn man sie einer short-Variablen zuweist.
  • Schreibt einen Scriptteil, der die Modulo-Operation für die short-Variablen a und b durchführt. Modulo bezeichnet den Rest einer Division.

    Code:
    short mod
    short div
    
    set div to a / b
    set mod to a - ( div * b )

    Auch hier verwende ich wieder die besondere Eigenschaft der Zuweisung von Kommazahlen auf short-Variablen. Da in div * b das größte Vielfache von b gibt, das kleiner ist als a, muss die Differenz von den beiden natürlich den Rest der Division ergeben.
  • Versucht euch an einem Scriptteil, der nur ausgeführt wird, wenn zwei Vergleiche wahr sind (könnte man auch als Bool'sches AND bezeichnen).

    Code:
    begin kf_sk_and_script
    
    short a
    short b
    
    if ( a == 1 )
    	if ( b == 1 )
    		;mache irgendwas
    	endif
    endif
    
    end

  • Schreibt einen Scriptteil, der ausgeführt wird, wenn mindestens einer von zwei Vergleichen wahr ist (könnte man auch als Bool'sches OR bezeichnen).

    Code:
    begin kf_sk_or_script
    
    short a
    short b
    short c   ;Kontrollvariable für das ODER
    
    if ( a == 1 )
      set c to 1
    elseif ( b == 1 )
      set c to 1
    endif
    
    if ( c == 1 )
      set c to 0
      ;mache irgendwas
    endif
    
    end


  • Schreibt ein Quiz mit drei Fragen (mit Messageboxen). Der Spieler soll jeweils mehrere Antwortmöglichkeiten haben, von denen nur eine richtig ist. Der Spieler soll sich eine falsche Antwort erlauben können. Beantwortet er eine zweite Frage falsch, soll er verlieren.

    Code:
    begin kf_sk_quiz_script
    
    short state		;speichert den Status des Scripts
    short button		;speichert die Antwort des Spielers auf die aktuelle Frage
    short answer	;speichert die richtige Antwort auf die aktuelle Frage
    short false		;speichert die Anzahl der falschen Antworten
    
    if ( state == 0 )
    	if ( OnActivate == 1 )
    		set state to 1
    		MessageBox, "Willkommen beim TES-Quiz. Ihr müsst drei Fragen beantworten. Wenn Ihr zwei falsch beantwortet, habt Ihr verloren.", "In Ordnung", "Nein, danke"
    	endif
    elseif ( state == 1 )
    	set button to GetButtonPressed
    	if ( button == 0 )
    		set state to 2
    		MessageBox, "Wie hieß der erste Teil der TES-Reihe?", "Arena", "Daggerfall", "Morrowind", "Oblivion"
    		set answer to 0
    		return
    	elseif ( button == 1 )
    		MessageBox, "Kommt später wieder."
    		set state to 0
    	endif
    elseif ( state == 2 )
    	set button to GetButtonPressed
    	if ( button == answer )
    		set state to 3
    		MessageBox, "Richtig. Nächste Frage: Wie hieß der zweite Teil der TES-Reihe?", "Arena", "Daggerfall", "Morrowind", "Oblivion"
    		set answer to 1
    		return
    	elseif ( button > -1 )
    		set state to 3
    		MessageBox, "Falsch. Nächste Frage: Wie hieß der zweite Teil der TES-Reihe?", "Arena", "Daggerfall", "Morrowind", "Oblivion"
    		set answer to 1
    		set false to 1
    		return
    	endif
    elseif ( state == 3 )
    	set button to GetButtonPressed
    	if ( button == answer )
    		set state to 4
    		MessageBox, "Richtig. Nächste Frage: Wie hieß der dritte Teil der TES-Reihe?", "Arena", "Daggerfall", "Morrowind", "Oblivion"
    		set answer to 2
    		return
    	elseif ( button > -1 )
    		if ( false == 0 )
    			set state to 4
    			MessageBox, "Falsch. Nächste Frage: Wie hieß der dritte Teil der TES-Reihe?", "Arena", "Daggerfall", "Morrowind", "Oblivion"
    			set answer to 2
    			set false to 1
    			return
    		else
    			MessageBox, "Ihr habt die zweite Frage falsch beantwortet. Ihr habt verloren."
    			set false to 0
    			set state to 0
    		endif		
    	endif
    elseif ( state == 4 )
    	set button to GetButtonPressed
    	if ( button == answer )
    		MessageBox, "Richtig. Ihr habt gewonnen"
    		set false to 0
    		set state to 0
    		return
    	elseif ( button > -1 )
    		if ( false == 0 )
    			MessageBox, "Falsch. Ihr habt trotzdem gewonnen."
    			set false to 0
    			set state to 0
    		else
    			MessageBox, "Ihr habt die zweite Frage falsch beantwortet. Ihr habt verloren."
    			set false to 0
    			set state to 0
    		endif		
    	endif
    endif
    
    end
 
Ich bring mal das Script mit der Uhr aus dem ersten Teil (OHNE AUF LÖSUNGEN ZU SCHAUEN):

Code:
begin BoHe_Uhrscript

float time
short hour
short minutes


if ( OnActivate == 1 )[INDENT]Set time to %.2f, GameHour
Set hour to %.0f, GameHour
Set minutes to (time - hour)*60
if ( minutes < 10 )
[INDENT]messagebox, "Es ist %.0f.0%0f Uhr"
[/INDENT]else
[INDENT]messagebox, "Es ist %0f.%0f Uhr "
[/INDENT] [/INDENT]endif

end
Was war jetzt daran so schwierig? Das hatten wir letztes jahr in Mathe
edit: läuft wohl so nicht, oder? habs jetzt nicht ausprobiert, aber ich habe die lösungen angeschaut...
 
Zuletzt bearbeitet: