Rückgabewert von Funktion an Global(variable) übergeben?

Daimonicon

Neuankömmling
Hallo,

ich möchte für meine Mod ein Beispielscript übernehmen das für sich alleine auch prima funktioniert. Nur würde ich gern den Rückgabewert in eine Globale Variable speichern.

Auszug Scriptkopf:

Code:
Scriptname jmUtility

Import Utility
Import Math

GlobalVariable Property jmVollmondGlobal  Auto
GlobalVariable Property jmObjektIndexGlobal  Auto
FormList Property ListOfObjectsFLST Auto

Die betreffende Funktion:

Code:
Int Function GetCurrentMoonphase() Global
    Int GameDaysPassed
    Int GameHoursPassed
    Int PhaseTest
    GameDaysPassed = GetPassedGameDays()
    GameHoursPassed = GetPassedGameHours()
 
    If (GameHoursPassed >= 12.0)
        GameDaysPassed += 1
    EndIf
 
    PhaseTest = GameDaysPassed % 24 ;A full cycle through the moon phases lasts 24 days
    If PhaseTest >= 22 || PhaseTest == 0
        Return 7
    ElseIf PhaseTest < 4
        [COLOR=#ff0000]Return 0[/COLOR]
    ElseIf PhaseTest < 7
        Return 1
    ElseIf PhaseTest < 10
        Return 2
    ElseIF PhaseTest < 13
        Return 3
    ElseIf PhaseTest < 16
        Return 4
    ElseIf PhaseTest < 19
        Return 5
    ElseIf PhaseTest < 22
        Return 6
    EndIf
 
EndFunction

Ruturn 0 wäre Vollmond und genau diese Variable hätte ich gern global abgelegt - Um sie dann hoffentlich an diversen Stellen weiterverwenden zu können.

Meine bisherigen Versuche waren leider erfolglos und wahrscheinlich seh ich mal wieder den Wald vor .... ;)

jmVollmondGlobal.SetValue(0) .. geht nicht hier war ich mir anhand Beispielen sicher das sie theoretisch so übergeben werden müsste. Was er aber quittiert mit:

G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\jmUtility.psc(80,2): variable jmVollmondGlobal is undefined
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\jmUtility.psc(80,19): none is not a known user-defined type

Ich meinte eigentlich alles korrekt angelegt zu haben.

Frage01.JPG Frage02.JPG

Wäre super wenn mir da wer auf die Sprünge helfen könnte.
 
If you are calling a function from outside the current script or script fragment, note that no properties defined in the function's own script will be valid when it is called. Therefore you must pass any properties you wish to use in the function as parameters, defined in the calling script.

Auf deutsch gesagt, die Funktion kennt die Variable jmVollmondGlobal nicht und gibt daher einen Error. Mir würden jetzt zwei Möglichkeiten einfallen. Entweder, du übergibst die Global Variable der Funktion als Parameter,

Code:
Int Function GetCurrentMoonphase(GlobalVariable myGlobal) Global
...
ElseIf PhaseTest < 4
        myGlobal.SetValueInt(0)
...
der Funktionsaufruf würde dann so aussehen:

Code:
GetCurrentMoonphase(jmVollmondGlobal)

Oder du lässt die Funktion wie sie ist und änderst den Code innerhalb des Events bzw. Skript Fragments, wo auch immer du den Funktionsaufruf machst, zB.

Code:
int Moonphase = GetCurrentMoonphase()
if Moonphase == 0
   jmVollmondGlobal.SetValueInt(MoonPhase)
endif

Ich würde wahrscheinlich letztere Variante wählen, aber beides ist möglich.
 
  • Like
Reaktionen: Daimonicon
Die Weise von Ghaunadaur ist an sich des Rätsels Lösung, ich versuche noch eine kleine Erklärung beizusteuern, bezüglich des warum du den Fehler nun hast.

Wie Ghaunadaur gesagt hat kennt deine Funktion deine globale Variable nicht, dies kommt daher da deine Funktion als globale Funktion deklariert ist.
Int Function GetCurrentMoonphase() Global
Für den ursprünglichen Nutzen war dies in Ordnung, da du jedoch nun eigene Variablen dazubringst, gibt es ein Durcheinander. Du kannst eine Funktion in verschiedenen Arten und Weisen deklarieren, neben Funktionen die bestimme Werte zurückliefern, kannst du auch noch zwischen global und native deklarieren.
Native Funktionen sind jene, die vom Spiel implementiert sind und somit über keinen Methodenrumpf verfügen, globale Funktionen besitzen einen Rumpf, dafür über keinen Verweis auf die eigene Skriptinstanz. Es fehlt ein "self"-Verweis, dieser wäre nötig, um auf die Variablen zuzugreifen, die im Skript sind, aber der Funktion unbekannt sind, außer du fügst diese Mithilfe einer entsprechenden Angabe der jeweiligen Parameter hinzu. Mit den Parametern kannst du dann auch darauf zugreifen und wie gewohnt agieren.

MfG Master of Worlds
 
  • Like
Reaktionen: Daimonicon
Erstmal danke euch beiden für die schnelle Antwort. Das mit der Funktion würde der Compiler akzeptieren, aber das aufrufen klappt leider nicht ;(

Wenn als Fragment ausgeführt sagt er (hatte Funktion belassen wie sie ist):

Compiling "QF_jmStartupQuest_01000D62"...
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\QF_jmStartupQuest_01000D62.psc(17,3): variable jmVollmondGlobal is undefined
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\QF_jmStartupQuest_01000D62.psc(17,20): none is not a known user-defined type

Bei einem Questscript sagt er:

Compiling "jmStartupQuestScript"...
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\Source\temp\jmStartupQuestScript.psc(7,19): no viable alternative at input '('
No output generated for jmStartupQuestScript, compilation failed.

Code:
Scriptname jmStartupQuestScript extends Quest

import jmUtility

GlobalVariable Property jmVollmondGlobal  Auto

GetCurrentMoonphase(jmVollmondGlobal)

Dazu und bereits in Verbindung mit dem Questscript die Funktion:

Code:
Int Function GetCurrentMoonphase(GlobalVariable jmVollmondGlobal) Global
    Int GameDaysPassed
    Int GameHoursPassed
    Int PhaseTest
    GameDaysPassed = GetPassedGameDays()
    GameHoursPassed = GetPassedGameHours()
 
    If (GameHoursPassed >= 12.0)
        GameDaysPassed += 1
    EndIf
 
    PhaseTest = GameDaysPassed % 24 ;A full cycle through the moon phases lasts 24 days
    If PhaseTest >= 22 || PhaseTest == 0
        Return 7
    ElseIf PhaseTest < 4
        Return 0
        jmVollmondGlobal.SetValueInt(0)
    ElseIf PhaseTest < 7
        Return 1
    ElseIf PhaseTest < 10
        Return 2
    ElseIF PhaseTest < 13
        Return 3
    ElseIf PhaseTest < 16
        Return 4
    ElseIf PhaseTest < 19
        Return 5
    ElseIf PhaseTest < 22
        Return 6
    EndIf
 
EndFunction

Sprich die Funktion akzeptiert er aber ich kann sie nicht aufrufen - Was ich wohl öfter mal tun muss.
 
Wenn als Fragment ausgeführt sagt er (hatte Funktion belassen wie sie ist):

Compiling "QF_jmStartupQuest_01000D62"...
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\So urce\temp\QF_jmStartupQuest_01000D62.psc(17,3): variable jmVollmondGlobal is undefined
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\So urce\temp\QF_jmStartupQuest_01000D62.psc(17,20): none is not a known user-defined type

Der gleiche Error wie zuvor, d.h. dein Skript kennt die Variable nicht. Hast du denn auch die globale Variable als Property zu dem Quest Fragment hinzugefügt? Das geht relativ komfortabel über den Properties-Button -> Add Property. Du kannst aber auch das Skript per RK -> Edit Source manuell bearbeiten.

Kleine Ergänzung zum Code. Ich bin mir gerade nicht sicher, ob man andere Skripts in Fragments "importieren" kann. Wenn nicht, muss das Skript vor die Funktion geschrieben werden:
int MoonPhase = jmUtility.GetCurrentMoonPhase()
if Moonphase == 0
jmVollmondGlobal.SetValueInt(MoonPhase)
endif




Bei einem Questscript sagt er:

Compiling "jmStartupQuestScript"...
G:\Tools und Apps\Steam\steamapps\common\skyrim\Data\Scripts\So urce\temp\jmStartupQuestScript.psc(7,19): no viable alternative at input '('
No output generated for jmStartupQuestScript, compilation failed.

Code:
Scriptname jmStartupQuestScript extends Quest

import jmUtility

GlobalVariable Property jmVollmondGlobal  Auto

GetCurrentMoonphase(jmVollmondGlobal)

Eine Funktion kann nur innerhalb eines Event-Blocks oder einer anderen Funktion aufgerufen werden. Welches Event hier passend wäre, ist schwer zu sagen. Dafür mußt du schon genauer erklären, wie du das Skript implementieren willst und was es genau bewirken soll. Eine Liste aller Events findest du hier. Als Beispiel mal ein OnInit() Event:

Code:
Scriptname jmStartupQuestScript extends Quest

import jmUtility

GlobalVariable Property jmVollmondGlobal  Auto

Event OnInit()
   GetCurrentMoonphase(jmVollmondGlobal)
   debug.messagebox(jmVollmondGlobal.GetValueInt())
EndEvent
 
Also ein Stück weiter bin ich aber irgendwie haut es noch nicht ganz hin. Ich beschreib vll. mal wo ich gerne hin möchte mit der Mod.

Also ich hab mir verschiedene Orte(Zellen) gesucht die quasi tief überwiegend im Wald liegen. Hier wollte ich gerne Werwölfe spawnen lassen. Immer vll. ne Gruppe von 10 Zellen (bzw. die xmarker dort) per Zufall über ne FormListe aktive schalten. Script am xmarker dachte ich mir entscheidet dann ist er aktive; ist Vollmond; ist es Nacht; ggf. noch FailSafe Dinge. Das wäre die ausbaufähige Basis - Bzw. würde wenn es läuft die anderen Werwolf-Mods recht gut ergänzen.

Letzter Stand ist das die Funktion welche den Mondstand ermittelt keinen Wert liefert oder ihn nicht an die Globale Variable übergibt. Ich hatte die Globale Variable mit einem Anfangswert "8" ausserhalb der Werte belegt welche die Funktion zurückgibt also 0-7. Beim Debug gibt er immer die "8" aus - Der Compiler akzeptiert alles ohne Fehlermeldung. Hier mal die aktuellen Scripte:

Hab die Funktion ergänzt das sie dann theoretisch alle Werte an die GloVar übergibt.

Code:
Int Function GetCurrentMoonphase(GlobalVariable jmVollmondGlobal) Global
    Int GameDaysPassed
    Int GameHoursPassed
    Int PhaseTest
    GameDaysPassed = GetPassedGameDays()
    GameHoursPassed = GetPassedGameHours()
 
    If (GameHoursPassed >= 12.0)
        GameDaysPassed += 1
    EndIf
 
    PhaseTest = GameDaysPassed % 24 ;A full cycle through the moon phases lasts 24 days
    If PhaseTest >= 22 || PhaseTest == 0
        Return 7
        jmVollmondGlobal.SetValueInt(7)
    ElseIf PhaseTest < 4
        Return 0
        jmVollmondGlobal.SetValueInt(0)
    ElseIf PhaseTest < 7
        Return 1
        jmVollmondGlobal.SetValueInt(1)
    ElseIf PhaseTest < 10
        Return 2
        jmVollmondGlobal.SetValueInt(2)
    ElseIF PhaseTest < 13
        Return 3
        jmVollmondGlobal.SetValueInt(3)
    ElseIf PhaseTest < 16
        Return 4
        jmVollmondGlobal.SetValueInt(4)
    ElseIf PhaseTest < 19
        Return 5
        jmVollmondGlobal.SetValueInt(5)
    ElseIf PhaseTest < 22
        Return 6
        jmVollmondGlobal.SetValueInt(6)
    EndIf
 
EndFunction

Das aktuelle Testscript am XMarker wo dann später vll. alles abläuft:

Code:
Scriptname JmPoAMarkerZelleGeladen extends ObjectReference

GlobalVariable Property jmObjektIndexGlobal  Auto
GlobalVariable Property jmVollmondGlobal  Auto

Event OnUpdate()
    jmUtility.GetCurrentMoonphase(jmVollmondGlobal)

    if jmVollmondGlobal.GetValue() == 0
        Debug.Notification("Es ist VOLLMOND!")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 3
        Debug.Notification("Zunehmend - Viertelmond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 2
        Debug.Notification("Zunehmend - Halbmond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 1
        Debug.Notification("Zunehmend - dreiviertel Mond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 4
        Debug.Notification("Es ist NEUMOND!")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 5
        Debug.Notification("Abnehmend - dreiviertel Mond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 6
        Debug.Notification("Abnehmend - dreiviertel Mond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    elseif jmVollmondGlobal.GetValue() == 7
        Debug.Notification("Abnehmend - dreiviertel Mond")
        Utility.Wait(3.0) ; 3 Sek. Pause
    else
        Debug.Notification("Kein TREFFER! - " + jmVollmondGlobal.GetValue())
        Utility.Wait(3.0) ; 3 Sek. Pause
    endif    
endEvent

Event OnCellLoad()

    Debug.Notification("Scriptaufruf von xMarker")
    Utility.Wait(3.0) ; 3 Sek. Pause
    Debug.Notification("Spieler hat Zelle betreten !")

    RegisterForUpdate(5)
EndEvent

Also dein Tip mit dem Event war gut und ist wenn die richtigen Werte ankommen wohl auch die beste Wahl. Denke für Basis dessen was ich erstmal anstrebe könnte ich auf das anlegen einer Quest dazu auch verzichten.

Vieleicht hilft die Original-Funktion von Bethesda bei der Fehlersuche:

http://www.creationkit.com/Complete...ync_between_the_two_moons_and_day_of_the_week

Die funktionierte Anfangs nicht weil die Typen float/int vertauscht waren - Hatte ich selbst korregiert und im Forum gebeten das jemand mal drüberschaut und das schien soweit ok.
 
Zuletzt bearbeitet:
Beseitige die returns und lass nur jmVollmondGlobal.SetValueInt(x) drin.
Aufgrund des Returns wirst du aus der Funktion geworfen, die Funktion gibt den Wert zurück und ist fertig, in die Zeile danach dürfte dein Skript nicht mehr kommen.
Demnach kommt es also nie zum Setzen der Values.

MfG Master of Worlds
 
Die oben genannten Lösungen sind super und werden mit Sicherheit auch funktionieren, doch ich würde lieber mal eine vielleicht praktischere Herangehensweise vorschlagen: (keine globalen Variablen, keine Quests, kein OnInit, kein irgendwas...)

Problembeschreibung:
Axiom 1: Ich habe ein Skript indem ich die Mondphase wissen will.
Axiom 2: Ich habe in den Creation-Kit-Beispielen eine super Funktion gefunden die diese Frage beantwortet.

Lösung:
Der Einfachheit halber machen wir das Mondphasen-Skript ein bisschen kürzer:

Code:
ScriptName DerMannImMond
Int Function SachMalWasMondphaseIst() global
Return 1
EndFunction

Dies ist unsere globale Funktion und die speichern wir nun in der neuen Datei DerMannImMond.psc und compilieren die.

Soweit hattest du das ja ungefair schon richtig. Das einzige Problem besteht nun darin, wie du die obige SachMalWasMondphaseIst-Funktion in irgendeinem anderen Skript aufrufen kannst.
Und Simsalabim: Die Lösung besteht darin, diese Funktion deinem Skript „bekannt“ zu machen, damit der Compiler das auch checkt und du beim compilieren eben keine Fehlermeldung mehr bekommst (und es damit hoffentlich auch funktioniert). :p

Nehmen wir nun also ein x-beliebiges neues Skript, in dem wir die Mondphase wissen wollen.
[Dein Skript indem du die Mondphase wissen willst]
Code:
...
Int Mondphase=SachMalWasMondphaseIst()
...
Auch soweit hattest du das ja alles schon, doch es tat ja nicht. Das Einzige was hier noch fehlte ist dem Skript die Funktion auch bekannt zu machen und das machen wir nun am Anfang unseres Skriptes mit der Zeile:
Code:
Import DerMannImMond

Ich denke einen großen Teil der Verwirrung kam vielleicht dadurch zustande, das sich alle in die Idee der globale Variable verstrickt hatten, die dafür gar nicht notwendig ist.

TL;DR

MeineGlobaleFunktion:

Code:
ScriptName DerMannImMond
Int Function SachMalWasMondphaseIst() global
Return 1
EndFunction

In irgendeinem Script in dem ich diese Funktion benutzen will:
Code:
...
Import DerMannImMond 
...
Int Mondphase=SachMalWasMondphaseIst()
...
Oder, wenn man noch weniger Zeilen haben möchte:

Code:
Int Mondphase=DerMannImMond.SachMalWasMondphaseIst()


Und nun troll ich mich. :p
 
Jep, wie MoW sagt, die returns rauswerfen oder die Zeilen vertauschen. Ein weiterer Grund warum es nicht funktioniert, könnte an GetValue() liegen. Die Funktion liefert einen Float-Wert, den du mit einem Integer Wert vergleichst. Versuche es mal mit GetValueInt() oder jmVollmondGlobal.GetValue() as int.
 
Vielen dank euch zusammen!

Funktioniert jetzt super ;)

Sowohl diese Variante:

Code:
Import jmUtility
...
Event OnUpdate()
    GetCurrentMoonphase(jmVollmondGlobal)
...

Also auch die Version die Ladyfalk beschrieben hat. Werte nach dem Return übergeben - Das war ja mal nen EpicFail ;) .. Momentan hab ich beide Scripte direkt auf dem xMarker und vieleicht brauch ich diesen Spagat mit ner Hilfsquest ja garnicht. Eine Hürde genommen werd ich mich direkt wieder frisch ans Werk machen und es verbleibt nur noch euch nochmal vielen Dank zu sagen.
 
prima, wenn du noch Hilfe brauchst, einfach bescheid sagen :)