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

 

Ergebnis 1 bis 5 von 5
  1. Beiträge anzeigen #1 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline

    [Tool] FeatShare

    Wenn man ein grösseres Feature untereinander oder in der Modderdatenbank teilen will, ist es meist mit viel Aufwand verbunden, es in eine (modifizierte) Gothic Installation einzubinden. In viele Skripte müssen einige Zeilen hinzugefügt oder geändert werden und das beansprucht Zeit und Arbeit.

    FeatShare (Feature+Share) hilft da aus. FeatShare integriert die Skripte an die richtigen Stellen, unabhängig davon, wie weit diese von den originalen abweichen. Das ganze kann man sich als eine Art Merge-Tool vorstellen, allerdings werden nicht zwei komplette Gothic Installationen abgeglichen, sondern lediglich ausgewählte Teile in eine andere Gothic Installation eingepflegt. Dabei ist es auch möglich alle Art von Dateien (inkl. Binärdateien) zu kopieren, zu löschen und zu überschreiben. Natürlich wird vorher von allen zu verändernden Dateien ein Backup angelegt. Es ist keine Überraschung, dass das nicht alles von selbst geht (woher soll FeatShare wissen, in welche Datei ein Feature in welche Zeile eingetragen muss). Die "Arbeit" das festzulegen liegt am Vertreiber der Features.

    Mittels regulären Ausdrücken* legt man die möglichst generellsten Anhaltspunkte in Skripten fest und bestimmt so, wo FeatShare die Skriptstücke einfügt. Bei solchen Aufgaben wird man aber nicht allein gelassen. Ich habe einige Hilfstools dazu geschrieben und eine umfangreiche Dokumentation verfasst.
    (*) Diese habe ich noch erweitert (geschachtelte Klammerzuordnung, nter Treffer von vorne oder hinten)

    • Felper.exe ist ein kleines Tool, mit dem man ein bisschen mit regulären Ausdrücken anhand seiner Skripte herumspielen kann, so wie es FeatShare tut.
    • BuildSetup.exe ist ein Tool, dass die erstellten FeatShare-Konfigurationen und die Features (inkl. jeglicher Binärdateien) in ein Setup (bestehend aus einer Datei) zusammenpackt und mit LZMA komprimiert.
    • FeatShare.chm ist eine (Compiled HTML Help) Hilfe-Datei mit Referenz, Einleitung und Beispielen.
    • FeatShare.exe selbst steckt in BuildSetup.exe mit drin und kommt zum Einsatz, wenn jemand das Feature installiert.
    • In FeatShare.exe stecken noch weitere Tools, wie z.B. ein Diff-Utility-artiges Tool, dass die Änderungen anzeigen kann bevor man die Änderungen übernimmt.

    FeatShare hat sehr viele Möglichkeiten zur Anpassung und ist sehr flexibel. Die Einstellungen werden über JSON-Dateien vorgenommen mit denen man mir alles erdenkliche anpassen kann. Das Programm ist sehr generell - also nicht Gothic-spezifisch. Deshalb ist die Dokumentation auf Englisch. Ich weiss nicht genau, ob es im Gothic Modden nützlich sein wird, da es verhältnismässig komplex ist. Es ist eher eine Verlagerung als die Abnahme von Arbeit; um das Einzupflegen kümmert sich der Ersteller anstatt der Empfänger.
    Für die Modderdatenbank finde ich es sehr gut, siehe das Zauberpaket.
    Für Skriptpakete wie LeGo, die gelegentlich Updates hervorbringen ist es besonders geeignet, da man auch Einfüge-Konditionen ("Ist das Feature schon drin/auf dem neusten Stand?") einbauen kann. Wer interessiert ist, kann sich hier beispielhaft anhand von LeGo anschauen, wie so etwas aussieht: [Source] [Setup].



    Download / GitHub

  2. Beiträge anzeigen #2 Zitieren
    Schwertmeister Avatar von Ska-Ara
    Registriert seit
    Nov 2010
    Ort
    Bayern
    Beiträge
    801
     
    Ska-Ara ist offline
    könnte man das programm nicht einfacher gestallten indem man einfach eine .d auswählt.. zb
    die meleewaepon.d die dann alle instanzen auflistet welche man ähnlich dem installer an oder abwählen kann.
    hat man seine wahl getroffen wird dann automatisch alle passenden daten dazu aus der installation gesaugt?

    quasi ähnlich deinem installer

  3. Beiträge anzeigen #3 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Ska-Ara Beitrag anzeigen
    könnte man das programm nicht einfacher gestallten indem man einfach eine .d auswählt.. zb
    die meleewaepon.d die dann alle instanzen auflistet welche man ähnlich dem installer an oder abwählen kann.
    hat man seine wahl getroffen wird dann automatisch alle passenden daten dazu aus der installation gesaugt?

    quasi ähnlich deinem installer
    Das würde sicherlich das Erstellen eines solchen Setups vereinfachen, allerdings sind da viele Probleme mit verbunden.
    Das "automatisch aus der Installation saugen" wird zum Problem, sobald es sich nicht um ein normales Feature handelt. Man könnte tatsächlich für alle standardmässigen Erweiterungen eine Automatisierung einbauen. Beispielsweise so.

    Neue Waffe: Hole Itemscript, 3ds-Datei, Einträge aus der Text.d, ...
    Neue Animation: Hole ASC-Datei, Einträge aus der Humans.mds, ...
    Neuer Zauber: Hole Itemscript, Spell script, Einträge aus der Text.d, Einträge aus der Constants.d, ...

    Was ist aber nun, wenn mein Zauber auch eine neue Animation beinhaltet, oder Einträge in der AI_Constants.d vornimmt oder komplexere Mechaniken implementiert, die in weiteren Dateien liegen. Das kann so ein SetupErsteller unmöglich wissen und das komplette Tool wird nutzlos bei komplexeren Features, für genau die FeatShare entwickelt wurde.

    Ein weiteres Problem, dass ich damit sehe, ist, dass man so möglicherweise die passenden Daten aus der Installation holen könnte, allerdings bleibt immer noch völlig offen wie das Setup diese dann Integrieren soll. Einen solchen regulären Ausdruck zu automatisieren ist schier unmöglich - das muss manuell geschehen.
    Nur ein Mensch mit Verständnis von Deadalus weiss, dass
    Code:
    const int KONSTANTE = 0;
    Code:
    const      INT Konstante  /* gut gesetztes Kommentar */   =   2 ; // Noch eins
    Code:
       CONST int   KoNSTanTE =  60      ;
    funktional die selben Zeilen sind. Es gibt im Grunde unendlich viele Möglichkeiten diese Zeile zu schreiben und ein herkömmliches Programm kann dafür keinen passenden regulären Ausdruck finden.


    FeatShare ist unglaublich mächtig und flexibel, bezahlt dafür aber mit dem Preis ziemlich komplex zu sein.

    Eine gute Arbeitsweise neue Features in Gothic zu implementieren, ist möglichst immer eigene Dateien zu erstellen und vermeiden bestehende zu erweitern. In LeGo ist das ziemlich gut gelungen: Zum Installieren von LeGo braucht man nur einen einzigen Eintrag in der Gothic.src vor zu nehmen. Der Rest des Codes ist in eigenen Dateien, die man einfach nur kopieren braucht. Daher eignet sich LeGo extrem gut für FeatShare. Alles was FeatShare tut (siehe die Datei LeGo_2_3_6Install.feat in [Source]), ist alle Dateien zu kopieren und den Eintrag in der Gothic.src vorzunehmen (zusätzlich wird es auch noch in der Startup.d initialisiert).
    Wer so arbeitet, hat mit FeatShare nicht mehr so viel Arbeit. FeatShare lohnt sich daher vielleicht kaum für LeGo.
    Wenn man sich aber das Zauberpaket anschaut, sieht man, dass einige Sachen nicht ausgelagert werden können (siehe Constants.d, Text.d, Spell_ProcessMana.d, ...). Dort ist FeatShare eine gute Sache.

    Am besten schreibe ich noch einmal einen Post, wie man im Gothic Modding FeatShare benutzen kann. Das Tool hier einfach reinzuklatschen und zu sagen "Lest doch die Dokumentation" ist nicht gerade sehr ansprechend. So etwas folgt in Kürze.

    Auch könnte ich vielleicht gerade solche Fälle von standardmässigen Erweiterungen, wie ich sie oben genannt habe, einige Templates (bei FeatShare sind das Anchors) erstellen, die man dann leicht verwenden kann, wenn man z.B. einen neuen Zauber in die Modderdatenbank stellen will.
    Geändert von mud-freak (23.10.2016 um 13:34 Uhr)

  4. Beiträge anzeigen #4 Zitieren
    Dea
    Registriert seit
    Jul 2007
    Beiträge
    10.447
     
    Lehona ist offline
    Das Tool klingt gut, aber du hast es ja selber gesagt: LeGo ist so einfach zu installieren, da braucht es wirklich kein Programm für
    Die einzige Anwendungsmöglichkeit die ich sehe, ist um zu verhindern, dass bereits vorhandene Änderungen in den LeGo-Dateien verloren gehen.
    Allerdings sollten sowieso nur wenige Dateien in LeGo überhaupt vom Nutzer geändert werden (eigentlich nur die Userconst.d und die Focusnames.d, wobei ich letzteres schon länger mal auslagern wollte), insofern ist der Nutzen im Vergleich zum Aufwand auch hier fraglich. Außerdem würde man im Endeffekt auch nur ein VersionControlSystem neu implementieren, das erscheint mir irgendwie unnötig.

    RegEx ist übrigens nicht ausreichend, um Daedalus zu parsen, insofern sollte man dieses Tool mit Bedacht einsetzen (ach was).

  5. Beiträge anzeigen #5 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    So, eine Mini-Einführung:

    Zauber sind ein gutes Beispiel, weil dafür viele kleine Änderungen in verschiedenen Dateien vorgenommen werden müssen. Wir haben also einen Zauber "Manasucht". Der ist also ein Feature, dass wir gern in der Modderdatenbank bereitstellen wollen.
    Für so ein Feature erstellen wir eine Feature-Datei. Wie die aussieht ist in der Konfiguration von FeatShare komplett anpassbar, aber wir nehmen jetzt einmal die Defaulteinstellungen. Eine solche Feature-Datei besteht ausschliesslich aus Schlüsselwort-Wert Paaren. Es gibt drei Schlüsselworte, die immer verfügbar sind.
    1. Das einfachste Schlüsselwort ist infoText. Der dazugehörige Wert bestimmt, was im Setup als Beschreibung steht. Das entspricht diesem Screenshot aus dem Einleitungspost.
    2. Dann gibt es noch copyFiles. Damit kann man auflisten, welche Dateien beim Installieren in die Gothic Installation kopiert werden.
    3. Und deleteFiles listet alle Dateien auf, die aus der Gothic Installation gelöscht werden sollen. Das ist nicht häufig notwendig, es sei dann man möchte bereits kompilierte Animationen/Texturen o.ä. löschen.

    Nehmen wir unser Beispiel mit dem Manasucht-Zauber, sieht der Anfang der Feature-Datei so aus:
    Code:
    ### infoText ###
    Manasucht. Der Spieler tauscht sein Leben gegen Mana.
    Dabei kann der Spieler durch gedrückthalten des Zaubers bestimmen wie viel er tauscht.
    ### END ###
    Die Syntax hier ist ziemlich einfach. Ein Schlüsselwort wird durch einschliessende # gekennzeichnet, der dazu gehörige Wert folgt anschliessend bis zum nächsten Schlüsselwort. Schlüsselwörter, die nicht definiert sind werden ignoriert, wie hier END. Das dient dazu um den Wert einzufassen, sonst ist das Schlüsselwort-Wert Paar unvollständig und wird ignoriert. Zu beachten ist hier, dass die Syntax in der Konfiguration von FeatShare geändert werden kann. Das ist wichtig, denn es kann ja sein dass "###" in meinem Code drin vorkommt.

    Neben den erwähnten drei Schlüsselwörtern kann man nun in sogenannten Anchors weitere definieren. Ein Anchor enthält alle Informationen wie man einen bestimmten Wert aus einem Feature einpflegen soll (welche Datei, welche Position in der Datei, usw.). Für Zauber könnte man z.B. ein Schlüsselwort "spltext" definieren, dessen Wert von einem Anchor dann in die Text.d eingepflegt werden soll und den Namen/Item-Beschreibung des Zaubers enthält.
    Ein Anchor kann von mehreren Features verwendet werden. D.h. wenn ich jetzt einen weiteren Zauber hinzufügen wollte, brauche ich nicht alle Anchors zweimal.

    Alle Schlüsselwörter die ich für einen Zauber definiert habe, habe ich hier aufgelistet:
    spl: Die SpellID in Constants.d, z.B. "Sleep" für SPL_Sleep.
    splinst: Die Spell Instanz in Constants.d (spellFxInstanceNames), z.B. "Sleep" für Spell_Sleep.
    splani: Die Animationskürzel in Constants.d (spellFxAniLetters), z.B. "SLE".
    spltext: Die Zauberbeschreibung in Text.d (TXT_SPELLS), z.B. "Schlaf".
    valueItRu: Runenkaufwert in It_Runen.d (Value_Ru_Light), z.B. "500".
    scriptItRu: Die Runen-Instanz in It_Scrolls.d, z.B. "INSTANCE ItRu_Light (C_Item) { ... }".
    valueItSc: Schriftrollenkaufwert in ItRu.d (Value_Sc_Light), z.B. "10".
    scriptItSc: Die Schriftrollen-Instanz in It_Scrolls.d, z.B. "instance ItSc_Light (C_Item) { ... }".
    scriptPFX: Die PFX-Instanz in PfxInstMagic.d, z.B. "INSTANCE MFX_LIGHT_INIT (C_PARTICLEFX) { ... }".
    scriptVisFx: Die VFX-Instanz in VisualFxInst.d, z.B. "INSTANCE spellFX_Light(CFx_Base_Proto) { ... }".
    scriptSFX: Die SFX-Instanz (falls der Zauber keinen Sound hat, kann man das Schlüsselwort weglassen) in SfxInst.d
    processManaRelease: Wenn dieses Schlüsselwort existiert (Wert egal), wird ein Eintrag in die Spell_Processmana_Release.d vorgenommen.
    humansmds: Die entsprechenden Zeilen in Humans.mds, falls der Zauber neue Animationen hat.
    Diese Informationen muss ich mir jetzt zusammensuchen und kann sie dann in eine Feature-Datei mit den Schlüsselwörtern eintragen. In etwa so (ganz am Ende wir auch eine List von zu kopierenden Dateien anglegt):
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    ### infoText ###
    Manasucht. Der Spieler tauscht sein Leben gegen Mana. Dabei kann der Spieler durch gedrückthalten des Zaubers bestimmen wie viel er tauscht. Ikarus wird nicht benötigt.
    ### spl ###
    ManaForLife
    ### splinst ###
    ManaForLife
    ### splani ###
    SAC
    ### spltext ###
    Manasucht
    ### valueItRu ###
    1500
    ### scriptItRu ###
    /*******************************************************************************************/
    INSTANCE ItRu_ManaForLife (C_Item)
    {
        name                =   NAME_Rune;
    
        mainflag            =   ITEM_KAT_RUNE;
        flags               =   0;
    
        value               =   Value_Ru_ManaForLife;
    
        visual              =   "ItRu_ManaForLife.3DS";
        material            =   MAT_STONE;
    
        spell               =   SPL_ManaForLife;
        mag_circle          =   3;
    
        wear                =   WEAR_EFFECT;
        effect              =   "SPELLFX_WEAKGLIMMER_RED";
    
        description         =   NAME_SPL_ManaForLife;
        TEXT    [0]         =   NAME_Mag_Circle;
        COUNT   [0]         =   mag_circle;
    
        TEXT    [1]         =   NAME_Spell_Invest;
    
        TEXT    [2]         =   ConcatStrings(PRINT_Beliarshitpoints_MAX, "1");
    
        TEXT    [3]         =   ConcatStrings(PRINT_LearnMANA_MAX,
                                    IntToString(SPL_ManaForLife_RELATION));
    
        TEXT    [5]         =   NAME_Value;
        COUNT   [5]         =   value;
    };
    /*******************************************************************************************/
    ### valueItSc ###
    200
    ### scriptItSc ###
    /*******************************************************************************************/
    INSTANCE ItSc_ManaForLife (C_Item)
    {
        name                =   NAME_Spruchrolle;
    
        mainflag            =   ITEM_KAT_RUNE;
        flags               =   ITEM_MULTI;
    
        value               =   Value_Sc_ManaForLife;
    
        visual              =   "ItSc_ManaForLife.3DS";
        material            =   MAT_LEATHER;
    
        spell               =   SPL_ManaForLife;
    
        wear                =   WEAR_EFFECT;
        effect              =   "SPELLFX_WEAKGLIMMER_RED";
    
        description         =   NAME_SPL_ManaForLife;
    
        TEXT    [0]         =   Name_MageScroll;
    
        TEXT    [1]         =   NAME_Spell_Invest;
    
        TEXT    [2]         =   ConcatStrings(PRINT_Beliarshitpoints_MAX, "1");
    
        TEXT    [3]         =   ConcatStrings(PRINT_LearnMANA_MAX,
                                    IntToString(SPL_ManaForLife_RELATION));
    
        TEXT    [5]         =   NAME_Value;
        COUNT   [5]         =   value;
    };
    /*******************************************************************************************/
    ### scriptPFX ###
    ///                     XXXXXXXXXXXXXXXXXXXXXXXXXXXXX                      ///
    ///                     XX  M A N A F O R L I F E  XX                      ///
    ///                     XXXXXXXXXXXXXXXXXXXXXXXXXXXXX                      ///
    ///                                mud-freak                               ///
    
    /* MFX_MANAFORLIFE_16BIT_TRIPOLY.TGA ist die gleiche Textur wie
     * MFX_MASTEROFDISASTER_AURA_16BIT.TGA, allerdings als Tri-Poly. Damit spar
     * ich mir die Option vistexisquadpoly, die doppelt so rechenaufwendig ist. */
    INSTANCE MFX_ManaForLife_INIT (C_PARTICLEFX)
    {
         ppsvalue = 75.000000000;
         ppsscalekeys_s = "1";
         shptype_s = "POINT";
         shpfor_s = "object";
         shpoffsetvec_s = "15 0 0";
         dirmode_s = "NONE";
         dirfor_s = "object";
         dirmodetargetfor_s = "OBJECT";
         velavg = 0;
         lsppartavg = 150.000000000;
         flygravity_s = "0 0 0";
         flycolldet_b = 0;
         visname_s = "MFX_MANAFORLIFE_16BIT_TRIPOLY.TGA";
         vistexisquadpoly = 0;
         visorientation_s = "NONE";
         vistexcolorstart_s = "100 100 255";
         vistexcolorend_s = "0 0 250";
         vissizestart_s = "10 10";
         vissizeendscale = 1;
         visalphafunc_s = "ADD";
         visalphastart = 255.000000000;
         visalphaend = 255.000000000;
         trlFadeSpeed = 1;
         trltexture_s = "HEAVENLIGHT.TGA";
         trlwidth = 1;
         useemittersfor = 1;
    };
    INSTANCE MFX_ManaForLife_INIT2 (C_PARTICLEFX)
    {
         ppsvalue = 75.000000000;
         ppsscalekeys_s = "1";
         shptype_s = "POINT";
         shpfor_s = "object";
         shpoffsetvec_s = "0 15 0";
         dirmode_s = "NONE";
         dirfor_s = "object";
         dirmodetargetfor_s = "OBJECT";
         velavg = 0;
         lsppartavg = 150.000000000;
         flygravity_s = "0 0 0";
         flycolldet_b = 0;
         visname_s = "MFX_MANAFORLIFE_16BIT_TRIPOLY.TGA";
         vistexisquadpoly = 0;
         visorientation_s = "NONE";
         vistexcolorstart_s = "255 100 100";
         vistexcolorend_s = "250 0 0";
         vissizestart_s = "10 10";
         vissizeendscale = 1;
         visalphafunc_s = "ADD";
         visalphastart = 255.000000000;
         visalphaend = 255.000000000;
         trlFadeSpeed = 1;
         trltexture_s = "HELLLIGHT.TGA";
         trlwidth = 1;
         useemittersfor = 1;
    };
    
    // Wir bedienen uns dem Inflatezauber und passen den Spritz-Effekt an
    INSTANCE MFX_ManaForLife_SPATTER_0 (MFX_INFLATE_FOUNTAIN)
    {
        ppsscalekeys_s = "2";           // Wir loopen den Effekt, weil er unter-
        ppsIsLooping = 1;               //  schiedlich lang sein kann.
        diranglehead = 0;               // Spritzwinkel
        velavg = 0.200000024;           // Spritzstärke
        vistexcolorstart_s = "98 0 0";  // In Blutrot
        vistexcolorend_s = "191 28 28";
    };
    INSTANCE MFX_ManaForLife_SPATTER_90 (MFX_INFLATE_FOUNTAIN)
    {
        ppsscalekeys_s = "2";
        ppsIsLooping = 1;
        diranglehead = 170;
        dirAngleElev = 30;
        velavg = 0.200000024;
        vistexcolorstart_s = "98 0 0";
        vistexcolorend_s = "191 28 28";
    };
    INSTANCE MFX_ManaForLife_SPATTER_180 (MFX_INFLATE_FOUNTAIN)
    {
        ppsscalekeys_s = "2";
        ppsIsLooping = 1;
        diranglehead = 160;
        dirAngleElev = -20;
        velavg = 0.200000024;
        vistexcolorstart_s = "98 0 0";
        vistexcolorend_s = "191 28 28";
    };
    
    INSTANCE MFX_ManaForLife_RING_LARGE1 (C_PARTICLEFX)
    {
        ppsvalue = 250.000000000;
        ppsscalekeys_s = "1";
        shptype_s = "LINE";
        shpfor_s = "OBJECT";
        shpoffsetvec_s = "70 -30 0";
        shpDistribType_S = "WALK";
        shpDistribWalkSpeed = 0.0008;
        shpDim_S = "100";
        dirmode_s = "NONE";
        velavg = 0;
        lsppartavg = 600.000000000;
        flygravity_s = "0 0 0";
        flycolldet_b = 0;
        visname_s = "MFX_MANAFORLIFE_16BIT_TRIPOLY.TGA";
        vistexisquadpoly = 0;
        visorientation_s = "NONE";
        vistexcolorstart_s = "100 100 255"; // "0 0 255"; // Lichterkettenartefakt
        vistexcolorend_s = "0 0 255";
        vissizestart_s = "25 25";
        vissizeendscale = 2;
        visalphafunc_s = "ADD";
        visalphastart = 255.000000000;
        visalphaend = 255.000000000;
    };
    
    INSTANCE MFX_ManaForLife_RING_LARGE2 (C_PARTICLEFX)
    {
        ppsvalue = 250.000000000;
        ppsscalekeys_s = "1";
        shptype_s = "LINE";
        shpfor_s = "OBJECT";
        shpoffsetvec_s = "-70 -30 0";
        shpDistribType_S = "WALK";
        shpDistribWalkSpeed = 0.0008;
        shpDim_S = "100";
        dirmode_s = "NONE";
        velavg = 0;
        lsppartavg = 600.000000000;
        flygravity_s = "0 0 0";
        flycolldet_b = 0;
        visname_s = "MFX_MANAFORLIFE_16BIT_TRIPOLY.TGA";
        vistexisquadpoly = 0;
        visorientation_s = "NONE";
        vistexcolorstart_s = "255 100 100"; // "255 0 0"; // Lichterkettenartefakt
        vistexcolorend_s = "255 0 0";
        vissizestart_s = "25 25";
        vissizeendscale = 2;
        visalphafunc_s = "ADD";
        visalphastart = 255.000000000;
        visalphaend = 255.000000000;
    
    };
    
    /* Kopie von MFX_Fear_ORIGIN aber mit mehr Partikeln (ppsvalue), wichtig!
     * Mit zu wenig pps weigert sich Gothic unter Umständen den FX zu rendern.  */
    INSTANCE MFX_ManaForLife_ORIGIN (C_PARTICLEFX)
    {
         ppsvalue = 75;
         ppsscalekeys_s = "1 1 1 1 1 1 1 1";
         ppsissmooth = 1;
         ppsfps = 2;
         shptype_s = "CIRCLE";
         shpfor_s = "object";
         shpoffsetvec_s = "0 -120 0";
         shpdistribtype_s = "RAND";
         shpdim_s = "20";
         shpscalekeys_s = "1";
         dirmode_s = "DIR";
         dirfor_s = "world";
         dirmodetargetfor_s = "OBJECT";
         dirangleheadvar = 180;
         dirangleelev = 90;
         velavg = 0.00999999978;
         lsppartavg = 1000;
         lsppartvar = 150;
         flygravity_s = "0 0 0";
         visname_s = "HEAVENLIGHT.TGA";
         visorientation_s = "VELO";
         vistexisquadpoly = 1;
         vistexcolorstart_s = "255 0 0";
         vistexcolorend_s = "255 0 50";
         vissizestart_s = "3 18";
         vissizeendscale = 20;
         visalphafunc_s = "ADD";
         visalphastart = 255;
    };
    ### scriptSFX ###
    // ManaForLife
    INSTANCE MFX_MANAFORLIFE_HEARTBEAT      (C_SFX_DEF) {file= "MFX_HEARTBEAT.WAV";             vol = 127;       loop=1;       };
    ### scriptVisFx ###
    ///                     XXXXXXXXXXXXXXXXXXXXXXXXXXXXX                      ///
    ///                     XX  M A N A F O R L I F E  XX                      ///
    ///                     XXXXXXXXXXXXXXXXXXXXXXXXXXXXX                      ///
    ///                               mud-freak                                ///
    
    // Blaues "Elekron" auf der Hand
    INSTANCE spellFX_ManaForLife (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_INIT";
        emtrjoriginnode         = "ZS_RIGHTHAND";
        emtrjmode_s             = "FIXED";
        emtrjloopmode_s         = "NONE";
        emtrjeasefunc_s         = "LINEAR";
        emSelfRotVel_S          = "0 500 -250";
        emtrjdynupdatedelay     = 0.;
        emFXCreate_S            = "spellFX_ManaForLife_2OBJ";
        emFXInvestOrigin_S      = "spellFX_ManaForLife_INVEST"; // SPL_NEXTLEVEL
        };
        INSTANCE spellFX_ManaForLife_KEY_CAST (C_ParticleFXEmitKey)
        {
            visname_S           = "MFX_ManaForLife_ORIGIN";
            sfxid               = "SFX_HealObsession";
            sfxIsAmbient        = 1;
    };
    // Rotes "Elekron" auf der Hand
    INSTANCE spellFX_ManaForLife_2OBJ (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_INIT2";
        emtrjoriginnode         = "ZS_RIGHTHAND";
        emtrjmode_s             = "FIXED";
        emtrjloopmode_s         = "NONE";
        emtrjeasefunc_s         = "LINEAR";
        emSelfRotVel_S          = "500 0 250";
        emtrjdynupdatedelay     = 0.;
        };
        INSTANCE spellFX_ManaForLife_2OBJ_KEY_INIT (C_ParticleFXEmitKey)
        {
            pfx_ppsisloopingChg  = 1; // Beenden sonst bleibt es nach Zauber
        };
        INSTANCE spellFX_ManaForLife_2OBJ_KEY_CAST (C_ParticleFXEmitKey)
        {
            pfx_ppsisloopingChg  = 1; // Beenden sonst bleibt es nach Zauber
    };
    // Investphase
    INSTANCE spellFX_ManaForLife_INVEST (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_SPATTER_0";
        emTrjOriginNode         = "BIP01 Spine2";
        emFXCreatedOwnTrj       = 1;
        sfxid                   = "MFX_MANAFORLIFE_HEARTBEAT";
        sfxIsAmbient            = 1;
        lightPresetname         = "AURA";
        emFXCreate_S            = "spellFX_ManaForLife_SPATTER_90";
        emFXLifeSpan            = 30; // Kindersicherung: Falls es hängen bleibt.
    };
    INSTANCE spellFX_ManaForLife_SPATTER_90 (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_SPATTER_90";
        emTrjOriginNode         = "BIP01 Spine2";
        emFXCreatedOwnTrj       = 1;
        emFXCreate_S            = "spellFX_ManaForLife_SPATTER_180";
    };
    INSTANCE spellFX_ManaForLife_SPATTER_180 (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_SPATTER_180";
        emTrjOriginNode         = "BIP01 Pelvis";
        emFXCreatedOwnTrj       = 1;
        emFXCreate_S            = "spellFX_ManaForLife_SPIRAL";
    };
    // Spirale in HP-Rot und Mana-Blau um den Caster
    INSTANCE spellFX_ManaForLife_SPIRAL (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_RING_LARGE1";
        emTrjOriginNode         = "Bip01";
        emtrjmode_s             = "FIXED";
        emSelfRotVel_S          = "0 400 0";
        emtrjdynupdatedelay     = 0;
        emFXCreatedOwnTrj       = 1;
        emFXCreate_S            = "spellFX_ManaForLife_SPIRAL2";
    };
    INSTANCE spellFX_ManaForLife_SPIRAL2 (CFx_Base_Proto)
    {
        visname_S               = "MFX_ManaForLife_RING_LARGE2";
        emTrjOriginNode         = "Bip01";
        emtrjmode_s             = "FIXED";
        emSelfRotVel_S          = "0 400 0";
        emtrjdynupdatedelay     = 0;
        emFXCreatedOwnTrj       = 0;
        emFXCreate_S            = "DEMENTOR_FX";
    };
    ### processManaRelease ###
    TRUE
    ### humansmds ###
    // Sacrifice (Modifiziert von Hum_SuckEnergy_Victim_K01.asc)
    ani         ("t_MagRun_2_SacCast"   1   "s_SacCast"     0.2 0.0 M.  "HUM_MAGSAC_1_225.ASC"  F   1   18)
    ani         ("s_SacCast"            1   "s_SacCast"     1.0 1.0 M.  "HUM_MAGSAC_1_225.ASC"  F   19  120    FPS:25)
    ani         ("t_SacCast_2_Stand"    1   ""              0.5 0.2 M.  "HUM_MAGSAC_1_225.ASC"  R   1   18     FPS:25)
    
    ani         ("t_SacCast_2_SacShoot" 1   "s_SacShoot"    0.2 0.0 M.  "HUM_MAGSAC_1_225.ASC"  F   121 156    FPS:35)
    {
                   *eventSFX   (151 "M_FALL_SMALL"  EMPTY_SLOT  )
    }
    ani         ("s_SacShoot"           1   "s_SacShoot"    0.0 0.0 M.  "HUM_MAGSAC_1_225.ASC"  F   157 157    FPS:25)
    ani         ("t_SacShoot_2_Stand"   1   ""              0.0 0.1 M.  "HUM_MAGSAC_1_225.ASC"  F   158 225    FPS:16)
    ### copyFiles ###
    SPL_ManaForLife\Spell_ManaForLife.d|_work\data\Scripts\Content\AI\Magic\Spells\
    SPL_ManaForLife\TexturesItems\ItArRune_ZP.tga|_work\data\Textures\Items\
    SPL_ManaForLife\TexturesItems\ItAr_Scroll_ZP.tga|_work\data\Textures\Items\
    SPL_ManaForLife\MeshesItems\ItRu_ManaForLife.3ds|_work\data\Meshes\Items\IT_Runen\
    SPL_ManaForLife\MeshesItems\ItSc_ManaForLife.3ds|_work\data\Meshes\Items\IT_Scrolls\
    SPL_ManaForLife\Anims\HUM_MAGSAC_1_225.ASC|_work\data\Anims\
    SPL_ManaForLife\SoundSFX\MFX_HEARTBEAT.WAV|_work\data\Sound\SFX\
    SPL_ManaForLife\TexturesEffectsMagic\HellLight.tga|_work\data\Textures\Effects\Magic\
    SPL_ManaForLife\TexturesEffectsMagic\MFX_ManaForLife_16bit_tripoly.tga|_work\data\Textures\Effects\Magic\
    ### END ###


    Und hier sind die Anchor, die die Schlüsselwörter definieren und referenzieren (wie diese definiert sind, ist etwas umfangreicher und darauf werde ich hier nicht weiter eingehen. Dazu ist die Dokumentation hilfreich).
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    [
        {
            "description": "Add SPL_ to Constants.d and increase MAX_SPELL",
            "path": "_work\\data\\Scripts\\Content\\_intern\\Constants.d",
            "regex": {
                "needle": "const.+int.+MAX_SPELL.*=[^\\d]*(\\d+).*$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": true,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {
                "max_spell": "$1"
            },
            "hook": {
                "start": "$0",
                "length": "$0",
                "before": true,
                "replace": {
                    "$1": "{idx}"
                }
            },
            "insert": {
                "string": "const int SPL_{spl}{ :spl:22}= {idx};\n",
                "replace": {
                    "spl": "spl"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 0,
            "newlinesAfter": 1,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [
                {
                    "needle": "idx",
                    "replace": "max_spell",
                    "incr": 1
                }
            ],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend spellFxInstanceNames array in Constants.d",
            "path": "_work\\data\\Scripts\\Content\\_intern\\Constants.d",
            "regex": {
                "needle": "const.+string.+spellFxInstanceNames.*\\[.*MAX_SPELL.*\\][^\\{]*\\{[^\\}]*\"[^\\}\"]*\"((.)[^\\}\"]*)}",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1",
                "length": "$1",
                "before": false,
                "replace": {
                    "$2": "{comma}"
                }
            },
            "insert": {
                "string": "\"{splinst}\"{comma}{ :splinst:21}// {idx}{ :idx:5}SPL_{spl}\n",
                "replace": {
                    "spl": "spl",
                    "splinst": "splinst"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [
                {
                    "needle": "idx",
                    "replace": "max_spell",
                    "incr": 1
                },
                {
                    "needle": "comma",
                    "replace": ",",
                    "last": " "
                }
            ],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [
                "max_spell"
            ],
            "dependencies": [
                "spl",
                "splinst"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend spellFxAniLetters array in Constants.d",
            "path": "_work\\data\\Scripts\\Content\\_intern\\Constants.d",
            "regex": {
                "needle": "const.+string.+spellFxAniLetters.*\\[.*MAX_SPELL.*\\][^\\{]*\\{[^\\}]*\"[^\\}\"]*\"((.)[^\\}\"]*)}",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1",
                "length": "$1",
                "before": false,
                "replace": {
                    "$2": "{comma}"
                }
            },
            "insert": {
                "string": "\"{splani}\"{comma}{ :splani:21}// {idx}{ :idx:5}SPL_{spl}\n",
                "replace": {
                    "spl": "spl",
                    "splani": "splani"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [
                {
                    "needle": "idx",
                    "replace": "max_spell",
                    "incr": 1
                },
                {
                    "needle": "comma",
                    "replace": ",",
                    "last": " "
                }
            ],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [
                "max_spell"
            ],
            "dependencies": [
                "spl",
                "splani"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend TXT_SPELLS array in Text.d",
            "path": "_work\\data\\Scripts\\Content\\Story\\Text.d",
            "regex": {
                "needle": "const.+string.+TXT_SPELLS.*\\[.*MAX_SPELL.*\\][^\\{]*\\{[^\\}]*\"[^\\}\"]*\"((.)[^\\}\"]*)}",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1",
                "length": "$1",
                "before": false,
                "replace": {
                    "$2": "{comma}"
                }
            },
            "insert": {
                "string": "\"{spltext}\"{comma}{ :spltext:26}// {idx}{ :idx:5}SPL_{spl}\n",
                "replace": {
                    "spl": "spl",
                    "spltext": "spltext"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [
                {
                    "needle": "idx",
                    "replace": "max_spell",
                    "incr": 1
                },
                {
                    "needle": "comma",
                    "replace": ",",
                    "last": " "
                }
            ],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [
                "max_spell"
            ],
            "dependencies": [
                "spl",
                "spltext"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add NAME_SPL_ to Text.d",
            "path": "_work\\data\\Scripts\\Content\\Story\\Text.d",
            "regex": {
                "needle": "const.+string.+NAME_SPL_.+($)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": true,
                    "ungreedy": false,
                    "occurrence": -1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1+2",
                "length": 1,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "const string NAME_SPL_{spl}{ :spl:22}= \"{spltext}\";\n",
                "replace": {
                    "spl": "spl",
                    "spltext": "spltext"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl",
                "spltext"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend Spell_ProcessMana.d",
            "path": "_work\\data\\Scripts\\Content\\AI\\Magic\\Spell_ProcessMana.d",
            "regex": {
                "needle": "func.+INT.+Spell_ProcessMana.*\\(.*VAR.+INT.+manaInvested.*\\)[^{]*({)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {
                "EOprocessmana": "$1"
            },
            "storeVars": {},
            "hook": {
                "start": "$EOprocessmana",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "if (activeSpell == SPL_{spl}{ :spl:21})   {   return  Spell_Logic_{splinst}{ :splinst:16}(manaInvested); };\n",
                "replace": {
                    "spl": "spl",
                    "splinst": "splinst"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl",
                "splinst"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend Spell_ProcessMana_Release.d",
            "path": "_work\\data\\Scripts\\Content\\AI\\Magic\\Spell_ProcessMana_Release.d",
            "regex": {
                "needle": "\\n(.)[^;]*return.+SPL_SENDSTOP",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": -1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "if (activeSpell == SPL_{spl}{ :spl:17})   {   return  SPL_SENDCAST;   };\n",
                "replace": {
                    "spl": "spl"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 1,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl",
                "processManaRelease"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add item value to It_Scrolls.d",
            "path": "_work\\data\\Scripts\\Content\\Items\\It_Scrolls.d",
            "regex": {
                "needle": "const.+int.+Value_Sc_.*($)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": true,
                    "ungreedy": false,
                    "occurrence": -1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1+2",
                "length": 1,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "const int Value_Sc_{spl}{ :spl:21}=   {value};\n",
                "replace": {
                    "spl": "spl",
                    "value": "valueItSc"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl",
                "valueItSc"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add item script to It_Scrolls.d",
            "path": "_work\\data\\Scripts\\Content\\Items\\It_Scrolls.d",
            "regex": {
                "needle": "$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$0",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{script}\n\n",
                "replace": {
                    "script": "scriptItSc"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 5,
            "newlinesAfter": 2,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "scriptItSc"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add item value to It_Runes.d",
            "path": "_work\\data\\Scripts\\Content\\Items\\It_Runen.d",
            "regex": {
                "needle": "const.+int.+Value_Ru_.*($)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": true,
                    "ungreedy": false,
                    "occurrence": -1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$1+2",
                "length": 1,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "const int Value_Ru_{spl}{ :spl:21}=   {value};\n",
                "replace": {
                    "spl": "spl",
                    "value": "valueItRu"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 1,
            "newlinesAfter": 0,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "spl",
                "valueItRu"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add item script to It_Runes.d",
            "path": "_work\\data\\Scripts\\Content\\Items\\It_Runen.d",
            "regex": {
                "needle": "$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$0",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{script}\n\n",
                "replace": {
                    "script": "scriptItRu"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 5,
            "newlinesAfter": 2,
            "localHeader": "",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "scriptItRu"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add visualFx to VisualFxInst.d",
            "path": "_work\\data\\Scripts\\System\\VisualFX\\VisualFxInst.d",
            "regex": {
                "needle": "$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$0",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{script}\n\n\n\n\n",
                "replace": {
                    "script": "scriptVisFx"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 5,
            "newlinesAfter": 5,
            "localHeader": "{globalHeader}\n",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "scriptVisFx"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add particleFx to PfxInstMagic.d",
            "path": "_work\\data\\Scripts\\System\\PFX\\PfxInstMagic.d",
            "regex": {
                "needle": "$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$0",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{script}\n\n\n\n\n",
                "replace": {
                    "script": "scriptPFX"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 5,
            "newlinesAfter": 5,
            "localHeader": "{globalHeader}\n",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "scriptPFX"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add soundFx to SfxInst.d",
            "path": "_work\\data\\Scripts\\System\\SFX\\SfxInst.d",
            "regex": {
                "needle": "$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {},
            "storeVars": {},
            "hook": {
                "start": "$0",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{script}\n",
                "replace": {
                    "script": "scriptSFX"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:4}",
                    "exclFirstLine": false,
                    "exclHeader": true
                }
            },
            "newlinesBefore": 5,
            "newlinesAfter": 1,
            "localHeader": "{globalHeader}\n\n",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "scriptSFX"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add constants (AIV) to AI_Constants.d",
            "path": "_work\\data\\Scripts\\Content\\AI\\AI_Intern\\AI_Constants.d",
            "regex": {
                "needle": "const.+int.+AIV_.*=[^\\d]*(\\d+).*$",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": true,
                    "ungreedy": false,
                    "occurrence": -1
                }
            },
            "matchBracket": {},
            "storeVars": {
                "aiv": "$1"
            },
            "hook": {
                "start": "$0",
                "length": "$0",
                "before": false,
                "replace": {
                    "$1": "{idx}"
                }
            },
            "insert": {
                "string": "{aivars}\n",
                "replace": {
                    "aivars": "aivars"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "",
                    "exclFirstLine": false,
                    "exclHeader": false
                }
            },
            "newlinesBefore": 2,
            "newlinesAfter": 0,
            "localHeader": "{globalHeader}\n",
            "setHeader": true,
            "finalReplace": [
                {
                    "needle": "idx",
                    "replace": "aiv",
                    "incr": 1
                }
            ],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "aivars"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Extend B_AssessMagic.d",
            "path": "_work\\data\\Scripts\\Content\\AI\\Magic\\B_AssessMagic.d",
            "regex": {
                "needle": "func.+void.+B_AssessMagic.*\\(.*\\)[^{]*({)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {
                "BOb_assessmagic": "$1"
            },
            "storeVars": {},
            "hook": {
                "start": "$BOb_assessmagic",
                "length": 0,
                "before": false,
                "replace": {}
            },
            "insert": {
                "string": "{b_assessmagic}\n",
                "replace": {
                    "b_assessmagic": "b_assessmagic"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:1}",
                    "exclFirstLine": false,
                    "exclHeader": true
                }
            },
            "newlinesBefore": 0,
            "newlinesAfter": 1,
            "localHeader": "{globalHeader}\n",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "b_assessmagic"
            ],
            "ignoreOnFail": false
        },
    
        {
            "description": "Add lines at end of Humans.mds",
            "path": "_work\\data\\Anims\\Humans.mds",
            "regex": {
                "needle": "aniEnum[^{]*({)",
                "flags": {
                    "caseSensitive": false,
                    "dotInclNL": false,
                    "multiLine": false,
                    "ungreedy": false,
                    "occurrence": 1
                }
            },
            "matchBracket": {
                "EOHumansmds": "$1"
            },
            "storeVars": {},
            "hook": {
                "start": "$EOHumansmds",
                "length": "$EOHumansmds",
                "before": true,
                "replace": {
                    "$EOHumansmds": "{\t:2}}"
                }
            },
            "insert": {
                "string": "{lines}\n",
                "replace": {
                    "lines": "humansmds"
                },
                "stripTrailingNL": false,
                "indent": {
                    "string": "{\t:3}",
                    "exclFirstLine": false,
                    "exclHeader": true
                }
            },
            "newlinesBefore": 3,
            "newlinesAfter": 4,
            "localHeader": "{globalHeader}\n",
            "setHeader": true,
            "finalReplace": [],
            "deleteFiles": {
                "paths": [
                    "_work\\data\\Anims\\_compiled\\Humans.msb"
                ],
                "replace": {}
            },
            "globalDependencies": [],
            "dependencies": [
                "humansmds"
            ],
            "ignoreOnFail": false
        }
    ]


    Nun bedarf es nur noch einer Konfigurationsdatei. Hier mal eine Minimalversion (dort kann man aber optional noch vieles mehr einstellen):
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    {
        "title": "Manasucht Installation",
        "globalHeader": "// Die folgende(n) Zeile(n) wurden für Manasucht erstellt",
        "installInstruction": "Wähle den Ordner in dem sich Gothic 2 dNdR (modkit) befindet",
        "defaultPath": "C:\\Program Files (x86)\\JoWooD\\Gothic II\\",
        "diffGUI": true,
        "features": {
            "filePattern": ".*\\.feat"
        },
        "anchors": {
            "": "^anchors.*\\.json$"
        }
    }


    Jetzt haben wir drei Dateien (+ die zu kopierenden Dateien):
    • config.json (die Konfigurationsdatei)
    • anchors.json (die Datei mit allen Anchors)
    • Manasucht.feat (die Feature-Datei für unseren Zauber)

    Jetzt startet man BuildSetup.exe und fügt die drei Dateien (+ die zu kopierenden Dateien) per drag-and-drop hinzu und lässt sich sein Setup erstellen.

    Hier noch mal alles zusammen, um es besser zu inspizieren. Sowohl die Source-Dateien, also auch ein fertig-erstelltes Setup:
    manasucht_src.zip
    manasucht_setup.zip




    Die Fragwürdigkeiten und Bedenken, die Lehona anspricht sind richtig und die hätte ich im Einleitungspost erwähnen sollen:
    • Es kann nicht gewährleistet werden, dass ein FeatShare Setup in 100% der Fällen funktioniert, da ein RegEx vielleicht bei jemandem einfach nicht greift, da seine Gothic Installation einfach zu sehr abweicht. Im Beispiel vom Zauberpaket ist mir bisher jedoch nur ein Fall bekannt, bei dem ein RegEx nicht funktioniert hat. (Dort lag es daran, dass die Skripte aus dem GothicSource dekompiliert waren und Konstanten fehlten). Es hängt sehr davon ab, wo und wie man etwas einfügen möchte. Die Anchors oben für Zauber sollten im Normalfall immer greifen. Ein RegEx soll hier nicht missverstanden werden: Es soll Deadalus nicht parsen; der Ersteller eines FeatShare Setups sollte sich einfach Gedanken machen, einen festdefinierbaren Anhaltspunkt zu finden, der in Gothic Installationen wenig bis gar nicht abweicht, an dem er sich orientieren und den er als verlässlichen RegEx ausdrücken kann. Wenn jemand eine Konstante tatsächlich so blödsinnig definiert wie im dritten Post, der sollte sich nicht wundern, wenn ein solches Setup bei ihm nicht funktioniert.
    • Der Sinn von FeatShare ist nicht ein Verson-Control-System zu simulieren oder gar zu ersetzen. Ich fand es nur äussert umständlich die gesamte Gothic Installation in ein solches zu stecken. Leute, die nicht am gleichen Mod-Projekt arbeiten, können sowieso nichts untereinander mergen. FeatShare ist also einfach ein Einpflege-Tool.
    • Da ich beim Veröffentlichen vom Zauberpaket dieses Tool in seiner ersten (hardgecodeten) Version so nützlich fand, habe ich es generalisiert, um es zu hier zu teilen. Ob es tatsächlich überhaupt von anderen einsetzbar ist, konnte und kann ich nicht sagen. Teilen kann nicht schaden, habe ich mir gedacht. Im schlimmsten Fall, kann mindestens sicher jemand etwas mit dem Sourcecode auf Github etwas anfangen.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
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