Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Page 1 of 5 12345 Last »
Results 1 to 20 of 84
  1. View Forum Posts #1 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline

    Bätsch [Patch] Manaregeneration für alle

    Jetzt auf Basis von Ninja 2 !

    Ich habe vor kurzem angefangen zu lernen, wie man Scripte für Gothic (2) schreibt, da kam es gelegen, dass ich schon immer mal Manaregeneration in jeder möglichen Mod haben wollte und Ninja dies ermöglichen kann.


    Gerne akzeptiere ich konstruktive Kritik, wenn vorhanden

    Historie
    Spoiler:(zum lesen bitte Text markieren)

    Version 1.0.0 (Erste öffentliche Version, veraltet)
    Version 1.0.1 (kleinere Verbesserungen, veraltet)
    Version 1.1.0 (Gothic.INI Konfiguration!, veraltet)
    Version 1.2.0 (Mehr kompatibilität, veraltet)
    Version 1.2.1 (Eigene Frequenz/Tickrate)
    Spoiler:(zum lesen bitte Text markieren)
    Neue Option für die Gothic.INI: "NINJA_MANAREG"->"TICKRATE"

    Code:
    [NINJA_MANAREG]
    THRESHOLD=50
    DIVISOR=20
    # Frequenz/Tickrate der Manaregeneration in Millisekunden 1000=1 Sekunde
    TICKRATE=2000


    Konfiguration des Patches
    Um die Standardwerte (THRESHOLD/Schwellenwert: 50 Mana, DIVISOR: 50) zu überschreiben,
    trägt man folgendes (z.B. ans Ende) in die System\Gothic.ini ein:

    Code:
    [NINJA_MANAREG]
    THRESHOLD=50
    DIVISOR=20
    TICKRATE=2000
    #PER_TICK=1
    Erklärung
    THRESHOLD: Der "Maximales Mana"-Wert, den der Held benötigt, damit die Manaregeneration freigeschaltet wird. (Standard: 50)
    DIVISOR: Der Wert mithilfe dessen, die Regenerationsrate bestimmt wird. (Standard: 50)
    - Berechnung: Regenerationsrate = (Maximales Mana + (DIVISOR / 2)) / DIVISOR
    TICKRATE: Frequenz/Tickrate der Manaregeneration in Millisekunden (1000=1 Sekunde)
    PER_TICK: Feste Menge Mana welche Pro Tick regeneriert wird. (Sinnvoll für G1, wo Manakosten gering sind)

    Vorraussetzungen:
    - Gothic 2 DndR mit Reportversion 2.6.0.0 / Gothic 1.08k
    - Ninja 2+

    Installation:
    ManaReg.vdf nach "C.\Spiele\[Gothic2 oder Gothic1]\Data" kopieren. (Pfad entsprechen anders bei euch)

    Download (extern) : GitHub Release

    Quellcode: GitHub
    Last edited by Kirides; 22.11.2019 at 17:52. Reason: Systempack entfernt, URL korrigiert

  2. View Forum Posts #2 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,200
     
    Lehona is offline
    Quote Originally Posted by johnnyboyy View Post
    Gerne akzeptiere ich konstruktive Kritik, wenn vorhanden
    Na dann leg ich mal los

    In der *_INIT.d:

    Code:
        Timer_SetPauseInMenu(1);
        if(!FF_Active(Ninja_ManaReg_Regeneration)) {
            FF_ApplyExt(Ninja_ManaReg_Regeneration, 2000, -1);
        };
    Die If-Klausel kannst du dir mit FF_ApplyOnceExt sparen (die macht genau das).

    Das setzen des Timers ist ein bisschen gefährlich, denn das ist eine globale Einstellung. Falls sich andere Teile der Mod darauf verlassen, dass die Timer im Menü weiterlaufen, machst du das damit kaputt. Ist allerdings nicht unbedingt deine Schuld: Man kann das in LeGo 2.5 nicht für einzelne FFs einstellen. Im nächsten Release gibt es eine Möglichkeit, FFs an den Gametimer zu hängen, dann brauchst du das nicht mehr. Insgesamt gibt es dann zwei getrennte Timer, anstatt einem, den man umstellen kann.

    Dann in der Manareg_Init(): Das meiste kannst du dir da sparen, scheinst du ja von mud-freaks Vorlage kopiert zu haben. Die Kommentare sind ziemlich irreführend oder mud-freak und ich verwenden andere Begrifflichkeiten. Zumindest wird die ManaReg_InitOnce() einmal pro Spielstand aufgerufen, nicht einmal pro Session (das heißt für mich: Zwischen Starten und Beenden der Anwendung). Um es wirklich 1x pro Session zu machen, müsste die Variable Ninja_ManaReg_Initialized eine Konstante mit dem Wert 0 sein.


    In der *_REGENERATION.d:

    Die Funktion wird nur einmal alle zwei Sekunden aufgerufen, aber Float-Operationen sind dennoch nicht soo billig (zumindest im Vergleich zum Rechnen mit Integern). In deinem Fall lässt sich die Mana-Menge auch problemlos ohne Floats berechnen:

    Code:
    var int mreg_div; mreg_div = n.attribute[ATR_MANA_MAX]/50; 
    // Falls du korrekt runden möchtest:
    var int mreg_div; mreg_div = (n.attribute[ATR_MANA_MAX]+25)/50;
    Das ist zwar eher eine Mikro-Optimierung, aber der Code wird lesbarer und du kannst den Faktor jetzt (einfacher) als Konstante ausdrücken. Insgesamt solltest du deine Einstellungen als Konstanten deklarieren und nicht in einer Init-Funktion befüllen.

  3. View Forum Posts #3 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Quote Originally Posted by Lehona View Post
    Das setzen des Timers ist ein bisschen gefährlich, denn das ist eine globale Einstellung. Falls sich andere Teile der Mod darauf verlassen, dass die Timer im Menü weiterlaufen, machst du das damit kaputt. Ist allerdings nicht unbedingt deine Schuld: Man kann das in LeGo 2.5 nicht für einzelne FFs einstellen. Im nächsten Release gibt es eine Möglichkeit, FFs an den Gametimer zu hängen, dann brauchst du das nicht mehr. Insgesamt gibt es dann zwei getrennte Timer, anstatt einem, den man umstellen kann.
    D.h. um das sauberer zu implementieren sollte ich warten, verstehe ich das richtig? (Oder gibt es eine Variable/Methode mit der ich "pausieren/überspringen" kann)


    Ich habe mal bisschen aufgeräumt, da war ja noch viel nicht verwendeter Code aus der inspirierenden Vorlage.

    refactor-wog (GitHub, diff)
    Last edited by Kirides; 28.08.2018 at 22:12. Reason: Quote gefixt

  4. View Forum Posts #4 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,200
     
    Lehona is offline
    Code:
    var int menge; menge = (n.attribute[ATR_MANA_MAX] + 25) / NINJA_MANAREG_MAX_MANA_DIVISOR;
    // nicht eher
    var int menge; menge = (n.attribute[ATR_MANA_MAX] + (NINJA_MANAREG_MAX_MANA_DIVISOR/2)) / NINJA_MANAREG_MAX_MANA_DIVISOR;
    Wegen dem Timer-Problem kannst du einfach das in deine FF schreiben:

    Code:
    if (MEM_Game.timeStep) {
        return;
    };
    Dann wird der Code nicht ausgeführt, falls das Spiel gerade pausiert ist. Ist dann ein bisschen ungenau wegen dem 2-Sekunden Timer, der ja trotzdem läuft, aber fürs erste funktioniert das.

  5. View Forum Posts #5 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Quote Originally Posted by Lehona View Post
    Code:
    var int menge; menge = (n.attribute[ATR_MANA_MAX] + 25) / NINJA_MANAREG_MAX_MANA_DIVISOR;
    // nicht eher
    var int menge; menge = (n.attribute[ATR_MANA_MAX] + (NINJA_MANAREG_MAX_MANA_DIVISOR/2)) / NINJA_MANAREG_MAX_MANA_DIVISOR;
    Du hast natürlich recht - hatte schon viel zu lange nicht wirklich mit Mathe zu tun, sogar simple Mathematik kann man vergessen

    Bezüglich des Timers, genau sowas hatte ich mir als workaround gedacht - aber kannte / kenne die ganzen variablen noch nicht wirklich. Kommt noch

    refactor-wog (GitHub, diff)


    EDIT:
    Quote Originally Posted by Lehona View Post
    Wegen dem Timer-Problem kannst du einfach das in deine FF schreiben:

    Code:
    if (MEM_Game.timeStep) {
        return;
    };
    Dann wird der Code nicht ausgeführt, falls das Spiel gerade pausiert ist. Ist dann ein bisschen ungenau wegen dem 2-Sekunden Timer, der ja trotzdem läuft, aber fürs erste funktioniert das.

    Das scheint leider nicht zu funktionieren, mit diesem Code wird die Methode nicht ausgeführt :/
    Last edited by Kirides; 28.08.2018 at 23:11.

  6. View Forum Posts #6 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,200
     
    Lehona is offline
    Quote Originally Posted by johnnyboyy View Post
    Das scheint leider nicht zu funktionieren, mit diesem Code wird die Methode nicht ausgeführt :/
    Vielleicht hab ich die Bedingung umgedreht - überprüf mal das Gegenteil.

  7. View Forum Posts #7 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Ich habe auch noch ein bisschen Feedback (für Übersichtlichkeit nummeriert).
    1. Cool, dass du dich bei dem Ninja-Patch so an die Vorlagen gehalten hast. Das macht alles recht übersichtlich!

    2. Wünschenswert wäre sowohl eine Readme_Ninja_ManaReg.txt als auch eine Info-Beschreibung in der VDF-Datei (siehe GFA Ninja-Patch). Da ist es auch wichtig zu erwähnen, dass es ich eben nicht um LeGo 2.5 handelt, sondern um eine angepasste Version (die du scheinbar aus dem GFA Ninja-Patch übernommen hast):
      Quote Originally Posted by Readme vom GFA-Ninja-Patch
      LeGo 2.5.0-rev-170*
      [...]
      * For compatibility with LeGo 2.4, some functions are not included
      (ViewPtr_AddText, View_AddText, View_AddTextColored, Button_SetCaption)
    3. Die Dateinamen der angepassten LeGo-Version solltest du auch an deinen Patchnamen anpassen, diese heißen noch
      Code:
      __BUTTONS_NINJA_GFA.D
      __VIEW_NINJA_GFA.D
      (Entsprechende Referenzen in der HEADER.SRC auch anpassen.) Das ist wichtig, falls sich die Inhalte der beiden Patches mal unterscheiden sollten, denn jede Datei mit identischem Pfad wird nur einmal aus den VDF-Dateien geladen (daher müssen alle Patch-spezifischen Dateien einzigartige Namen tragen).


    4. Quote Originally Posted by Lehona View Post
      Dann in der Manareg_Init(): Das meiste kannst du dir da sparen, scheinst du ja von mud-freaks Vorlage kopiert zu haben. Die Kommentare sind ziemlich irreführend oder mud-freak und ich verwenden andere Begrifflichkeiten. Zumindest wird die ManaReg_InitOnce() einmal pro Spielstand aufgerufen, nicht einmal pro Session (das heißt für mich: Zwischen Starten und Beenden der Anwendung). Um es wirklich 1x pro Session zu machen, müsste die Variable Ninja_ManaReg_Initialized eine Konstante mit dem Wert 0 sein.
      In den GFA-Skripten, wo johnnyboyy das glaube ich her hat, ist das eine Konstante mit null. Ich denke wir haben da das gleiche Verständnis von Session und Spielstand.

    5. Damit die Mana-Regeneration auch nach Weltenwechsel problemlos läuft, solltest du hier lieber hero anstatt PC_Hero verwenden.


    6. Quote Originally Posted by johnnyboyy View Post
      Das scheint leider nicht zu funktionieren, mit diesem Code wird die Methode nicht ausgeführt :/
      Du könntest auch folgendes probieren:
      Code:
      if (MEM_Game.pause_screen) {
          return;
      };

    7. Ich habe den Ninja-Patch nicht getestet. Hast du mal ein paar Tests mit einer handvoll verschiedener und verschieden-alter Mods gemacht? Auch in Verbindung mit anderen Ninja-Patches? Hast du Randfälle überprüft (während Regeneration Spiel speichern/laden, Weltenwechsel, Spiel beenden und neu starten, neues Spiel, usw.).
      Meiner Meinung nach ist das Testen von Ninja-Patches besonders wichtig, denn sonst verursachst du Mod-Entwicklern eine Menge Ärger, wenn sie sich um Bugs kümmern sollen, die gar nicht durch ihre Mod entstanden sind (außerdem wird bei Problemen gern schnell pauschalisiert, z.B. "Ninja-Patches sind alle von Vornherein verbuggt!").


    Gute Arbeit!


    EDIT: Ein Verbesserungsvorschlag wäre, dass sich der Schwellenwert von 50 Mana und die Regenerierungsgeschwindigkeit/-menge in der Gothic.ini einstellen ließe.
    Last edited by mud-freak; 29.08.2018 at 01:45.

  8. View Forum Posts #8 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Quote Originally Posted by Lehona View Post
    Vielleicht hab ich die Bedingung umgedreht - überprüf mal das Gegenteil.
    Damit gehts


    Quote Originally Posted by mud-freak View Post
    Gute Arbeit!


    EDIT: Ein Verbesserungsvorschlag wäre, dass sich der Schwellenwert von 50 Mana und die Regenerierungsgeschwindigkeit/-menge in der Gothic.ini einstellen ließe.
    D.h. aus den Konstanten werden wieder Variablen, die ich im "initOnce" befülle, korrekt?


    Sporadisch erhalte ich beim Speichern eine Access Violation, hier kann ja eigentlich nur "hero" der pointer sein, oder irre ich mich?
    Gibt es beim Speichern/Levelwechsel etwas wichtiges zu beachten, was ich nicht tue?

    EDIT: Kann es zurückführen auf den Marvin-Modus, sobald ich ihn Aktiviere und Deaktiviere (c42c) tritt das verhalten auf. Auch ohne mein Script. (Nur LeGo und Ikarus)
    Reproduzierbar durch Marvin->"edit abilities" -> Attribute -> 2 = 80 -> c42c -> speichern. Zufällig (häufig) Fehler und crash

    Code (Ninja_ManaReg_Regeneration)
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    func void Ninja_ManaReg_Regeneration() {
        // HACK: Entfernen wenn es FF gibt, welche nur im nicht pausierten Modus feuern.
        if (!mem_game.timestep) {
            return;
        };
        //var c_npc n; n = Hlp_GetNpc(PC_Hero);
        var c_npc n; n = Hlp_GetNpc(hero);
        
        if (n.attribute[ATR_MANA_MAX] >= NINJA_MANAREG_MANA_THRESHOLD) {
            if (n.attribute[ATR_MANA] < n.attribute[ATR_MANA_MAX]) {
                var int menge; menge = (n.attribute[ATR_MANA_MAX] + (NINJA_MANAREG_MAX_MANA_DIVISOR/2)) / NINJA_MANAREG_MAX_MANA_DIVISOR;
                Npc_ChangeAttribute(n, ATR_MANA, menge);
            };
        };
    };


    Stacktrace
    Spoiler:(zum lesen bitte Text markieren)
    [f] 03:08 Fault: 0 Q: MEM_PtrToInst: Invalid pointer: -2141662528
    [i] 03:08 Info: 5 X: Vid_SetScreenMode: No changes ... .... <zRndD3D_Vid.cpp,#559>
    [i] 03:08 Info: 5 X: Vid_SetScreenMode: No changes ... .... <zRndD3D_Vid.cpp,#559>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.ARRAY .... <zParser_Symbol.cpp,#365>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.NUMALLOC .... <zParser_Symbol.cpp,#365>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.NUMALLOC .... <zParser_Symbol.cpp,#365>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.ARRAY .... <zParser_Symbol.cpp,#365>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.ARRAY .... <zParser_Symbol.cpp,#365>
    [i] 03:20 Info: 2 U: PAR: Adressing an empty Instance : ZCARRAY.NUMINARRAY .... <zParser_Symbol.cpp,#365>
    [f] 03:20 Fault: 0 Q: [start of stacktrace]
    [f] 03:20 Fault: 0 Q: MEM_WRITEINT_() + 35 bytes
    [f] 03:20 Fault: 0 Q: MEM_WRITEINTARRAY(0, 0, 827877824) + 45 bytes
    [f] 03:20 Fault: 0 Q: MEM_ARRAYINSERT(-2141662528, 827877824) + 238 bytes
    [f] 03:20 Fault: 0 Q: PM_SAVESTRING('loop', 'NINJA_MANAREG_REGENERATION') + 52 bytes
    [f] 03:20 Fault: 0 Q: PM_SAVEFUNCID('loop', 10000) + 58 bytes
    [f] 03:20 Fault: 0 Q: PM_SAVEFUNCOFFSET('loop', 123832) + 32 bytes
    [f] 03:20 Fault: 0 Q: PM_SAVEFUNCPTR('loop', 246088664) + 33 bytes
    [f] 03:20 Fault: 0 Q: FFITEM_ARCHIVER((instance)1755378040) + 26 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALLBYID(8266) + 224 bytes
    [f] 03:20 Fault: 0 Q: _PM_DATATOSAVESTRUCT_ARCHIVER(0, 8266) + 59 bytes
    [f] 03:20 Fault: 0 Q: _PM_DATATOSAVEOBJECT('', 'FFITEM') + 633 bytes
    [f] 03:20 Fault: 0 Q: _PM_INSTTOSAVESTRUCT(1755378040, 8265) + 275 bytes
    [f] 03:20 Fault: 0 Q: _PM_ARCHIVE_LISTSUB(1906445232) + 84 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALLBYID(8266) + 224 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALL(LIST_FORF.FNC) + 21 bytes
    [f] 03:20 Fault: 0 Q: LIST_FORF(1906445232, _PM_ARCHIVE_LISTSUB) + 75 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALLBYID(8266) + 224 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALL(LIST_FORF.FNC) + 21 bytes
    [f] 03:20 Fault: 0 Q: _PM_ARCHIVE() + 199 bytes
    [f] 03:20 Fault: 0 Q: _BW_SAVEGAME() + 89 bytes
    [f] 03:20 Fault: 0 Q: MEM_CALLBYID(8266) + 224 bytes
    [f] 03:20 Fault: 0 Q: _HOOK(1755714816, 1554527544, 159025696, 159025696, 20314684, 1, 20578304, 2, 180250296) + 498 bytes
    [f] 03:20 Fault: 0 Q: [UNKNOWN] +847941955 bytes
    [f] 03:20 Fault: 0 Q: [end of stacktrace]


    EDIT:
    Update 1.1.0
    (Siehe start-post)
    Last edited by Kirides; 29.08.2018 at 23:21.

  9. View Forum Posts #9 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Quote Originally Posted by johnnyboyy View Post
    D.h. aus den Konstanten werden wieder Variablen, die ich im "initOnce" befülle, korrekt?
    Das sieht im Code auf Github ganz gut aus. Sollte so klappen.

    Quote Originally Posted by johnnyboyy View Post
    Sporadisch erhalte ich beim Speichern eine Access Violation, hier kann ja eigentlich nur "hero" der pointer sein, oder irre ich mich?
    Nein, der Pointer ist ein nicht vorhandenes Array (_PM_Head.content) beim Schreiben in PermMem in Zusammenhang mit deiner FrameFunction. Wenn das wie du schreibst auch ohne dein Skript vorkommt, stimmt da was nicht. Kann es sein, dass das mit einem geladenem Speicherstand passiert ist?

    Speicherst du mit deinem Ninja-Patch, wird die FrameFunction mit in den Speicherstand gelegt. Lädst du dann den Speicherstand ohne den Ninja-Patch, kann PermMem den Funktionsnamen "Ninja_ManaReg_Regeneration" keinem Symbol zuordnen. Ich meine aber, das war kein Problem und LeGo würde in solchen Fällen lediglich eine Warnung auswerfen. Vor allem kann ich mir nicht vorstellen, dass es an einem nicht existierendem Array (_PM_Head.content) scheitert...

    Kannst du versuchen, den Fehler etwas mehr einzugrenzen? (Mit/ohne Ninja-Patch, neues Spiel/geladenes Spiel jeweils mit/ohne Ninja-Patch, ...) Hast du noch andere Änderungen in Gothic, die die Ursache dafür sein könnten?

  10. View Forum Posts #10 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Vorweg: mein Gothic2 Verzeichnis für das Scripten ist ein frisch installiertes, nach empfohlener Reihenfolge + Mdk mit Rohdaten


    Ich habe einen Speicherstand, welchen ich ohne Mod-Starter / Scripts & Ninja erstellt habe, "START1" diesen habe ich als Basis für alle meine Tests benutzt.

    Diesen habe ich immer geladen (Modstarter + Scripte parsen) und anschließend auf "START2" gespeichert. Soweit so gut.
    Wenn ich jedoch, im Marvin Modus meine Attribute ändere und den Marvin-Modus dann beende, anschließend versuche auf START3 zu speichern, bekomme ich teilweise eine Access Violation.
    Diese tritt auch auch, wenn ich die FF_ApplyOnce-Zeile auskommentiere (d.h. nur der INIT-Code mit dem Mergen von Flags wird ausgeführt).

    Nach der Arbeit versuche ich das noch genauer zu reproduzieren.


    EDIT: Also sind Speicherstände kaputt, wenn man den Ninjapatch wieder entfernt? // derp
    Last edited by Kirides; 30.08.2018 at 19:26.

  11. View Forum Posts #11 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Versuch es am besten immer mit neuen Spielen als Basis anstatt einem geladenen Spielstand (ausgenommen du willst eben gerade das Speicher- und Ladeverhalten mit und ohne Ninja-Patch testen).
    Wenn du nur Änderungen an Ninja vornimmst, brauchst du übrigens nicht das Häkchen bei "Skripte parsen" im Mod-Starter, dann geht's schneller. Ninja parst immer seine Skripte.

    Vielleicht finde ich am Wochenende Zeit zu probieren, ob ich den Fehler reproduzieren kann.

    Zu deinem Edit:
    Nein. Im Normalfall kann man sie problemlos entfernen und hinzufügen (solang sie keine Symbolindices abspeichern, was mir nur vom EventHandler in LeGo bekannt ist, den man aber auch ohne PermMem-Handle benutzen kann, um das Problem zu umgehen). Allerdings hatte ich in meinen Ninja-Patches nie eine fortlaufende FrameFunction und kann mich nicht mehr erinnern, ob das ein Problem war.
    Last edited by mud-freak; 19.01.2019 at 19:53.

  12. View Forum Posts #12 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Mein Ziel ist es einen Patch zu kreieren, welcher mit vorhandenen Spielständen verwendet werden kann, deswegen hatte ich das als Basis genommen.

    Mein Script lasse ich aktuell noch über Gothic.src Parsen und erst nach dem testen landet das im separaten "ninjasrc" Verzeichnis, mit der Struktur vom Patch

  13. View Forum Posts #13 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Bloßes speichern nach einem neuen Spiel hat das Spiel zum absturz gebracht.
    Aktive Mods / Patches: Ninja_ManaReg


    Video auf YouTube (Xardas bei ~50 Sekunden)

    zSpy Log auf Pastebin
    Last edited by Kirides; 30.08.2018 at 19:20.

  14. View Forum Posts #14 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Quote Originally Posted by johnnyboyy View Post
    Bloßes speichern nach einem neuen Spiel hat das Spiel zum absturz gebracht.
    Aktive Mods / Patches: Ninja_ManaReg


    Video auf YouTube (Xardas bei ~50 Sekunden)

    zSpy Log auf Pastebin
    Danke für den zSpy Log. Bis ich mir das genauer angucken kann, kannst du einmal unter deiner Funktion "Ninja_ManaReg_Init()" eine "leere" Funktion anfügen? Also in /NINJA/CONTENT/NINJA_ManaReg_INITCONTENT.D nach Zeile 57 etwas wie:
    Code:
    func void Ninja_ManaReg_Dummy() {
        var int i; i = i;
        return;
    };

  15. View Forum Posts #15 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,200
     
    Lehona is offline
    Ikarus weigert sich, negative Pointer zu dereferenzieren (MEM_PtrToInst), was dann später zu einem MEM_WriteInt(0, x) führt (und MEM_WriteInt hat aus Performance-Gründen keine Sanity-Checks) Wenn ich mich nicht irre ist es aber keinesfalls unmöglich, negative Pointer zu erzeugen. Eine kurze Google-Suche hat bestätigt, dass alle 32bit-Werte ungleich NULL gültige Pointer sind.

    Die Frage ist natürlich, warum das jetzt mehr oder weniger zum ersten Mal aufgetreten ist (bzw. ich davon gehört habe). Benutzt das neuste SystemPack vielleicht das Flag, dass den Adressraum von 2 auf 4 GiB erweitert?

    Du kannst mal versuchen, in MEM_PtrToInst nur bei ptr == 0 abzubrechen bzw. gar nicht abzubrechen und nur eine Warnung auszugeben.

    Edit: Eh, da gehen unsere Lösungsansätze aber ganz schön auseinander

  16. View Forum Posts #16 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Da fällt mir ein: Ich hab ja das LAA-FLAG gesetzt auf meiner gothic.exe!

    Hab mal ohne den FLAG getestet: Das Problem tritt nicht mehr auf (zumindest in meinen tests)


    Hatte den mal auf meine "clean" installation gesetzt, weil das früher mal vor OutOfMemory geholfen hatte, meine ich mich zu erinnern

    EDIT:
    Quote Originally Posted by mud-freak View Post
    Danke für den zSpy Log. Bis ich mir das genauer angucken kann, kannst du einmal unter deiner Funktion "Ninja_ManaReg_Init()" eine "leere" Funktion anfügen? Also in /NINJA/CONTENT/NINJA_ManaReg_INITCONTENT.D nach Zeile 57 etwas wie:
    Code:
    func void Ninja_ManaReg_Dummy() {
        var int i; i = i;
        return;
    };
    Warum zum Geier hilft das gegen das Problem?? *interessiert*

    Habe das mal eingebaut, und die gothic2.exe mit LAA-Flag getestet und das Problem scheint nicht mehr aufzutreten

    EDIT2:
    Quote Originally Posted by Lehona View Post
    Du kannst mal versuchen, in MEM_PtrToInst nur bei ptr == 0 abzubrechen bzw. gar nicht abzubrechen und nur eine Warnung auszugeben.
    Ich habe mal Ikarus.d->MEM_PtrToInst geändert und damit getestet:
    Code:
    func MEMINT_HelperClass MEM_PtrToInst (var int ptr) {
        var MEMINT_HelperClass hlp;
        const int hlpOffsetPtr = 0;
        if (!hlpOffsetPtr) {
            hlpOffsetPtr = MEM_ReadIntArray (currSymbolTableAddress, hlp) + zCParSymbol_offset_offset;
        };
    
        if (ptr == 0) {
            if (!MEM_AssignInstSuppressNullWarning) {
                /* Instanzen die Null sind, will man eigentlich nicht, die machen nur Ärger. */
                MEM_Warn ("MEM_PtrToInst: ptr is NULL. Use MEM_NullToInst if that's what you want.");
            };
    
            MEM_WriteInt(hlpOffsetPtr, 0);
        } else {
            MEM_WriteInt(hlpOffsetPtr, ptr);
        };
        MEMINT_StackPushInst (hlp);
    };
    Damit tritt das Problem auch nicht auf
    Last edited by Kirides; 30.08.2018 at 20:22.

  17. View Forum Posts #17 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,200
     
    Lehona is offline
    Quote Originally Posted by johnnyboyy View Post
    Warum zum Geier hilft das gegen das Problem?? *interessiert*

    Habe das mal eingebaut, und die gothic2.exe mit LAA-Flag getestet und das Problem scheint nicht mehr aufzutreten


    Das würde ich allerdings auch gerne wissen

  18. View Forum Posts #18 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Vorher noch die Frage: Bist du wirklich sicher, dass das Problem durch die leere Funktion behoben ist (inkl. gesetztem LAA-Flag) oder hast du es nur ein-zwei mal getestet?


    Was FrameFunctions in Ninja-Patches angeht: Entfernst du den Ninja-Patch von einer Mod, die LeGo benutzt, stürzt das Spiel beim Laden der zuvor gespeicherten Spiele ab. Das liegt daran, dass die FrameFunctions mitgespeichert/-geladen werden, aber die Funktion ohne den Ninja-Patch nicht mehr existiert. LeGo anzupassen, dass es erst schaut, ob eine entsprechende Funktion existiert, wird nichts bringen, weil sich das ja nicht rückwirkend auf ältere Mods auswirkt. Die Spieler müssten also die "SCRPTSAVE.SAV" editieren und die FrameFunction herauslöschen, was nicht besonders Benutzerfreundlich ist. Das ist aber nun ein spezieller Fall, denn die bisherigen Ninja-Patches benutzen keine (fortlaufenden) FrameFunctions.
    Mir fallen einige Alternativen ein (FrameFunction-Handle beim Speichern ausschließen, FrameFunction über Hooks emulieren, FrameFunctions Handle-los nachbauen), die aber alle mehr oder weniger große Probleme mit sich bringen.

    Dass das nun nicht von Haus aus funktioniert, liegt nicht an Ninja, geschweige denn an LeGo. (Ninja öffnet ja nur die Tür für Skriptpatches, setzt aber nicht die Verwendung von LeGo voraus. Und niemand hätte bei der Entwicklung von LeGo so etwas ahnen können oder Rücksicht darauf nehmen müssen.) Es ist also beim Erstellen des Patches, wo man sich etwas einfallen lassen muss, wie man seine Ideen realisiert. Deshalb ist das Ganze nicht so ganz geradlinig wie normales Skripten und ein bisschen mehr herausfordernd. Ich hoffe, das ging schon aus der Dokumentation von Ninja etwas hervor.

    Hier meine Empfehlung:

    Anstatt einer FrameFunction erstellst du einen Hook (z.B. an selber Adresse), mit dem du die verstrichene Zeit mit der Verzögerung von 2 Sekunden abgleichst und entsprechend die Manapunkte erhöhst (wenn das Spiel gerade nicht pausiert ist). Das ist aber sehr speziell für diesen Fall und löst das Problem nicht in anderen Fällen. Denn durch den Hook läuft diese "Schleife" in jedem geladenen Spielstand und lässt sich nicht von Spielstand zu Spielstand de-/aktivieren, oder mitspeichern. Bei der Manaregeneration ist das ja kein Problem, weil sie immer stattfindet und nicht beispielsweise erst gelernt werden muss o.ä.

  19. View Forum Posts #19 Reply With Quote
    Veteran Kirides's Avatar
    Join Date
    Jul 2009
    Location
    Bremen
    Posts
    513
     
    Kirides is offline
    Quote Originally Posted by mud-freak View Post
    Vorher noch die Frage: Bist du wirklich sicher, dass das Problem durch die leere Funktion behoben ist (inkl. gesetztem LAA-Flag) oder hast du es nur ein-zwei mal getestet?

    ...

    Hier meine Empfehlung:

    Anstatt einer FrameFunction erstellst du einen Hook (z.B. an selber Adresse), mit dem du die verstrichene Zeit mit der Verzögerung von 2 Sekunden abgleichst und entsprechend die Manapunkte erhöhst (wenn das Spiel gerade nicht pausiert ist). Das ist aber sehr speziell für diesen Fall und löst das Problem nicht in anderen Fällen. Denn durch den Hook läuft diese "Schleife" in jedem geladenen Spielstand und lässt sich nicht von Spielstand zu Spielstand de-/aktivieren, oder mitspeichern. Bei der Manaregeneration ist das ja kein Problem, weil sie immer stattfindet und nicht beispielsweise erst gelernt werden muss o.ä.
    Ich hatte es ca 5x probiert, jeweils Neigeladen und neuen Spielstand (10x Ges.)
    Kann natürlich auch einfach sein, dass in den Speichervorgängen einfach kein negativer Pointer aufgetreten ist. Ich probiere das nach der Arbeit noch ein paar Mal.

    Zum anderen Thema:
    Gibt es da eine (verständliche) Anleitung wie man die Adresse herausbekommt und hooks in die gewünschte Adresse einbindet?

  20. View Forum Posts #20 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,332
     
    mud-freak is offline
    Quote Originally Posted by johnnyboyy View Post
    Ich probiere das nach der Arbeit noch ein paar Mal.
    Das wäre gut zu wissen, denn ich glaube es liegt nicht zwingend am LAA-Flag, bzw. mich wundert dass beide Lösungsansätze funktionieren.


    Quote Originally Posted by johnnyboyy View Post
    Gibt es da eine (verständliche) Anleitung wie man die Adresse herausbekommt und hooks in die gewünschte Adresse einbindet?
    Im LeGo-Thread hatte sich glaube ich Lehona mal die Mühe gemacht eine verständliche Anleitung zu Hooks zu schreiben, aber ich habe den Post jetzt auf die schnelle nicht gefunden. Hier ist es aber ziemlich einfach: mit "an selber Adresse" meinte ich die Adresse von FrameFunctions aus LeGo ("oCGame__Render"). Es ginge zwar auch eleganter (z.B. in oCAIHuman::PC_walkcycle oder so ähnlich, dann würde die Funktion direkt nur während des laufenden Spiels aufgerufen werden), aber das sollte so passen (code ungetestet):

    Code:
    func void Ninja_ManaReg_Regeneration() {
        // Not during loading
        if (!Hlp_IsValidNpc(hero)) {
             return;
        };
    
        // Only in-game
        if (!MEM_Game.timestep) {
            return;
        };
    
        // Only in a certain interval
        var int delayTimer; delayTimer += MEM_Timer.frameTime;
        if (delayTimer < 2000) {
            return;
        };
        delayTimer -= 2000;
    
        // Increase mana
        if (hero.attribute[ATR_MANA_MAX] >= Ninja_ManaReg_Mana_Threshold) {
            if (hero.attribute[ATR_MANA] < hero.attribute[ATR_MANA_MAX]) {
                var int menge; menge = (hero.attribute[ATR_MANA_MAX] + (Ninja_ManaReg_Max_Mana_Divisor/2)) / Ninja_ManaReg_Max_Mana_Divisor;
                Npc_ChangeAttribute(hero, ATR_MANA, menge);
            };
        };
    };
    Die Initialisierung von LeGo kann man sich so komplett sparen, weil die HookEngine auf keinem Paket aufbaut (seit 2.4), d.h. die ganze "MergeLeGoFlags"-Geschichte kannst du dir so sogar sparen.
    Code:
    func void Ninja_ManaReg_Init() {
        MEM_Info(ConcatStrings(ConcatStrings("Initialize ", NINJA_MANAREG_VERSION), "."));
    	
        Ninja_ManaReg_ApplyINI();
        HookEngineF(oCGame__Render, 7, Ninja_ManaReg_Regeneration);
    
        MEM_Info(ConcatStrings(NINJA_MANAREG_VERSION, " was initialized successfully."));
    };

Page 1 of 5 12345 Last »

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide