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

 

Results 1 to 20 of 20
  1. View Forum Posts #1 Reply With Quote
    Legend of Ahssûn TheEternal's Avatar
    Join Date
    Jun 2013
    Location
    Frankfurt
    Posts
    4,297
     
    TheEternal is offline

    Script function via Gothic Konsole

    Gibt es ne möglichkeit, wie man Deadalus script Funktionen von der Konsole aus aufrufen kann?

    Das brauchen wir besonders für Workarounds während des testing, um nicht jedes mal einen Patch basteln zu müssen.
    [Bild: LoA_Banner_Skyline2.jpg]
    LoA Website
    Checkout Cloudevo: unlimited Cloud-Drive


  2. View Forum Posts #2 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Dafür sollte man perfekt die ConsoleCommands von LeGo verwenden können. Wenn du mir ein paar Minuten gibst schreib ich dir ein Beispiel.

  3. View Forum Posts #3 Reply With Quote
    Legend of Ahssûn TheEternal's Avatar
    Join Date
    Jun 2013
    Location
    Frankfurt
    Posts
    4,297
     
    TheEternal is offline
    das wär echt toll.

    Kann es sein, dass man vorher jeden Befehl registrieren muss, denn man verwenden will, oder kann man direkt sagen: füge alle bekannten/geparsten Funktionen aus der Gothic.DAT hinzu?
    [Bild: LoA_Banner_Skyline2.jpg]
    LoA Website
    Checkout Cloudevo: unlimited Cloud-Drive

    Last edited by TheEternal; 02.05.2017 at 21:48.

  4. View Forum Posts #4 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Ich hatte das viel genereller gedacht. Anstatt all nötigen Funktion einzeln zu registrieren, habe ich eine Funktion geschrieben, die Funktionen aufrufen kann. Dabei ist die Funktionssignatur (Anzahl oder Typ der Argumente) nicht festgelegt, sondern wird automatisch ermittelt.
    Das ganze sieht dann so aus.
    Hier unsere Funktion, die einen String und zwei Integer als Argumente nimmt.
    Code:
    func string testFunc(var string str, var int a, var int b) {
        str = ConcatStrings(str, ": ");
        str = ConcatStrings(str, IntToString(a+b));
        return str;
    };
    So kann man sie über die Konsole aufrufen:
    [Bild: callFunc.png]


    So wie ich das geschrieben habe gibt es drei Einschränkungen (die man aber umgehen kann):
    1. Die aufzurufene Funktion muss einen String zurückgeben (das kann man aber auch rausnehmen).
    2. Die Argumente dürfen keine Leerzeichen enthalten (die Delimiter kann man aber auch in Kommas oder Semikolons ändern)
    3. Nummern als Argumente werden immer als Integer und nie als String interpretiert

    Zu beachten ist noch folgendes:
    1. Es gibt keine Autovervollständigung für etwaige Funktionen (sonst müssten sie tatsächlich alle einzeln registriert werden). Man muss den Funktionsnamen und die Anzahl und Reihenfolge der Argument also genau wissen.
    2. Es kann zu Abstürzen kommen, wenn man sich vertippt.
    3. Für jedes String-Argument kommt eine Warnung im zSpy, aber das ist nicht weiter schlimm. Das liegt, daran wie getestet wird ob es sich um einen String oder um einen Integer handelt.

    Code:
    /*
     * Call a deadalus function with arbitrary signature (arguments) from console
     * Limitations:
     * - The called function must return a string
     * - No spaces in arguments allowed
     * - Numbers are always interpreted as integers
     */
    func string callFunc(var string command) {
    
        // Retrieve number of arguments
        var int nArgs; nArgs = STR_SplitCount(command, " ")-1;
    
        // Loop over arguments and push them onto the stack
        var int i;
        repeat(i, nArgs);
            // Get current argument
            var string arg; arg = STR_Split(command, " ", i+1);
    
            // Check if it is an integer or a string
            if (Hlp_StrCmp(IntToString(STR_ToInt(arg)), arg)) {
                MEM_PushIntParam(STR_ToInt(arg));
            } else {
                MEM_PushStringParam(arg);
            };
        end;
    
        // Call the function
        MEM_CallByString(STR_Split(command, " ", 0));
    
        // Return the return string of the function
        return MEM_PopStringResult();
    };
    Last edited by mud-freak; 02.05.2017 at 22:29.

  5. View Forum Posts #5 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,300
     
    Lehona is offline
    Quote Originally Posted by TheEternal View Post
    das wär echt toll.

    Kann es sein, dass man vorher jeden Befehl registrieren muss, denn man verwenden will, oder kann man direkt sagen: füge alle bekannten/geparsten Funktionen aus der Gothic.DAT hinzu?
    Prinzipiell muss man jeden Befehl erst registrieren, aber wie mud-freak schon "angedeutet" hat kann man sich das natürlich so zurechtbauen, dass alle Daedalus-Funktionen über die Konsole verfügbar sind.

    Ich habe den ConsoleCommands-Artikel im Wiki jetzt erstellt - für ein richtiges Beispiel habe ich heute keine Zeit mehr. Daher die ganz knappe Version:

    Code:
    func string sayNo(var string s) {
        return "No!";
    };
    
    // Initialisierung
    CC_Register("myCommand", sayNo, "just says no");
    Gibt man jetzt "myCommand" (ohne Anführungszeichen, Groß-/Kleinschreibung egal) in der Konsole ein, wird die Funktion sayNo() aufgerufen. Danach wird "No!" in der Konsole angezeigt (weil das eben der Rückgabewert ist).

    Gibt man zum Beispiel "myCommand hello" in die Konsole ein, hat der Parameter s den Wert "hello" (im ersten Fall ist er einfach leer bzw. "").

  6. View Forum Posts #6 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Mein Skript war vielleicht etwas zu vorschnell. Wenn es um einzelne Funktionen geht, ist es besser diese einfach als Konsolenbefehl zu registrieren, wie Lehona schreibt.

    Mir ging es um die Möglichkeit, jede Funktion aufrufen zu können, ohne diese vorher registrieren zu müssen. Ich habe gestern noch ein wenig weitergemacht mit der Spielerei. Aus dieser Spielerei könnte ein starkes Debugging-Tool werden, wenn sämtliche Funktionen mit jeglicher Art von Argument aus der Konsole aufrufbar werden. Deshalb will ich noch ein bisschen in der Idee verharren. Ich bin gestern nicht ganz fertig geworden, um den Code zu teilen, aber hier ein paar Sachen, die ich noch hinzugefügt habe:
    • Man kann nicht nur Strings und Integer als Argumente übergeben, sondern auch Variablen, und auch Instanzen (z.B. PC_Hero). Die werden automatisch erkannt. Damit kann man z.B. problemlos Funktionen aufrufen wie: B_StopLookAt(var C_NPC npc).
    • Der Returntyp einer Funktion wird automatisch ermittelt (und ggf. auf der Konsole ausgegeben), sodass man nicht daran gebunden ist und tatsächlich jede Funktion aufrufen kann (egal ob void, int, string oder Instanz).
    • Auch Externals können aufgerufen werden.
    • Was noch nicht ganz fertig ist, ist die Angleichung an die Skript Syntax um Strings von Variablen zu unterscheiden, also: Funktion(hero, "hero")

    Warum ich es noch nicht teile ist, weil Instanzen als Argumente sich gegenseitig überschreiben. Z.B. ein Aufruf von B_Attack(PC_ThiefOw,hero,0,0) funktioniert nicht, da PC_ThiefOW mit hero überschrieben wird. Das muss ich noch korrigieren.
    An den Rückgabetyp komm ich übrigens über das Parsersymbol der Funktion (sym.offset >> 12 == zPAR_TYPE_INT usw.). Hat jemand eine Idee, ob man auch die Argumente ermitteln kann? Ich gehe davon aus, dass das nicht geht. So kommt es nämlich immer zu Abstürzen, wenn die Anzahl oder Typ der Argumente nicht stimmt.


    @Lehona: Danke für die Einträge zu CC im Wiki! Sieht sehr gut aus. Ich habe einen kleinen "Fehler" entdeckt. Das Argument description wird nicht angezeigt, falls man keine weiteren Parameter eingibt, sondern dient tatsächlich einfach als Beschreibung des Befehls, sollte man help in der Konsole eingeben. Ich weiss nicht, ob ich das im Wiki vielleicht nur missverstanden habe.

  7. View Forum Posts #7 Reply With Quote
    research NicoDE's Avatar
    Join Date
    Dec 2004
    Posts
    7,405
     
    NicoDE is offline
    Quote Originally Posted by mud-freak View Post
    Hat jemand eine Idee, ob man auch die Argumente ermitteln kann?
    Die Anzahl der Parameter sollte im Symbol der Funktion stehen und die Symbole der Parameter (sind Variablen mit <FuncName>.<ParamName>) sollten direkt darauf folgen und die Funktion als Parent haben.
    "Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor

  8. View Forum Posts #8 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Ich habe gerade den Code von vor einem halben Jahr wieder entdeckt und ihn zu Ende geschrieben. Der ist nicht besonders schön und vor allem nicht übersichtlich, aber ich hatte keine Lust mehr den noch weiter zu überarbeiten.

    Damit steht nun eine, wie ich finde, sehr mächtige Debugging-Möglichkeit zur Verfügung:
    Sämtliche Funktionen (ob Skriptfunktion oder External) lassen sich aus der Konsole aufrufen, egal was für Parametertypen oder Rückgabewerte.

    Während man mit den ConsoleCommands schon im laufenden Spiel in alle Variablen hineinschauen und -schreiben kann (dazu muss man sich nur jeweilige Funktionen als ConsoleCommand registrieren), kann man jetzt beliebige Funktionen ausführen, die man nicht vorher zu einem ConsoleCommand zuschneiden muss.
    Z.B. kann man NPCs jegliche AI_*-Funktionen ausführen lassen.
    Code:
    call AI_TurnToNpc pc_thief pc_hero
    Nach call, kommt der Funktionsname, anschliessend die Argumente. Jeweils mit Leerzeichen getrennt (schönere Syntax war mir zu viel Arbeit, bzw. ist auch nervig beim Eingeben in der Konsole). Gross- und Kleinschreibung spielt keine Rolle. Mögliche Rückgabewerte der Funktion werden sinnvoll auf der Konsole ausgegeben.
    Symbolnamen, so wie hier pc_thief, werden automatisch erkannt, sodass man für Integerparameter sowohl Zahlen als auch Intergerparameter angeben kann, z.B.
    Code:
    call inttostring 42
    call inttostring SPL_Firerain
    Ebenso geht das mit Strings
    Code:
    call print "Suchender"
    call print NAME_Dementor
    Ein wirklich sinnvolles Beispiel wäre das Triggern von Kapiteln:
    Code:
    call b_kapitelwechsel 3 CurrentLevel
    Andere wirklich nützliche Beispiel konnte ich jetzt noch nicht bringen, aber man könnte diesen Konsolenbefehl auch präventiv in seine Mods einbauen, um Spielern mögliche Workarounds anzubieten, bis ein schwerwiegender Bug per Patch gefixt werden kann.




    Skript:
    Code:
    /*
     * Call any function (including externals) from console
     */
    
    
    /*
     * Initialization function
     */
    func void CC_CallInit() {
        CC_Register(CC_Call, "call ", "Call any daedalus or external function");
    };
    
    
    /*
     * Push symbol of almost any type onto the stack
     */
    func int CC_Call_PushSymbol(var int symbID) {
        var zCPar_Symbol symb; symb = _^(MEM_GetSymbolByIndex(symbID));
    
        if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INSTANCE) {
            // What is this: See MEMINT_PushStringParamSub()
            var int n; n += 1; if (n == 10) { n = 0; };
            if (n == 0) { var MEMINT_HelperClass inst0; inst0 = _^(symb.offset); MEM_PushInstParam(inst0); };
            if (n == 1) { var MEMINT_HelperClass inst1; inst1 = _^(symb.offset); MEM_PushInstParam(inst1); };
            if (n == 2) { var MEMINT_HelperClass inst2; inst2 = _^(symb.offset); MEM_PushInstParam(inst2); };
            if (n == 3) { var MEMINT_HelperClass inst3; inst3 = _^(symb.offset); MEM_PushInstParam(inst3); };
            if (n == 4) { var MEMINT_HelperClass inst4; inst4 = _^(symb.offset); MEM_PushInstParam(inst4); };
            if (n == 5) { var MEMINT_HelperClass inst5; inst5 = _^(symb.offset); MEM_PushInstParam(inst5); };
            if (n == 6) { var MEMINT_HelperClass inst6; inst6 = _^(symb.offset); MEM_PushInstParam(inst6); };
            if (n == 7) { var MEMINT_HelperClass inst7; inst7 = _^(symb.offset); MEM_PushInstParam(inst7); };
            if (n == 8) { var MEMINT_HelperClass inst8; inst8 = _^(symb.offset); MEM_PushInstParam(inst8); };
            if (n == 9) { var MEMINT_HelperClass inst9; inst9 = _^(symb.offset); MEM_PushInstParam(inst9); };
            return TRUE;
        } else if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INT)
        || ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_FLOAT) {
            MEM_PushIntParam(symb.content);
            return TRUE;
        } else if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_STRING) {
            MEM_PushStringParam(MEM_ReadString(symb.content));
            return TRUE;
        } else if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_FUNC) {
            MEM_PushIntParam(symbID);
            return TRUE;
        } else {
            // zPAR_TYPE_CLASS
            // zPAR_TYPE_PROTOTYPE
            return FALSE;
        };
    };
    
    
    /*
     * Console command function to call any deadalus or external function from the console in-game
     */
    func string CC_Call(var string query) {
        if (Hlp_StrCmp(query, "")) || (Hlp_StrCmp(query, " ")) {
            return "";
        };
    
        // Find function name
        var string funcName;
        var string args;
        var int i; i = STR_IndexOf(query, " ");
        if (i != -1) {
            funcName = STR_SubStr(query, 0, i);
            args = STR_SubStr(query, i, STR_Len(query)-i);
        } else {
            funcName = query;
            args = "";
        };
    
        // Find function symbol by function name
        var int fSymbID; fSymbID = MEM_GetSymbolIndex(funcName);
        if (fSymbID < 0) || (fSymbID >= currSymbolTableLength) {
            return ConcatStrings("Function not found: ", funcName);
        };
        var zCPar_Symbol fSymb; fSymb = _^(MEM_GetSymbolByIndex(fSymbID));
    
        // Verify that it is a function
        if ((fSymb.bitfield & zCPar_Symbol_bitfield_type) != zPAR_TYPE_FUNC) {
            return ConcatStrings("Symbol is not a function: ", funcName);
        };
    
        // Get number of function paramerters
        var int numParams; numParams = (fSymb.bitfield & zCPar_Symbol_bitfield_ele);
    
        // Get return type
        var int retType; retType = fSymb.offset << 12;
    
        // Validate arguments against parameters
        if (numParams) {
            // Remaining argument string
            var string rArgs; rArgs = args;
            var zString zrArgs; zrArgs = _^(_@s(rArgs));
    
            // Parameter types
            const string SYMBOL_TYPES[8] = {
                "void",         // zPAR_TYPE_VOID
                "float",        // zPAR_TYPE_FLOAT
                "int",          // zPAR_TYPE_INT
                "string",       // zPAR_TYPE_STRING
                "class",        // zPAR_TYPE_CLASS
                "func",         // zPAR_TYPE_FUNC
                "prototype",    // zPAR_TYPE_PROTOTYPE
                "instance"      // zPAR_TYPE_INSTANCE
            };
    
            // Loop over paramter-argument pairs and see if they match in type and push argument if so
            repeat(i, numParams);
                // Get next parameter type
                var zCPar_Symbol pSymb; pSymb = _^(MEM_GetSymbolByIndex(fSymbID+1+i));
                var int pType; pType = pSymb.bitfield & zCPar_Symbol_bitfield_type;
                var string pTypeS; pTypeS = MEM_ReadStatStringArr(SYMBOL_TYPES, pType >> 12);
    
                // Set up error message
                var string errStr1;
                errStr1 = ConcatStrings("Argument #", IntToString(i+1));
                errStr1 = ConcatStrings(errStr1, ": ");
    
                // Check if any arguments provided
                if (zrArgs.len < 1) {
                    return ConcatStrings("Not enough arguments. Expected ", IntToString(numParams));
                };
    
                // Extract start of next argument from query
                var int j; j = 0;
                var int l; l = MEM_ReadByte(zrArgs.ptr+j);
                while(l == 32); // Skip spaces
                    if (zrArgs.len <= j+1) {
                        return ConcatStrings("Not enough arguments. Expected ", IntToString(numParams));
                    };
                    j += 1;
                    l = MEM_ReadByte(zrArgs.ptr+j);
                end;
    
                // Update remaining argument string
                rArgs = STR_SubStr(rArgs, j, zrArgs.len-j);
    
                // Check first character
                var int firstChar; firstChar = MEM_ReadByte(zrArgs.ptr);
                var int argIsStr; argIsStr = (firstChar == 34); // Double quotes
                var int argIsNumber; argIsNumber = ((firstChar >= 48) && (firstChar <= 57)) || (firstChar == 45); // Digit
    
                // Match types
                if (argIsStr) {
                    if (pType != zPAR_TYPE_STRING) {
                        return ConcatStrings(ConcatStrings(errStr1, "Expected type "), pTypeS);
                    };
    
                    // Iterate over query to find end of string
                    j = 1;
                    l = MEM_ReadByte(zrArgs.ptr+j);
                    while(l != 34); // Double quote
                        if (zrArgs.len <= j+1) {
                            return ConcatStrings(errStr1, "Unexpected end of string");
                        };
                        j += 1;
                        l = MEM_ReadByte(zrArgs.ptr+j);
                    end;
    
                    // Push string parameter
                    MEM_PushStringParam(STR_SubStr(rArgs, 1, j-1));
    
                    // Update remaining arguments string
                    rArgs = STR_SubStr(rArgs, j+1, zrArgs.len-(j+1));
                } else if (argIsNumber) {
                    var int argIsFloat; argIsFloat = FALSE;
                    var string argInt; argInt = "";
                    var string argDec; argDec = "";
    
                    // Iterate over query to find argument offset (space) or decimal point
                    j = 0;
                    l = MEM_ReadByte(zrArgs.ptr+j);
                    while(l != 32); // Space
                        if (MEM_ReadByte(zrArgs.ptr+j) == 46) { // Decimal point
                            if (argIsFloat) {
                                return ConcatStrings(errStr1, "Syntax error '.'");
                            };
                            argIsFloat = TRUE;
                        } else if (MEM_ReadByte(zrArgs.ptr+j) == 45) {
                            if (j != 0) {
                                return ConcatStrings(errStr1, "Syntax error '-'");
                            };
                            argInt = "-";
                        } else if (MEM_ReadByte(zrArgs.ptr+j) < 48) || (MEM_ReadByte(zrArgs.ptr+j) > 57) {
                            return ConcatStrings(ConcatStrings(errStr1, "Syntax error "), STR_SubStr(rArgs, j, 1));
                        } else {
                            if (argIsFloat) {
                                argDec = ConcatStrings(argDec, STR_SubStr(rArgs, j, 1));
                            } else {
                                argInt = ConcatStrings(argInt, STR_SubStr(rArgs, j, 1));
                            };
                        };
                        if (zrArgs.len <= j+1) {
                            break;
                        };
                        j += 1;
                        l = MEM_ReadByte(zrArgs.ptr+j);
                    end;
                    rArgs = STR_SubStr(rArgs, j, zrArgs.len-j);
    
                    var int argIntI; argIntI = STR_ToInt(argInt);
                    // If an integer is expected and a float is provided, it will not be rounded but passed as integer float
    
                    if (argIsFloat) {
                        if (pType != zPAR_TYPE_FLOAT) {
                            return ConcatStrings(ConcatStrings(errStr1, "Expected type "), pTypeS);
                        };
    
                        // Shift decimal numbers to the left beyond decimal point
                        var int argDecF; argDecF = mkf(STR_ToInt(argDec));
                        repeat(k, STR_Len(argDec)); var int k;
                            argDecF = mulf(argDecF, castToIntf(0.1)); // n*0.1 = 0.n
                        end;
    
                        // Add integer to decimal points
                        argIntI = addf(mkf(argIntI), argDecF);
                    } else if (pType == zPAR_TYPE_FLOAT) {
                        // Turn integer into integer float
                        argIntI = mkf(argIntI);
                    } else if (pType != zPAR_TYPE_INT) {
                        // Check if it might be a valid symbol ID
                        if (argIntI < 0) || (argIntI >= currSymbolTableLength) {
                            return ConcatStrings(errStr1, "Invalid symbol index");
                        };
    
                        // Check symbol type (exception: expected float, given integer)
                        var zCPar_Symbol iSymb; iSymb = _^(MEM_GetSymbolByIndex(argIntI));
                        if ((iSymb.bitfield & zCPar_Symbol_bitfield_type) != pType)
                        && (!(((iSymb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INT)
                                && (pType == zPAR_TYPE_FLOAT))) {
                            return ConcatStrings(ConcatStrings(errStr1, "Expected type "), pTypeS);
                        };
    
                        // Self, other and item are difficult to control
                        if (Hlp_StrCmp(iSymb.name, "self"))
                        || (Hlp_StrCmp(iSymb.name, "other"))
                        || (Hlp_StrCmp(iSymb.name, "victim"))
                        || (Hlp_StrCmp(iSymb.name, "item")) {
                            return ConcatStrings(errStr1, "Symbol is not allowed");
                        };
    
                        // Push symbol
                        if (!CC_Call_PushSymbol(argIntI)) {
                            return ConcatStrings(ConcatStrings(errStr1, "Don't know how to push type "), pTypeS);
                        };
                        continue;
                    };
    
                    // Push integer or float integer parameter
                    MEM_PushIntParam(argIntI);
                } else { // Symbol name
                    // Get end of argument
                    j = 0;
                    l = MEM_ReadByte(zrArgs.ptr+j);
                    while(l != 32); // Space
                        j += 1;
                        l = MEM_ReadByte(zrArgs.ptr+j);
                        if (zrArgs.len <= j) {
                            break;
                        };
                    end;
    
                    // Check if valid symbol
                    var int aSymbID; aSymbID = MEM_GetSymbolIndex(STR_Prefix(rArgs, j));
                    if (aSymbID < 0) || (aSymbID >= currSymbolTableLength) {
                        return ConcatStrings(errStr1, "Invalid symbol name");
                    };
    
                    // Validate symbol type (exception: expected float, given integer)
                    var zCPar_Symbol aSymb; aSymb = _^(MEM_GetSymbolByIndex(aSymbID));
                    if ((aSymb.bitfield & zCPar_Symbol_bitfield_type) != pType)
                    && (!(((aSymb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_INT) && (pType == zPAR_TYPE_FLOAT))) {
                        return ConcatStrings(ConcatStrings(errStr1, "Expected type "), pTypeS);
                    };
    
                    // Self, other and item are difficult to control
                    if (Hlp_StrCmp(aSymb.name, "self"))
                    || (Hlp_StrCmp(aSymb.name, "other"))
                    || (Hlp_StrCmp(aSymb.name, "victim"))
                    || (Hlp_StrCmp(aSymb.name, "item")) {
                        return ConcatStrings(errStr1, "Symbol is not allowed");
                    };
    
                    // Push symbol
                    if (!CC_Call_PushSymbol(aSymbID)) {
                        return ConcatStrings(ConcatStrings(errStr1, "Don't know how to push type "), pTypeS);
                    };
    
                    // Update remaining arguments string
                    rArgs = STR_SubStr(rArgs, j, zrArgs.len-j);
                };
            end;
        } else if (!Hlp_StrCmp(args, "")) && (!Hlp_StrCmp(args, " ")) {
            return "Function does not take arguments";
        };
    
        // Check if return type can be popped, otherwise don't allow the call!
        if (retType > zPAR_TYPE_CLASS) && (retType < zPAR_TYPE_INSTANCE) {
            return "Return type of function not supported";
        };
    
        // Call function
        MEM_CallByID(fSymbID);
    
        // Pop return value if
        if (retType == zPAR_TYPE_VOID) {
            return "return (void)";
        } else if (retType == zPAR_TYPE_STRING) {
            var string resStr; resStr = MEM_PopStringResult();
            return ConcatStrings(ConcatStrings("return '", resStr), "'");
        } else if (retType == zPAR_TYPE_INT) {
            var int resInt; resInt = MEM_PopIntResult();
            return ConcatStrings(ConcatStrings("return ", IntToString(resInt)), " (int)");
        } else if (retType == zPAR_TYPE_FLOAT) {
            var int resF; resF = MEM_PopIntResult();
            return ConcatStrings(ConcatStrings("return ", toStringf(resF)), " (float)");
        } else { // zPAR_TYPE_INSTANCE
            var MEMINT_HelperClass result; result = MEM_PopInstResult();
            // The instance is now CC_CALL.RESULT (no gain in information ever)
            // Instead return the pointer
            var int rPtr; rPtr = _@(result);
            return ConcatStrings(ConcatStrings("return *", IntToString(rPtr)), " (instance)");
        };
    };
    
    
    
    /*
     * Example getter and setter functions for strings, integers and floats
     */
    func string getS(var string s) {
        return s;
    };
    func int getI(var int i) {
        return i;
    };
    func float getF(var float f) {
        MEM_ReadInt(_@f(f));
    };
    func float getIF(var int f) {  // From floats.d
        f;
    };
    func int getFI(var float f) {  // From floats.d
        return MEM_ReadInt(_@f(f));
    };
    
    
    func int verifySymbol(var string name, var int type) {
        var int symPtr; symPtr = MEM_GetParserSymbol(name);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            if ((sym.bitfield & zCPar_Symbol_bitfield_type) == type)
            && ((sym.bitfield & zCPar_Symbol_bitfield_ele)  == 1) {
                return symPtr;
            };
        };
        return 0;
    };
    
    func string setS(var string name, var string val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_STRING);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            MEM_WriteString(sym.content, val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setI(var string name, var int val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_INT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = val;
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setF(var string name, var float val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_FLOAT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = castToIntf(val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setIF(var string name, var float val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_INT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = castToIntf(val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setFI(var string name, var int val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_FLOAT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = val;
            return "Done";
        };
        return "Invalid symbol";
    };

    In der Init_Global() registrieren:
    Code:
    CC_CallInit();
    Last edited by mud-freak; 30.03.2019 at 17:48. Reason: Funktioniert jetzt auch mit Funktionen als Parameter, Syntaxfehler behoben, negative Integer/Floats nun als Argumente unterstützt, Getter- und Setterfunktionen hinzugefügt

  9. View Forum Posts #9 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,300
     
    Lehona is offline
    Ich glaube Funktionen sind im Endeffekt auch nur ihre Symbol-IDs (wie Instanzen die in einen Int-Parameter übergeben werden).

  10. View Forum Posts #10 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    EDIT: Habe dich falsch verstanden. Ich probiere das mal mit Funktionen. Danke für den Tipp.

    Habe den Code oben korrigiert, damit es nun auch mit Funktionen als Parameter klappt.
    Last edited by mud-freak; 27.10.2017 at 22:39.

  11. View Forum Posts #11 Reply With Quote
    Legend of Ahssûn TheEternal's Avatar
    Join Date
    Jun 2013
    Location
    Frankfurt
    Posts
    4,297
     
    TheEternal is offline
    Top, danke Mud-Freak, das ist echt 'ne große Hilfe.
    Jetzt müssen die Leute das nur noch verwenden, das spart viel Zeit, im vergleich zum Bauen und deployen eines Patches
    [Bild: LoA_Banner_Skyline2.jpg]
    LoA Website
    Checkout Cloudevo: unlimited Cloud-Drive


  12. View Forum Posts #12 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Ich habe das Skript oben aktualisiert, sodass nun auch negative Integer/Floats als Argumente erlaubt sind. Das hatte ich bei der Implementierung übersehen.

  13. View Forum Posts #13 Reply With Quote
    now also in your universe  Milky-Way's Avatar
    Join Date
    Jun 2007
    Posts
    13,952
     
    Milky-Way is offline
    Ließe sich damit auch etwas machen, um beliebige Variablen sehen / setzen zu können? Bisher klang es für mich so, als müsste ich für jede Variable eine Funktion erstellen.

  14. View Forum Posts #14 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,300
     
    Lehona is offline
    Quote Originally Posted by Milky-Way View Post
    Ließe sich damit auch etwas machen, um beliebige Variablen sehen / setzen zu können? Bisher klang es für mich so, als müsste ich für jede Variable eine Funktion erstellen.
    Du kannst dir ja eine Funktion schreiben, die den Wert einer Variable (via Namen) liest/setzt.

    Code:
    func string readVar(var string varname) {
        var zCPar_Symbol symb; symb = _^(MEM_GetParserSymbol(varname));
        return IntToString(symb.content);
    };
    Das funktioniert jetzt allerdings nur mit Ints, entweder schreibst du dir für die anderen Typen (Int/String/Instance) jeweils eine eigene Funktion oder du musst in die Symboleigenschaften gucken, was für ein Typ die Variable hat.

  15. View Forum Posts #15 Reply With Quote
    Sword Master
    Join Date
    Aug 2009
    Location
    Hessen
    Posts
    959
     
    Cryp18Struct is offline
    Für integer hat Sektenspinner das in Ikarus_Doc.d vorgemacht:
    Code:
    func void SetVarTo (var string variableName, var int value) {
        var int symPtr;
        symPtr = MEM_GetParserSymbol (variableName);
        
        if (symPtr) { //!= 0 
            var zCPar_Symbol sym;
            sym = MEM_PtrToInst (symPtr);
            
            if ((sym.bitfield & zCPar_Symbol_bitfield_type)
                                          == zPAR_TYPE_INT) {
                sym.content = value;
            } else {
                MEM_Error ("SetVarTo: Die Variable ist kein Integer!");
            };
        } else {
            MEM_Error ("SetVarTo: Das Symbol existiert nicht!");
        };
    };

  16. View Forum Posts #16 Reply With Quote

  17. View Forum Posts #17 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Der Vollständigkeit halber, habe ich hier Getter- und Setter-Funktionen für Strings, Integers, Floats und Integerfloats (funktioniert für Variablen und Konstanten). Man kann einen Integerfloat auch bequem als Float definieren. EDIT: Was aber nicht geht sind statische Arrays.

    Anwendung:
    Code:
    call getS str1     // Get string, output: "hello world"
    call getI int1     // Get integer, output: 42
    call getF float1   // Get float, output: 1.234
    call getIF intf1   // Get int as float, output: 2.345
    call getFI float1  // Get float as int, output: 1067316150
    
    call setS "str1" "hello world" // Set string
    call setI "int1" 42            // Set integer
    call setF "float1" 1.234       // Set float
    call setIF "intf1" 2.345       // Set integer with float
    call setFI "float1" 1067316150 // Set float with integer
    Die Notwendigkeit der Anführungszeichen in den Setter-Funktionen lässt sich leider nicht ändern. Ich hänge die Funktionen an das Skript an, damit sie gleich immer dabei sind.


    Spoiler:(zum lesen bitte Text markieren)
    Code:
    /*
     * Example getter and setter functions for strings, integers and floats
     */
    func string getS(var string s) {
        return s;
    };
    func int getI(var int i) {
        return i;
    };
    func float getF(var float f) {
        MEM_ReadInt(_@f(f));
    };
    func float getIF(var int f) {  // From floats.d
        f;
    };
    func int getFI(var float f) {  // From floats.d
        return MEM_ReadInt(_@f(f));
    };
    
    
    func int verifySymbol(var string name, var int type) {
        var int symPtr; symPtr = MEM_GetParserSymbol(name);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            if ((sym.bitfield & zCPar_Symbol_bitfield_type) == type)
            && ((sym.bitfield & zCPar_Symbol_bitfield_ele)  == 1) {
                return symPtr;
            };
        };
        return 0;
    };
    
    func string setS(var string name, var string val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_STRING);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            MEM_WriteString(sym.content, val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setI(var string name, var int val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_INT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = val;
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setF(var string name, var float val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_FLOAT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = castToIntf(val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setIF(var string name, var float val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_INT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = castToIntf(val);
            return "Done";
        };
        return "Invalid symbol";
    };
    func string setFI(var string name, var int val) {
        var int symPtr; symPtr = verifySymbol(name, zPAR_TYPE_FLOAT);
        if (symPtr) {
            var zCPar_Symbol sym; sym = _^(symPtr);
            sym.content = val;
            return "Done";
        };
        return "Invalid symbol";
    };

  18. View Forum Posts #18 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Was noch gefehlt hat war, dass Skriptfunktionen beim Eintippen auto-vervollständigt werden, so wie man das von anderen Konsolenbefehlen gewöhnt ist. Das habe ich oben im Skript hinzugefügt.

    Beispiel: Schreibe ich in die Konsole "call hello" wird daraus "call helloworld", sollte eine Funktion mit dem Namen in den Skripten enthalten sein und keine andere Funktion mit "hello" im Namen beginnen.

    Die entsprechende Änderung werde ich dann auch bald in den Workaround-Patch aufnehmen.

  19. View Forum Posts #19 Reply With Quote
    Knight mud-freak's Avatar
    Join Date
    Dec 2005
    Posts
    1,776
     
    mud-freak is offline
    Quote Originally Posted by mud-freak View Post
    Was noch gefehlt hat war, dass Skriptfunktionen beim Eintippen auto-vervollständigt werden, so wie man das von anderen Konsolenbefehlen gewöhnt ist. Das habe ich oben im Skript hinzugefügt.

    Beispiel: Schreibe ich in die Konsole "call hello" wird daraus "call helloworld", sollte eine Funktion mit dem Namen in den Skripten enthalten sein und keine andere Funktion mit "hello" im Namen beginnen.

    Die entsprechende Änderung werde ich dann auch bald in den Workaround-Patch aufnehmen.
    Ich habe diese Autovervollständigung wieder aus dem Skript oben heraus genommen, da dadurch Ruckler beim Eintippen in der Konsole entsanden sind (sämtliche Daedalus und externe Funktionen sind halt etwas viele). Falls jemand den entsprechenden Code trotzdem haben will, habe ich ihn hier noch einmal separat.

    Code:
    // Register auto-complete for all functions
    const int once = 0;
    if (!once) {
        repeat(i, MEM_Parser.symtab_table_numInArray); var int i;
            var zCPar_Symbol symb; symb = _^(MEM_ReadIntArray(MEM_Parser.symtab_table_array, i));
            if ((symb.bitfield & zCPar_Symbol_bitfield_type) == zPAR_TYPE_FUNC) {
                CC_AutoComplete(ConcatStrings("CALL ", symb.name), "");
            };
        end;
        once = 1;
    };

  20. View Forum Posts #20 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,300
     
    Lehona is offline
    Wer dennoch Autcompletion für alle Funktionen haben möchte und sehr viel Langeweile hat, könnte die entsprechende Enginefunktion hooken und einen eigenen Lookup einbauen. Mit einem PATRICIA-Trie geht der Lookup in logarithmischer Zeit, unabhängig von der Menge der registrierten Funktionen und die Implementierung ist gar nicht mal so schwierig (gibt auch einige Beispiele im Netz)

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