Nirn.de

Gast

Thema: Skript für Autoload, wenn Spieler entdeckt wurde  (Gelesen 3588 mal)

  • Neuling
    • Neuling
Hallo werte Skyrim-Mod-Community!

Eine Kommilitonin und ich führen im Rahmen eines Medienpsychologie-Seminars eine Studie durch. Als Stimulusmaterial haben wir uns für Skyrim entschieden und sind deshalb nun seit über einem Monat fleißig am Modden, um das Spiel an unsere Bedürfnisse anzupassen.
Vieles konnten wir uns durch die zahlreichen englischen und deutschen Internetseiten zum Creation Kit schon selbst beibringen, an einigen Stellen hapert es aber noch und wir würden uns deshalb sehr freuen, wenn ihr uns helfen könntet.

Das Dungeon ist soweit fertig erstellt und wir haben einige Autosave-Points eingebaut. Das größte Problem besteht derzeit darin, dass der Spielstand von diesen Autosave-Points geladen werden soll, sobald der schleichende Spieler von jemanden (einer Wache) entdeckt wird.
Hierzu haben wir mit dem Befehl "IsDetectedBy" herumexperimentiert, leider ohne Erfolg. Seht ihr den Fehler im folgenden Skript?

Code
Scriptname aaaEntdecktSkript extends ObjectReference 

Function IsDetectedBy(Actor akWache)

If Game.GetPlayer().IsDetectedBy(Wache)
Debug.MessageBox("Entdeckt!")
Input.TapKey(67) (Quickkey for Autoload)
EndIf
EndFunction

Actor Property Wache  Auto 
Ich weiß auch nicht, ob das "ak-" vor "Wache" notwendig ist, oder nicht, aber ich hab beides probiert und nichts hat sich geändert.

Wir haben es außerdem mit dem Befehl "OnCombatStateChanged" probiert. Aber die States, wie sie bei http://www.creationkit.com/OnCombatStateChanged_-_Actor aufgeführt sind, scheinen so nicht zu stimmen. Die States scheinen sich in einem seltsamen Muster zu wiederholen, welches uns aber nicht nachvollziehbar erscheint.
Leider habe ich das Skript dazu nicht auf meinem Computer, das kann ich euch aber morgen nachreichen.

Vielen Dank schonmal für eure Hilfe!
  08.12.2014, 13:18
  • Offline


  • Skelett-Krieger
    • Untot
Na ja, so allein nützt die Funktion die du da geschrieben hast natürlich nichts. Wo wird sie denn aufgerufen?

Es muss noch irgendwo ein Skript auf einem Objekt geben, das diese Funktion aufruft, um festzustellen, ob der Spieler nun entdeckt wurde. Das ist also erst die halbe Arbeit. Und entweder nutzt du die Variable "Wache", die du dann vorher auf einen bestimmten NPC setzen musst, oder aber du verwendest "akWache", den Funktionsparameter. In beiden Fällen musst du aber den NPC "kennen", den du überprüfen willst.

Ich bin schon lange raus aus der Materie, habe auch nur Oblivion-Erfahrung und mich nicht mit Papyrus von Skyrim beschäftigt. Grundsätzlich wäre die Vorgehensweise aber wohl so:

Dein Dungeon braucht ein Script, das alle Ref-IDs aller Wachen als Variablen speichert. So etwas lässt sich im Creation Kit leicht anlegen.
Wenn ein Event auftritt - zum Beispiel der Spieler einen Aktivierungspunkt betritt - muss dein Script die "IsDetectedBy" Funktion für jede der gespeicherten Ref-IDs der Wachen aufrufen. Kommt dabei "true" heraus, muss dein Script neu laden.

Ich hoffe, ich konnte etwas Licht ins Dunkel bringen.
"Maiq has heard the people of Skyrim are better looking than the people of Cyrodiil. Maiq has no opinion on the matter. All people are beautiful to him."
  08.12.2014, 15:00
  • Offline
  • Google+


  • Graf
    • Adel
Du wirst immer die ganze ID angeben müssen. "akother" ist allerdings nur der Name des Parameters und nicht Bestandteil der Syntax. Da gehört die Ref-ID der Wache hin.

Auf den ersten Blick stört mich die Zeile Input.TapKey(67) (Quickkey for Autoload). Denn nicht jeder Spieler hat die gleiche Tastenbelegung, und ich kann mir vorstellen, das ein gesrcipteter Tastendruck nicht unbedingt so funktioniert, wie erwartet.

Wenn es keinen direkten Befehl dafür gibt, würde ich dem Spieler eine Nachricht anzeigen, das er entdeckt wurde, und ihn nach ein oder zwei Sekunden, die er Zeit hat die Nachricht zu sehen und zu lesen, töten. Dann muss er zwangsläufig laden.
Mit SKSE ist es allerdings möglich, Savegames mit einem bestimmten Namen zu speichern und zu laden.

Ehrlich gesagt, fände ich es aber nicht besonders toll, wenn jemand an meinen Savegames rumpfuscht. Der eleganteste Weg ist, bei Entdeckung den Quest einfach scheitern zu lassen.
« Letzte Änderung: 08.12.2014, 15:24 von Grom »
  08.12.2014, 15:16
  • Offline
  • SCP-Wiki-DE


  • Skelett-Krieger
    • Untot
Die If-Funktion ist unvollständig. Es muss heißen:
If Game.GetPlayer().IsDetectedBy(Wache)=1 oder =true, weiß ich nicht genau.

Der Vergleichsoperator für Papyrus ist '==' um ihn von einer Zuweisung '=' zu unterscheiden.

Soweit ich weiß, testet das 'IF' den Ausdruck nur auf den Rückgabewert 0 (unwahr): Kommt etwas anderes als 0 heraus, wird die IF-Anweisung ausgeführt.
Man muss also keinen Vergleichsoperator verwenden, wenn der Ausdruck schon wahr / unwahr zurückgibt:

If 1    ;immer "wahr"
Endif

If EinAusdruck()    ;wenn EinAusdruck() "wahr" ergibt
Endif

If EinAusdruck() == EinWert    ;wenn Vergleich "wahr" ergibt
Endif


Das Script sollte mindestens einmal pro Sekunde durchlaufen.

Dann muss man einen Timer setzen, der die Funktion zyklisch durchläuft. Das ist aber schlecht für die Performance und die Response-Zeiten (wird das Script einmal pro Sek. durchlaufen, dauert es bis zu einer Sekunde, bevor das Game "merkt", dass man entdeckt wurde.) Dieses "Pollen" sollte man unbedingt vermeiden, wenn es unnötig ist, weil theoretisch in dieser einen Sekunde vieles passieren kann, was sich auf den Ausgang des Ereignisses auswirken könnte. Zum Beispiel: Eine Wache entdeckt dich und stirbt direkt darauf an einem Pfeil von dir. Dann hast du trotzdem verloren, weil es noch eine Sekunde dauert, bis die "Entdeckung" registriert wird.

Da die Threadersteller ja bereits Aktivierungspunkte gesetzt haben, ist eine Event-Basierte Lösung zeitnaher und weniger CPU-lastig. Einfach bei jedem Aktiverungspunkt jede Wache einmal überprüfen.

Auf den ersten Blick stört mich die Zeile Input.TapKey(67) (Quickkey for Autoload). Denn nicht jeder Spieler hat die gleiche Tastenbelegung, und ich kann mir vorstellen, das ein gesrcipteter Tastendruck nicht unbedingt so funktioniert, wie erwartet.

Wenn es keinen direkten Befehl dafür gibt, würde ich dem Spieler eine Nachricht anzeigen, das er entdeckt wurde, und ihn nach ein oder zwei Sekunden, die er Zeit hat die Nachricht zu sehen und zu lesen, töten. Dann muss er zwangsläufig laden.

Ja, das sieht für mich auch nach keiner guten Lösung aus. Ich glaube bei Nehrim wird eine Messagebox angezeigt und danach der Spieler gekillt. Das ist wohl die ökonomisch beste Variante.

Der eleganteste Weg ist, bei Entdeckung den Quest einfach scheitern zu lassen.

Das kommt auf das "Spielziel" bzw. den Erzählkontext an. Wenn es wirklich nur eine Nebenaufgabe sein soll, wäre eine Quest natürlich sehr elegant. Wenn es aber das primäre Spielziel ist, nicht entdeckt zu werden, spricht auch nichts dagegen, den Spieler zu killen.  :ugly:
« Letzte Änderung: 08.12.2014, 15:51 von Hanrok »
"Maiq has heard the people of Skyrim are better looking than the people of Cyrodiil. Maiq has no opinion on the matter. All people are beautiful to him."
  08.12.2014, 15:37
  • Offline
  • Google+


  • Graf
    • Adel
Ich habe auch gerade gelesen, das If-Abfragen von boolschen Variablen bei "true" immer den Rest ausführen, und bei "false" nichts tun.

In der Beschreibung der IsDetectedBy()-Funktion steht, das sollte mindestens einmal pro Sekunde ausgeführt werden, aber wenn das so ist wie bei Oblivion, ist das ohnehin nur bei Questscripts relevant, alle anderen Scripts laufen öfter durch.

Nehrim teleportiert den Spieler eher an einen Ausgangspunkt zurück, wenn er Mist baut, und zeigt dazu eine Nachricht. Dabei müssen natürlich Combat Stances usw. zurückgesetzt werden.
  08.12.2014, 16:07
  • Offline
  • SCP-Wiki-DE


  • Skelett-Krieger
    • Untot
In der Beschreibung der IsDetectedBy()-Funktion steht, das sollte mindestens einmal pro Sekunde ausgeführt werden, aber wenn das so ist wie bei Oblivion, ist das ohnehin nur bei Questscripts relevant, alle anderen Scripts laufen öfter durch.

Das kommt tatsächlich sehr auf den Fall bzw. die Anwendung an. Es gibt Bedingungen, die sind so komplex, dass es am einfachsten ist, sie zyklisch abzufragen. Aber generell sollte man erst einmal versuchen, die Events zu nutzen, die einem Script zur Verfügung stehen. Wenn das im offiziellen Papyrus-Wiki so steht, ist das allerdings schon etwas merkwürdig. Gerade die sollten es eigentlich besser wissen.

Nehrim teleportiert den Spieler eher an einen Ausgangspunkt zurück, wenn er Mist baut, und zeigt dazu eine Nachricht. Dabei müssen natürlich Combat Stances usw. zurückgesetzt werden.

Mag sein. Ich erinnere mich jetzt nur an die Stelle in der MQ wo man mit Callisto aus dem Gefängnis flüchten muss. Da darf man den Wachen nicht zu nahe kommen, ansonsten wirkt der Zauber von Callisto nicht mehr und sie erwischen einen. Dort wird eine Dialogbox angezeigt und der Spieler gekillt (oder direkt ein Ladebildschirm angezeigt - kann auch sein).
"Maiq has heard the people of Skyrim are better looking than the people of Cyrodiil. Maiq has no opinion on the matter. All people are beautiful to him."
  08.12.2014, 16:17
  • Offline
  • Google+


  • Neuling
    • Neuling
Erst einmal vielen Dank für eure schnellen Antworten! Ihr scheint wohl eine der aktivsten Communities zu sein, denn ich habe diese Frage schon in anderen Foren gepostet und keine bzw. keine sinnvollen Antworten erhalten.
Um zunächst einmal Licht ins Dunkle zu bringen: Es handelt sich lediglich um eine Mod für eine Studie, die immer am selben Rechner ausgeführt wird, von daher passt das mit TapKey. ;-)
Und damit kommen wir gleich zum nächsten Punkt, warum der Spielstand zurückgesetzt werden soll, sobald der Spieler entdeckt wurde. Es soll sich nämlich um eine gewaltfreie Variante handeln, von daher darf der Spieler nicht sterben, ja noch nicht einmal angegriffen werden. Er hat auch keine Waffen, sondern lediglich die Möglichkeit, sich an allen Wachen vorbeizuschleichen.

Das "Entdeckt"-Skript haben wir auf eine Wache gelegt. Ich habe es aber anscheinend völlig falsch interpretiert. Ich dachte es wird nur aktiviert, WENN diese Wache den Spieler entdeckt, unabhängig von zeitlicher Überprüfung. Ich hatte auch gehofft, nicht mit Bool'schen Operatoren hantieren zu müssen, da mir das (bisher) echt zu hoch ist.  :blink:

Habt ihr vielleicht eine Idee, wie man das anders umsetzen könnte?
Wie gesagt, wir probieren noch mit den "OnCombatStateChanged"-Befehl herum. Leider habe ich das Skript immer noch nicht auf meinem Rechner, reiche es aber schnellstmöglich nach.
  09.12.2014, 15:26
  • Offline


  • Graf
    • Adel
Mit boolschen Operatoren und zeitlicher Überprüfung musst du auch nicht hantieren, lass dich da nicht von unserer Fachsimpelei irritieren.

Als erstes würde ich es damit versuchen, den Parameter der Wache zu korrigieren, und zwar:
Function IsDetectedBy(Actor akWache)
If Game.GetPlayer().IsDetectedBy(Wache)


Das beides ist der Parameter, der bestimmt, welcher NPC gemeint ist. Da gehört die Ref-ID der Wache hin. Lautet die z.B. "Heinz", muss da stehen:
Function IsDetectedBy(Heinz)
If Game.GetPlayer().IsDetectedBy(Heinz)


Wobei ich nicht weiß, ob die erste der beiden Zeilen überhaupt notwendig ist, dafür kenne ich mich mit Papyrus nicht genug aus.
  09.12.2014, 16:20
  • Offline
  • SCP-Wiki-DE


  • Skelett-Krieger
    • Untot
IsDetectedBy() ist kein Event der Creation-Engine. Das heißt, es ist dem Spiel Schnurz, ob du eine Funktion mit diesem Namen schreibst, oder ob du sie Hinnerk() nennst. Die Funktion ist eine reine Benutzer-Funktion, die du selbst aufrufen kannst / musst.

Du musst zuerst mal den Zeitpunkt festlegen, WANN deine Bedingung überprüft werden soll. Die Creation-Engine stellt für jeden Objekt-Typ vordefinierte Ereignisse (Events) zur Verfügung. Bei einem Actor, also einer Spielfigur oder einem NPC, gibt es zum Beispiel das OnDeath oder das OnCombatStateChanged event.

Implementiert dein Wache-Script zum Beispiel OnDeath, dann wird dieser Eventhandler vom Spiel aufgerufen, wenn die Wache aus irgendeinem Grund stirbt. Mit OnCombatStateChanged warst du also schon nah an einer möglichen Lösung dran. Dieses Event wird von der Engine ausgelöst, wenn der NPC in den Kampfmodus wechselt, bzw. den Spieler bemerkt und nach ihm sucht.

Auf der Wiki-Seite gibt es einen Beispielcode. Versuch im ersten Schritt doch mal, den in dein Wache-Script einzubauen. Wenn das dann funktioniert, also du soweit bist, dass du diese Meldungen siehst, melde dich wieder und wir gucken weiter. ;)

EDIT: Was du machen musst, damit du die Debug.Trace() Ausgaben sehen kannst, steht hier. Alternativ kannst du natürlich auch Debug.Trace() durch Debug.MessageBox() ersetzen.
« Letzte Änderung: 09.12.2014, 17:04 von Hanrok »
"Maiq has heard the people of Skyrim are better looking than the people of Cyrodiil. Maiq has no opinion on the matter. All people are beautiful to him."
  09.12.2014, 16:49
  • Offline
  • Google+


  • Neuling
    • Neuling
Okay, ich habe es jetzt mit folgendem Skript probiert:

Code
Scriptname aaaEntdecktSkript extends ObjectReference 

Event OnCombatStateChanged(Actor akTarget, int aeCombatState)
if (akTarget == Game.GetPlayer())
  if (aeCombatState == 1)
    if akTarget.IsDetectedBy(Wache)
    Input.TapKey(67)
    endif
  endIf
endIf
endEvent

Actor Property Wache  Auto 

Das funktioniert auch, jedoch nicht so, wie es soll. Denn zwar bedeutet State1 laut Creation Wiki "In Combat", jedoch wird der Autoload schon ausgeführt, sobald die Wache den schleichenden Spieler schon ansatzweise bemerkt, also sich das geschlossene Auge leicht öffnet und nicht erst, wenn es voll geöffnet ist und "Enteckt" erscheint.
Ich habe es jedoch auch mit State0 und State2 ausprobiert, da wird der Autoload gar nicht ausgelöst, egal in welcher "Such-Stufe" die Wache gerade ist.
Irgendetwas stimmt also wie gesagt mit der Erklärung der States auf der Creation Kit Wiki nicht.  :huh:

Die IsDetected-Zeile bewirkt im Übrigen, so wie sie gerade eingebunden ist, überhaupt nichts. Es funktioniert genauso gut ohne. Der Befehl ist ja sowieso überflüssig, wenn der OnCombatStateChanged-Befehl schon das Entdecken überwacht, oder wie seht ihr das?
  12.12.2014, 14:35
  • Offline


  • Graf
    • Adel
Vielleicht beginnt der Combat State 1 sobald die Wache den Spieler auch nur ansatzweise bemerkt. Ich meine mich zu erinnern, das Wachen ihre Waffen erst ziehen wenn sie angreifen, also dann, wenn sie den Spieler vollständig entdeckt haben. Darum würde ich mal die IsWeaponDrawn Funktion statt dessen probieren.

State 0 und 2 bedeuten, mMn das die Wache den Spieler gerade nicht detected hat, weshalb das auch nicht funktioniert.
« Letzte Änderung: 12.12.2014, 14:45 von Grom »
  12.12.2014, 14:43
  • Offline
  • SCP-Wiki-DE


  • Skelett-Krieger
    • Untot
Okay, ich habe es jetzt mit folgendem Skript probiert:

Sieht gut aus. Nur die IsDetectedBy() Funktion kannst du dir natürlich sparen. Wenn das Event ausgelöst wurde, impliziert das ja, dass der Spieler entdeckt wurde.

Das funktioniert auch, jedoch nicht so, wie es soll. Denn zwar bedeutet State1 laut Creation Wiki "In Combat", jedoch wird der Autoload schon ausgeführt, sobald die Wache den schleichenden Spieler schon ansatzweise bemerkt, also sich das geschlossene Auge leicht öffnet und nicht erst, wenn es voll geöffnet ist und "Enteckt" erscheint.

Die Events der Creation-Engine sind leider nicht so detailliert, wie sie sein müssten, damit man sie "sinnvoll" einsetzen kann. Wünschenswert wäre hier sicher ein zusätzlicher State, der ausgelöst wird, wenn der Spieler vollständig entdeckt wurde. Auch wäre es sinnvoll, dass State == 1 wirklich nur bedeutet, dass der NPC nun den Spieler angreift. Dem ist aber nicht so. In der Tat, reicht schon ein "sehen" des Spielers aus, um in den Combat-State zu wechseln (also State 1). Den Searching-State (State 2) kann man nur mit sehr viel Aufwand und Geschick herbeiführen. Dieser wird nur ausgelöst, wenn die NPCs auf dich aufmerksam werden, aber nicht wissen wo du bist.

Entferne mal die IsDetectedBy() Funktion aus dem Code und probiere es mit State 2. Dann schleich dich mal an die Wache an, OHNE dass sie dich sieht / bemerkt und feuere einen Pfeil in ihre Richtung ab. Dann müsste der NPC in den Searching State gehen. Das nützt dir aber nichts für deine Aufgabe.

Du willst ja neu laden, wenn der Spieler GESEHEN wurde, und das heißt, der NPC wechselt sofort in State 1. (Wobei gesehen eben leider nicht bedeutet, dass das Spiel wartet, bis das "Auge" ganz offen ist.) Ich habe mal eben gegoogelt, aber scheinbar gibt es nichts im Vanilla Skyrim, womit man den "fully seen" Übergang abfragen kann. Zumindest nichts, wofür man nicht mehrere, komplizierte Scripte braucht. Vielleicht bietet SKSE da noch eine Erweiterung an.
"Maiq has heard the people of Skyrim are better looking than the people of Cyrodiil. Maiq has no opinion on the matter. All people are beautiful to him."
  12.12.2014, 16:14
  • Offline
  • Google+