Heyho Leutz,
Da mir grade langweilig ist dachte ich mir ich mache mal ein Tutorial für ein Haussystem, da ich bereits eins Geschrieben habe, ein grundgerüst dachte ich mir ich erkläre es mal.
Als Speicherung habe ich SQLite benutzt, welches ihr Hier nachlesen könnt: [ SCRIPTING ] SQLite | Die alternative zu MySQL
Ihr könnt es natürlich in jeder anderen Speicherart umschreiben aber ich kam damit am besten Klar deswegen.
Da ich nicht der Beste im erklären bin, Hoffe ich es ist verständlich geschrieben.
Fangen wir mal an, Ich habe folgende Includes verwendet:
ocmd: [ INCLUDE ] ocmd 2.1.0 [ Update 24.7.2013 ]
streamer: http://forum.sa-mp.com/showthread.php?t=102865
So als erstes Treffen wir ein Paar definierungen, welche die Farben, SendCliendMessage, und die Maximale Hausanzahl betrifft eingehen.
#define rot 0xFF0A00FF
#define gruen 0x4BB400FF
#define orange 0xFF9600FF
#define SCM SendClientMessage
#define MAX_HAUS 100
So nun benötigen wir eine Variable für die SQLite Datenbank
new DB:Database;
Okay nun fangen wir mit dem Eigendlichem System an, wir benötigen nun die Variablen für die Häuser, welche dann gespeichert, geupdatet etc.
Dies geht am Besten per enum.
enum haus
{
Float:X, //X Koordinate des Pickups/Label
Float:Y, //Y Koordinate des Pickups/Label
Float:Z, //Z Koordinate des Pickups/Label
hausobjekt, // Ist das einzelnde Haus
hPickup, // ist die Variable für das Hauspickup
Text3D:hLabel, //Ist der 3D TextLabel für das Label
Preis, //Die Variable für den Preis
vergeben, //Eine Variable ob das Haus vergeben ist
Besitzer[MAX_PLAYER_NAME], //Und der Besitzer des Hauses
bool:erstellt //Eine Variable, ob das Haus überhaupt vergeben ist. Warum "bool?" weil man einen Bool nur auf "1" oder "0" Setzen kann, welches hier auch nur bernötigt wird
}
new HausInfo[MAX_HAUS][haus]; //Und die Variable um auf das Enum zuzugreifen
Nun gehen wir zu OnGamemodeInit()
da brauchen wir nur 3 Sachen, diese währen:
Erstellung der SQLite datenbank, mit db_Open wird die Datenbank, wenn benötigt geöffnet, oder wie hier erstellt, "Database" ist dann die Variable, die in den Querys verwendet wird um die Datenbank zu öffnen und was eintragen oder zu löschen.
Database = db_open("Haus.db");
Wir benötigen auch die erstellung der Tabellen, diese werden hiermit automatisch aus dem Script erstellt.
db_query(Database,"CREATE TABLE IF NOT EXISTS `haus`(`ID`,`X`,`Y`,`Z`,`Preis`,`vergeben`,`Besitzer`)");
Und als 3. Laden wir die Häuser bequem über einen Stock, welcher createhouse() heißt, da es übersichtlicher ist.
createhouse();
So nun erstellen wir schritt für schritt den Stock...
stock createhouse()//der Stock ansich
{
new DBResult:Result, str[512],Text[256], rows;
for(new i=0;i<MAX_HAUS;i++)//nun gehen wir mit Hilfe einer Schleife alle Häuser einmal durch.
{
Nun gehen wir alle Häuser einmal durch, nun müssen wir aber auch was auslesen, was wir hier vorbereiten
format(str,sizeof(str),"SELECT * FROM `haus` WHERE `ID` = '%i'",i);//Nun formatieren wir einen string, welcher aus der Tabelle "haus" auslesen soll
Result = db_query(Database,str);//Die Variable wird nun beim aufrufen von Result den Query ausführen um was auszulesen
rows = db_num_rows(Result);//rows ist nun die variable für die Felder
if(rows == 0)continue;//Falls ein Feld in der Datanbank leer ist, wird sofort zum nächsten gegangen, ohne das die schleife unterbrochen wird
Nun haben wir allgemein aus der Tabelle auslesen lassen, jetzt gehen wir auf die Einzelnden Felder ein, diese weisen wir dann den daführ vorgesehenden Variablen zu
db_get_field_assoc(Result,"X",str,sizeof(str));//Nun Lesen wir das Feld "X" in der Tabelle aus
HausInfo[i][X]=floatstr(str);//Und geben diesen wert der Variabl "X"
db_get_field_assoc(Result,"Y",str,sizeof(str));//das passiert jetzt so wie bei "X", es werden jeweils Integer geladen
HausInfo[i][Y]=floatstr(str);
db_get_field_assoc(Result,"Z",str,sizeof(str));
HausInfo[i][Z]=floatstr(str);
db_get_field_assoc(Result,"Preis",str,sizeof(str));
HausInfo[i][Preis]=strval(str);
db_get_field_assoc(Result,"vergeben",str,sizeof(str));
HausInfo[i][vergeben]=strval(str);
db_get_field_assoc(Result,"Besitzer",str,sizeof(str));//Nun Lesen wir das Feld "Besitzer" aus
format(HausInfo[i][Besitzer],MAX_PLAYER_NAME,"%s",str);//Nun formatieren wir die Variable "Besitzer" in einen string, und geben den Wert vom besitzer dieser Variable
So nun haben wir Alles ausgelesen was wir Brauchen, das Haus ist Theoretisch erstellt, daher können wir die Variable auf 1 oder besser gesagt true setzen, da wir einen bool haben.
bei einen bool geht jeweils nur 0 oder 1, welches so gesetzt wird:
0 =false;
1 =true;
HausInfo[i][erstellt] = true;
So nun müssen wir herausfinden ob das Haus vergeben ist oder Nicht,
Falls es vergeben ist, Erstellen wir ein Textlabel, was den Besitzer anzeigt,
if(HausInfo[i][vergeben] == 1)//Haus ist vergeben
{
format(Text,sizeof(Text),"Haus\nBesitzer:\t%s",HausInfo[i][Besitzer]);//String wird für das Label Formatiert, es Zeigt Nur den Besitzer an.
HausInfo[i][hausobjekt] = CreateDynamicPickup(1239, 1, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z]);// Nun erstellen wir mit dem Streamer das Pickup, das Pickup ist nun der Variable "Hausobjekt" zugehörig
}
Fas es frei ist, zeigen wir das es zum Verkauf steht, und zeigen den Preis des Hauses an
else
{
format(Text,sizeof(Text),"Haus %d Zum Verkauf\n\nPreis:\t%d",i,HausInfo[i][Preis]);//String wird für das Label Formatiert, es Zeigt an das es Zum verkauf ist, zudem auch den Preis
HausInfo[i][hausobjekt] = CreateDynamicPickup(1273, 1, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z]); // Nun erstellen wir mit dem Streamer das Pickup, das Pickup ist nun der Variable "Hausobjekt" zugehörig
}
So nun haben wir die Schrift für das Label formatiert und die Pickups erstellt, nun müssen wir das Label anzeigen lassen, und zu Guter Letzt den Speicher den wir benötigt haben wieder frei geben.
HausInfo[i][hLabel] = Create3DTextLabel(Text, orange, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z], 15, 0);//erstellen des Labels, es gehört nun der Variable hLabel
db_free_result(Result);//Frei geben des benötigten Speichers.
}//schließen der Klammern
}//schließen der Klammern
So nun haben wir die Häuser nach einem Serverrestart geladen, Jezt gehen wir an die Erstellung.
Hierbei werde ich versuchen auf die Dynamic einzugehen, also alles sogut wie möglich zu erklären
ocmd:chaus(playerid,params[])
{
new Float:x,Float:y,Float:z,Float:a,preis,Text[256], query[256];
if(!IsPlayerAdmin(playerid)) return SCM(playerid,rot,"Du bist nicht befugt!");
if(sscanf(params,"d", preis)) return SCM(playerid,rot,"Benutze: /chaus [Preis]");
Okay Soweit söllte es noch klar sein, was für was steht.
Nun finden wir die Position und die Blickrichtung des Spielers heraus, dies machen wir hiermit,
GetPlayerPos(playerid, x, y, z);//daführ benötigen wir die oben erstellten floats Float:x,Float:y,Float:z
GetPlayerFacingAngle(playerid,a); //daführ benötigen wir die oben erstellten floats Float:a
So nun haben wir einen Grundbefehl, Und die Position und Blickrichtung des Spielers
Das ist im Grunde schon die Halbe Miete. Nun benötigen wir allerdings eine For new schleife die einmal alle häuser durchgeht.
for(new i = 0;i < MAX_HAUS; i++)
{
}
Nun müssen wir abfragen ob ein Haus schon erstellt ist, falls ja wird es übersprungen.
Das hat den Sinn das wir für die Datenbank eine ID brauchen die sich nicht überscheidet.
das machen wir damit, dies komm in die Schleife, weil wir ja alle häuser durchgehen
if(HausInfo[i][erstellt] == true)continue;
Danach können wir das Haus als erstellt setzen, Zeitgleich setzen wir die Variablen für die Position, der variable die wir durch die position herausgefunden haben
HausInfo[i][erstellt] = true;
HausInfo[i][X] = x;
HausInfo[i][Y] = y;
HausInfo[i][Z] = z;
So nun haben die Variablen den Wert welchen sie haben sollen, nun setzen wir den Preis und den Besitzer, und erstellen das Label und Pickup gleich mit.
HausInfo[i][Preis] = preis;
HausInfo[i][vergeben] = 0;
HausInfo[i][Besitzer] = 0;
HausInfo[i][hausobjekt] = CreateDynamicPickup(1273, 1, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z]);
format(Text,sizeof(Text),"Haus %d Zum Verkauf\n\nPreis:\t%d",i,HausInfo[i][Preis]);
HausInfo[i][hLabel] = Create3DTextLabel(Text, orange, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z], 15, 0);
Nun haben wir das Haus erstellt, aber es wird nichts gespeichert, das tragen wir mit einem Update Query in die Datenbank ein, am ende geben wir über ne SendClientMessage aus das das Haus erstellt ist, und unterbrechen die schleife mit einem return 1; es söllte selbsterklärend sein.
format(query,sizeof(query),"INSERT INTO `haus` (`ID`, `X`,`Y`,`Z`,`Preis`,`vergeben`,`Besitzer`) VALUES ('%i','%f','%f','%f','%d','Niemand')",i,x,y,z,preis,0);
db_query(Database,query);
SCM(playerid,gruen,"Haus erstellt");
return 1;
Und nun sind wir mit dem Befehl fertig, wir schließen nun die Restlichen Klammern und returnen es.
return 1;
}
Nun Basteln wir einen befehl um ein Haus in der nähe zu löschen, dazu benötigen wir als erstes einen Stock, da dies einfacher und schneller geht.
Die Funktion geht eigendlich nur einer whille schleife durch alle häuser und prüft ob er in der nähe des pickups ist.
stock IsHaus(playerid)
{
new i=0;
while(i != MAX_HAUS)
{
if(IsPlayerInRangeOfPoint(playerid, 3.0, HausInfo[i][X], HausInfo[i][Y], HausInfo[i][Z]))
{
return i;
}
i++;
}
return -1;
}//da gibt es nicht viel mehr zu erklären.
So nun können wir erstmal den Befehl erstellen
ocmd:delhaus(playerid, params[])
{
if(!IsPlayerAdmin(playerid)) return SCM(playerid,rot,"Du bist nicht befugt!");
Soweit söllte alles Klar sein, Nun erstellen wir eine Neue Variable, und rufen mit dieser den eben erstellten Stock auf.
Dann Fragen wir ob die Variable auf -1 ist, wenn es so ist ist er in der nähe eines Hauses
new id = IsHaus(playerid),query[256];
if(id != -1)
{
Nun setzen wir alle Variablen des einzelnden Hauses auf 0, damit sie beim nächsten Haus wieder verwendet werden können.
HausInfo[id][erstellt] = false;
HausInfo[id][X] = 0.0;
HausInfo[id][Y] = 0.0;
HausInfo[id][Z] = 0.0;
HausInfo[id][Preis] = 0;
HausInfo[id][vergeben] = 0;
HausInfo[id][Besitzer] = 0;
So nun Steht nichts mehr im Wege das wir das Label und den Pickup löschen können, dies können wir einfach machen, da wir es den Variablen zugewiesen haben.
DestroyDynamicPickup(HausInfo[id][hausobjekt]);
Delete3DTextLabel(HausInfo[id][hLabel]);
Um das Haus endgültig zu löschen müssen wir nun den Eintrag in der Datenbank löschen.
dazu formatieren wir einen string, welchen wir dann über einen query ausgeben, dann geben wir eine SendClientMessage aus das das haus gelöscht wurde und unterbrechen es mit einem return 1;
format(query,sizeof(query),"SELECT * FROM haus WHERE ID = '%d'",id);
format(query,sizeof(query),"DELETE FROM haus WHERE ID = '%d'",id);
db_query(Database,query);
SCM(playerid,gruen,"Du hast das Haus gelöscht");
return 1;
So nun schließen wir die Klammern und geben aus, wenn er nicht in der nähe ist, das er an keinem haus ist. zusätzlich returnen wir das ganze.
}
else
{
SCM(playerid,rot,"Du bist an keinem Haus");
}
return 1;
}
So Was haben wir nun erreicht?
Wir haben erreicht das wir häuser erstellen, löschen und sie geladen werden, nun wird es zeit das man sie Kaufen/Verkaufen kann, das ist auch nichtmal soschwer, wenn man es einmal begriffen hat.
Damit wir den Namen einfacher herausbekommen, und anwenden können rufen wir ihn per stock auf.
stock SpielerName(playerid)
{
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid,name,sizeof(name));
return name;
}
So aber nun an den Kauf befehl..
ocmd:hauskaufen(playerid,params[])
{
new id = IsHaus(playerid),Text[256],query[256];
if(id != -1) //hier brauch ich nicht mehr viel erklären, da es das selbe wie beim lösch befehl ist.
{
So nun währe der fall, das wenn ein spieler das haus besitzt und ein anderer spieler es haben möchte das er es einfach "wegnimmt"
Dies können wir hiermit verhindern, wir fragen einfach ab ob das haus vergeben ist.
if(HausInfo[id][vergeben] != 0) return SCM(playerid,rot,"Das haus ist bereits vergeben!");
Falls es nicht vergeben ist setzen wir die Variablen für den Namen des Besitzers den spielernamen, und setzen die variable das das haus vergeben ist auf true; und zu guter letzt ziehen wir dem spieler das geld ab, welches als preis für das haus gilt
HausInfo[id][vergeben] = 1;
HausInfo[id][Besitzer] = SpielerName(playerid);
SCM(playerid,gruen,"Du hast das Haus gekauft");
GivePlayerMoney(playerid,-HausInfo[id][Preis]);
Nun müssen wir auch das Pickup ändern, ich hab es so gemacht das es ein anderes als beim freien haus ist, das textlabel muss auch geändert werden, am besten löschen wir die beiden sachen,
Und setzen sie dann neu
Delete3DTextLabel(HausInfo[id][hLabel]);
DestroyDynamicPickup(HausInfo[id][hausobjekt]);
HausInfo[id][hausobjekt] = CreateDynamicPickup(1273, 1, HausInfo[id][X], HausInfo[id][Y], HausInfo[id][Z]);
So nun haben wir das Pickup schon neu gesetzt, jetzt müssen wir noch das Textlabel neu formatieren und erstellen, dies machen wir so,
format(Text,sizeof(Text),"Haus\nBesitzer:\t%s",HausInfo[id][Besitzer]);
HausInfo[id][hLabel] = Create3DTextLabel(Text, orange, HausInfo[id][X], HausInfo[id][Y], HausInfo[id][Z], 15, 0);
Rein vom Aussehen her gehört das Haus nun jemanden, aber in der Datenbank ist es noch frei.
Dies ändern wir einfach mit nem Update Query, darauf werde ich aber nicht weiter drauf eingehen.
format(query,sizeof(query),"UPDATE `haus` SET `vergeben` = '%d',`Besitzer` = '%s' WHERE `ID` = '%d'",HausInfo[id][vergeben],HausInfo[id][Besitzer],id);
db_query(Database,query);
return 1;
Nun haben wir das auch in der Datanbank aktualisiert, der befehl ist fast fertig, wir müssen nur noch die meldung ausgeben, wenn er nicht am haus ist, und es returnen
}
else
{
SCM(playerid,rot,"Du bist an keinem Haus");
}
return 1;
}
Okay nun habt ihr für immer ein Haus Muhahahaha, nein spaß, Nun zum Verkaufen befehl, der letzte in dem Tutorial.
Fangen wir mit dem Grundbefehl an, wir fragen gleich wieder ab ob er in der nähe eines Hauses ist.
ocmd:hausverkaufen(playerid,params[])
{
new id = IsHaus(playerid),Text[256],query[256];
if(id != -1)
{
Nun fragen wir ab ob das haus überhaupt zum verkauf ist, also ob es überhaupt vergeben ist,
falls ja überprüfen wir ob das haus dem spieler gehört, welcher es verkaufen will
if(HausInfo[id][vergeben] != 1) return SCM(playerid,rot,"Du kannst das Haus nich verkaufen!");
if(strcmp(HausInfo[id][Besitzer], SpielerName(playerid), false)) return SCM(playerid,rot,"Das ist nicht dein Haus!");
So falls der Spieler der Inhaber des Hauses ist, setzen wir die Variable für den besitzer und das vergeben ist auf 0,
Nun geben wir dem Spieler den Preis des hauses wieder
HausInfo[id][vergeben] = 0;
HausInfo[id][Besitzer] = 0;
SCM(playerid,gruen,"Du hast das Haus Verkauft");
GivePlayerMoney(playerid,HausInfo[id][Preis]);
So nun hat der Spieler sein geld, haus ist frei alles schön und gut, nun müssen wir es noch "optisch" ändern, also an Label.
Daführ löschen wir das Label wieder und formatieren einen string den wir dann mit dem neuen Label ausgeben
Delete3DTextLabel(HausInfo[id][hLabel]);
format(Text,sizeof(Text),"Haus %d Zum Verkauf\n\nPreis:\t%d",id,HausInfo[id][Preis]);
HausInfo[id][hLabel] = Create3DTextLabel(Text, orange, HausInfo[id][X], HausInfo[id][Y], HausInfo[id][Z], 15, 0);
Okay, Haus frei sowie in den Variablen wie auch optisch, nun muss es auch in der Datenbank geändert werden.
daführ geben wir einen Update query aus
format(query,sizeof(query),"UPDATE `haus` SET `vergeben` = '%d',`Besitzer` = 'Niemand' WHERE `ID` = '%d'",HausInfo[id][vergeben],id);
db_query(Database,query);
return 1;
So nun haben wir das Haus komplett verkauft, der befehl ist somit vom inhalt vollendet, nun müssen wir nur noch die Klammern schließen und ausgeben wenn er an keinem haus ist.
}
else
{
SCM(playerid,rot,"Du bist an keinem Haus");
}
return 1;
}
Okay Das war mein Tutorial für das Grundgerüst eines Dynamischen Haussystems, ich hoffe es war soweit gut erklärt, da ich nicht gut erklären kann.
Bei Fragen oder wie man es Besser machen könnte, schreibt es bitte in den Thread.
Ich hoffe ebenfalls das es für manche hilfreich ist.
Ich habe versucht das es nicht so ein Copy&Paste tut ist, ob es gelungen ist, ka^^
MfG Music4You