Construction Set Morrowind-Scriptkurs - Lektion 2

IvanDaVile

Abenteurer
The Elder Scrolls III: Morrowind - Scriptkurs


2. Inventar-Scripte

Im letzten Teil haben wir die Funktion OnActivate kennengelernt. So wie man mit OnActivate viele Interaktionen des Spielers mit seiner Umwelt feststellen kann, gibt es auch Möglichkeiten verschiedene Interaktionen mit dem Inventar zu erkennen. In vielen fällen ist das zwar sehr viel komplizierter als man sich vielleicht vorstellt, in anderen aber auch sehr leicht. Was OnActivate für die Umgebung des Spielers ist, ist in gewisser Weise die Funktion OnPCEquip für das Inventar.

Um OnPCEquip verwenden zu können, muss man es zuvor als lokale Variable short OnPCEquip deklarieren.


Die Wirkung von "OnPCEquip" hängt vom Typ des Gegenstands ab, auf dem ein Script liegt.

Kategorie 1; ausrüstbare Gegenstände: Rüstungen, Waffen, Kleidung, tragbare Lichter, Dietriche, Sonden



OnPCEquip wird auf 1 gesetzt, wenn der Spieler den Gegenstand ausrüstet (auf sein Charakterbild im Inventar zieht oder per Hotkey benutzt).
Die Variable wird beim ABLEGEN automatisch auf 0 zurückgesetzt, kann aber auch von Hand zurückgesetzt werden, via set OnPCEquip to 0.
Ansonsten bleibt ihr Wert 1.


Code:
Begin IdV_EquipTest_equipable

; Armor, Weapons, Clothing, Lights, Picks, Probes

short OnPCEquip
short IsEquiped

if ( OnPCEquip )
	if ( IsEquiped == 0 )
		MessageBox "Equiped"
		set IsEquiped to 1
	endif
endif

if ( IsEquiped )
	if ( OnPCEquip == 0 )
		MessageBox "Un-Equiped"
		set IsEquiped to 0
	endif
endif

End

Kategorie 2; sonstige Gegenstände: alles unter Misc Item im Objekfenster des CS, außer geladenen Seelensteinen

OnPCEquip wird auf 1 gesetzt, wenn der Spieler den Gegenstand ausrüstet und wird nicht automatisch zurückgesetzt, sondern bleibt 1. Man muss dies also von Hand tun oder alles im OnPCEquip Block wird jeden Frame ausgeführt.


Code:
Begin IdV_EquipTest_misc

short OnPCEquip

if ( OnPCEquip )
	MessageBox "Equiped"
	set OnPCEquip to 0
endif

End

Bei geladenen Seelensteinen bleibt OnPCEquip auch beim ausrüsten 0, es aber eine andere Funktion mit der man das Benutzen eines Seelensteins erkennen kann.


Kategorie 3; allen anderen Inventargegenständen: Zutaten, Tränke, Alchemie-Apparaten, Reparturwerkzeug, Bücher/schriftrollen

OnPCEquip funktioniert nur in verbindung mit PCSkipEquip.


short PCSkipEquip muss ebenfalls als lokale Variable deklatiert werden. Und kann dann auf 1 gesetzt werden.
Wenn PCSkipEquip gleich 1 ist, dann verhält sich ein Gegenstand wie ein Misc-Item.


Code:
Begin IdV_EquipTest_else

short OnPCEquip
short PCSkipEquip

set PCSkipEquip to 1

if ( OnPCEquip )
	MessageBox "Equiped"
	set OnPCEquip to 0
endif

End

Das lässt zwar die OnPCEquip Funktion korrekt auslösen macht den Gegenstand aber nutzlos, denn er kann so nicht mehr benutzt oder verbraucht werden. Das lässt sich zwar auch wieder umgehen, benötigt aber ein weiteres (globales) Script und ist uns im Moment noch zu kompliziert.
Funktioniert nicht bei geladenen Seelensteinen.

Ein weiteres Problem ist, dass Gegenstände, die ein Script tragen sich nicht mehr im Inventar stapeln lassen, was sehr hässlich aussehen kann.

Man kann PCSkipEquip natürlich auch ohne OnPCEquip verwenden und somit verhindern dass der Spieler einen bestimmten Gegenstand verwendet.

Eine besonderheit von PCSkipEquip ist, dass es bei Büchern beim Ausrüsten (= Lesen) auf 1 gesetzt wird (was bei allen anderen Gegenständen scheinbar nicht passiert).


Code:
Begin IdV_BookActivate

short PCSkipEquip

if ( PCSkipEquip )
	MessageBox "Gelesen"
	set PCSkipEquip to 0
endif

End


Dies gilt nicht für Bücher die aus der Welt heraus gelesen werden, was sich aber durch OnActivate feststellen lässt.

Bei Büchern kann man mit OnActivate drei verschiedene Aktionen festellen: Den Versuch das Buch mit der Maus ins geöffnete Inventar zu ziehen, Lesen (Benutzen) in der Welt und das anklicken von 'nehmen' beim Lesen.
Der 'Activate' Befehl hingegen erzwingt immer lesen.

Dies bedeutet man muss mit 'OnActivate' auf Büchern SEHR vorsichtig sein, da man sonst einen Gegenstand erschafft den man nicht mehr aufheben kann falls man ihn einmal ablegt. Hier ist zum Beispiel ein Script das verhindert, dass man ein Buch aufheben kann, es wurde von Dave Humphrey entdeckt:

Code:
Begin DontPickMeUp_Simple

if ( OnActivate )
	Activate
endif

End


Es gilt also festzustellen ob das Buch bereits gelesen wird oder jemand nur versucht es in das Inventar zu ziehen. Um diese Ereignisse abzufangen, brauchen wir folgende Funktionen:


MenuMode

Gibt 1 zurück, wenn irgendein Menü geöffnet ist. Dies betrifft das Spielmenü (Esc-Taste), Inventar, Dialoge, Messageboxen, Wartezeiten beim Schlafen und Reisen, Bücher lesen sowie Alchemie-Menüs etc., gilt aber nicht für eine auf dem HUD fixierte Karte.

return

Wenn man return aufruft, wird jeglicher Code unterhalb davon für den momentanen Frame ignoriert. Bereits durchlaufener Code wird NICHT rückgängig gemacht.

häufige verwendung:

Code:
if ( Menumode )
	return
endif



Aufgaben

1) Probiert die Beispiel-Scripte aus, weißt sie unpassenden Objekten zu und seht euch an was passiert.

2) Erschafft eine tragbare Uhr, die dem Spieler beim Ausrüsten die Zeit anzeigt.

3) Erschafft ein Buch, aus dem beim ersten lesen ein Schlüssel fällt und dabei einen Tagebucheintrag erstellt.

4) Erschafft ein Schwert, das der Spieler nur tragen kann wenn er einen bestimmten Tagebucheintrag hat, zum Beispiel den von oben.

Tipps: am anspruchsvollsten ist 3), es gilt hier aber eigentlich nur den Inhalt der Beispielscripte in eine "sinnvolle" Reihenfolge zu bringen (und euer wissen aus den vorherige Lektionen anzuwenden)
 
Zuletzt bearbeitet von einem Moderator:
Momentan bin ich noch nicht dazu gekommen, die Aufgaben anzugehen, weil viel zeit mit RL eingeplant ist, sorry. Ich hoffe, dass ich es dieses Wochenende hinbekomme.
 
Vielleicht mag auch keiner Inventarskripte... :p

Meine Versuche:

Code:
Begin digitaluhr_script

short OnPCEquip

short hours
short minutes

if ( OnPCEquip )
 set hours to GameHour
 set minutes to ( ( GameHour - hours ) * 60 )
 if minutes < 10
  MessageBox, "Es ist jetzt %.0f:0%.0f Uhr!", hours, minutes
 else
  MessageBox, "Es ist jetzt %.0f:%.0f Uhr!", hours, minutes
 endif
 set OnPCEquip to 0
endif

end

Code:
Begin buch_script

short OnPCEquip
short PCSkipEquip

set PCSkipEquip to 1

if ( MenuMode )
 return
endif

if ( OnActivate )
 if ( GetJournalIndex, "buch_quest" < 10 )
  "Player"->AddItem, "schluessel_id", 1
  Journal, "buch_quest", 10
  activate
 endif
endif

end

Code:
Begin schwert_script

short OnPCEquip

if ( OnPCEquip )
 if ( GetJournalIndex, "schwert_quest", < 20
  return
 endif
endif

end

Btw. wie lautet denn das Gegenstück zu "Equip"? Hab jetzt keinen Befehl à la "Unequip" gefunden.
 
Zuletzt bearbeitet:
Möchte sich denn niemand an den Aufgaben versuchen?
Geduld, Geduld. Ich habe die Hälfte der Aufgaben geschafft. Ich wollte aber nur mal kurz melden, dass so ein Erfolgserlebnis wie das Gelingen von Aufgabe 2 sehr angenehm ist. ;)

Morgen habe ich mehr Zeit und versuche mich an den anderen beiden Aufgaben.
 
Ich werd mich auch mal in den nächsten Tagen darum kümmern, hab bloß wenig Zeit diese Woche und komm kaum zur Ruhe, um mich mal damit zu beschäftigen.
 
Btw. wie lautet denn das Gegenstück zu "Equip"? Hab jetzt keinen Befehl à la "Unequip" gefunden.

Den gibt es nicht. Entweder du verhinderst mit PCSkipEquip das Ausrüsten von vorne herein oder du rüstest einen anderen Gegenstand zwangsweise mit Equip aus, der den entsprechenden Slot belegt. Dann wird das vorher angezogene Item abgelegt.
 
Juhu es geht los :)

die 2) ist natürlich als Erfolgserlebnis gedacht und wird von mir auch vorerst nicht kommentiert. (Sonst müsst ihr noch mal zurück zu Lektion 1)


@Diarrhoe

3) ist schon mal zur hälfte in Ordnung, aber im Inventar sollte dich das Buch auch öffnen lassen.

4) ihr könnt natürlich auch ein ein Script schreiben das den Gegenstand wieder ablegt, aber eigentlich ist das übertrieben.
 
3) ist schon mal zur hälfte in Ordnung, aber im Inventar sollte dich das Buch auch öffnen lassen.

Ich dachte, dann ließe sich das Objekt nie wieder ausrüsten... :huh:

Code:
Begin buch_script

short OnPCEquip
short PCSkipEquip

set PCSkipEquip to 1

if ( GetJournalIndex, "buch_quest" < 10 )
 if ( OnPCEquip )
  "Player"->AddItem, "schluessel_id", 1
  Journal, "buch_quest", 10
  set OnPCEquip to 0
 elseif ( OnActivate )
  if ( MenuMode )
   return
  endif
  "Player"->AddItem, "schluessel_id", 1
  Journal, "buch_quest", 10
  activate
 endif
endif

end
 
Also, Aufgabe 1-3 habe ich hinbekommen, aber ich verzweifel an Aufgabe 4:

Begin Teri_Axt_Script

short OnPCEquip
short PCSkipEquip

if ( OnPCEquip )
if ( GetJournalIndex "Teri_Key" >=10 )
Set OnPCEquib to 1
else
MessageBox "Eine geheimnisvolle Macht reisst Euch die Waffe aus den Händen."
set PCSkipEquip to 1
set OnPCEquip to 0
endif
endif

End Teri_Axt_Script

So wie ich es jetzt eingestellt habe, kann ich die Waffe nicht mehr anlegen, wenn ich den Tagebucheintrag habe und wenn ich den Tagebucheintrag nicht habe, kann ich die Waffe anlegen, aber die Messagebox erscheint korrekt. Ich habe auch schon versucht die Werte einfach mal zu tauschen, aber dann wirft er mir ohne Ende Messageboxen raus und das Anlegen funktioniert auch nicht richtig.

Achja, der Vollständigkeit halber:

begin Teri_Tragbare_Uhr_Script

short OnPCEquip
short hour
short min
float time

if ( OnPCEquip )
set time to GameHour
set hour to time
set min to ( time - hour ) * 60
if ( min < 10 )
MessageBox, "Es ist %.0f:0%.0f Uhr.", hour, min, Day, Month, Year, "OK"
set OnPCEquip to 0
else
MessageBox, "Es ist %.0f:%.0f Uhr.", hour, min, Day, Month, Year, "OK"
set OnPCEquip to 0
endif
endif

end Teri_Tragbare_Uhr_Script
Begin Teri_KeyBook_Script

short OnPCEquip
short PCSkipEquip

if ( GetJournalIndex, "Teri_Key" >= 10 )
return
endif

if ( OnActivate )
MessageBox "Als Ihr das Buch öffnet, fällt ein kleiner Metallschlüssel heraus."
Player->AddItem "Teri_Key_01l" 1
Journal "Teri_Key" 10
activate
endif

if ( OnPCEquip )
MessageBox "Als Ihr das Buch öffnet, fällt ein kleiner Metallschlüssel heraus."
Player->AddItem "Teri_Key_01" 1
Journal "Teri_Key" 10
set OnPCEquip to 0
endif

End Teri_KeyBook_Script
 
Wo ich Teridans Ansatz gerade gesehen habe, ist mir noch ein Möglichkeit für 4 eingefallen:

Code:
Begin schwert_script

short OnPCEquip
short PCSkipEquip

if ( GetJournalIndex, "schwert_quest" < 20 )
 set PCSkipEquip to 1
else
 set PCSkipEquip to 0
endif

if ( OnPCEquip )
 if ( PCSkipEquip )
  set OnPCEquip to 0
  MessageBox "Ihr könnt das Schwert noch nicht ausrüsten!"
 endif
endif

end
 
ja so geht das.

Ich sags zur Sicherheit noch mal ganz deutlich: Weder mit PCSkipEquip noch mit OnPCEquip kann man das anlegen nachträglich rückgängig machen, aber den Wert von PCSkipEquip kann man jederzeit änderen um den Gegenstand wieder anlegbar zu machen (sofern er das im Normalzustand überhaupt ist).

Noch eine kleine Anmerkung: die Uhr kann man durchaus als Amulett oder so realisieren, das kann man den auf einen Hotkey legen, was mit Miscs ja nicht geht.
 
Ich werkel noch an den Aufgaben, leider war letztes Wochenende keine Zeit dafür. Werd sobald möglich meine Lösungen hier reinstellen. Aber von mir aus könnt ihr mit Lektion 3 langsam starten, sofern die anderen nix dagegen haben.
 
Ich würde gerne noch.:D Aber fangt ruhig mit 3 an. Ich habe wenn am Wochenende dafür Zeit.
 
Dann warten wir noch. Wir müssen uns ja nicht hetzen.

Wollt ihr die 3. Lektion eigentlich lieber als einen ganz großen Klotz (so hab ich sie derzeit) oder soll ich sie in mehrere aufteilen? Nach den etwas ernüchternden Erfahrungen mit meiner ersten Lektion hatte ich eigentlich beschlossen, meine 3. Lektion in 4 (!) Einzellektionen aufzuteilen, die wären dann aber wirklich klein.
 
Ich denke, das spielt keine Rolle. Wenn die Elemente von Lektion 3 aufeinander aufbauen und miteinander verflechtet sind (davon gehe ich mal einfach aus), dann wäre es wohl sinnvoller alles auf einem Blick zu haben.
Nur ist sind kleine Lektionsbausteine motivierender als eine große Textwüste. Aber wie gesagt, im Grunde ist das egal. ;)
 
Ich bin mal langsam dazu gekommen, mich an deine Aufgaben ranzuwagen, Ivan.

Aufgabe 2:

PHP:
begin Merc_TragbareUhr_Script


short hour
short minute
short OnPCEquip
float time

if (OnPCEquip ==1)

    set time to GameHour
    set hour to time
    set minute to ( time - hour ) * 60

    if ( minute < 10 )
        MessageBox, "Es ist %.0f:0%.0f Uhr.", hour, minute, "OK"
    else
        MessageBox, "Es ist %.0f:%.0f Uhr.", hour, minute, "OK"
    Set OnPCEquip to 0
    endif
endif
end

Aus reinem Interesse hab ich mich mal an eine Variante gewagt, die ständig die Uhrzeit angibt. Das geht logischerweise am besten mit Items der Kategorie 1:

PHP:
begin Merc_TragbareUhr2_Script


short hour
short minute
short OnPCEquip
float time

if (OnPCEquip ==1)

    set time to GameHour
    set hour to time
    set minute to ( time - hour ) * 60

    if ( minute < 10 )
        MessageBox, "Es ist %.0f:0%.0f Uhr.", hour, minute
    else
        MessageBox, "Es ist %.0f:%.0f Uhr.", hour, minute
    
    endif
endif
end
Sieht nur ingame etwas bescheuert aus mit den drei gleichzeitig geöffneten Messageboxen. Gibt es evtl dafür ne Lösung, in der immer nur eine Messagebox ingame angezeigt wird?

Aufgabe 3: Lösung folgt

Aufgabe 4:
PHP:
begin Merc_SchwertAnlegen_Script


short journal
short OnPCEquip
short PCSkipEquip

set PCSkipEquip to 1
if ( OnPCEquip == 1 )
    if ( GetJournalIndex, Journal "A1_Sleepers_Assi" < 1 )
    set PCSkipEquip to 1
    set OnPCEquip to 0
    MessageBox, "Euch fehlt ein Eintrag im Tagebuch!"          
   else
    set OnPCEquip to 1
    set PCSkipEquip to 0
    endif
endif

end
Hier hab ich aber ein Problem:
Wenn ich versuche, nach dem Tagebucheintrag das Schwert anzulegen, klappt das erst beim zweiten Versuch.
 
Zuletzt bearbeitet:
Sieht nur ingame etwas bescheuert aus mit den drei gleichzeitig geöffneten Messageboxen. Gibt es evtl dafür ne Lösung, in der immer nur eine Messagebox ingame angezeigt wird?
Das kannst du realisieren, indem du vor deiner MessageBox mehrmals folgendes aufrufst:
Code:
messagebox, ""
wie in Lektion 1 gelernt, entspricht die Darstellungszeit der Zeichennanzahl * fMessageTimePerChar ... bei Zeichenanzahl 0 ist entsprechend die Darstellungszeit auch 0, aber trotzdem gilt es als abgesetzte Message ... wenn du das nun also 3 mal aufrufst hast du den Bildschirm wieder leer und kannst deine MessageBox absetzen, die dann auch alleine dasteht