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 3 of 6 « First 123456 Last »
Results 41 to 60 of 119
  1. View Forum Posts #41 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Das habe ich absichtlich rausgelassen, weil es extrem gefährlich ist. Vobs aller Art wechseln im Laufe des Spiels ständig den Vobtree. So wird z.B. der Held ein Kind eines Movers, wenn er damit verschoben wird. Möglicherweise wird er auch das Kind eines Mobs, das er gerade benutzt. Dabei würden mindestens Vobs auf unerklärliche Weise verschwinden, wenn nicht sogar das Spiel abstürzen wenn Referenzzähler nicht aufgehen oder plötzlich der Held gelöscht wird.

    Wenn man im Spiel ein Vob mit allen Kindern löschen möchte, weiss man meistens auch welche Vobs das beinhalten sollte und kennt sie idealerweise mit Namen. Wenn nicht, kann man über dessen Vobtree iterieren (zCVob.globalVobTreeNode ist ein zCTree und in Ikarus dokumentiert) und nur die Vobs löschen, die in Frage kommen und als letztes das Vob selbst (alle anderen Kinder werden beim Löschen automatisch in den nächst höheren oder den globalen Vobtree verschoben).

    Natürlich steht es dir aber frei die Funktion (RemoveoCVobSafe) auf eigene Gefahr trotzdem zu benutzen. Sie sollte nach wie vor funktionieren.

  2. View Forum Posts #42 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Ich habe mal wieder ein paar Skripte angesammelt und möchte sie hier teilen. Ob sie tatsächlich was für ScriptBin taugen, kann Lehona sich dann überlegen. Weil das nicht alles passt, schreibe mehrere Posts um es übersichtlich zu halten und für die Möglichkeit einzelne Skripts besser zu verlinken.
    Und weil die Scripte sich teilweise gegenseitig voraussetzen (alle vermerkt) fange ich mit den simpelsten an.


    strings.d – Miscellaneous string functions
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * strings.d
     *
     * Miscellaneous string functions
     *
     * - Requires Ikarus
     * - Compatible with Gothic 1 and Gothic 2
     *
     *
     *  func string STR_Lower(string str)
     *
     *  func string STR_ReplaceOnce(string haystack, string needle, string replace)
     *  func string STR_ReplaceAll (string haystack, string needle, string replace)
     *
     *  func string STR_Postfix(string str, int off)
     *  func string STR_Trim(string str, string tok)
     *  func string STR_TrimChar(string str, int chr)
     *
     *  func int    STR_ToFloat(string str)
     *
     *  func int    STR_IndexOfFirstNonNumeric(string str)
     */
    
    
    /*
     * Complement to STR_Upper in Ikarus
     */
    func string STR_Lower(var string str) {
        const int zSTRING__Lower_G1 = 4608640; //0x465280
        const int zSTRING__Lower_G2 = 4631024; //0x46A9F0
    
        var int ptr; ptr = _@s(str);
    
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_PutRetValTo(0);
            CALL__thiscall(_@(ptr), MEMINT_SwitchG1G2(zSTRING__Lower_G1, zSTRING__Lower_G2));
    
            call = CALL_End();
        };
    
        return str;
    };
    
    
    /*
     * Replace first occurrence of needle in haystack and replace it
     */
    func string STR_ReplaceOnce(var string haystack, var string needle, var string replace) {
        var zString zSh; zSh = _^(_@s(haystack));
        var zString zSn; zSn = _^(_@s(needle));
        if (!zSh.len) || (!zSn.len) {
            return haystack;
        };
    
        var int startPos; startPos = STR_IndexOf(haystack, needle);
        if (startPos == -1) {
            return haystack;
        };
    
        var string destStr; destStr = "";
    
        destStr = STR_Prefix(haystack, startPos);
        destStr = ConcatStrings(destStr, replace);
        destStr = ConcatStrings(destStr, STR_Substr(haystack, startPos+zSn.len, zSh.len-(startPos+zSn.len)));
    
        return destStr;
    };
    
    
    /*
     * Replace all occurrences of needle in haystack and replace them
     */
    func string STR_ReplaceAll(var string haystack, var string needle, var string replace) {
        var string before; before = "";
        while(!Hlp_StrCmp(haystack, before));
            before = haystack;
            haystack = STR_ReplaceOnce(before, needle, replace);
        end;
        return haystack;
    };
    
    
    /*
     * Complement to STR_Prefix in Ikarus
     */
    func string STR_Postfix(var string str, var int off) {
        return STR_SubStr(str, off, STR_Len(str)-off);
    };
    
    
    /*
     * Retrieve the string position (starting at 0) of the first non-numeric character
     */
    func int STR_IndexOfFirstNonNumeric(var string str) {
        var int len; len = STR_Len(str);
        var int buf; buf = STR_toChar(str);
    
        var int valid; valid = FALSE;
    
        var int index; index = 0;
    
        while(index < len);
            var int chr; chr = MEM_ReadInt(buf + index) & 255;
    
            if (chr >= 48 /* 0 */) && (chr <= 57 /* 9 */) {
                valid = TRUE;
            } else if ((chr != 45 /*-*/) && (chr != 43 /*+*/)) || (index != 0) {
                // Allow leading plus/minus, e.g. -5
                break;
            };
    
            index += 1;
        end;
    
        // "-" is not a number
        if (!valid) {
            index = 0;
        };
    
        return index;
    };
    
    
    /*
     * Retrieve a string trimmed from left and right by all characters in tok
     * E.g. (" .. hello .. ", ". ") -> "hello"
     */
    func string STR_Trim(var string str, var string tok) {
        var int lenS; lenS = STR_Len(str);
        var int lenT; lenT = STR_Len(tok);
    
        // Start from the beginning
        var int startP; startP = 0;
        while(startP < lenS);
            var string ss; ss = STR_Substr(str, startP, 1);
            var int cont; cont = FALSE;
    
            var int t; t = 0;
            while(t < lenT);
                var string ts; ts = STR_Substr(tok, t, 1);
    
                if (Hlp_StrCmp(ss, ts)) {
                    cont = TRUE;
                    break;
                };
    
                t += 1;
            end;
    
            if (!cont) {
                break;
            };
    
            startP += 1;
        end;
    
        // Start from the end
        var int endP; endP = lenS-1;
        while(endP >= startP);
            ss = STR_Substr(str, endP, 1);
            cont = FALSE;
    
            t = 0;
            while(t < lenT);
                ts = STR_Substr(tok, t, 1);
    
                if (Hlp_StrCmp(ss, ts)) {
                    cont = TRUE;
                    break;
                };
    
                t += 1;
            end;
    
            if (!cont) {
                break;
            };
    
            endP -= 1;
        end;
    
        // Convert offset to length (0 -> 1, 1 -> 2, ...)
        endP += 1;
    
        if (startP >= endP) {
            return "";
        } else {
            return STR_Substr(str, startP, endP-startP);
        };
    };
    
    
    /*
     * Trim string from left and right of a certain char
     */
    func string STR_TrimChar(var string str, var int chr) {
        var int sPtr; sPtr = _@s(str);
    
        const int zSTRING__TrimLeft_G1 = 4617312; //0x467460
        const int zSTRING__TrimLeft_G2 = 4638256; //0x46C630
    
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_IntParam(_@(chr));
            CALL__thiscall(_@(sPtr), MEMINT_SwitchG1G2(zSTRING__TrimLeft_G1, zSTRING__TrimLeft_G2));
            call = CALL_End();
        };
    
        const int zSTRING__TrimRight_G1 = 4617632; //0x4675A0
        const int zSTRING__TrimRight_G2 = 4638576; //0x46C770
    
        const int call1 = 0;
        if (CALL_Begin(call1)) {
            CALL_IntParam(_@(chr));
            CALL__thiscall(_@(sPtr), MEMINT_SwitchG1G2(zSTRING__TrimRight_G1, zSTRING__TrimRight_G2));
            call1 = CALL_End();
        };
    
        return str;
    };
    
    
    /*
     * Convert string to IEEE754 32-bit float
     */
    func int STR_ToFloat(var string str) {
        var zString zStr; zStr = _^(_@s(str));
        var int ptr; ptr = zStr.ptr;
        var int f;
        var int fPtr; fPtr = _@(f);
    
        const int _atoflt_G1 = 7876596; //0x782FF4
        const int _atoflt_G2 = 8243410; //0x7DC8D2
    
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_PtrParam(_@(ptr));
            CALL_PtrParam(_@(fPtr));
            CALL_PutRetValTo(0);
            CALL__cdecl(MEMINT_SwitchG1G2(_atoflt_G1, _atoflt_G2));
            call = CALL_End();
        };
    
        return f;
    };




    convert.d – Number conversion functions (hex to dec, dec to bin, dec to hex, ...)
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * convert.d
     *
     * Number conversion functions
     *
     * - Requires Ikarus, strings.d
     * - Compatible with Gothic 1 and Gothic 2
     *
     *
     *  func string dec2hex(int    dec)
     *  func int    hex2dec(string hex)
     *
     *  func string dec2bin(int    dec)
     *  func int    bin2dec(string bin)
     *
     *  func string hex2bin(string hex)
     *  func string bin2hex(string bin)
     *
     *  func int    h(string hex)       Shorter alias for hex2dec
     *  func int    b(string bin)       Shorter alias for bin2dec
     */
    
    
    /*
     * Fix function from Ikarus: Based on MEMINT_ByteToKeyHex
     */
    func string byte2hex(var int byte) {
        const int ASCII_0 = 48;
        const int ASCII_A = 65;
        byte = byte & 255;
    
        // Fix ASCII characters (A to F)
        var int c1; c1 = (byte >> 4);
        if (c1 >= 10) {
            c1 += ASCII_A-ASCII_0-10;
        };
        var int c2; c2 = (byte & 15);
        if (c2 >= 10) {
            c2 += ASCII_A-ASCII_0-10;
        };
    
        const int mem = 0;
        if (!mem) { mem = MEM_Alloc(3); };
    
        MEM_WriteByte(mem    , c1 + ASCII_0);
        MEM_WriteByte(mem + 1, c2 + ASCII_0);
        return STR_FromChar(mem);
    };
    
    
    /*
     * Convert decimal to hexadecimal (big endian)
     */
    func string dec2hex(var int dec) {
        var string hex; hex = "";
        hex = ConcatStrings(hex, byte2hex(dec >> 24));
        hex = ConcatStrings(hex, byte2hex(dec >> 16));
        hex = ConcatStrings(hex, byte2hex(dec >> 8));
        hex = ConcatStrings(hex, byte2hex(dec));
        return hex;
    };
    
    
    /*
     * Convert hexadecimal to decimal (big endian)
     */
    func int hex2dec(var string hex) {
        var zString zStr; zStr = _^(_@s(hex));
        if (!zStr.len) {
            return 0;
        };
    
        // Remove 0x prefix and h postfix
        hex = STR_Lower(hex);
        if (Hlp_StrCmp(STR_Prefix(hex, 2), "0x")) {
            hex = STR_SubStr(hex, 2, zStr.len-2);
        } else if (MEM_ReadByte(zStr.ptr+zStr.len-1) == /*h*/ 104) {
            hex = STR_Prefix(hex, zStr.len-1);
        };
    
        // Remove any spaces
        hex = STR_ReplaceAll(hex, " ", "");
    
        // Check length
        if (zStr.len > 8) {
            MEM_Error("hex2dec: Hexadecimal number to big. Considering the last 4 bytes only.");
            hex = STR_Postfix(hex, zStr.len-8);
        };
    
        // Iterate over all characters (from back to front)
        var int dec; dec = 0;
        repeat(i, zStr.len); var int i;
            dec += MEMINT_HexCharToInt(MEM_ReadByte(zStr.ptr+(zStr.len-1)-i)) << 4*i;
        end;
    
        return dec;
    };
    func int h(var string hex) {
        return hex2dec(hex);
    };
    
    
    /*
     * Convert decimal to binary
     */
    func string dec2bin(var int dec) {
        var string bin; bin = "";
        repeat(i, 32); var int i;
            if (dec & (1 << i)) {
                bin = ConcatStrings("1", bin);
            } else {
                bin = ConcatStrings("0", bin);
            };
        end;
        return bin;
    };
    
    
    /*
     * Convert hexadecimal to binary
     */
    func string hex2bin(var string hex) {
        return dec2bin(hex2dec(hex));
    };
    
    
    /*
     * Convert binary to decimal
     */
    func int bin2dec(var string bin) {
        var zString zStr; zStr = _^(_@s(bin));
        if (!zStr.len) {
            return 0;
        };
    
        // Remove any spaces
        bin = STR_ReplaceAll(bin, " ", "");
    
        // Check length
        if (zStr.len > 32) {
            MEM_Error("bin2dec: Binary number to big. Considering the last 32 bits only.");
            bin = STR_Postfix(bin, zStr.len-32);
        };
    
        // Iterate over all characters (from back to front)
        const int ASCII_0 = 48;
        const int ASCII_1 = 49;
        var int dec; dec = 0;
        repeat(i, zStr.len); var int i;
            var int c; c = MEM_ReadByte(zStr.ptr+(zStr.len-1)-i);
            if (c < ASCII_0) || (c > ASCII_1) {
                MEM_Error(ConcatStrings("bin2dec: Invalid binary char: ", STR_FromChar(_@(c))));
                return 0;
            };
    
            dec += (c - ASCII_0) << i;
        end;
    
        return dec;
    };
    func int b(var string bin) {
        return bin2dec(bin);
    };
    
    
    /*
     * Convert binary to hexadecimal
     */
    func string bin2hex(var string bin) {
        return dec2hex(bin2dec(bin));
    };




    searchVobs.d – Search vobs by different criteria
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * searchVobs.d
     *
     * Search vobs by different criteria
     *
     * - Requires Ikarus, objCheckInheritance.d, insertAnything.d
     * - Compatible with Gothic 1 and Gothic 2
     *
     * The function argument vobListPtr may always be zero, or the pointer to a previously created array.
     * The return value is the number of found vobs.
     *
     *
     *  func int SearchVobsByClass     (string className,        int vobListPtr)
     *  func int SearchVobsByVisual    (string visual,           int vobListPtr)
     *  func int SearchVobsByProximity (int posPtr, int maxDist, int vobListPtr)
     *  func int SearchVobsByRemoteness(int posPtr, int minDist, int vobListPtr)
     */
    
    
    /*
     * Search all or given vobs by base class
     */
    func int SearchVobsByClass(var string className, var int vobListPtr) {
        const int zCWorld__SearchVobListByBaseClass_G1 = 6250016; //0x5F5E20
        const int zCWorld__SearchVobListByBaseClass_G2 = 6439712; //0x624320
    
        var zCArray vobList; vobList = _^(vobListPtr);
        if (!vobList.numInArray) {
            var int vobTreePtr; vobTreePtr = _@(MEM_Vobtree);
            var int worldPtr;   worldPtr   = _@(MEM_World);
            var int classDef;   classDef   = GetClassDefByString(className);
    
            const int call = 0;
            if (CALL_Begin(call)) {
                CALL_PtrParam(_@(vobTreePtr));
                CALL_PtrParam(_@(vobListPtr));
                CALL_PtrParam(_@(classDef));
                CALL__thiscall(_@(worldPtr), MEMINT_SwitchG1G2(zCWorld__SearchVobListByBaseClass_G1,
                                                               zCWorld__SearchVobListByBaseClass_G2));
                call = CALL_End();
            };
        } else {
            // Iterate over all vobs and remove the ones not matching the criteria
            var int i; i = 0;
            while(i < vobList.numInArray);
                var int vobPtr; vobPtr = MEM_ArrayRead(vobListPtr, i);
                if (objCheckInheritance(vobPtr, classDef)) {
                    // Keep vob
                    i += 1;
                } else {
                    // Otherwise remove vob from array
                    MEM_ArrayRemoveIndex(vobListPtr, i);
                };
            end;
        };
    
        return vobList.numInArray;
    };
    
    
    /*
     * Search all or given vobs by visual
     */
    func int SearchVobsByVisual(var string visual, var int vobListPtr) {
        // Create vob list if empty
        var zCArray vobList; vobList = _^(vobListPtr);
        if (!vobList.numInArray) {
            if (!SearchVobsByClass("zCVob", vobListPtr)) {
                return 0;
            };
        };
    
        // Iterate over all vobs and remove the ones not matching the criteria
        var int i; i = 0;
        while(i < vobList.numInArray);
            var int vobPtr; vobPtr = MEM_ArrayRead(vobListPtr, i);
            if (vobPtr) {
                // Check for visual
                var zCVob vob; vob = _^(vobPtr);
                if (vob.visual) {
                    // Compare visual
                    var zCObject visualObj; visualObj = _^(vob.visual);
                    if (Hlp_StrCmp(visualObj.objectname, visual)) {
                        // Keep vob
                        i += 1;
                        continue;
                    };
                };
            };
    
            // Otherwise remove vob from array
            MEM_ArrayRemoveIndex(vobListPtr, i);
        end;
    
        return vobList.numInArray;
    };
    
    
    /*
     * Search all or given vobs by proximity
     */
    func int SearchVobsByProximity(var int posPtr, var int maxDist, var int vobListPtr) {
        // Create vob list if empty
        var zCArray vobList; vobList = _^(vobListPtr);
        if (!vobList.numInArray) {
            if (!SearchVobsByClass("zCVob", vobListPtr)) {
                return 0;
            };
        };
    
        var int pos[3];
        MEM_CopyWords(posPtr, _@(pos), 3);
    
        // Iterate over all vobs and remove the ones not matching the criteria
        var int i; i = 0;
        while(i < vobList.numInArray);
            var int vobPtr; vobPtr = MEM_ArrayRead(vobListPtr, i);
            if (vobPtr) {
                // Check distance
                var zCVob vob; vob = _^(vobPtr);
    
                // Compute distance between vob and position
                var int dist[3];
                dist[0] = subf(vob.trafoObjToWorld[ 3], pos[0]);
                dist[1] = subf(vob.trafoObjToWorld[ 7], pos[1]);
                dist[2] = subf(vob.trafoObjToWorld[11], pos[2]);
                var int distance;
                distance = sqrtf(addf(addf(sqrf(dist[0]), sqrf(dist[1])), sqrf(dist[2])));
    
                // Check if distance is with in maxDist
                if (lef(distance, maxDist)) {
                    // Keep vob
                    i += 1;
                    continue;
                };
            };
    
            // Otherwise remove vob from array
            MEM_ArrayRemoveIndex(vobListPtr, i);
        end;
    
        return vobList.numInArray;
    };
    
    
    /*
     * Search all or given vobs by remoteness
     */
    func int SearchVobsByRemoteness(var int posPtr, var int minDist, var int vobListPtr) {
        // Create vob list if empty
        var zCArray vobList; vobList = _^(vobListPtr);
        if (!vobList.numInArray) {
            if (!SearchVobsByClass("zCVob", vobListPtr)) {
                return 0;
            };
        };
    
        var int pos[3];
        MEM_CopyWords(posPtr, _@(pos), 3);
    
        // Iterate over all vobs and remove the ones not matching the criteria
        var int i; i = 0;
        while(i < vobList.numInArray);
            var int vobPtr; vobPtr = MEM_ArrayRead(vobListPtr, i);
            if (vobPtr) {
                // Check distance
                var zCVob vob; vob = _^(vobPtr);
    
                // Compute distance between vob and position
                var int dist[3];
                dist[0] = subf(vob.trafoObjToWorld[ 3], pos[0]);
                dist[1] = subf(vob.trafoObjToWorld[ 7], pos[1]);
                dist[2] = subf(vob.trafoObjToWorld[11], pos[2]);
                var int distance;
                distance = sqrtf(addf(addf(sqrf(dist[0]), sqrf(dist[1])), sqrf(dist[2])));
    
                // Check if distance is beyond minDist
                if (gf(distance, minDist)) {
                    // Keep vob
                    i += 1;
                    continue;
                };
            };
    
            // Otherwise remove vob from array
            MEM_ArrayRemoveIndex(vobListPtr, i);
        end;
    
        return vobList.numInArray;
    };
    Last edited by mud-freak; 14.02.2018 at 17:50. Reason: searchVobs.d vereinfacht (setzt jetzt insertAnything.d voraus), Alias-Funktionen für convert.d

  3. View Forum Posts #43 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    sound.d – Sound and music functions
    Hier ist die Funktion stopAllSounds, die bereits im ScriptBin ist, enthalten.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * sound.d
     *
     * Sound and music functions
     *
     * - Requires Ikarus, LeGo (Anim8), searchVobs.d, insertAnything.d
     * - Compatible with Gothic 1 and Gothic 2
     * - Initialization with restoreMasterVolumeSoundsToDefault() and/or restoreVolumeMusicToDefault() recommended
     *
     * When using the setVolumne-functions or fadeOut-functions, make sure to call
     *  restoreMasterVolumeSoundsToDefault() and/or restoreVolumeMusicToDefault()
     * in Init_Global to restore the volume on loading/new game!
     *
     * The volumes will always be reset to their defaults after loading a game. Thus, this script does not take care of
     * maintaining the volume over saving and loading a game.
     *
     * Keep in mind, that you cannot call the fadeOut-functions from startup. LeGo has to be initialized first. The LeGo
     * package GameState can compensate for that.
     *
     *
     *  func void   stopAllSounds()
     *  func void   fadeOutAllSounds(int fadeOutMS, int waitMS, int fadeInMS, int killSounds)
     *  func int    getMasterVolumeSounds()
     *  func void   setMasterVolumeSounds(int volume)
     *  func void   restoreMasterVolumeSoundsToDefault()
     *
     *  func void   stopMusic()
     *  func void   fadeOutMusic(int fadeOutMS, int waitMS, int fadeInMS, int killMusic)
     *  func void   playMusic(string music, int transition)
     *  func int    getVolumeMusic()
     *  func void   setVolumeMusic(int volume)
     *  func void   restoreVolumeMusicToDefault()
     *
     *  func void   setMusicZoneTheme(string vobName, string musicTheme)
     *  func void   setCurrentMusicZoneTheme(string musicTheme)
     *  func string getCurrentMusicZoneTheme()
     *  func void   setAllMusicZoneThemes(string musicTheme)
     */
    
    
    /*
     * Stop all effect and speech sounds of the game instantly
     */
    func void stopAllSounds() {
        MEM_InitAll();
    
        const int zsound_G1                              =  9236044; //0x8CEE4C
        const int zsound_G2                              = 10072124; //0x99B03C
        const int zCSndSys_MSS__RemoveAllActiveSounds_G1 =  5112224; //0x4E01A0
        const int zCSndSys_MSS__RemoveAllActiveSounds_G2 =  5167008; //0x4ED7A0
    
        var int zsoundPtr; zsoundPtr = MEM_ReadInt(MEMINT_SwitchG1G2(zsound_G1, zsound_G2));
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL__thiscall(_@(zsoundPtr), MEMINT_SwitchG1G2(zCSndSys_MSS__RemoveAllActiveSounds_G1,
                                                            zCSndSys_MSS__RemoveAllActiveSounds_G2));
            call = CALL_End();
        };
    };
    
    
    /*
     * Get master volume sound
     */
    func int getMasterVolumeSounds() {
        const int zCSndSys_MSS__prefs_G1 = 8837192; //0x86D848
        const int zCSndSys_MSS__prefs_G2 = 9249512; //0x8D22E8
        return MEM_ReadInt(MEMINT_SwitchG1G2(zCSndSys_MSS__prefs_G1, zCSndSys_MSS__prefs_G2));
    };
    
    
    /*
     * Backup default master volume sound
     */
    func int getMasterVolumeSoundsDefault() {
        const int soundDefVol = 0;
    
        if (!soundDefVol) {
            soundDefVol = getMasterVolumeSounds();
        };
    
        return soundDefVol;
    };
    
    
    /*
     * Set master volume of sounds
     * Caution: This control differs from the volume settings in the menu, be sure to always reset it!
     */
    func void setMasterVolumeSounds(var int volume) {
        const int zsound_G1                        =  9236044; //0x8CEE4C
        const int zsound_G2                        = 10072124; //0x99B03C
        const int zCSndSys_MSS__SetMasterVolume_G1 =  5112544; //0x4E02E0
        const int zCSndSys_MSS__SetMasterVolume_G2 =  5167328; //0x4ED8E0
        const int mss32_AILptr_G1                  =  8838412; //0x86DD0C
        const int mss32_AILptr_G2                  =  9251444; //0x8D2A74
    
        // Prevent crash by checking if sound was initialized (if sound is disabled)
        if (!MEMINT_SwitchG1G2(MEM_ReadInt(mss32_AILptr_G1), MEM_ReadInt(mss32_AILptr_G2))) {
            return;
        };
    
        // Backup default volume before changing it
        var int i; i = getMasterVolumeSoundsDefault();
    
        var int zsoundPtr; zsoundPtr = MEM_ReadInt(MEMINT_SwitchG1G2(zsound_G1, zsound_G2));
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_FloatParam(_@(volume));
            CALL__thiscall(_@(zsoundPtr), MEMINT_SwitchG1G2(zCSndSys_MSS__SetMasterVolume_G1,
                                                            zCSndSys_MSS__SetMasterVolume_G2));
            call = CALL_End();
        };
    };
    
    
    /*
     * Restore default sound master volume
     * Call this function from Init_Global to ensure working sound after loading
     */
    func void restoreMasterVolumeSoundsToDefault() {
        setMasterVolumeSounds(getMasterVolumeSoundsDefault());
    };
    
    
    /*
     * Fade out all sounds
     * Leave sound muted indefinitely by setting fadeInMS to -1
     */
    func void fadeOutAllSounds(var int fadeOutMS, var int waitMS, var int fadeInMS, var int killSounds) {
        // Retrieve and backup master volume
        var int sVol; sVol = getMasterVolumeSounds();
    
        // Start fade out
        var int a8; a8 = Anim8_NewExt(sVol, soundFadeHandler, killSounds, TRUE);
        Anim8_RemoveIfEmpty(a8, TRUE);
    
        Anim8(a8, FLOATNULL, fadeOutMS, A8_SlowEnd);
        Anim8q(a8, FLOATNULL, waitMS, A8_Wait);
        if (fadeInMS != -1) {
            Anim8q(a8, sVol, fadeInMS, A8_SlowStart);
        };
    };
    func void soundFadeHandler(var int killSounds, var int value) {
        // Once quiet: Kill all sounds if desired
        if (!value) && (killSounds) {
            stopAllSounds();
        };
        setMasterVolumeSounds(value);
    };
    
    
    /*
     * Stop the music instantly
     */
    func void stopMusic() {
        MEM_InitAll();
    
        const int zmusic_G1                               = 8836220; //0x86D47C
        const int zmusic_G2                               = 9248532; //0x8D1F14
        const int zCMusicSys_DirectMusic__Stop_G1         = 5098480; //0x4DCBF0
        const int zCMusicSys_DirectMusic__Stop_G2         = 5152544; //0x4E9F20
        const int zCMusicSystem__s_musicSystemDisabled_G1 = 8836224; //0x86D480
        const int zCMusicSystem__s_musicSystemDisabled_G2 = 9248536; //0x8D1F18
    
        // Prevent crash by checking if music system was initialized (if music is disabled)
        if (MEMINT_SwitchG1G2(MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G1),
                              MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G2))) {
            return;
        };
    
        var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2));
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__Stop_G1,
                                                            zCMusicSys_DirectMusic__Stop_G2));
            call = CALL_End();
        };
    };
    
    
    /*
     * Get music volume
     */
    func int getVolumeMusic() {
    const int zmusic_G1 = 8836220; //0x86D47C
        const int zmusic_G2 = 9248532; //0x8D1F14
        const int zCMusicSys_DirectMusic_volume_offset = 12; //0Ch same for G1 and G2
    
        var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2));
        return MEM_ReadInt(zmusicPtr+zCMusicSys_DirectMusic_volume_offset);
    };
    
    
    /*
     * Backup default music volume
     */
    func int getVolumeMusicDefault() {
        const int musicDefVol = 0;
    
        if (!musicDefVol) {
            musicDefVol = getVolumeMusic();
        };
    
        return musicDefVol;
    };
    
    
    /*
     * Set volume of music
     * Caution: This control differs from the volume settings in the menu, be sure to always reset it!
     */
    func void setVolumeMusic(var int volume) {
        const int zmusic_G1                               = 8836220; //0x86D47C
        const int zmusic_G2                               = 9248532; //0x8D1F14
        const int zCMusicSys_DirectMusic__SetVolume_G1    = 5098624; //0x4DCC80
        const int zCMusicSys_DirectMusic__SetVolume_G2    = 5152720; //0x4E9FD0
        const int zCMusicSystem__s_musicSystemDisabled_G1 = 8836224; //0x86D480
        const int zCMusicSystem__s_musicSystemDisabled_G2 = 9248536; //0x8D1F18
    
        // Prevent crash by checking if music system was initialized (if music is disabled)
        if (MEMINT_SwitchG1G2(MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G1),
                              MEM_ReadInt(zCMusicSystem__s_musicSystemDisabled_G2))) {
            return;
        };
    
        // Backup default volume before changing it
        var int i; i = getVolumeMusicDefault();
    
        var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2));
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_FloatParam(_@(volume));
            CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__SetVolume_G1,
                                                            zCMusicSys_DirectMusic__SetVolume_G2));
            call = CALL_End();
        };
    };
    
    
    /*
     * Restore default music volume
     * Call this function from Init_Global to ensure working music after loading
     */
    func void restoreVolumeMusicToDefault() {
        setVolumeMusic(getVolumeMusicDefault());
    };
    
    
    /*
     * Fade out the music
     * Leave music muted indefinitely by setting fadeInMS to -1
     */
    func void fadeOutMusic(var int fadeOutMS, var int waitMS, var int fadeInMS, var int killMusic) {
        // Retrieve and backup music volume
        var int mVol; mVol = getVolumeMusic();
    
        // Start fade out
        var int a8; a8 = Anim8_NewExt(mVol, musicFadeHandler, killMusic, TRUE);
        Anim8_RemoveIfEmpty(a8, TRUE);
    
        Anim8(a8, FLOATNULL, fadeOutMS, A8_SlowEnd);
        Anim8q(a8, FLOATNULL, waitMS, A8_Wait);
        if (fadeInMS != -1) {
            Anim8q(a8, mVol, fadeInMS, A8_SlowStart);
        };
    };
    func void musicFadeHandler(var int killMusic, var int value) {
        // Once quiet: Kill music if desired
        if (!value) && (killMusic) {
            stopMusic();
        };
        setVolumeMusic(value);
    };
    
    
    /*
     * Play music by script instance, e.g. "XAR_Day_Std"
     * The second argument may be either be 0 (musical transition?), 1 (?) or 2 (some thing like fade out/fade in?)
     */
    func void playMusic(var string music, var int transition) {
        const int zmusic_G1                                    = 8836220; //0x86D47C
        const int zmusic_G2                                    = 9248532; //0x8D1F14
        const int zCMusicSys_DirectMusic__PlayThemeByScript_G1 = 5093456; //0x4DB850
        const int zCMusicSys_DirectMusic__PlayThemeByScript_G2 = 5147312; //0x4E8AB0
    
        var int zmusicPtr; zmusicPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zmusic_G1), MEM_ReadInt(zmusic_G2));
        var int musicPtr; musicPtr = _@s(music);
    
        var int zero;
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_PtrParam(_@(zero));       // Some pointer
            CALL_IntParam(_@(transition)); // zTMus_TransType: either 0, 1 or 2
            CALL_PtrParam(_@(musicPtr));
            CALL__thiscall(_@(zmusicPtr), MEMINT_SwitchG1G2(zCMusicSys_DirectMusic__PlayThemeByScript_G1,
                                                            zCMusicSys_DirectMusic__PlayThemeByScript_G2));
            call = CALL_End();
        };
    };
    
    
    /*
     * Overwrite the music theme of a music zone
     *
     * This function will permanently change the music theme for a certain music zone. This change is preserved over
     * saving/loading, but not across saves.
     * The first parameter is the object name of the oCZoneMusic vob.
     * The second parameter is the new post fix identifying the music theme, e.g. "XAR"
     *
     * The transition in music will be instant (given that the player is in the affected zone).
     */
    func void setMusicZoneTheme(var string vobName, var string musicTheme) {
        // Find all vobs of this zone, there are multiple!
        var int arrPtr; arrPtr = MEM_SearchAllVobsByName(vobName);
    
        // Build new vob name
        var string newName; newName = ConcatStrings(STR_Prefix(vobName, STR_Len(vobName)-3), musicTheme);
    
        // Iterate over all music zones and exchange their identifier
        var zCArray arr; arr = _^(arrPtr);
        repeat(j, arr.numInArray); var int j;
            var int vobPtr; vobPtr = MEM_ArrayRead(arrPtr, j);
            MEM_RenameVob(vobPtr, newName);
        end;
    
        // Free array
        MEM_ArrayFree(arrPtr);
    };
    
    
    /*
     * Overwrite the music theme of the current music zone
     */
    func void setCurrentMusicZoneTheme(var string musicTheme) {
        if (!MEM_ReadInt(oCZoneMusic__s_musiczone_Address)) {
            MEM_Warn("No music zone active. No changes performed.");
            return;
        };
    
        // Not only change the current oCZoneMusic, but all matching ones in the area
        var zCObject vob; vob = _^(MEM_ReadInt(oCZoneMusic__s_musiczone_Address));
        setMusicZoneTheme(vob.objectName, musicTheme);
    };
    
    
    /*
     * Get music theme of current music zone (as a prior backup for setCurrentMusicZoneTheme above)
     */
    func string getCurrentMusicZoneTheme() {
        if (!MEM_ReadInt(oCZoneMusic__s_musiczone_Address)) {
            MEM_Warn("No music zone active.");
            return "";
        };
    
        var zCObject vob; vob = _^(MEM_ReadInt(oCZoneMusic__s_musiczone_Address));
        return STR_SubStr(vob.objectName, STR_Len(vob.objectName)-3, 3);
    };
    
    
    /*
     * Overwrite the music theme of all music zones
     */
    func void setAllMusicZoneThemes(var string musicTheme) {
        var int arrPtr; arrPtr = MEM_ArrayCreate();
        if (SearchVobsByClass("oCZoneMusic", arrPtr)) {
            // Iterate over all oCZoneMusic vobs
            var zCArray arr; arr = _^(arrPtr);
            repeat(i, arr.numInArray); var int i;
                var int vobPtr; vobPtr = MEM_ArrayRead(arrPtr, i);
                var zCObject vob; vob = _^(vobPtr);
    
                // Build new vob name
                var string vobName; vobName = vob.objectName;
                var string newName; newName = ConcatStrings(STR_Prefix(vobName, STR_Len(vobName)-3), musicTheme);
    
                // Exchange music theme identifier
                MEM_RenameVob(vobPtr, newName);
            end;
        };
    
        // Free array
        MEM_ArrayFree(arrPtr);
    };




    hidePlayerStatus.d – Simple script to remove all player info on-screen continuously until showing it again
    Dies ist eine Alternative zu hideBars, die im Gegensatz dazu alle on-screen Informationen dauerhaft ausblendet (ausgenommen von Views). Daher ist sie eine bessere Grundlage für ScreenBlend.d
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * hidePlayerStatus.d
     *
     * Simple script to remove all player info on-screen continuously until showing it again.
     *
     * - Requires Ikarus, LeGo (FrameFunctions)
     * - Compatible with Gothic 1 and Gothic 2
     *
     * The info includes health bar, mana bar, swim bar, focus bar and focus names. This change is preserved over saving and
     * loading, but not across saves/starting a new game.
     *
     *
     *  hidePlayerStatus() once to hide all information and keep it hidden.
     *  showPlayerStatus() once to show all again.
     */
    
    
    /*
     * Internal wrapper for oCGame::SetShowPlayerStatus
     * This engine function merely sets ogame->showPlayerStatus to zero and removes all bar-view-items from screen.
     */
    func void setShowPlayerStatus(var int on) {
        const int oCGame__SetShowPlayerStatus_G1 = 6523872; //0x638BE0
        const int oCGame__SetShowPlayerStatus_G2 = 7089552; //0x6C2D90
    
        var int gamePtr; gamePtr = _@(MEM_Game);
    
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_IntParam(_@(on));
            CALL__thiscall(_@(gamePtr), MEMINT_SwitchG1G2(oCGame__SetShowPlayerStatus_G1, oCGame__SetShowPlayerStatus_G2));
            call = CALL_End();
        };
    };
    
    func void hidePlayerStatus() {
        setShowPlayerStatus(0);          // Remove all on screen info
        FF_ApplyOnce(_hidePlayerStatus); // And then never draw it again
    };
    func void showPlayerStatus() {
        if (InfoManager_hasFinished()) {
            setShowPlayerStatus(1);
        };
        FF_Remove(_hidePlayerStatus);
    };
    func void _hidePlayerStatus() {
        if (MEM_Game.showPlayerStatus) {
            // Will be called sparingly; only after exiting the main menu and after dialogs
            setShowPlayerStatus(0);
        };
    };
    
    
    /*
    All of the above could be done more elegantly and performant without FrameFunctions by modifying the setter function.
    However, this would not allow to maintain the visibility state across saving and loading. For completeness, that
    approach is shown below.
    
    func void forceHidePlayerStatus(var int on) {
        const int set = 0;
        if (set == on) {
            return;
        };
    
        const int oCGame__SetShowPlayerStatus_G1 = 6523872; //0x638BE0
        const int oCGame__SetShowPlayerStatus_G2 = 7089552; //0x6C2D90
        var int addr; addr = MEMINT_SwitchG1G2(oCGame__SetShowPlayerStatus_G1, oCGame__SetShowPlayerStatus_G2)+2;
    
        if (on) {
            // Overwrite to hide always: replace argument with zero
            MemoryProtectionOverride(addr, 4);
            MEM_WriteInt(addr, -1869545677); //33 FF 90 90  xor edi, edi
        } else {
            // Reset to default
            MEM_WriteInt(addr,   203717771); //8B 7C 24 0C  mov edi, [esp+8+4]
        };
    
        set = on;
    }; */




    blockAllPlayerInput.d – Block all player input with or without blocking the main menu as well
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * blockAllPlayerInput.d
     *
     * Block all player input with or without blocking the main menu as well.
     *
     * - Requires Ikarus, LeGo (HookEngine, >= 2.5.0), LeGo Cursor optional
     * - Compatible with Gothic 1 and Gothic 2
     * - Resetting with unblockAllPlayerInput() in Init_Global recommended to restore player input on loading/new game!
     *
     * Blocking the main menu is not recommended and should only be done in highly controlled cases!
     *
     *
     * Main functions to use:
     *  blockAllPlayerInput(int blockGameMenu) once to block all player input and keep it blocked.
     *  unblockAllPlayerInput()                once to unblock all again.
     *
     * Sub-functions (called from the functions above):
     *  blockInGameMenus(int on)
     *  blockMainMenu(int on)
     *  blockHotkeys(int on)
     *  blockControls(int on)
     *  blockMouse(int on)
     */
    
    
    /*
     * Block all in-game menus (status screen, log screen, map)
     */
    func void blockInGameMenus(var int on) {
        const int set = 0;
        if (set == on) {
            return;
        };
    
        const int oCGame__HandleEvent_G1 = 6680288; //0x65EEE0
        const int oCGame__HandleEvent_G2 = 7324016; //0x6FC170
        var int addr; addr = MEMINT_SwitchG1G2(oCGame__HandleEvent_G1, oCGame__HandleEvent_G2);
    
        if (on) {
            ReplaceEngineFuncF(addr, 1, Hook_ReturnFalse);
        } else {
            RemoveHookF(addr, 5, Hook_ReturnFalse);
            if (!IsHooked(addr)) {
                MEM_WriteInt(addr, MEMINT_SwitchG1G2(/*0xA164*/ 41316, /*0x8568FF6A*/ 2238250858));
            };
        };
    
        set = on;
    };
    
    
    /*
     * Block game menu (ESC key). This actually also disables the hot keys
     */
    func void blockMainMenu(var int on) {
        const int set = 0;
        if (set == on) {
            return;
        };
    
        const int cGameManager__HandleEvent_G1 = 4363200; //0x4293C0
        const int cGameManager__HandleEvent_G2 = 4369744; //0x42AD50
        var int addr; addr = MEMINT_SwitchG1G2(cGameManager__HandleEvent_G1, cGameManager__HandleEvent_G2);
    
        if (on) {
            ReplaceEngineFuncF(addr, 1, Hook_ReturnFalse);
        } else {
            RemoveHookF(addr, 5, Hook_ReturnFalse);
            if (!IsHooked(addr)) {
                MEM_WriteInt(addr, MEMINT_SwitchG1G2(/*0xD98B5351*/ 3649786705, /*0xA164*/ 41316));
            };
        };
    
        set = on;
    };
    
    
    /*
     * Disable hot keys
     */
    func void blockHotkeys(var int on) {
        const int set = 0;
        if (set == on) {
            return;
        };
    
        const int cGameManager__HandleEvent_quickload_G1 = 4363453; //0x4294BD
        const int cGameManager__HandleEvent_quicksave_G1 = 4363312; //0x429430
        const int oCGame__s_bUsePotionKeys_G2            = 9118156; //0x8B21CC
        const int oCGame__s_bUseQuickSave_G2             = 9118160; //0x8B21D0
        const int cGameManager__HandleEvent_F9keyJZ_G2   = 4369832; //0x42ADA8
    
        const int enabled_G2 = 0;
    
        if (on) {
            if (GOTHIC_BASE_VERSION == 1) {
                // Disable quick saving
                MemoryProtectionOverride(cGameManager__HandleEvent_quicksave_G1, 1);
                MEM_WriteByte(cGameManager__HandleEvent_quicksave_G1, /*EB short jmp*/ 235);
    
                // Disable quick loading
                MemoryProtectionOverride(cGameManager__HandleEvent_quickload_G1, 1);
                MEM_WriteByte(cGameManager__HandleEvent_quickload_G1, /*EB short jmp*/ 235);
            } else {
                // Back up if they were enabled beforehand
                enabled_G2 = enabled_G2 | (MEM_ReadInt(oCGame__s_bUsePotionKeys_G2) << 0);
                enabled_G2 = enabled_G2 | (MEM_ReadInt(oCGame__s_bUseQuickSave_G2)  << 1);
    
                // Disabled them
                MEM_WriteInt(oCGame__s_bUsePotionKeys_G2, 0);
                MEM_WriteInt(oCGame__s_bUseQuickSave_G2,  0);
    
                // Quick loading is always possible due to a logic mistake in the engine
                MemoryProtectionOverride(cGameManager__HandleEvent_F9keyJZ_G2, 4);
                MEM_WriteInt(cGameManager__HandleEvent_F9keyJZ_G2, 995); // jump beyond broken logic: 4370831-(4369830+6)
            };
        } else {
            if (GOTHIC_BASE_VERSION == 1) {
                MEM_WriteByte(cGameManager__HandleEvent_quicksave_G1, /*74 short jz*/ 116);
                MEM_WriteByte(cGameManager__HandleEvent_quickload_G1, /*74 short jz*/ 116);
            } else {
                // Re-enabled if they were enabled beforehand
                MEM_WriteInt(oCGame__s_bUsePotionKeys_G2, (enabled_G2 &  1));
                MEM_WriteInt(oCGame__s_bUseQuickSave_G2,  (enabled_G2 >> 1));
    
                // Re-instate original, broken logic
                MEM_WriteInt(cGameManager__HandleEvent_F9keyJZ_G2, 237); //ED 00 00 00
            };
        };
    
        set = on;
    };
    
    
    /*
     * Remove player control (essentially turns the hero AI into an NPC AI)
     */
    func void blockControls(var int on) {
        const int set = 0;
        if (set == on) {
            return;
        };
    
        const int oCAIHuman__DoAI_player_G1 = 6381143; //0x615E57
        const int oCAIHuman__DoAI_player_G2 = 6930571; //0x69C08B
        const int oCNpc__CanDrawWeapon_G1   = 7647728; //0x74B1F0
        const int oCNpc__CanDrawWeapon_G2   = 6817216; //0x6805C0
    
        var int doAIplayerAddr; doAIplayerAddr = MEMINT_SwitchG1G2(oCAIHuman__DoAI_player_G1, oCAIHuman__DoAI_player_G2);
        var int canDrawWeaponAddr; canDrawWeaponAddr = MEMINT_SwitchG1G2(oCNpc__CanDrawWeapon_G1, oCNpc__CanDrawWeapon_G2);
    
        if (on) {
            // Detach player AI
            MemoryProtectionOverride(doAIplayerAddr, 5);
            MEM_WriteByte(doAIplayerAddr, MEMINT_SwitchG1G2(/*EB short jmp*/ 235, /*long jmp*/ ASMINT_OP_jmp));
            if (GOTHIC_BASE_VERSION == 2) {
                MEM_WriteInt(doAIplayerAddr+1, 432); // Jump to 0x69C240: 6931008-6930571-5
            };
    
            // Block combat keys (1-0)
            ReplaceEngineFuncF(canDrawWeaponAddr, 0, Hook_ReturnFalse);
        } else {
            // Restore player AI
            MEM_WriteByte(doAIplayerAddr, MEMINT_SwitchG1G2(/*75 jnz*/ 117, /*0F jne*/ 15));
            if (GOTHIC_BASE_VERSION == 2) {
                MEM_WriteInt(doAIplayerAddr+1, 110469); //0x01AF85
            };
    
            // Re-instate combat keys (1-0)
            RemoveHookF(canDrawWeaponAddr, 5, Hook_ReturnFalse);
            if (!IsHooked(canDrawWeaponAddr)) {
                MEM_WriteInt(canDrawWeaponAddr, /*0xE8F18B56*/ -386823338);
            };
        };
    
        set = on;
    };
    
    
    /*
     * Backup mouse enable state and then disable it (requires LeGo_Cursor)
     */
    func void blockMouse(var int on) {
        Cursor_NoEngine = on;
    };
    
    
    /*
     * Block all player input with or without blocking the game menu (not recommended)
     */
    func void blockAllPlayerInput(var int blockGameMenu) {
        MEM_SendToSpy(zERR_TYPE_WARN, "Blocking all player input");
    
        blockInGameMenus(1);
        blockHotkeys(1);
        blockControls(1);
        blockMouse(1);
    
        if (blockGameMenu) {
            // Kenny Loggins was here in 1986
            blockMainMenu(1);
        };
    };
    
    
    /*
     * Re-enable all player input
     */
    func void unblockAllPlayerInput() {
        MEM_SendToSpy(zERR_TYPE_WARN, "Unblocking all player input");
    
        blockInGameMenus(0);
        blockHotkeys(0);
        blockControls(0);
        blockMouse(0);
        blockMainMenu(0);
    };
    Last edited by mud-freak; 14.02.2018 at 18:16. Reason: sound.d vereinfacht (setzt jetzt insertVobs.d voraus)

  4. View Forum Posts #44 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    screenFade.d – This script is a modified version of ScreenFade.d from ScriptBin written by Lehona (et al.)
    Das Skript habe ich etwas geändert um u.A. das neue hidePlayerStatus einzubauen, um auch Fokusnamen zu verstecken.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * screenFade.d
     *
     * This script is a modified version of ScreenFade.d from ScriptBin written by Lehona (et al.)
     *
     * - Requires Ikarus, LeGo (Anim8, > 2.5.0), hidePlayerStatus.d
     * - Compatible with Gothic 1 and Gothic 2
     *
     * Changes include:
     *  - Substitution of hideManaBar with hidePlayerStatus
     *  - Usage of OnRemove-Callback available in Anim8 after LeGo 2.5.0
     *  - Possibility to pass an existing zCView handle to the function (may be 0)
     *  - Possibility to keep screen faded indefinitely (if fadeOutMS == -1), if so, returns zCView handle, 0 otherwise
     *
     *
     * func void ScreenFade   (          int fadeInMS, int waitInMS, int fadeOutMS) // Usage as before
     * func int  ScreenFadeExt(int view, int fadeInMS, int waitInMS, int fadeOutMS) // Extended usage
     */
    func int ScreenFadeExt(var int view, var int fadeInMS, var int waitInMS, var int fadeOutMS) {
        hidePlayerStatus();
    
        // Allow existing view to be used
        if (!Hlp_IsValidHandle(view)) {
            view = View_Create(0, 0, PS_VMAX, PS_VMAX);
            View_SetTexture(view, "default.tga");
            View_SetColor(view, 0);
            View_Open(view);
        };
    
        var int a8; a8 = Anim8_NewExt(0, ScreenFadeHandler, view, false);
        Anim8_RemoveIfEmpty(a8, true);
        Anim8_RemoveDataIfEmpty(a8, true);
        Anim8_CallOnRemove(a8, TurnScreenBackOn);
    
        Anim8(a8, 255, fadeInMS, A8_Constant);
        Anim8q(a8, 255, waitInMS, A8_Wait);
        if (fadeOutMS != -1) {
            Anim8q(a8, 0, fadeOutMS, A8_Constant);
        };
    
        // Return view handle
        if (fadeOutMS == -1) {
            return view;
        } else {
            return -1;
        };
    };
    func void ScreenFade(var int fadeInMS, var int waitInMS, var int fadeOutMS) {
        var int i; i = ScreenFadeExt(0, fadeInMS, waitInMS, fadeOutMS);
    };
    
    func void ScreenFadeHandler(var int view, var int alpha) {
        View_SetColor(view, RGBA(0, 0, 0, alpha));
    };
    
    func void TurnScreenBackOn() {
        showPlayerStatus();
    };




    rollCredits.d – Roll credits, including screen blend/fade, music and blocking of user input with optional subsequent function call
    Mit dieses Skript erübrigt sich das lästige Credits-Video schneiden und neu rendern, wenn doch noch ein Schreibfehler auftaucht. Mit Screenblende, Hintergrundmusik, ... Dazu hier ein Beispielvideo.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * rollCredits.d
     *
     * Roll credits, including screen blend/fade, music and blocking of user input with optional subsequent function call.
     *
     * - Requires Ikarus, LeGo (View, Anim8, > 2.5.0), screenFade.d, blockAllPlayerInput.d, sound.d
     * - Compatible with Gothic 1 (untested) and Gothic 2
     *
     * Caution: The game will continue in the background. Also any FrameFunction and Anim8 instances. You have to stop them
     * individually! Do not stop the Timer or set MEM_Game.singleStep, this will also stop the credits from rolling.
     * It's best to teleport the player to a secluded location (a few seconds after starting the credits), to avoid any
     * game sounds during the credits rolling.
     *
     * For an example see rollCreditsExample() at the bottom of this file.
     *
     *
     * rollCredits  (int linesPtr, int numLines, int fadeInMS, int durationMS, int fadeOutMS)
     * rollCreditsF (int linesPtr, int numLines, int fadeInMS, int durationMS, int fadeOutMS, func postCreditFunc)
     * rollCreditsM (int linesPtr, int numLines, int fadeInMS, int durationMS, int fadeOutMS,                      string music)
     * rollCreditsFM(int linesPtr, int numLines, int fadeInMS, int durationMS, int fadeOutMS, func postCreditFunc, string music)
     */
    
    
    /*
     * Variables and constants
     */
    const string ROLLCREDITS_SKIP_MESSAGE = "[ESC] to skip";
    var   int    rollCreditsTextHeight;
    var   int    rollCreditsPostFunc;
    var   string rollCreditsMusic;
    var   string rollCreditsCurrentMusicTheme;
    
    
    /*
     * [Internal] Roll credits machinery
     */
    func void rollCreditsExt(var int linesPtr, var int numLines, var int fadeInMS, var int durationMS, var int fadeOutMS,
            var int postCreditFunc, var string music) {
        if (numLines < 1) || (!linesPtr) {
            return;
        };
    
        // Build textlines
        var string text; text = "";
        repeat(i, numLines); var int i;
            text = ConcatStrings(text, MEM_ReadStatStringArr(MEM_ReadString(linesPtr), i));
            if (i < numLines) {
                text = ConcatStrings(text, Print_LineSeperator);
            };
        end;
    
        // Call screen fade before, because of view layering
        ScreenFade(fadeInMS, durationMS+2000, fadeOutMS);
        fadeOutAllSounds(fadeInMS, 0, 0, TRUE);
        fadeOutMusic(fadeInMS, 0, 0, TRUE);
        rollCreditsCurrentMusicTheme = getCurrentMusicZoneTheme();
        setCurrentMusicZoneTheme("XXX"); // Has to be three characters long
    
    
        // Create TextField
        var int y; y = PS_VMAX;
        var int hi; hi = Print_GetFontHeight(PF_Font);
        rollCreditsTextHeight = Print_ToVirtual(hi, (hi*numLines+2));
        var int txt; txt = Print_TextField(0, y, text, PF_Font, rollCreditsTextHeight);
    
        // Create view to hold the text
        var int viewHndl; viewHndl = View_Create(0, 0, PS_VMAX, PS_VMAX);
        var zCView view; view = get(viewHndl);
        view.textLines_next = txt;
        ViewPtr_AlignText(getPtr(viewHndl), 0);
        View_Open(viewHndl);
    
        // Animate text
        var int a8; a8 = Anim8_NewExt(y, rollCreditsHandler, viewHndl, FALSE);
        Anim8_RemoveIfEmpty(a8, TRUE);
        Anim8_RemoveDataIfEmpty(a8, TRUE);
        Anim8_CallOnRemove(a8, rollCreditsPost);
        rollCreditsPostFunc = postCreditFunc;
    
        Anim8(a8, y, fadeInMS+1000, A8_Wait);
        Anim8q(a8, -(rollCreditsTextHeight*(numLines+1)), durationMS, A8_Constant);
        Anim8q(a8, -(rollCreditsTextHeight*(numLines+1)), 500, A8_Wait);
    
    
        // Block all player input (after fade in)
        FF_ApplyExtData(rollCreditsPre1, fadeInMS, 1, viewHndl);
        if (!Hlp_StrCmp(music, "")) {
            rollCreditsMusic = music;
            FF_ApplyExt(rollCreditsPre2, fadeInMS+500, 1);
        };
    };
    
    
    /*
     * Callable functions
     */
    func void rollCredits(var int linesPtr, var int numLines, var int fadeInMS, var int durationMS, var int fadeOutMS) {
        rollCreditsExt(linesPtr, numLines, fadeInMS, durationMS, fadeOutMS, /*NOFUNC*/ -1, "");
    };
    func void rollCreditsF(var int linesPtr, var int numLines, var int fadeInMS, var int durationMS, var int fadeOutMS,
            var func postCreditFunc) {
        rollCreditsExt(linesPtr, numLines, fadeInMS, durationMS, fadeOutMS, MEM_GetFuncID(postCreditFunc), "");
    };
    func void rollCreditsM(var int linesPtr, var int numLines, var int fadeInMS, var int durationMS, var int fadeOutMS,
            var string music) {
        rollCreditsExt(linesPtr, numLines, fadeInMS, durationMS, fadeOutMS, /*NOFUNC*/ -1, music);
    };
    func void rollCreditsFM(var int linesPtr, var int numLines, var int fadeInMS, var int durationMS, var int fadeOutMS,
            var func postCreditFunc, var string music) {
        rollCreditsExt(linesPtr, numLines, fadeInMS, durationMS, fadeOutMS, MEM_GetFuncID(postCreditFunc), music);
    };
    
    
    /*
     * Anim8 handler to scroll the text
     */
    func void rollCreditsHandler(var int viewHndl, var int yPos) {
        var zCView view; view = get(viewHndl);
        var int lp; lp = view.textLines_next;
        var int i; i = 1;
        while(lp);
            var zCList l; l = _^(lp);
            var zCViewText vt; vt = _^(l.data);
    
            // Exclude skip message
            if (!Hlp_StrCmp(vt.text, ROLLCREDITS_SKIP_MESSAGE)) {
                vt.posy = yPos+(rollCreditsTextHeight*i);
                i += 1;
            };
    
            lp = l.next;
        end;
    };
    
    
    /*
     * Functions called pre and post credits roll
     */
    func void rollCreditsPre1(var int viewHndl) {
        blockAllPlayerInput(1);
    
        // Allow skipping
        FF_ApplyData(rollCreditsCheckEsc, viewHndl);
    };
    func void rollCreditsPre2() {
        playMusic(rollCreditsMusic, 2);
    };
    func void rollCreditsPost() {
        unblockAllPlayerInput();
        setCurrentMusicZoneTheme(rollCreditsCurrentMusicTheme);
        if (!Hlp_StrCmp(rollCreditsCurrentMusicTheme, "")) {
            playMusic(ConcatStrings(rollCreditsCurrentMusicTheme, "_DAY_STD"), 2);
        };
        FF_Remove(rollCreditsCheckEsc);
        if (rollCreditsPostFunc > 0) {
            MEM_CallByID(rollCreditsPostFunc);
            rollCreditsPostFunc = 0;
        };
    };
    
    
    /*
     * For-each function to identify Anim8 and View to increase their velocity/timing
     */
    func int rollCreditsSkip(var int hndl) {
        // Quite ugly approach, but I don't have the handles
        var A8Head h; h = get(hndl);
        if (h.fnc != MEM_GetFuncPtr(rollCreditsHandler))
        && (h.fnc != MEM_GetFuncPtr(ScreenFadeHandler)) {
            return rContinue;
        };
    
        var int ldata; ldata = List_Get(h.queue, 2);
        var A8Command c; c = get(ldata);
        c.startVal = h.value;
        c.startTime = Timer();
        if (h.fnc == MEM_GetFuncPtr(rollCreditsHandler)) {
            c.timeSpan = mkf(1000);
        } else {
            c.timeSpan = mkf(2500);
        };
        _Anim8_SetVelo(h, c);
    };
    
    
    /*
     * Frame function to check for escape key presses
     */
    func void rollCreditsCheckEsc(var int viewHndl) {
        // Watch the escape key
        if (MEM_KeyState(KEY_ESCAPE) == KEY_PRESSED) {
            var int lastKeyPress;
            var int cTime; cTime = Timer();
    
            // Reset lastKeyPress from previous credits
            if (lastKeyPress >= cTime) {
                lastKeyPress = 0;
            };
    
            var zCView view; view = get(viewHndl);
    
            // Check if pressed twice within 2.0 seconds
            if (lastKeyPress+2000 >= cTime) {
                // Increase credits roll and fade speed
                foreachHndl(A8Head@, rollCreditsSkip);
    
                // Remove this very FF
                FF_Remove(rollCreditsCheckEsc);
            } else {
                // Otherwise create skip message
                var int ptr; ptr = Print_CreateTextPtrColored(ROLLCREDITS_SKIP_MESSAGE, PF_Font, -1);
                var zCViewText txt; txt = _^(ptr);
                var int width;
                width = Print_ToVirtual(Print_GetStringWidthPtr(txt.text, txt.font), PS_X) * PS_VMAX / view.vsizex;
                txt.posx = PS_VMAX - width - 200;
                var int height;
                height = Print_ToVirtual(Print_GetFontHeight(PF_Font), PS_Y) * PS_VMAX / view.vsizey;
                txt.posy = PS_VMAX - height - 200;
                txt.timed = TRUE;
                txt.timer = mkf(2000);
    
                // Add to view
                List_Add(view.textLines_next, ptr);
            };
    
            // Update last key press
            lastKeyPress = cTime;
        };
    };
    
    
    /*
     * Usage example function
     */
    func void rollCreditsExample() {
        const int lineNum = 16;
        const string lines[lineNum] = {
            "CREDITS",
            "",
            "",
            "Scripter           Person Person",
            "Tester             Person Person",
            "Player             Person Person",
            "",
            "ENGLSIH TRANSLATION",
            "Translator         Person Person",
            "Tester             Person Person",
            "Player             Person Person",
            "",
            "SPECIAL THANKS",
            "Player for playing",
            "",
            "The Name of the Game"
        };
    
        // End game session after credits rolled
        rollCreditsFM(_@s(lines), lineNum, 1500, 20000, 0, rollCreditsExample_after, "PIE_DAY_STD");
    
        // OR: Continue game afterwards
        //rollCreditsM(_@s(lines), lineNum, 1500, 20000, 1000, "PIE_DAY_STD");
    };
    func void rollCreditsExample_after() {
        ExitSession();
    };

  5. View Forum Posts #45 Reply With Quote
    Serima Fisk2033's Avatar
    Join Date
    Dec 2010
    Location
    Dresden
    Posts
    5,528
     
    Fisk2033 is offline
    Wow, wirklich tolle Sachen dabei! Vielen Dank fürs teilen.

  6. View Forum Posts #46 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Die Skripte hier einfach abzuladen bringt sicher niemandem was. Für Leute die bisher auch gut ohne mögliche Hilfestellungen ausgekommen sind, möchte ich noch erklären, wo die nützlich sein können.

    strings.d Keine direkten Einsatzmöglichkeiten, ausser String-Manipulationen.
    convert.d Das Skript ist vorwiegend gut fürs Debuggen und Arbeiten mit Ikarus. Hier drei Beispiele:
    Speicheradressen lassen sich direkt als Hex-Zahl in Skripte schreiben.
    Code:
    HookEngineF(h("0x68B840"), 6, hookingFunc); // Nur zum Testen so!
    Das hat allerdings den massiven Nachteil der Unleserlichkeit. Damit entsteht ein Haufen von "Magicnumbers" die man nachher nicht mehr nachvollziehen kann. Für schnelle Tests, ob man die richtige Adresse erwischt hat, ist das aber genau das richtige. Anschliessend sollte man die Zahl als Konstante mit beschreibenden Namen speichern.
    Folgendes Beispiel ist da besser:
    Code:
    MemoryProtectionOverride(addr, 1);
    MEM_WriteByte(addr, h("6A"));
    Hier interessiert niemanden, wie das Byte in Dezimaldarstellung aussieht und die Funktion erspart das manuelle "Umrechnen".
    Die wohl sinnvollste Anwendung ist es, sich Bitfelder besser anzeigen zu lassen:
    Code:
    var zCVob oth; oth = _^(her.focus_vob);
    oth.bitfield[0];          // 493 -> Welche bits sind das jetzt genau?
    dec2bin(oth.bitfield[0]); // 00000000000000000000000111101101 -> Einfacher abzulesen und mit zCVob_bitfield0_* abzugleichen
    
    searchVobs.d MEM_SeachVobByName/MEM_SearchAllVobsByName aus Ikarus benutzt sicher jeder mal irgendwann. Die Funktionen hier geben noch mehr Suchkriterien um Vobs zu finden: Nach Klasse (z.B: "oCMobContainer"), nach Visual (z.B. "OW_LOB_TREE_V6.3DS"), in einem bestimmten Umkreis oder ausserhalb eines bestimmten Umkreises. Diese Funktionen lassen sich hintereinander verketten, um die Vobsuche noch weiter einzugrenzen (z.B. Container mit bestimmten Visual, in bestimmtem Radius von einer Koordinate). Zusammen mit dem insertAnything-Skript lassen sich damit viel Storybasierende Änderungen in der Welt vornehmen oder sogar einfach die Spacerarbeit minimieren.
    Code:
    var int vobArray; vobArray = MEM_ArrayCreate();
    const float pos[3] = { 12525.603516, 1198.112549, -3076.614258 };
    
    if (SearchVobsByClass("oCMobContainer", vobArray))               // Finde alle Container in der Welt
    && (SearchVobsByVisual("CHESTSMALL_NW_POOR_OPEN.MDS", vobArray)) // Grenze die Suche ein auf ein Visual
    && (SearchVobsByProximity(_@f(pos), mkf(1000), vobArray)) {      // Grenze die Suche ein auf die Position
    
        // Im vobArray sind nun nur noch alle Vobs, die mit den Kriterien übereinstimmen
        // (Vielleicht wäre es mal Zeit für eine ForEach-Funktion für Arrays)
    
    } else {
    
        // Keine Vobs mit den Kriterien gefunden
    
    };
    MEM_ArrayFree(vobArray);
    sound.d Dieses Skript ist ein besonders gutes Instrument für Atmosphäre. Damit lassen sich alle Sounds als auch die Spielmusik aus-"faden", um z.B. ein Intro-Video oder andere Cutscene schöner heranzuführen. Ausserdem lassen sich auch Musikstücke gezielt abspielen oder ganze Musikzonen ändern (für einschneidende Storyereignisse). Ein gutes Beispiel ist das Aus-"faden" der Menu-Musik (wird als Sound abgespielt) beim Ende vom Laden für eine bessere Überleitung in das Spiel:
    Code:
    // In der Startup.d
    func void Init_Global() {
    
        // ...
    
        // Menu-Musik (Sound) am Ende des Ladebildschirms aus-"faden"
        fadeOutAllSounds(2500, 0, 1100, TRUE);
    };
    Wichtig zu Bedenken ist, dass die fadeOut-Funktionen nicht in der Startup benutzt werden können, da sie LeGo benötigen, was erst anschliessend in der Init_Global initialisiert wird. Um also den Menü-Sound vor einem Intro-Video verstummen zulassen, sollte man auf stopAllSounds() zurückgreifen.
    Was sounds.d noch so alles hergibt, kann man sich im Skript rollCredits.d anschauen.
    hidePlayerStatus.d Dazu ist nicht viel zu sagen. In einigen Hinsichten nützlicher als das hideBars-Skript, in anderen nicht (wenn es z.B. darum geht einzelne Bars zu verstecken oder anzuzeigen).
    hidePlayerStatus() muss nur einmal aufgerufen werden und alle Bars und Fokus-Informationen verschwinden und bleiben versteckt bis man showPlayerStatus() aufruft. Dieser "Zustand" wandert mit in den Speicherstand, was auch gut ist.
    blockAllPlayerInput.d Auch ziemlich selbsterklärend. Mit dem Aufruf von blockAllPlayerInput(0) werden alle Eingaben vom Spieler blockiert/ignoriert, bis unblockAllPlayerInput aufgerufen wird. Das Argument in blockAllPlayerInput(0) entscheidet, ob auch das Spielmenü (also Escape) blockiert werden soll. Darauf sollte möglichst verzichtet werden, dann wenn was schief läuft, kann der Spieler gar nichts mehr machen.
    Der "Zustand" wandert nicht mit in den Speicherstand und bleibt über die Session hinweg bestehen, man sollte also in der Init_Global immer unblockAllPlayerInput() aufrufen.
    Das Skript bietet auch einzelne Sub-Funktionen an, um bspw. nur alle InGame-Menüs oder nur die Spielersteuerung zu blockieren.
    rollCredits.d Dieses Skript bedient sich vieler der obigen Funktionen. Man kann damit Credits abspielen lassen. Dabei wird automatisch jeglicher Spieler-Input blockiert und alle Sounds und Musik ausge-"fadet". Am besten visualisiert das dieses Video (der Code dazu ist im Skript unten als Beispiel-Code enthalten).
    Im Video sieht man beim zweiten Durchlauf der Credits, was passiert, wenn man Escape drückt: Anstatt dem Spielmenü, erscheint unten rechts für einige Sekunden die Information, dass erneutes Escape-Drücken die Credits überspringt. Geschieht das, werden die Credits innerhalb einer Sekunde zu Ende gespielt.
    Das Skript ermöglicht es auch eine Funktion anzugeben, die anschliessend aufgerufen wird. In dem Video ruft diese Funktion ExitSession() auf, dort kann aber auch beliebig anderes oder gar nichts passieren. Auch bestimmte Musik kann optional abgespielt werden und erhöht das "Credits-Feeling".
    Last edited by mud-freak; 25.01.2018 at 11:45.

  7. View Forum Posts #47 Reply With Quote
    Waldläufer Siemekk's Avatar
    Join Date
    May 2016
    Posts
    119
     
    Siemekk is offline
    I have a little probelm - Why sometimes, i have crash when i'm using GetCurrentZoneActive?
    Code:
    [start of stacktrace]
    [f] 01:37 Fault: 0 Q:             MEMINT_HANDLEERROR(2, 'No music zone active.')                 +   62 bytes
    [f] 01:37 Fault: 0 Q:             MEM_WARN('No music zone active.')                              +   21 bytes
    [f] 01:37 Fault: 0 Q:             GETCURRENTMUSICZONETHEME()                                     +   26 bytes
    [f] 01:37 Fault: 0 Q:             CMUSIC_GETTHEME()                                              +    5 bytes
    [f] 01:37 Fault: 0 Q:             CMUSIC_CALLBACK()                                              +    5 bytes
    [f] 01:37 Fault: 0 Q:             FRAMEFUNCTIONS(13)                                             +  104 bytes
    [f] 01:37 Fault: 0 Q:             FOREACHHNDL(9104, FRAMEFUNCTIONS)                              +  263 bytes
    [f] 01:37 Fault: 0 Q:             [UNKNOWN]                                                      +301338389 bytes
    [f] 01:37 Fault: 0 Q:             _FF_HOOK()                                                     +   32 bytes
    [f] 01:37 Fault: 0 Q:             MEM_CALLBYID(43239)                                            +  224 bytes
    [f] 01:37 Fault: 0 Q:             _HOOK(529031632, 808577952, 0, 505315136, 20313484, 5376, 449594656, 689782792, 5376) +  498 bytes
    [f] 01:37 Fault: 0 Q:             [UNKNOWN]                                                      +305836739 bytes
    [f] 01:37 Fault: 0 Q:     [end of stacktrace]
    [w] 01:37 Warn:  0 Q:     No music zone active.
    In Access Violation screen, I have zSTRING::zSTRING operator problem? It's mistake in my scripts?

  8. View Forum Posts #48 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Quote Originally Posted by Siemekk View Post
    I have a little probelm - Why sometimes, i have crash when i'm using GetCurrentZoneActive?
    GetCurrentZoneActive is not part of the scripts here, nobody can help you with that. You would have to post the code of that function.


    The stack trace you posted is not the cause of the crash. It is only a warning, stating that there is no active music zone (at the moment or in that area). So getCurrentMusicZoneTheme returns an empty string ("").

    The crash might be, because you do operations with that empty string afterwards. You should check first if the returned string is empty.

  9. View Forum Posts #49 Reply With Quote
    Waldläufer Siemekk's Avatar
    Join Date
    May 2016
    Posts
    119
     
    Siemekk is offline
    Can you look (Full code of my music system)
    Code:
    const int oCZoneMusic_HeroStatus = 10111520;
    
    
    //-------- Library -------- //
    var int CMusic_Inited;
    var int CMusic_Library;
    var int Lib_PlayMusic;
    var int Lib_SetVolume;
    var int Lib_Tidy;
    
    
    //-------- MusicSystem -------- //
    var int CMusic_CurrentZone;
    var int CMusic_VolumeInited;
    var int CMusic_MusicVolume;
    var int CMusic_HeroStatus_Last;
    var int CMusic_LastZone;
    var string CMusic_OldTheme;
    
    
    func void CMusic_Init()
    {
        if(CMusic_Inited){ return; };
        
        CMusic_Library     = LoadLibrary("CMusic.dll");
        Lib_PlayMusic      = GetProcAddress(CMusic_Library, "PlayMusic");
        Lib_SetVolume      = GetProcAddress(CMusic_Library, "SetVolume");
        Lib_Tidy          = GetProcAddress(CMusic_Library, "Tidy");
        CMusic_Inited = true;
    };
    
    
    func void CMusic_Play(var string file, var int vol, var int IsInstant)
    {
        CMusic_Init();
        CALL_IntParam(IsInstant);
        CALL_PtrParam(vol);
        CALL_cStringPtrParam(file);
        CALL__cdecl(Lib_PlayMusic);
    };
    
    
    func void CMusic_SetVolume(var int vol)
    {
        CMusic_Init();
        CALL_PtrParam(vol);
        CALL__cdecl(Lib_SetVolume);
    };
    
    
    func void CMusic_Tidy()
    {
        CMusic_Init();
        CALL__cdecl(Lib_Tidy);
    };
    
    
    func int CMusic_GetVolume(var string vol)
    {
        var int firstChar;     firstChar     = STR_GetCharAt(vol, 0);
        var int result;     result         = mkf(1);
        
        //ToDo: Maybe use zSTRING::ToFloat Method...
        if(firstChar != 49) //'1' in ASCII
         {
            var string AfterCom;     AfterCom = STR_SubStr(vol, 2, STR_Len(vol) - 2);
            var int min; min = 4;
            if(min > STR_Len(AfterCom)){
                min = STR_Len(AfterCom);
            };
            AfterCom = STR_SubStr(vol, 2, min);
            var int ret; ret = STR_ToInt(AfterCom);
            var int mret; mret = Math_Power(10, min);
            result = divf(mkf(ret), mkf(mret));
        };
        return result;
    };
    
    
    func void CMusic_VolumeUpdate()
    {
        var string MusicVol;    MusicVol    = MEM_GetGothOpt ("SOUND", "musicVolume"); 
        var string MusicEnable;    MusicEnable = MEM_GetGothOpt ("SOUND", "musicEnabled"); 
    
    
        if(STR_ToInt(MusicEnable) == 0)
        {
            CMusic_MusicVolume = FLOATNULL;
        }
        else
        {
            CMusic_MusicVolume = CMusic_GetVolume(MusicVol);
        };
        CMusic_SetVolume(CMusic_MusicVolume);
    };
    
    
    func string CMusic_GetTheme()
    {
        return getCurrentMusicZoneTheme();
    };
    
    
    func string CMusic_GetWorldTheme()
    {
        var string zone; zone = CMusic_GetTheme();
        return CMusic_DEF_Soundtrack_NW(zone);
    };
    
    
    func string CMusic_GetFightTheme()
    {
        var string zone; zone = CMusic_GetTheme();
        return CMusic_DEF_Soundtrack_NW(zone);
    };
    
    
    func void CMusic_SetTheme()
    {
        var int IsInstant; IsInstant = 0;
        var string filename;
        var int HeroStatus; HeroStatus = MEM_ReadInt(oCZoneMusic_HeroStatus);
    
    
        filename = CMusic_GetWorldTheme();
        
        if(Hlp_StrCmp(filename, CMusic_OldTheme) && herostatus == CMusic_HeroStatus_Last)
        {
            return;
        }
        else
        {
            CMusic_OldTheme = filename;
        };
    
    
        if(HeroStatus <= 1)
        {
            filename = CMusic_GetWorldTheme();
        }
        else
        {
            filename = CMusic_GetFightTheme();
            IsInstant = true;
        };
        //Debug: ToDO:
        PrintS("New!");
        PrintS(filename);
        
        CMusic_Play(filename, CMusic_MusicVolume, IsInstant);
        CMusic_HeroStatus_Last = HeroStatus;
    };
    
    
    func void CMusic_Callback()
    {
        Print(CMusic_GetTheme());
        //return;
        if(MEM_Game.singleStep){
            return;
        };
        
        if(!CMusic_VolumeInited)
        {    
            CMusic_VolumeUpdate();
            CMusic_VolumeInited = true;
        };
    
    
        var int zone;
        var int herostatus;
        
        if(CMusic_MusicVolume == FLOATNULL){
            return;
        };
        
        //ToDO: BossFights
        zone = MEM_ReadInt(10111524);
        if(zone)
        {
            if(zone != CMusic_LastZone)
            {
                CMusic_SetTheme();
            }
            else
            {
                herostatus = MEM_ReadInt(oCZoneMusic_HeroStatus);
                
                if(herostatus != CMusic_HeroStatus_Last)
                {
                    PrintS("New oHeroStatus!");
                    var string file; file = CMusic_GetWorldTheme();
                    CMusic_SetTheme();
                    CMusic_OldTheme = file;
                };
            };
            CMusic_LastZone = zone;
        };
    
    
        CMusic_Tidy();
    };
    
    
    func void CMusic_ReInit()
    {
        CMusic_Inited        = false;
        CMusic_VolumeInited = false;
    };

  10. View Forum Posts #50 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,209
     
    Lehona is offline
    You should really start to debug your own code. At least find out where the crash actually occurs! You can use MEM_InfoBox() or MEM_Debug() (if you have debug infos turned on) to pinpoint which lines are being executed when the crash occurs. You don't even supply the definition for getCurrentMusicZoneTheme(), which is the only thing the warning points to. Unless you find out what's going wrong, we can't really figure out why it's doing that.

  11. View Forum Posts #51 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Ich habe oben in den Skripten noch zwei String-Funktionen hinzugefügt.
    STR_TrimChar ist wie STR_Trim nur mit einem Char anstatt einem String und STR_ToFloat erlaubt die Konvertierung von Strings zu Floats (Rückgabe ist aber ein Integerfloat).

    Ausserdem habe ich, auf Hinweis von Cryp18Struct, die Funktion showPlayerStatus aktualisiert, sodass sie die Bars (usw.) nicht während eines Dialogs wieder anzeigt, sondern erst anschliessend. Danke dafür!

  12. View Forum Posts #52 Reply With Quote
    Lehrling LOGX's Avatar
    Join Date
    Sep 2012
    Posts
    27
     
    LOGX is offline
    Hi mud-freak,

    Ich würde gerne dein Roll-Credits-Skript in G1 einsetzen, scheitere aber an zwei Dingen:
    1) in screenfade.d rufst du Anim8_CallOnRemove() auf, welches ich aber nicht in Anims8.d von LeGo finden kann. Ich habe Version 2.5.0, du verlangst >2.5.0 Allerdings kann ich diese Funktionalität auch im dev-Branch des LeGo-Repos nicht finden (https://app.assembla.com/spaces/lego2/subversion/source) Woher hast du eine aktuellere LeGo-Version?
    2) In deinem Beispielvideo rufst du die Credit-Funktion mittels eines "call" Commands auf. Gibt es den nur in G2 oder hast du den selbst implementiert? Wenn selbst geschrieben, gibt es dafür irgendwo eine Anleitung? So etwas wäre super praktisch zum Debuggen.

    Würde mich freuen, wenn du mir weiterhelfen könntest.

  13. View Forum Posts #53 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Quote Originally Posted by LOGX View Post
    Hi mud-freak,

    Ich würde gerne dein Roll-Credits-Skript in G1 einsetzen, scheitere aber an zwei Dingen:
    1) in screenfade.d rufst du Anim8_CallOnRemove() auf, welches ich aber nicht in Anims8.d von LeGo finden kann. Ich habe Version 2.5.0, du verlangst >2.5.0 Allerdings kann ich diese Funktionalität auch im dev-Branch des LeGo-Repos nicht finden (https://app.assembla.com/spaces/lego2/subversion/source) Woher hast du eine aktuellere LeGo-Version?
    2) In deinem Beispielvideo rufst du die Credit-Funktion mittels eines "call" Commands auf. Gibt es den nur in G2 oder hast du den selbst implementiert? Wenn selbst geschrieben, gibt es dafür irgendwo eine Anleitung? So etwas wäre super praktisch zum Debuggen.

    Würde mich freuen, wenn du mir weiterhelfen könntest.
    Die Funktion Anim8_CallOnRemove ist neulich erst zu LeGo hinzugefügt worden (daher das >2.5.0). Bis eine nächste Version von LeGo herauskommt, kannst du sie hier finden (am besten ersetzt du deine Anim8.d im LeGo-Verzeichnis mit der verlinkten). Alternativ kannst du aber auch die "alte" ScreenFade.d aus dem ScriptBin nehmen, bei der das anderes geregelt ist. Dabei müsstest du dann die Aufrufe (Argumente und erwarteter Rückgabewert) in der rollCredits.d anpassen.

    Das Skript für den Konsolenbefehl "call" (jegliche Daealus und externe Funktionen von der Konsole aufrufen) hier.

  14. View Forum Posts #54 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Hier eine Funktion, mit dem man Symbole (Variablen, Konstanten, Funktionen, Klassen, Prototypen, Instanzen) aus anderen Skripten-Typen (z.B. Menü-Skripte, PFX-Skripte, Kamera-Skripte, ...) auslesen kann. Für ein Anwendungsbeispiel siehe hier.

    Code:
    /*
     * Get symbol by name from any parser
     *
     * - Requires Ikarus
     * - Compatible with Gothic 1 and Gothic 2
     */
    func int GetAnyParserSymbol(var int parserAddr, var string symbolName) {
        var int symTab; symTab = parserAddr+16; //0x10 zCParser.symtab
        var int namePtr; namePtr = _@s(symbolName);
    
        const int zCPar_SymbolTable__GetSymbol_G1 = 7316336; //0x6FA370
        const int zCPar_SymbolTable__GetSymbol_G2 = 8011328; //0x7A3E40
    
        const int call = 0;
        if (CALL_Begin(call)) {
            CALL_PtrParam(_@(namePtr));
            CALL_PutRetValTo(_@(ret));
            CALL__thiscall(_@(symTab), MEMINT_SwitchG1G2(zCPar_SymbolTable__GetSymbol_G1, zCPar_SymbolTable__GetSymbol_G2));
            call = CALL_End();
        };
    
        var int ret;
        return +ret;
    };

  15. View Forum Posts #55 Reply With Quote
    Waldläufer Siemekk's Avatar
    Join Date
    May 2016
    Posts
    119
     
    Siemekk is offline
    FIFO List
    Small enlargement for zCList, by this three functions you can easy make FIFO List [First in, first out List].
    Code:
    func void CList_Insert(var int list, var int obj)
    {
        var zCList l;     l = _^(list);
        var zCList it; it = get(new(zCList@));
        it.data = obj;
        it.next = l.next;
        l.next     = _@(it);
    };
    
    
    func int CList_GetAt(var int list, var int nr)
    {
        var zCList l;     l = _^(list);
        var zCList it; it = _^(l.next);
        var int c;        c = 0;
        
        while(_@(it));
            if(c == nr){
                return it.data;
            };
    
    
            it = _^(it.next);
            c+=1;
        end;
        
        return l.data;
    };
    
    
    func void CList_Remove(var int list, var int obj)
    {
        var zCList l;     l = _^(list);
        while(_@(l.next) != 0);    
            if(MEM_ReadInt(l.next) == obj) /*zCList::data*/
            {
                var zCList tmp; tmp = _^(l.next);
                l.next = MEM_ReadInt(l.next + 4); /*zCList::next*/
                tmp.next = 0;
                MEM_Free(_@(tmp));
                return;
            };        
            l = _^(l.next);
        end;    
    };
    Cinemascope + update dialogbox.
    Include to game CinemaScopes for dialogs. (Don't work with D3D11)
    Code:
    func void CinemaScopes()
    {
    //    if(!COpt_CinemaScopes)
    //    {
    //        return;
    //    };
        
        if(!_@(MEM_Game))
        {
            MEM_InitGlobalInst();
        };
        
        var int Alpha;
        MEM_Game.array_view_visible[3] = true;
        MEM_Game.array_view_enabled[3] = true;
        MEM_Camera.cinemaScopeEnabled     = true;
        MEM_Camera.cinemaScopeColor     = RGBA (0, 0, 0, Alpha);
        
        if(InfoManager_HasFinished())
        {
            if (Alpha >= 5)
            {
                Alpha -= 10;
            };
            
            if (Alpha == 5)
            {
                Alpha = 0;
            };
        }
        else
        {
            if (Alpha <= 250)
            {
                Alpha += 10;
            };
    
    
            if (Alpha == 250)
            {
                Alpha = 255;
            };
        };
        
        //Update ChoiceBox
        var int ptr; ptr = MEM_ReadInt(MEMINT_oCInformationManager_Address + 28); //zCViewDialogChoice*
        var int ySize; ySize = Print_ToPixel(970, PS_Y);
        
        MEM_WriteInt(ptr + 56, 0);     //xPos
        MEM_WriteInt(ptr + 60, Print_Screen[PS_Y] - ySize);     //yPos
        MEM_WriteInt(ptr + 64, STR_ToInt (MEM_GetGothOpt ("VIDEO", "zVidResFullscreenX")));
        MEM_WriteInt(ptr + 68, ySize);
        MEM_WriteInt(ptr + 96, zCTexture_Load("CA_Alpha"));
        
        
        //Update DialogBox
        var zCView v; v = _^(MEM_Game.array_view[1]);
        v.backTex = zCTexture_Load("CA_Alpha");
        
        MEM_Call(ChangeSelectionPosition);
    };
    
    
    func void ChangeSelectionPosition()
    {    
        var int i;
        var zCViewText2 pText; 
    
    
        var zCArray arr; arr = _^ (MEM_InformationMan.DlgChoice+172); //zCViewText2* 
        if(!InfoManager_HasFinished() && arr.array)
        {        
            //Zmiana położenia
            i = 0;        
            MEM_Label(0);
            if(i < arr.NumInArray)
            {
                if(MEM_ReadIntArray(arr.array, i))
                {
                    pText = _^(MEM_ReadIntArray(arr.array, i));
                    var int fontWidth; fontWidth = Print_GetStringWidthPtr(pText.text, pText.font);        
                    var int NewX; NewX = Print_ToPixel(4096 - Print_ToVirtual(fontWidth, PS_X) / 2, PS_X);
                    pText.posx = NewX;    
                    pText.color = RGBA(255, 255, 255, 255);
                    
                    i+=1;
                    MEM_Goto(0);
                };
            };
            
            //Zmiana koloru zaznaczonej opcji
            const int null = 0;
            CALL__fastcall (MEM_InformationMan.DlgChoice, _@ (null), MEMINT_SwitchG1G2 (7705536, 6878528));
            var zCViewText2 pColor; pColor = _^(CALL_RetValAsPtr());
            pColor.color = RGBA(255, 255, 0, 255);    
        };
    };
    Now it's all from me.

  16. View Forum Posts #56 Reply With Quote
    Lehrling
    Join Date
    Mar 2017
    Location
    Ukraine
    Posts
    11
     
    Orc Hunter UA is offline
    Hallo mud-freak. Ich mache einen Mod für den ersten Teil von Gothic, und ich würde gerne in meinem Modemanagement als in Gothic 2 arbeiten. Kannst du mir dabei helfen?

  17. View Forum Posts #57 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Ich habe hier zwei Skripte, die ich teilen möchte. Das erste ist ein Hilfsskript, um die Zeit nur über Aufrufe von bestimmten Funktionen zu zählen und sich Trigger oder Pulse in bestimmter Frequenz zu holen. Das zweite ermöglicht bequemes und performantes Auswechseln von Texturen aller Standardbars (HP, Mana, Schwimmen, Fokus). Im Falle der Schwimm-Bar werden einem auch Informationen über den verbleibenden Atem in Prozent bereitgestellt. In einem enthaltenen Beispel wird das benutzt, um die Bar blinken zu lassen, wenn man unter 40% kommt.


    freqTimer.d – This script offers triggers and pulses at certain frequency tracked for individual functions.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * freqTimer.d
     *
     * Get triggers or pulses at certain frequencies, see https://forum.worldofplayers.de/forum/threads/?p=25919441
     *
     * - Requires Ikarus 1.2.1 (!)
     * - Compatible with Gothic 1 and Gothic 2
     */
    
    
    /*
     * Return one of two pulse states (on or off) at certain frequency.
     *
     * Call this function in the following fashion:
     *
     *    var int timerVar;
     *    var int state; state = freqPulse(_@(timerVar), X);
     *
     * where X is an integer specifying the frequency in Hz, e.g. 2 for twice a second.
     * The variable "state" will then be either 1 or 0, depending on time.
     */
    func int freqPulse(var int timerPtr, var int frequencyHz) {
        var int timer; timer = MEM_ReadInt(timerPtr) + MEM_Timer.frameTime;
        var int interval; interval = 1000 / frequencyHz;
        timer = timer % (interval * 2);
        MEM_WriteInt(timerPtr, timer);
        return timer < interval;
    };
    
    
    /*
     * Return a trigger at certain frequency.
     *
     * Call this function in the following fashion:
     *
     *    var int timerVar;
     *    var int nTriggered; nTriggered = freqPulse(_@(timerVar), X);
     *
     * where X is an integer specifying the frequency in Hz, e.g. 2 for twice a second.
     * The variable "nTriggered" will contain the number of times the frequency matched since the last call.
     */
    func int freqTrigger(var int timerPtr, var int frequencyHz) {
        var int timer; timer = MEM_ReadInt(timerPtr) + MEM_Timer.frameTime;
        var int interval; interval = 1000 / frequencyHz;
        MEM_WriteInt(timerPtr, timer % interval);
        return timer / interval;
    };



    overrideBars.d – Conviniently override the texture of the standard bars (hp, mana, swim, focus).
    An example for flashing the swim bar when running out of breath is included that requires the above script.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * overrideBars.d
     *
     * Change the texture of the bars, e.g. for visualizing a poisoned state.
     *
     * - Requires Ikarus, LeGo (HookEngine), freqTimer (optional)
     * - Compatible with Gothic 1 and Gothic 2
     *
     * Instructions
     * - Add additional bar textures (if desired).
     * - Adjust the customizable functions that determine the bar textures, see example for red-flashing swim bar.
     * - Initialize from Init_Global with
     *     overrideBars_Init(BAR_ALL);
     *   where BAR_ALL == BAR_HP | BAR_MANA | BAR_SWIM | BAR_FOCUS
     */
    
    
    const int BAR_NONE   = 0; // Internal, do not use/change
    const int BAR_RED    = 1;
    const int BAR_BLUE   = 2;
    const int BAR_YELLOW = 3;
    
    const int BAR_MAX    = 4;
    
    const string BAR_TEX[BAR_MAX] = {
        "",                // BAR_NONE
        "BAR_HEALTH",      // BAR_RED
        "BAR_MANA",        // BAR_BLUE
        "BAR_MISC"         // BAR_YELLOW
    };
    
    
    /*
     * Customizable functions that determine the bar texture for NPCs
     */
    func int getNPCHealthState(var C_Npc npc) {
        // Change the texture by condition, e.g. (N)PC is poisoned
        if (FALSE) {
            return BAR_YELLOW;
        };
    };
    
    func int getPCManaState() {
        // Change the texture by condition, e.g. magic is disabled
        if (FALSE) {
            return BAR_YELLOW;
        };
    };
    
    func int getPCSwimState(var int remainingBreathPercent) {
        // EXAMPLE: Flash the swim bar red (8 Hz) when there is less than 40% breath left
        var int flashTimer;
        return (remainingBreathPercent < 40) * freqPulse(_@(flashTimer), 8) * BAR_RED;
    };
    
    
    
    /*
     * Main update function
     */
    func void overrideBar(var int barPtr, var int texID) {
        var oCViewStatusBar bar; bar = _^(barPtr);
        ViewPtr_SetTexture(bar.value_bar, MEM_ReadStatStringArr(BAR_TEX, texID));
    };
    
    
    /*
     * Hooking function when drawing the health bar
     */
    func void _updateHealthBar() {
        const int SET = BAR_RED;
        var int now; now = getNPCHealthState(hero);
        if (!now) {
            now = BAR_RED;
        };
        if (now != SET) {
            overrideBar(MEMINT_SwitchG1G2(ECX, EAX), now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the swim bar
     */
    func void _updateSwimBar() {
        const int SET = BAR_YELLOW;
    
        // Get remaining breath in percent
        var int divectr; divectr = MEM_ReadInt(ESP+28); // esp+0x80-0x64
        var int gil; gil = hero.guild;
        if (gil < GIL_SEPERATOR_HUM) {
            gil = 1;
        };
        var int divetime; divetime = MEM_ReadStatArr(Gil_Values.DIVE_TIME, gil);
        var int remainingBreath; remainingBreath = roundf(divectr) / 10 / divetime;
    
        var int now; now = getPCSwimState(remainingBreath);
        if (!now) {
            now = BAR_YELLOW;
        };
        if (now != SET) {
            overrideBar(EDX, now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the mana bar
     */
    func void _updateManaBar() {
        const int SET = BAR_BLUE;
        var int now; now = getPCManaState();
        if (!now) {
            now = BAR_BLUE;
        };
        if (now != SET) {
            overrideBar(EAX, now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the focus bar
     */
    func void _updateFocusBar() {
        const int SET = BAR_RED;
        var C_Npc npc; npc = _^(MEMINT_SwitchG1G2(EBP, EDI));
        var int now; now = getNPCHealthState(npc);
        if (!now) {
            now = BAR_RED;
        };
        if (now != SET) {
            overrideBar(MEMINT_SwitchG1G2(ECX, EDX), now);
            SET = now;
        };
    };
    
    
    const int BAR_HP     = 1<<0;
    const int BAR_MANA   = 1<<1;
    const int BAR_SWIM   = 1<<2;
    const int BAR_FOCUS  = 1<<3;
    const int BAR_ALL    = (1<<4) - 1;
    
    /*
     * Initialization function
     */
    func void overrideBars_Init(var int flags) {
        MEM_InitAll();
    
        const int oCGame__UpdatePlayerStatus_hpbar_G1    = 6524982; //0x639036
        const int oCGame__UpdatePlayerStatus_hpbar_G2    = 7090787; //0x6C3263
        const int oCGame__UpdatePlayerStatus_swimbar_G1  = 6525204; //0x639114
        const int oCGame__UpdatePlayerStatus_swimbar_G2  = 7091050; //0x6C336A
        const int oCGame__UpdatePlayerStatus_manabar_G1  = 6525379; //0x6391C3
        const int oCGame__UpdatePlayerStatus_manabar_G2  = 7091233; //0x6C3421
        const int oCGame__UpdatePlayerStatus_focusbar_G1 = 6525725; //0x63931D
        const int oCGame__UpdatePlayerStatus_focusbar_G2 = 7091981; //0x6C370D
    
        if (flags & BAR_HP) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_hpbar_G1,
                                           oCGame__UpdatePlayerStatus_hpbar_G2), 6, _updateHealthBar);
        };
    
        if (flags & BAR_SWIM) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_swimbar_G1,
                                           oCGame__UpdatePlayerStatus_swimbar_G2), 6, _updateSwimBar);
        };
    
        if (flags & BAR_MANA) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_manabar_G1,
                                           oCGame__UpdatePlayerStatus_manabar_G2), 6, _updateManaBar);
        };
    
        if (flags & BAR_FOCUS) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_focusbar_G1,
                                           oCGame__UpdatePlayerStatus_focusbar_G2), MEMINT_SwitchG1G2(9,
                                                                                                      6), _updateFocusBar);
        };
    };
    Last edited by mud-freak; 21.02.2019 at 23:50. Reason: freqTimer gefixt und vereinfacht

  18. View Forum Posts #58 Reply With Quote
    Serima Fisk2033's Avatar
    Join Date
    Dec 2010
    Location
    Dresden
    Posts
    5,528
     
    Fisk2033 is offline
    Quote Originally Posted by mud-freak View Post
    Ich habe hier zwei Skripte, die ich teilen möchte. Das erste ist ein Hilfsskript, um die Zeit nur über Aufrufe von bestimmten Funktionen zu zählen und sich Trigger oder Pulse in bestimmter Frequenz zu holen. Das zweite ermöglicht bequemes und performantes Auswechseln von Texturen aller Standardbars (HP, Mana, Schwimmen, Fokus). Im Falle der Schwimm-Bar werden einem auch Informationen über den verbleibenden Atem in Prozent bereitgestellt. In einem enthaltenen Beispel wird das benutzt, um die Bar blinken zu lassen, wenn man unter 40% kommt.


    freqTimer.d – This script offers triggers and pulses at certain frequency tracked for individual functions.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * freqTimer.d
     *
     * Get triggers or pulses at certain frequencies.
     *
     * - Requires Ikarus
     * - Compatible with Gothic 1 and Gothic 2
     *
     *
     * When using Gothic 1, initialize from Init_Global with
     *    freqTimer_Init();
     */
    
    
    /*
     * Return one of two pulse states (on or off) at certain frequency.
     *
     * Call this function in the following fashion:
     *
     *    var int timerVar;
     *    var int state; state = freqPulse(_@(timerVar), X);
     *
     * where X is an integer specifying the frequency in Hz, e.g. 2 for twice a second.
     * The variable "state" will then be either 1 or 0, depending on time.
     */
    func int freqPulse(var int timerPtr, var int frequencyHz) {
        var int timer; timer = MEM_ReadInt(timerPtr);
        var int interval; interval = 1000 / frequencyHz;
        MEM_WriteInt(timerPtr, timer + MEM_Timer.frameTime);
        if (timer >= interval * 2) {
            MEM_WriteInt(timerPtr, timer - interval * 2);
        };
    
        if (timer < interval) {
            return TRUE;
        } else {
            return FALSE;
        };
    };
    
    
    /*
     * Return a trigger at certain frequency.
     *
     * Call this function in the following fashion:
     *
     *    var int timerVar;
     *    var int trigger; trigger = freqPulse(_@(timerVar), X);
     *
     * where X is an integer specifying the frequency in Hz, e.g. 2 for twice a second.
     * The variable "trigger" will then be 1, only at the times where the frequency is matched, e.g. twice a second.
     */
    func int freqTrigger(var int timerPtr, var int frequencyHz) {
        var int timer; timer = MEM_ReadInt(timerPtr);
        var int interval; interval = 1000 / frequencyHz;
        MEM_WriteInt(timerPtr, timer + MEM_Timer.frameTime);
        if (timer >= interval) {
            MEM_WriteInt(timerPtr, timer - interval);
            return TRUE;
        } else {
            return FALSE;
        };
    };
    
    
    /*
     * Initialization only necessary for Gothic 1
     */
    func void freqTimer_Init() {
        const int once = 0;
        if (!once) {
            // Fix zTimer for Gothic 1 (the address in Ikarus is wrong)
            if (GOTHIC_BASE_VERSION == 1) {
                MEMINT_zTimer_Address = 9236968; //0x8CF1E8
                MEM_Timer = _^(MEMINT_zTimer_Address);
            };
            once = 1;
        };
    };



    overrideBars.d – Conviniently override the texture of the standard bars (hp, mana, swim, focus).
    An example for flashing the swim bar when running out of breath is included that requires the above script.
    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * overrideBars.d
     *
     * Change the texture of the bars, e.g. for visualizing a poisoned state.
     *
     * - Requires Ikarus, LeGo (HookEngine), freqTimer (optional)
     * - Compatible with Gothic 1 and Gothic 2
     *
     * Instructions
     * - Add additional bar textures (if desired).
     * - Adjust the customizable functions that determine the bar textures, see example for red-flashing swim bar.
     * - Initialize from Init_Global with
     *     overrideBars_Init(BAR_ALL);
     *   where BAR_ALL == BAR_HP | BAR_MANA | BAR_SWIM | BAR_FOCUS
     */
    
    
    const int BAR_NONE   = 0; // Internal, do not use/change
    const int BAR_RED    = 1;
    const int BAR_BLUE   = 2;
    const int BAR_YELLOW = 3;
    
    const int BAR_MAX    = 4;
    
    const string BAR_TEX[BAR_MAX] = {
        "",                // BAR_NONE
        "BAR_HEALTH",      // BAR_RED
        "BAR_MANA",        // BAR_BLUE
        "BAR_MISC"         // BAR_YELLOW
    };
    
    
    /*
     * Customizable functions that determine the bar texture for NPCs
     */
    func int getNPCHealthState(var C_Npc npc) {
        // Change the texture by condition, e.g. (N)PC is poisoned
        if (FALSE) {
            return BAR_YELLOW;
        };
    };
    
    func int getPCManaState() {
        // Change the texture by condition, e.g. magic is disabled
        if (FALSE) {
            return BAR_YELLOW;
        };
    };
    
    func int getPCSwimState(var int remainingBreathPercent) {
        // EXAMPLE: Flash the swim bar red (8 Hz) when there is less than 40% breath left
        var int flashTimer;
        return (remainingBreathPercent < 40) * freqPulse(_@(flashTimer), 8) * BAR_RED;
    };
    
    
    
    /*
     * Main update function
     */
    func void overrideBar(var int barPtr, var int texID) {
        var oCViewStatusBar bar; bar = _^(barPtr);
        ViewPtr_SetTexture(bar.value_bar, MEM_ReadStatStringArr(BAR_TEX, texID));
    };
    
    
    /*
     * Hooking function when drawing the health bar
     */
    func void _updateHealthBar() {
        const int SET = BAR_RED;
        var int now; now = getNPCHealthState(hero);
        if (!now) {
            now = BAR_RED;
        };
        if (now != SET) {
            overrideBar(MEMINT_SwitchG1G2(ECX, EAX), now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the swim bar
     */
    func void _updateSwimBar() {
        const int SET = BAR_YELLOW;
    
        // Get remaining breath in percent
        var int divectr; divectr = MEM_ReadInt(ESP+28); // esp+0x80-0x64
        var int gil; gil = hero.guild;
        if (gil < GIL_SEPERATOR_HUM) {
            gil = 1;
        };
        var int divetime; divetime = MEM_ReadStatArr(Gil_Values.DIVE_TIME, gil);
        var int remainingBreath; remainingBreath = roundf(divectr) / 10 / divetime;
    
        var int now; now = getPCSwimState(remainingBreath);
        if (!now) {
            now = BAR_YELLOW;
        };
        if (now != SET) {
            overrideBar(EDX, now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the mana bar
     */
    func void _updateManaBar() {
        const int SET = BAR_BLUE;
        var int now; now = getPCManaState();
        if (!now) {
            now = BAR_BLUE;
        };
        if (now != SET) {
            overrideBar(EAX, now);
            SET = now;
        };
    };
    
    
    /*
     * Hooking function when drawing the focus bar
     */
    func void _updateFocusBar() {
        const int SET = BAR_RED;
        var C_Npc npc; npc = _^(MEMINT_SwitchG1G2(EBP, EDI));
        var int now; now = getNPCHealthState(npc);
        if (!now) {
            now = BAR_RED;
        };
        if (now != SET) {
            overrideBar(MEMINT_SwitchG1G2(ECX, EDX), now);
            SET = now;
        };
    };
    
    
    const int BAR_HP     = 1<<0;
    const int BAR_MANA   = 1<<1;
    const int BAR_SWIM   = 1<<2;
    const int BAR_FOCUS  = 1<<3;
    const int BAR_ALL    = (1<<4) - 1;
    
    /*
     * Initialization function
     */
    func void overrideBars_Init(var int flags) {
        MEM_InitAll();
    
        const int oCGame__UpdatePlayerStatus_hpbar_G1    = 6524982; //0x639036
        const int oCGame__UpdatePlayerStatus_hpbar_G2    = 7090787; //0x6C3263
        const int oCGame__UpdatePlayerStatus_swimbar_G1  = 6525204; //0x639114
        const int oCGame__UpdatePlayerStatus_swimbar_G2  = 7091050; //0x6C336A
        const int oCGame__UpdatePlayerStatus_manabar_G1  = 6525379; //0x6391C3
        const int oCGame__UpdatePlayerStatus_manabar_G2  = 7091233; //0x6C3421
        const int oCGame__UpdatePlayerStatus_focusbar_G1 = 6525725; //0x63931D
        const int oCGame__UpdatePlayerStatus_focusbar_G2 = 7091981; //0x6C370D
    
        if (flags & BAR_HP) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_hpbar_G1,
                                           oCGame__UpdatePlayerStatus_hpbar_G2), 6, _updateHealthBar);
        };
    
        if (flags & BAR_SWIM) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_swimbar_G1,
                                           oCGame__UpdatePlayerStatus_swimbar_G2), 6, _updateSwimBar);
        };
    
        if (flags & BAR_MANA) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_manabar_G1,
                                           oCGame__UpdatePlayerStatus_manabar_G2), 6, _updateManaBar);
        };
    
        if (flags & BAR_FOCUS) {
            HookEngineF(+MEMINT_SwitchG1G2(oCGame__UpdatePlayerStatus_focusbar_G1,
                                           oCGame__UpdatePlayerStatus_focusbar_G2), MEMINT_SwitchG1G2(9,
                                                                                                      6), _updateFocusBar);
        };
    };
    Vielen Dank! Vor allem für die ausführliche Doku mit Beispiel.

  19. View Forum Posts #59 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,209
     
    Lehona is offline
    Gute Arbeit, aber ich verstehe den Unterschied zwischen freqPulse und freqTrigger noch nicht so richtig (und in deiner Dokumentation hast du ausversehen das Snippet von freqPulse für freqTrigger angegeben).

  20. View Forum Posts #60 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,391
     
    mud-freak is offline
    Quote Originally Posted by Lehona View Post
    Gute Arbeit, aber ich verstehe den Unterschied zwischen freqPulse und freqTrigger noch nicht so richtig (und in deiner Dokumentation hast du ausversehen das Snippet von freqPulse für freqTrigger angegeben).
    Das Frequenz-Skript habe ich nur hinzugefügt, weil ich es in dem Beispiel für die Schwimm-Bar benutzt habe. Da ist mir dann die Lust am Dokumentieren vergangen (vor allem, weil die Funktionen sehr speziell sind und ich nicht glaube, dass sie häufig verwendet werden). Ich gebe zu, dass die beiden Funktionen nicht gut bis gar nicht erklärt sind.

    Zur generellen Idee:
    Normalerweise ist man ja mit dem Timer von LeGo gut bedient, um Zeiten abzufragen. Wenn man allerdings ein Intervall benötigt (mache X alle Y Millisekunden) wird es problematisch, wenn man das Spiel pausiert (weil die Zeit weiterläuftt). Neuerdings/bald gibt es dafür den Game-Timer in LeGo, der nur läuft, wenn das Spiel nicht pausiert ist. Ich habe das Problem noch einen Schritt weiter genommen. Ich wollte, dass die Zeit nur weiter gezählt wird, in den Frames in denen meine Funktion aufgerufen wird.
    Mit den Frequenz-Funktionen kann ich mir jetzt individuell für eine Funktion Trigger oder Pulse geben lasssen, wobei ich Trigger und Pulse hier für mich so definiere:

    [Bild: 4iIIqTfreqTimer.png]

    Im Beispiel für die blinkende Schwimm-Bar werden Pulse verwendet, um sie für die gleiche Dauer rot und gelb anzuzeigen.

Page 3 of 6 « First 123456 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