Beiträge von Jeffry

    Auf Nachfrage von @Muho55 poste ich hier den Code zum Geld-System mit Cent-Beträgen.


    Es ist zwar etwas mehr als nur ein Schnipsel, aber für einen separaten Release ist mir das dann doch zu wenig.
    Für ein Tutorial lohnt sich das auch nicht wirklich, da der Code, bis auf die Berechnung, selbsterklärend ist.


    Anbei der Code:
    new PlayerText:pMoneyText[MAX_PLAYERS];
    new pMoney[MAX_PLAYERS];


    public OnPlayerConnect(playerid)
    {
    pMoneyText[playerid] = CreatePlayerTextDraw(playerid, 496.0000, 79.0000, "$0,00");
    PlayerTextDrawColor(playerid, pMoneyText[playerid], 0x27941EFF);
    PlayerTextDrawLetterSize(playerid, pMoneyText[playerid], 0.4000, 2.0000);
    PlayerTextDrawUseBox(playerid, pMoneyText[playerid], 1);
    PlayerTextDrawBoxColor(playerid, pMoneyText[playerid], 0x000000FF);
    PlayerTextDrawAlignment(playerid, pMoneyText[playerid], 1);
    PlayerTextDrawTextSize(playerid, pMoneyText[playerid], 610.0000, 10.0000);
    PlayerTextDrawSetShadow(playerid, pMoneyText[playerid], 0);

    pMoney[playerid] = 0; //Entsprechend beim Laden des Spielers mit Wert befüllen.
    return 1;
    }


    public OnPlayerSpawn(playerid)
    {
    PlayerTextDrawShow(playerid, pMoneyText[playerid]);
    return 1;
    }


    public OnPlayerDisconnect(playerid, reason)
    {
    PlayerTextDrawDestroy(playerid, pMoneyText[playerid]);
    return 1;
    }


    stock GivePlayerMoneyEx(playerid, money)
    {
    if(!IsPlayerConnected(playerid)) return 0;
    pMoney[playerid] += money;
    new str[16];
    if(pMoney[playerid] >= 0)
    {
    format(str, sizeof(str), "$%d,%02d", pMoney[playerid]/100, pMoney[playerid]%100);
    for(new i = strlen(str)-6; i > 1; i-=3) strins(str, ".", i);
    PlayerTextDrawColor(playerid, pMoneyText[playerid], 0x27941EFF);
    }
    else
    {
    format(str, sizeof(str), "$%d,%02d", (pMoney[playerid]/100)+1, ((pMoney[playerid]%100)-100)*-1);
    for(new i = strlen(str)-6; i > 2; i-=3) strins(str, ".", i);
    PlayerTextDrawColor(playerid, pMoneyText[playerid], 0xFF0000FF);
    }
    PlayerTextDrawSetString(playerid, pMoneyText[playerid], str);
    PlayerTextDrawShow(playerid, pMoneyText[playerid]);
    return 1;
    }


    stock ResetPlayerMoneyEx(playerid)
    {
    if(!IsPlayerConnected(playerid)) return 0;
    GivePlayerMoneyEx(playerid, -pMoney[playerid]);
    return 1;
    }


    stock SetPlayerMoneyEx(playerid, money)
    {
    if(!IsPlayerConnected(playerid)) return 0;
    ResetPlayerMoneyEx(playerid);
    GivePlayerMoneyEx(playerid, money);
    return 1;
    }


    stock GetPlayerMoneyEx(playerid)
    {
    if(!IsPlayerConnected(playerid)) return 0;
    return pMoney[playerid];
    }


    stock GetPlayerMoneyEx_Str(playerid)
    {
    if(!IsPlayerConnected(playerid)) return 0;
    new str[16];
    if(pMoney[playerid] >= 0)
    {
    format(str, sizeof(str), "$%d,%02d", pMoney[playerid]/100, pMoney[playerid]%100);
    for(new i = strlen(str)-6; i > 1; i-=3) strins(str, ".", i);
    }
    else
    {
    format(str, sizeof(str), "$%d,%02d", (pMoney[playerid]/100)+1, ((pMoney[playerid]%100)-100)*-1);
    for(new i = strlen(str)-6; i > 2; i-=3) strins(str, ".", i);
    }
    return str;
    }


    Außerdem hatte Muho55 gewünscht, die Sprunk-Maschinen (etc) abzufangen.
    Hierzu kann diese Include verwendet werden: http://forum.sa-mp.com/showthread.php?t=367838


    Eine Einschränkung ergibt sich auf Grund des 32-Bit Limits in SA:MP.
    Der maximale Geld-Betrag liegt bei +/-21.474.836,47. (https://de.wikipedia.org/wiki/2147483647)


    Solange man nicht mit Millionenbeträgen jongliert, sollte das aber ausreichend sein.


    Anbei noch Beispielbilder:




    Das TextDraw-Design kann natürlich angepasst werden, ich habe nur beispielhaft ein simples Design genommen.



    Für Nachfragen zum Code bitte die Scripting Base nutzen: Scripting Base

    Problem ist, dass du das Query in einer Spieler-Abhängigen Schleife hast, die eventuell nicht aufgerufen wird, wenn kein Spieler der Fraktion online ist.
    Außerdem fehlt im Befehl ein Anführungszeichen nach WHERE vor member.


    Zusätzlich nutzt du in der Schleife "pID", welches nie einen Wert bekommt, und "playerid", was der eingebende Spieler ist.


    Versuche es so:
    ocmd:frakdel(playerid,params[])
    {
    new frak,query[128];
    if(isAdmin(playerid,6))
    {
    if(sscanf(params, "d",frak)) return SendClientMessage(playerid,COLOR_RED,"Benutzung: /frakdel [FraktionsID]");
    for(new i; i<GetMaxPlayers(); i++)
    {
    if(PlayerInfo[i][pLoggedIn]==true && PlayerInfo[i][pMember]==frak)
    {
    PlayerInfo[i][pMember]=0;
    PlayerInfo[i][pLeader]=0;
    PlayerInfo[i][pFRang]=0;
    SpawnPlayer(i);
    SaveUserStats(i);
    SendClientMessage(i,COLOR_RED,"Du wurdest soeben aus deiner Fraktion gekickt. Grund: Fraktionsauflösung");
    SetPlayerVirtualWorld(i,0);
    }
    }
    format(query,sizeof(query),"UPDATE users SET member = '0' WHERE member = '%d'",frak);
    print(query);
    mysql_pquery(handle,query,"","");
    }
    return 1;
    }

    Damit kann ich leider nichts anfangen, das hat damit nicht wirklich was zu tun, da hier keine MySQL Befehle vorhanden sind.
    Zu dem Zeitpunkt, zu dem du den Gutschein erstellst (INSERT INTO ...) ist die Datenbank nicht verbunden.
    Das musst du prüfen, warum das so ist. Eventuell beendest du die Verbindung zuvor. Schaue im Log nach, ob die zwischen Server-Start und Befehlseingabe beendet wird.

    Ne Funktion um formatierte Nachrichten direkt mit SendClientMessageEx ausgeben zu koennen statt immer format zu nutzen

    Du solltest Quellen angeben, wenn du Funktionen postest, die von anderen entwickelt worden sind und nicht unbedingt trivial sind.


    Übrigens geht es viel einfacher:
    stock _g_str[145];
    #define SendClientMessageEx(%0,%1,%2,%3); \
    format(_g_str, sizeof(_g_str), %2, %3); \
    SendClientMessage(%0, %1, _g_str);


    Zu nutzen:
    SendClientMessageEx(playerid, 0xFF0000FF, "Hallo %s, du hast die ID %d!", pName(playerid), playerid);




    Keywords: SendClientMessageEx, SendClientMessageFormatted, SendFormattedClientMessage.

    Ab "fCol1" fehlen die Kommas am Ende.
    Nur die letzte Zeile (fSperrpreis) darf kein Komma haben.






    [20:29:59 03/08/17] [DEBUG] mysql_pquery - connection: 1, query: "ALTER TABLE `FracVehicles` ADD `fCarid` varchar(11) NOT NULL DEF", callback: "(null)", format: "(null)"

    Entferne diese Queries alle. Sonst bekommst du beim Server Start jedes Mal die Fehlermeldungen, weil die Spalten ja bereits existieren.
    Wenn du Spalten hinzufügen willst, mache das in der Datenbank direkt, da dies ja nur ein einmaliger Vorgang ist.
    Lediglich das CREATE TABLE IF NOT EXIST musst du anpassen, da dies die Tabelle komplett erstellt, wenn sie nicht existiert.

    und hier die Speicher Codes

    Basierend auf diesem Post (vom Zitat ^ #12) musst du folgende Anpassung machen:
    format(query, sizeof(query), "%s`fVehid`='%s', ", string, FactionCars[i][fVehid]);
    zu:
    format(query, sizeof(query), "%s`fVehid`='%s', ", query, FactionCars[i][fVehid]);


    Bei allen Zeilen, in beiden Funktionen (string -> query).
    Nehme ich auf meine Kappe, habe es selbst so gepostet. Ohne Compiler ist das nicht aufgefallen.


    Alles was zwischen Post #12 und diesem Post gemacht wurde, bitte rückgängig machen und vergessen.

    Findest du ?

    Bezogen auf Commands schon. So kann man z.B. bei mehreren Parametern unterschiedliche Nachrichten ausgeben, wenn bis zu Punkt X eingegeben wurde.
    Das geht zwar bei sscanf auch, sieht aber dann ziemlich grottig aus.


    Das sscanf mehr als strtok kann steht ja außer Frage. Die Frage ist nur, jeder alles braucht.
    Performanter ist es auch, nur eben unwesentlich, für Befehle spielt es keine Rolle welches man da nutzt.



    Habe ich mal gemacht Jetzt kommt folgendes raus

    Das sieht richtig aus. Wie du siehst in mein strtok wesentlich schneller.
    sscanf ist natürlich nochmal schneller, es kann die Vorteile des Plugins nutzen.

    Beim Laden setzt du Gutschein[gIDs][gErstellt] nicht auf 1.
    Außerdem muss
    new gIDs = cache_get_field_content_int(count, "id"); innerhalb der while-Schleife stehen, sonst liest du immer nur die ID der ersten Zeile aus.


    Zusätzlich solltest du die Schleife beim Speichern so schreiben, da sonst die Schleife stoppt, wenn ein Gutschein zwischendrin nicht existiert.
    new count;
    for(new gSchein = 1; gSchein<MAX_GUTSCHEINE; gSchein++)
    {
    if(Gutschein[gSchein][gErstellt] == 0) continue;
    format(query,sizeof(query),"UPDATE "#DATENBANKTAG"_gutschein SET `Erstellt`='%d', `Ersteller`='%s', `Datum`='%s', `Ablauf`='%d',",
    Gutschein[gSchein][gErstellt], Gutschein[gSchein][gErsteller], Gutschein[gSchein][gDatumErstellt], Gutschein[gSchein][gAblauf]);
    strcat(mainquery,query);
    format(query,sizeof(query),"`Code`='%s', `Typ`='%d', `Gebunden`='%d', `GebundenAn`='%s', `Eingeloest`='%d', `Wert`='%d', `Abgelaufen`='%d', `EingeloestVon`='%s' WHERE `id`='%d' ",
    Gutschein[gSchein][gCode], Gutschein[gSchein][gTyp], Gutschein[gSchein][gGebunden], Gutschein[gSchein][gGebundenAn], Gutschein[gSchein][gEingeloest], Gutschein[gSchein][gWert], Gutschein[gSchein][gAbgelaufen], Gutschein[gSchein][gEingeloestVon], Gutschein[gSchein][gID],gSchein);
    strcat(mainquery,query);
    mysql_function_query(MySqlConnection,mainquery,false,"","");
    strdel(mainquery,0,sizeof(mainquery));
    strdel(query,0,sizeof(query));
    count++;
    }
    printf("- Gutschein gespeichert %d/%d -",count,MAX_GUTSCHEINE);
    strdel(query,0,sizeof(query));

    Warum soll strtok eigentlich so schlecht sein?

    Für die meisten Anwendungen spielt es absolut keine Rolle.
    Ich persönlich finde strtok flexibler, sscanf ist allerdings für viele einfacher, da alles in einer Zeile steht.
    Schlecht ist strtok aber keineswegs.


    Habe gerade mal strtok (Das von DracoBlue), strtok(Das von Jeffry was schneller sein sollte) mit sscanf verglichen, und es kam raus dass das angebliche schnellere strtok von Jeffry langsamer war als strtok von Dracoblue und sscanf. Strtok von DracoBlue war jedoch nur extrem minimal von sscanf entfernt warum auch immer

    Das liegt daran, dass dein Test falsch ist.
    Du musst den idx vor jedem Durchlauf wieder auf 0 setzen, sonst wird immer nur ein leerer String zurück gegeben, da nichts gesplittet werden kann. Das gilt übrigens für beide strtok's, denn idx ist der Pointer auf das aktuelle Zeichen. Der steht sonst nach dem ersten Durchlauf immer ganz am Ende des Strings.
    Das dürfte bei meiner Funktion dazu führen, dass sie langsamer ist, da strmid in jedem Fall aufgerufen wird, und nicht durch die while-Bedingung umgangen wird. Das ließe sich natürlich zuvor abfragen, macht es aber dann in allen anderen Fällen, außer im Leer-Fall, langsamer als im aktuellen Zustand, was somit schlechter wäre.


    Anbei mein Post mit der Funktion sowie dem Test dazu:
    Nützliche Codeschnipsel

    [09:54:43 03/07/17] [ERROR] mysql_pquery - invalid connection handle (id: 0)
    [09:54:43 03/07/17] [ERROR] mysql_pquery - invalid connection handle (id: 0)
    [09:54:43 03/07/17] [DEBUG] mysql_connect - host: "localhost", user: "samp6231", database: "samp6231_samp", password: "****", port: 3306, autoreconnect: true, pool_size: 2

    Das Problem ist, dass du mysql_pquery ausführst, bevor du mit mysql_connect eine Verbindung aufbaust.
    Setze mysql_connect ganz oben unter OnGameModeInit hin, dann ist das Problem behoben.