[jTuT] Interaktive Dialoge
Hallo zusammen,
dies ist mein erstes Tutorial. Es wird in diesem Tutorial erklärt, wie man Dialoge interaktiv machen kann, das heißt, dass sich listitems während ein Dialog geöffnet ist, hinzufügen und entfernen lassen.
Kurzer Überblick
- Was bewirkt dieses Tutorial am Ende und warum lest ihr euch das durch?
Ganz einfach! Mit wenigen Schritten und ein paar kleinen Funktionen ist es möglich, die Dialoge im Menu-Style interaktiv zu machen. Das bedeutet, es lassen sich listitems zu einem Menu hinzufügen oder entfernen, und das während der Dialog einem oder mehrerer Spieler gezeigt wird. Es werden hier keinerlei Timer benutzt, das heißt die ganze Sache wirkt sich keineswegs negativ auf die Rechenleistung eures Servers aus.
Schaut es euch doch einfach mal an, es wird sich lohnen.
Wir arbeiten uns durch den Code
- Als erstes überlegen wir uns, was wir denn überhaupt an Variablen bzw. Speichermedien brauchen um unser Vorhaben zu realisieren.
Um später wissen zu können, welcher Spieler gerade welchen Dialog offen hat, müssen wir eine globale (g_) Variable für alle Spieler erstellen (daher das MAX_PLAYERS-Array). Um Fehler zu verhindern, setzen wir den Wert für alle Spieler gleich auf -1.
- Anschließend müssen wir auch noch Variablen definieren, die wir später brauchen, um die Dialoge sauber und mit möglichst wenig Aufwand wieder anzeigen zu können. Außerdem wollen wir ja verhindern, zig mal das gleiche im Code stehen zu haben, daher machen wir es gleich mit Variablen, die wir später flexibel aufrufen können.
Dazu benötigen wir eine Konstante MAX_OWN_DIALOGS, diese gibt an, wie viele Dialoge im gesamten Code benutzt werden. Hierbei sollte die größte Dialog-ID, die benutzt wird, beachtet werden.
Außerdem brauchen wir noch globale Variablen für die Überschrift (Caption), den Menutext (Info) und die zwei Buttons (Button1 & Button2). Die Zahlen geben die jeweilige maximale Länge an, diese kann beliebig geändert werden, falls mehr benötigt wird. Zu beachten sei hier aber, dass je größer die Arrays, desto mehr Speicher muss später reserviert werden.
- Jetzt erstellen wir die Funktion, die uns das Menu anzeigen lässt und gleichzeitig die jeweiligen vergebenen Werte speichert.C
Alles anzeigenstock ShowPlayerDialog_Ex(playerid, dialogid, style, caption[], info[], button1[], button2[]) { //Wir speichern in der Spielervariable, dass der Spieler (playerid) den jeweiligen Dialog (dialogid) geöffnet hat. g_PlayerDialog[playerid] = dialogid; //Der Dialog wird angezeigt. Bis auf das _Ex am Ende ändert sich an der Funktion gar nichts. ShowPlayerDialog(playerid, dialogid, style, caption, info, button1, button2); //Wurde ein existierender Dialog geöffnet, dann werden die Daten für die Anzeige gespeichert. if(dialogid > -1 && dialogid < MAX_OWN_DIALOGS) { format(g_dCaption[dialogid], sizeof(g_dCaption[]), caption); format(g_dInfo[dialogid], sizeof(g_dInfo[]), info); format(g_dButton1[dialogid], sizeof(g_dButton1[]), button1); format(g_dButton2[dialogid], sizeof(g_dButton2[]), button2); } //Nach erfolgreicher Ausführung der Funktion geben wir 1 zurück. return 1; }
- Und wenn wir schon dabei sind, dann erstellen wir noch ein paar kleine aber nützliche Funktionen um später die Werte angenehm auszulesen.
Die jeweilige Funktion gibt lediglich den definierten Wert der jeweiligen zu einem Dialog gehörenden Variable zurück.
- Und wenn wir schon dabei sind, dann definieren wir auch gleich noch SpielerName, einfach eine kleine Funktion die uns das Leben leichter macht.
- Jetzt kommen wir zu einem sehr wichtigen Teil der interaktiven Dialoge, dem Hinzufügen und dem Entfernen von Items im Menu.
Fangen wir mit dem Hinzufügen an. Wir definieren eine Funktion AddItemToDialog in der wir die dialogid und den Text des Items mitgeben. Um Fehler zu verhindern, überprüfen wir, ob das selbe Item bereits in der Liste ist, falls ja, wird es entfernt und erneut hinzugefügt.C
Alles anzeigenstock AddItemToDialog(dialogid, item[]) { //Wir suchen das item. new l_pos = strfind(g_dInfo[dialogid], item); //Wurde das item gefunden, dann wird es entfernt. if(l_pos != -1) strdel(g_dInfo[dialogid], l_pos, l_pos+strlen(item)+1); //Anschließend wird das item in die Liste eingetragen. format(g_dInfo[dialogid], sizeof(g_dInfo[]), "%s%s\n", g_dInfo[dialogid], item); //Wir beenden die Funktion mit der Anweisung, den Dialog für alle Spieler zu aktualisieren. return UpdateDialogForAll(dialogid); }
- Das Selbe machen wir nun auch mit dem Entfernen von Items aus dem Dialog.C
Alles anzeigenstock RemoveItemFromDialog(dialogid, item[]) { //Wir suchen das item. new l_pos = strfind(g_dInfo[dialogid], item); //Wurde das item nicht gefunden, dann wird auch nichts gemacht. if(l_pos == -1) return 0; //Ansonsten wird es entfernt. strdel(g_dInfo[dialogid], l_pos, l_pos+strlen(item)+1); //Wir beenden die Funktion mit der Anweisung, den Dialog für alle Spieler zu aktualisieren. return UpdateDialogForAll(dialogid); }
- Jetzt haben wir die Funktion UpdateDialogForAll zwar schon zwei mal aufgerufen, wir haben sie aber noch gar nicht definiert. Das machen wir jetzt:C
Alles anzeigenstock UpdateDialogForAll(dialogid) { //Wir machen einen Durchlauf durch alle Spieler-IDs (i) for(new i=0; i<MAX_PLAYERS; i++) { //Wenn der Spieler den veränderten Dialog offen hat... if(g_PlayerDialog[i] == dialogid) { //...dann wird er ihm/ihr erneut gezeigt. ShowPlayerDialog(i, g_PlayerDialog[i], DIALOG_STYLE_LIST, g_dCaption[g_PlayerDialog[i]], g_dInfo[g_PlayerDialog[i]], g_dButton1[g_PlayerDialog[i]], g_dButton2[g_PlayerDialog[i]]); } } return 1; }
- Kurze Erklärung zu dem hier:
Was macht das?
Es ruft den Info-Text (g_dInfo) von der dialog-id auf (g_PlayerDialog) die der Spieler (i) geöffnet hat auf. - Wir benötigen jetzt noch eine kleine Funktion, die uns ein item anhand des listitems von OnDialogResponse zurückgibt:
Dazu zählen wir einfach die Zeilenumbrüche (\n). Wurde die richtige Anzahl gefunden (=listitem), dann wird der string zerstückelt und das item zurückgegeben.
Ich spare mir hier die Erklärungen im Code, das würde es nur unleserlich und unverständlich machen.C
Alles anzeigenstock GetItemFromDialog(dialogid, listitem) { new l_str[64], c_count, l_lastpos = -1, tmp[sizeof(g_dInfo[])]; for(new i=0; i<strlen(g_dInfo[dialogid]); i++) { if(g_dInfo[dialogid][i] == '\n') { if(c_count == listitem) { tmp = g_dInfo[dialogid]; strdel(tmp, i, strlen(g_dInfo[dialogid])); strdel(tmp, 0, l_lastpos+1); break; } c_count++; l_lastpos = i; } } format(l_str, sizeof(l_str), tmp); return l_str; }
- Dann kommen wir jetzt zu den Callbacks die wir bestücken. Fangen wir zuerst mit dem kürzesten an:
- Und zu guter Letzt noch ein Nutzungsbeispiel der Funktionen:C
Alles anzeigenpublic OnPlayerCommandText(playerid, cmdtext[]) { //Wir erstellen den command if(!strcmp("/ListeZeigen", cmdtext, true)) { //Wenn die Länge des Info-Textes 0 (!) ist, dann ist niemand in der Liste (nichts eingetragen) if(!strlen(GetDialogInfo(0))) return SendClientMessage(playerid, 0xFF0000FF, "Es ist niemand in der Liste."); //Ansonsten wird dem Spieler die Liste angezeigt. ShowPlayerDialog_Ex(playerid, 0, DIALOG_STYLE_LIST, "Beispiel", GetDialogInfo(0), "Ausw.", "Cancel"); return 1; } if(!strcmp("/InListeEintragen", cmdtext, true)) { //Wir tragen uns in die Liste mit der ID 0 ein. AddItemToDialog(0, SpielerName(playerid)); return 1; } if(!strcmp("/AusListeAustragen", cmdtext, true)) { //Und wir tragen uns wieder aus der Liste mit der ID 0 aus. RemoveItemFromDialog(0, SpielerName(playerid)); return 1; } return 0; }
- Abschließend dann noch das Beispiel zu OnDialogResponse:C
Alles anzeigenpublic OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { //Wählt der SPieler etwas aus, dann wir der Dialog immer geschlossen, das ist Standard in SA-MP, daher hat er/sie keinen Dialog mehr offen, also -1. g_PlayerDialog[playerid] = -1; //Hier fragen wir nun ab, ob der dialog die ID 0 hat, und ob die Antwort (response) auch wahr ist (also nicht Cancel). if(dialogid == 0 && response == 1) { //Wenn ja, führen wir den gewünschten Code aus. Hier einfach ein Beispiel wie man es machen kann. //Wir suchen aus der Liste einfach die Spieler-ID anhand des Namens, der ja in der Liste eingetragen worden war. new item[64], l_found_id = -1; //GetItemFromDialog gibt uns den Name anhand des listitems zurück. item = GetItemFromDialog(dialogid, listitem); //Wurde ein falsches listitem übergeben (sollte hier nicht vorkommen, aber bei anderen Dingen vielleicht), dann wird ein Fehler ausgegeben. if(!strlen(item)) return SendClientMessage(playerid, 0xFF0000FF, "Fehler: Item nicht gefunden"); //Anschließend suchen wir den Name des Spielers. for(new i=0; i<MAX_PLAYERS; i++) { if(IsPlayerConnected(i) && !strcmp(SpielerName(i), item)) { //Wurde der Name gefunden, wird seine/ihre ID gespeichert und die Schleife beendet (break). l_found_id = i; break; } } //Schlussendlich geben wir einfach eine Nachricht aus. Man könnte hier alles mögliche machen, z.B. zu l_found_id teleportieren, eine Nachricht an ihn/sie Schicken, etc. new l_str[144]; format(l_str, sizeof(l_str), "Info: Ich habe Spieler %s mit der ID %d angeklickt.", SpielerName(l_found_id), l_found_id); return SendClientMessage(playerid, -1, l_str); } return 0; }
- Und damit wären wir auch durch. Alles ist jetzt funktionsfähig und kann beliebig erweitert werden.
Für die Faulen unter uns
Damit wäre alles gesagt. Falls noch Fragen sind, gerne hier in diesem Thread stellen. Ich hoffe dem einen oder anderen hilft dieses Tutorial. Damit es auch noch anderen hilft, hinterlasst doch einfach kurz eine Rückmeldung, damit der Thread nicht stirbt.
Gerne freue ich mich auch, wenn Ihr den grünen Daumen drückt und damit eure Anerkennung zeigt.
Beste Grüße,
Jeffry