Beiträge von Goldkiller

    Schau dir mal bitte die Grundlagen an.
    public Updater()
    {
    //SetTimer("Updater",20000,1); <-- überflüssig,erstellt nur 1000 von Timern.
    new zeit;
    gettime(zeit);
    if( ( zeit > 12 ) && ( zeit < 20 ) ) // *** - Diese Zeile mit Templer's austauschen,falls Andere Öffnugnszeiten
    {
    Update3DTextLabelText(Fschule1, 0x006300C5, "Fahrschule [GEÖFFNET]");
    Update3DTextLabelText(Fschule2, 0x006300C5, "Fahrschule [GEÖFFNET]");
    }
    else
    {
    Update3DTextLabelText(Fschule1, 0x006300C5, "Fahrschule [GESCHLOSSEN]");
    Update3DTextLabelText(Fschule2, 0x006300C5, "Fahrschule [GEÖFFNET]");
    }
    /*
    Das kann man doch auch vereinfachen und beides oben einfügen,sofern die
    Öffnungszeiten die selben sind
    if( ( zeit > 0 ) && ( zeit < 12 ) && ( zeit > 20 ) && ( zeit < 0 ) )
    {
    Update3DTextLabelText(Fschule2, 0x006300C5, "Fahrschule [GEÖFFNET]");
    }
    else
    {
    Update3DTextLabelText(Fschule2, 0x006300C5, "Fahrschule [GESCHLOSSEN]");
    }
    */
    return 1;
    }

    Templer hat dir gezeigt,wie man die Öffnungszeiten zwischen 10Uhr - 14uhr , 17Uhr - 22Uhr und 01Uhr - 4Uhr hat. Vielleicht willst du diese ja so,dann müsstest du diese Zeile einfügen,dort wo Ich es im Quellcode markiert habe.

    if(zeit < 10 || zeit > 14|| zeit < 17 || zeit > 22 || zeit < 1 || zeit > 4 )
    //
    if(zeit > 10 || zeit < 14|| zeit > 17 || zeit < 22 || zeit > 1 || zeit < 4 )

    Die sind ja mal völlig falsch.
    Nehmen wir mal an wir haben 16Uhr.


    zeit < 10 - FALSE
    zeit > 14 - TRUE
    zeit < 17 - TRUE
    zeit > 22 - FALSE
    zeit < 1 - FALSE
    zeit > 4 - TRUE


    Das hilft aber niemanden weiter o0.Denn egal bei welcher Uhrzeit,irgendwo wird TRUE rauskommen,was aber wohl nicht dein Ziel war.


    Mach es doch lieber so.
    if( ( Zeit > 12 ) && ( Zeit < 20 ) ) { // offen von 12uhr bis 20uhr
    }
    else { // geschlossen
    }


    Abgesehen davon,erstellst du 1000 von Timern.
    Entferne
    SetTimer("Updater",20000,1); in deinem Public.


    Und wie NeoPhoenix gesagt hat, wäre Update3DTextLabel viel praktischer

    Dann schreib mal weiter am PAWNO Buch.Wäre wirklich sehr hilfreich ein Buch für die PAWNO IDE.


    Sorry,aber wenn du schon es so erscheinen lässt, als wäre PAWNO die Sprache, kann es nicht sehr professionel werden.
    PAWN ist die Sprache,PAWNO eine IDE die beim SA:MP Server mitgeliefert wird.

    DINI hat kein Limit.Das einzige File-System was ein Limit hat ist SII,da es einen Cache benutzt,der nur für 100 Einträge ( Standartmäßig ) groß genug ist.

    Ich wollte schon seit längerem mal das Tutorial erweitern um ZCMD, hab jetzt endlich mal Zeit dafür gefunden.


    zcmd
    ZCMD ist ein weiterer Weg seine Commands einfach und schnell zu scripten.Die Methode funktioniert um einiges anders als dcmd.Hier wird der eingegebene Text, der bei OnPlayerCommandText() übergeben wird nicht wie bei DCMD mit allen Befehlen verglichen die ihr unter OnPlayerCommandText() habt, sondern es wird versucht ein public Funktion aufzurufen,die den Namen des Commands hat.


    Diese Technik wurde zum ersten mal von Y_Less vorgestellt.Allerdings wurde sie kaum benutzt,lag wohl darans,dass
    Y_Less diese Technik mehr oder weniger versteckt hatte in seinem YSI Include,welches relativ wenig genutzt wurde.
    Viel später kam dann eine Russe Namens ZeeX auf die Idee diese Technik zu nutzen und stellte diese
    im offiziellen SA:MP Forum vor.Seit der ersten Version wurde sie um einiges verändert und ist nun
    neben DCMD die wohl meist genutzte Command-Technik.


    Alle darauf folgenden XYZ-Commands sind nur basierten auf ZCMD und auch nicht schneller / besser,deshalb empfehle
    Ich beim Original zu bleiben.


    Die Version von ZeeX ist hier zu finden: [INC] zcmd 0.3.1 | Fast & Simple Command Processor (updated 30/10/2009)



    Es ist generell kein großer Aufwand,die Commands von dcmd in zcmd umzuschreiben.Nehmen wir mal an,unser Befehl sieht so aus ( Bereits im Tutorial erstellt ).
    public OnPlayerCommandText(playerid, cmdtext[])
    {
    dcmd(kick,4,cmdtext);
    return 0;
    }
    dcmd_kick(playerid,params[]) {
    new
    sGrund[128],
    pID;
    if(sscanf(params, "dz",pID,sGrund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid] ([grund],optional)");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,ThePlayer,sizeof(ThePlayer));
    format(string,sizeof(string),"%s (ID %d) wurde vom Server gekickt,Grund: %s",ThePlayer,pID,sGrund[0] ? sGrund : "<Kein Grund>");
    SendClientMessageToAll(COLOR_YELLOW,string);
    Kick(pID);
    return 1;
    }
    Wer dcmd verstanden hat, dem sollte klar sein, dass /kick der eigentliche Befehl ist.
    Um es nun in ZCMD umzuschreiben,sollte man zuerst den Teil unter OnPlayerCommandText() löschen ( dcmd(kick,4,cmdtext); )


    Den DCMD selber muss man natürlich auch verändern.Sind aber auch nur kleine Veränderungen.
    Aus dem
    dcmd_kick(playerid,params[]) {
    wird dabei :
    COMMAND:kick(playerid,params[]) {
    Viel muss man also nicht ändern.Man ersetz das dcmd_ aus dcmd_kick() durch COMMAND:.
    Daraus wird dann also COMMAND:kick()


    Deshalb erhält man nun das folgende Script:
    public OnPlayerCommandText(playerid, cmdtext[])
    {
    // dcmd(kick,4,cmdtext); - Brauchen wir nicht mehr
    return 0;
    }
    COMMAND:kick(playerid,params[]) {
    new
    sGrund[128],
    pID;
    if(sscanf(params, "uz",pID,sGrund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid] ([grund],optional)");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,ThePlayer,sizeof(ThePlayer));
    format(string,sizeof(string),"%s (ID %d) wurde vom Server gekickt,Grund: %s",ThePlayer,pID,sGrund[0] ? sGrund : "<Kein Grund>");
    SendClientMessageToAll(COLOR_YELLOW,string);
    Kick(pID);
    return 1;
    }



    Man muss aber auch auf Kleinigkeiten im Script achten.Solltet ihr ZCMD in einem Filterscript benutzen,
    solltet ihr sicher stellen,dass ihr im Kopf eures Scriptes, das Script als Filterscript definiert.
    #define FILTERSCRIPT
    Das ist deshalb nötig,da bei ZCMD einige Callbacks wichtig sind für das funktionieren des Technik.Wie das Ganze im Detail funktioniert sollte für die meisten unwichtig sein.


    Auch sollte man jetzt darauf achten,dass man nur mit isnull() überprüft ob der übergebene Text in
    params[] leer ist.Die Funktion isnull() ist übrigens im ZCMD Include enthalten.
    Bedeutet im Klartext,keine Abfragen mehr wie:


    if(!params[0]) { }
    if(!strlen(params)) { }


    Stattdessen müsst ihr es jetzt so machen
    if(isnull(params)) { }


    Falls ihr mehrere Commandhandler habt für eine Funktion, müsst ihr ebenfalls kleine Änderungen in eurem Script vor nehmen.
    Nehmen wir an /test ist der eigentliche Command den wir auch über /testaufruf aufrufen sollen,sieht es so aus.


    COMMAND:testaufruf(playerid,params[]) {
    cmd_test(playerid,params);
    }
    Dabei ist zu beachten,dass der zusätzliche Command-Handler ( testaufruf ) nach dem
    Command im Script kommt, zu dem es weiterleiten soll.Heisst also:

    COMMAND:test(playerid,params[]) {
    printf("COMMAND:test(%d,%s)",playerid,params);
    return 1;
    }
    COMMAND:testaufruf(playerid,params[]) {
    return cmd_test(playerid,params);
    }




    Ich selber benutze auch nur noch die ZCMD Methode.Im Endeffekt muss aber jeder für sich selber entscheiden welche Methode ihm am besten gefällt.

    Ließ dir den Thread durch, da steht alles.

    Zitat

    weil wenn z.B. pupsilon nicht angegeben wird, wird es zu 7 gemacht aber der Spieler wird's trotzdem angeben müssen.


    Ganz klar Nein.
    Der Spieler muss es nicht angeben,alle Platzhalter die Groß ( D ) geschrieben werden,sind Optional.Heisst also, sie brauchen nicht angegeben zu werden.


    Zitat

    Aber ich denke meins wird funken, ich werds mal testen...


    Tu dir keinen Zwang an :p

    << Zurück zu Teil 1 des Tutorials



    Im ersten Teil des Tutorials haben wir bereits gelernt,wie wir mit DCMD umgehen.Durch DCMD ist der Command nun
    bereits leichter gestaltet,doch das einfache durchsuchen des Befehls nach zusätzlichen Informationen wurde noch nicht
    großartig erleichtert.
    Dazu jetzt mehr in Teil 2.


    SSCANF
    sscanf wurde von Alex "Y_Less" C. erstellt.Eine sehr bekannte Person für jeden der sich des öfteren im SA:MP Forum rumtreibt.
    Zunächst einmal braucht ihr den sscanf - Code
    sscanf code - SA-MP
    Es gibt bereits ein SSCANF Plugin, womit die Performence gesteigert wurde sowie viele neue Verbesserung eingeführt wurden.
    SSCANF Plugin
    Ich rate jedoch sich nicht sofort mit dem Plugin zu beschäftigen, da es teilweise für Anfänger schwieriger sein kann,die neuen Platzhalter zu verstehen.


    Nun aber weiter im eigentlichem Tutorial
    Viel umschreiben muss man jetzt nicht mehr vom Befehl wie wir in ihn Teil 1 geschrieben haben.
    dcmd_kick(playerid,params[]) {
    new
    pID;
    if(sscanf(params, "u",pID)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid]");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    Kick(pID);
    SendClientMessage(playerid,COLOR_YELLOW,"Erfolgreich Spieler vom Server gekickt!");
    return 1;
    }
    Jetzt müsste euch die Zeile

    if(sscanf(params, "u",pID)) {


    auffallen.Diese Zeile spart euch nun das ganze getue mit strtok,strget oder Sonstigem.
    sscanf brauch zwei Parameter.Der erste Paramter ist der String in dem gesucht werden soll nach etwas.Da wir dcmd benutzten ist es params.Der zweite Paramter ( "u" ) ist der Typ der Information.Es kann so ziemlich alles sein,was man brauch.String,Integer,Float,Hex,Char oder sogar ein Spieler.Dabei steht der Platzhalter "u" für einen Spieler,es kann sowohl der Name als auch die SpielerID angeben werden.Beides ist möglich.


    Alle Datentypes mit ihren Charakterkürzeln gibt es hier:
    Fast Commands - SA-MP - Data types


    Jetzt gibt es aber noch weitere Paramter.Die Anzahl der weiteren Paramter sollte gleich zu der Anzahl sein wie die Anzahl an Datentypes die ihr im String sucht.
    In unserem Beispiel handelt es sich um "u".Demnach brauchen wir einen weiteren Parameter, dabei handelt es sich um den Spieler an dem wir die Operation durchführen wollen.


    sscanf(params, "udd",pID,WeaponID,Ammo) // /giveweapon [playerid] [weaponid] [ammo]
    sscanf(params, "s",sAnnounce) // /announce [text]
    sscanf(params, "f",fGrav) // /gravity [Float:Anziehungskraft]


    Wird ein Spieler ( Name oder ID ) gefunden in params,wird er pID zugewiesen.Sehr praktisch wenn ihr mich fragt.Sollte jetzt gültiger Wert für den Spielrnamen oder die SpielerID im String params sein,wird sscanf irgendwas returnen nur nicht 0.


    Nun wollen wir den Command etwas ausbreiten.Wir wollen einen Grund des Kicks als Grund mit angeben.Da der Grund für einen kick normalerweise ein Text ist,müssen wir jetzt als Datentype "s" oder "z".Da "z" ein Optionaler String ist,lassen wir den erst aus.Zu dem komm ich gleich ;).
    Wir brauchen natürlich noch eine neue Variable (ein String) ,in der wir den Grund speichern.Demnach sieht es so aus mit einer kleinen Extra Nachricht:
    dcmd_kick(playerid,params[]) {
    new
    sGrund[128],
    pID;
    if(sscanf(params, "us",pID,sGrund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid] [grund]");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,ThePlayer,sizeof(ThePlayer));
    format(string,sizeof(string),"%s (ID %d) wurde vom Server gekickt,Grund: %s",ThePlayer,pID,sGrund);
    Kick(pID);
    return 1;
    }
    Wenn das nicht einfach war.Keine große Veränderung der eigentlichen sscanfs-Zeile und schon ein neuer Parameter.
    Wir können den Grund auch optional angeben,also:Es muss kein Grund als Kick angegeben werden,nur wenn man möchte.
    Dafür gibt es einen extra Datentype,das ist "z".


    Achtung: Dies gilt nur für die PAWN Version SSCANF
    In der Plugin Version von SSCANF sind die Platzhalter für einen Datentyp Anders!
    http://forum.sa-mp.com/showthread.php?t=120356


    Also ändern wir erst einmal die sscanf Zeile:
    if(sscanf(params, "uz",pID,sGrund)) {
    Das tolle daran ist,wird kein Grund angegeben returnt sscanf nicht 0
    dcmd_kick(playerid,params[]) {
    new
    sGrund[128],
    pID;
    if(sscanf(params, "uz",pID,sGrund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid] ([grund],optional)");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,ThePlayer,sizeof(ThePlayer));
    format(string,sizeof(string),"%s (ID %d) wurde vom Server gekickt,Grund: %s",ThePlayer,pID,sGrund[0] ? sGrund : "<Kein Grund>");
    SendClientMessageToAll(COLOR_YELLOW,string);
    Kick(pID);
    return 1;
    }
    Was es mit dem sGrund[0] ? sGrund : "<Kein Grund>" auf sich hat möchte ich nicht genau erklären.Kurz gesagt,wenn das was vor dem "?" true ist (sGrund[0]) ,wird das nach dem "?" eingesetzt ( sGrund ),ansonsten das nach dem ":" ( "<Kein Grund>" ).Demnach,falls sGrund ein leerer string ist,also false,wird "<Kein Grund>" eingesetzt anstatt sGrund.


    Nun solltet ihr verstanden haben wie dcmd in Verbindung mit sscanf funktioniert.


    Hier noch ein weiterer Beispiele:
    public OnPlayerCommandText(playerid, cmdtext[])
    {
    dcmd(kick,4,cmdtext);
    dcmd(sethealth,9,cmdtext);
    dcmd(announce,8,cmdtext);
    return 0;
    }
    dcmd_sethealth(playerid,params[])
    {
    new
    pID,
    Float:fHP;
    if(sscanf(params, "uf",pID,fHP)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /sethealth [playerid] [healthpoints]");


    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");


    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    GivePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,GivePlayer,sizeof(GivePlayer));
    GetPlayerName(playerid,ThePlayer,sizeof(ThePlayer));
    SetPlayerHealth(pID,fHP);
    format(string,sizeof(string),"%s (ID %d) Healtpoints wurden von %s (ID %d) auf %.1f gesetzt!",GivePlayer,pID,ThePlayer,playerid,fHP);
    SendClientMessageToAll(COLOR_YELLOW,string);
    return 1;
    }
    dcmd_announce(playerid,params[]) {
    new
    sAnnounce[128];
    if(sscanf(params, "s",sAnnounce)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /announce [text]");
    }
    GameTextForAll(sAnnounce,3*1000,3);
    return 1;
    }
    dcmd_kick(playerid,params[]) {
    new
    sGrund[128],
    pID;
    if(sscanf(params, "uz",pID,sGrund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid] ([grund],optional)");
    }
    if(!IsPlayerConnected(pID)) {
    return SendClientMessage(playerid,COLOR_RED,"Kein Spieler mit angegebener ID Online");
    }
    new
    ThePlayer[MAX_PLAYER_NAME],
    string[128];
    GetPlayerName(pID,ThePlayer,sizeof(ThePlayer));
    format(string,sizeof(string),"%s (ID %d) wurde vom Server gekickt,Grund: %s",ThePlayer,pID,sGrund[0] ? sGrund : "<Kein Grund>");
    SendClientMessageToAll(COLOR_YELLOW,string);
    Kick(pID);
    return 1;
    }

    Wer sich trotzdem nochmal zu sscanf schlau machen möchte,sollte diesen Link hier anklicken:
    Fast Commands - SA:MP - sscanf


    Ich hoffe mal das ganze ist verständlich erklärt und von nun an werden einige mehr in diesem Forum auf dcmd + sscanf umsteigen.


    Goldkiller


    >> Teil 3 des Tutorials


    //Edit ( 3.10.2010 ) : Parameter u wird nun für Spieler genutzt anstatt d

    So ist es richtig als DCMD Killer_Kater, trotzdem solltest du auch darauf achten wieviele Strings du erstellst.
    new string1[256];
    new string2[256];
    new string3[256];

    Es würde auch reichen

    new str[128];

    Danach
    format(str,sizeof(str),"Du hast ID:%d %d WantedPunkte gegeben![Grund:%s]",pID,anzahl,grund);
    SendClientMessage(playerid,COLOR_RED,str);
    format(str,sizeof(str),"ID:%d %d hat dir %d WantedPunkte gegeben![Grund:%s]",playerid,anzahl,grund);
    SendClientMessage(playerid,COLOR_RED,str);
    format(str,sizeof(str),"HQ:%d hat %d %d WantedPunkte gegeben, weil %s",playerid,pID,anzahl,grund);
    for(new i = 0; i < MAX_PLAYERS; i++)
    {
    if(IsACop(i))
    {
    SendClientMessage(i,COLOR_RED,str);
    }
    }



    [iP]Zabus,diese Grafik ist ja mal ein Witz.
    http://www.kleiner-opa.de/pic/test.png
    Mich würde ja mal dazu der Code interessieren, mit dem es getestet wurde oder die genauen Timings.Find ich persöhnlich immernoch lustig zu sehen wie jmd da betreitet es gäbe ZCMD nicht :rolleyes: .


    Sollte WebsiteData[1][SiteCreat] ein String sein,dann musst du mit strcmp() vergleichen.
    if(!strcmp(WebsiteData[1][SiteCreat],deletorname,true)) { }

    Sehr gute Beschreibungen ;)
    Ich zitier mal:


    Alle infos auch pawn-lang.pdf.Das Kapitel dazu ist "Directives".

    if(sscanf(cmdtext, "uds",pID,anzahl,grund)) {


    cmdtext ist:

    Zitat

    /st Peter 2 Ein Test


    oder

    Zitat

    /straftat Peter 2 Ein Test


    Es wird nach 3 Parametern gesucht.
    Das Problem ist,der erste Parameter wird von sscanf() als /straftat erkannt./straftat passt aber nicht in den u Platzhalter,der nur für Spielername / SpielerID gedacht ist.Deshalb wird pID auch zu INVALID_PLAYER_ID ( Intern durch sscanf() ).
    Danach folgt das Peter als Integer gelesen werden soll. Peter ist aber keine Zahl,funktioniert als auch nicht es in anzahl zu speichern.
    Folglich wird dann 2 Ein Test als String gelesen.Das klappt,trotzdem war das ja nicht die Idee hinter dem ganzen.

    Ist auch richtig so,dass kein Spieler gefunden wird.

    if(sscanf(cmdtext, "uds",pID,anzahl,grund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /st [playerid][Anzahl an WantedPunkten][grund]");
    }

    Du darfst da auch nicht in cmdtext suchen.
    Denn cmdtext wird vermutlich etwas sein wie :

    Zitat

    /strafttat Peter 2 Eine Testverwarnung


    Deshalb mach lieber mal,auch wenn Ich dir lieber zu DCMD oder ZCMD raten würde.

    //Removed


    //Edit:
    Moment,bin gerade etwas verwirrt.cmd dürfte auch nicht funktionieren,denn cmd ist doch auch nur mit strtok ein Teil von cmdtext,eben "/straftat".


    new
    _pos;
    _pos = strfind(cmdtext," ");
    if(sscanf(cmdtext[_pos], "uds",pID,anzahl,grund)) {
    return SendClientMessage(playerid,COLOR_RED,"USAGE: /st [playerid][Anzahl an WantedPunkten][grund]");
    }