ZitatBitte nur Tutorials posten!
>> Verschoben
ZitatBitte nur Tutorials posten!
>> Verschoben
ZitatBitte nur Tutorials posten!
>> Verschoben
Ich bin mir ziemlich sicher du hast die Class ID mit der Skin ID vertauscht.Das ist beides nicht das gleiche.
AddPlayerClass - SA-MP Wiki
new
medicclass1,
medicclass2,
medicclass3,
policeclass1,
policeclass2,
policeclass3;
main()
{
print("\n----------------------------------");
print(" Blank Gamemode by your name here");
print("----------------------------------\n");
}
public OnGameModeInit()
{
SetGameModeText("Blank Script");
//Deine MedicClassen
medicclass1=AddPlayerClass(276, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
medicclass2=AddPlayerClass(278 , 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
medicclass3=AddPlayerClass(274, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
//Deine PolizeiClassen
policeclass1=AddPlayerClass(288, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
policeclass2=AddPlayerClass(285, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
policeclass3=AddPlayerClass(284, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
return 1;
}
public OnPlayerRequestClass(playerid, classid)
{
SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
//Anstatt die Skin ID jetzt die Class ID nehmen
if(classid == medicclass1 || classid == medicclass2 || classid == medicclass3)
{
gTeam[playerid] = TEAM_Medic;
}
if(classid == policeclass1 || classid == policeclass2 || classid == policeclass3)
{
gTeam[playerid] = TEAM_Cops;
}
return 1;
}
Huch,da hat eine ')' gefehlt :X. Hättest aber auch selber fixen können .
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid,name,sizeof(name));
if(!strcmp(name,"Pätzold",true,sizeof(name)) {
// team blabla
}
Alles anzeigenfrage:
{
if(name == Pätzold )
{
gTeam[playerid] = admin;
}
Du musst strcmp benutzten.
Also:
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid,name,sizeof(name);
if(!strcmp(name,"Pätzold",true,sizeof(name)) {
// team blabla
}
dcmd_givecash(playerid,params) {
new
ziel,
betrag
if (sscanf(params, "dd", ziel,betrag)) {
return SendClientMessage(playerid,0xFF0000FF,"Benutzung: /givecash [playerid] [betrag]");
}
if(!IsPlayerConnected(ziel) {
return SendClientMessage(playerid,0xFF0000FF,"Kein Spieler mit dieser ID gefunden");
}
if(betrag <= 0 || betrag > GetPlayerMoney(playerid)) {
return SendClientMessage(playerid,0xFF0000FF,"Ungültiger Geldbetrag");
}
GivePlayerMoney(ziel,betrag);
GivePlayerMoney(playerid,-betrag);
// Blabla nachrichten etc
return 1;
}
if(GetPlayerPos(i,X,Y,Z))
Kein großer Vorteil aber erspart die IsPlayerConnected Abfrage
if(IsPosInDistance(x,y,z,IconPos[j][0],IconPos[j][1],IconPos[j][2],DISTANCE))
Viel viel schneller als vorher die stock Funktion.
Zitat
Eine Ausnahme: Bei einem Derby ist Server immer abgestürzt. Wieso?
Ohne Source ist sowas immer schwer zu sagen.Kann viele Möglichkeiten haben.Meistens
kommt es vor das in Datein geschrieben wird die nicht existieren oder wenn man über ein Array hinnaus schreibt.
( new Test[MAX_PLAYERS]; new var=2423; Test[var]=-1; )
Das einzige was wirklich hilft ist den Server mit noch mehr Debug Nachrichten vollzupappen oder
gleich ganze Teile zu entfernen damit man den Bereich wo der Fehler sein könnte von vorne rein
eingeschränkt ist.Früher oder später findest du den Fehler / die Fehler dann sicherlich.
Crasht der Server denn immer bei "/erlaubnis hunter" oder tat er das nur einmal?
ZitatFührt der Server verschiedene Sachen im Script gleichzeitig aus? Denn dann würde das für mich heissen, dass der Bug auch woanders sein kann.
Nein,tut er nicht.Pawn arbeitet alles einzelnt nacheinander ab.
ZitatZusammenfassung: Kann es sein, dass ein enum den Server crasht oder dass jemand meinen Server crasht?
Ein Enum kann den Server nicht crashen,es ist eigentlich nichts Anderes als ein Array,Arrays crashen
ja auch nicht.Vorrausgesetzt
man benutzt sie richtig und nicht wie oben falsch.
Bei den for-player-Schleifen würde ich statt "MAX_PLAYERS", einfach "GetMaxPlayers()" benutzen.
Außerdem würde ich auf dcmd bzw. sscanf umsteigen. Verbraucht viel weniger Ressourcen.
Zum 1.Nein,das stimmt absolut nicht.Ich find leider den Post nicht mehr wo ich die Datan hatte.
//Edit: Hab es doch noch gefunden : >> Klick <<
Das ist vorallem besser es in der Methode #3 zu machen wenn man einen Server hat der nicht 200 Slots haben soll.Wer noch eine bessere Lösung möchte sollte sich das Ende des Posts nochmal angucken ...
Zum 2.Eindeutig,sehr zu empfehlen.
Zitat25 0er timer, 14 1er timer
Was sind denn 0er oder 1er timer?
Es gibt noch viel mehr möglichekeiten den Server zu entlasten.Ein großes Thema ist die deklaration von Variablen.
Wenn man von vorne rein weiss,das sein Server nicht 200 Slots für Spieler haben soll,kann man etwas ändern.
// unter #include <a_samp>
#if defined MAX_PLAYERS
#undef MAX_PLAYERS
#define MAX_PLAYERS 80
#endif
Das benutzte Ich zB.Da der Server sowieso nur auf 80 Slots gestellt ist,brauch ich keine Variablen mit einer größe von 200 ( = MAX_PLAYERS ) erstellen.Ob es wirklich schonender ist kann ich nicht sagen,wüsste nicht wie man es testen könnte.Es spart jedoch etwas an der *.AMX größe.
Außerdem ist es besser es so zu benutzten als in der oben gezeigten Methode #3 mit GetMaxPlayers.Es handelt sich nur um einen bruchteil einer ms,aber MAX_PLAYERS auf 80 definiert ist besser als eine Variable im Loop die auf 80 gesetzt ist.
Um ehrlich zu sein,es so zu lösen ist ziemlich schwach.Bei 2 Sprachen mag es noch gehen,aber bei 3,4 oder mehr wird es ziemliche fummelei.
Hab mir vor kurzem erst selber ein Language-System aufgebaut das ziemlich gut funktioniert.
Kannst es dir ja mal angegucken wenn du Lust hast:
gLanguageV2
Gute Frage.Beides ist wohl möglich.
enum e_Vehicle_Info {
bool:bLockCar,
LockCount,
bool:bDestroy
}
new VehicleInfo[MAX_VEHICLES][e_Vehicle_Info];
Funktioniert bei mir ohne Probleme.
Der Datentyp "u" ist natürlich was sehr feines.Gibts glaub ich noch gar nicht so lange.
Damit ist es jetzt sogar noch einfacher Commands mit Parametern zu erstellen bei denen ein Parameter der Spieler ist.
ZitatZum dritten kann man damit wirklich sehr elegant seinen gamemode strukturieren, indem man die Commands in eine include reinpfeffert, und so vor allem Freeroam oder RolePlay-Skripte viel übersichtlicher machen kann, weil in diesen Skripten, OnPlayerCommandText auch mal gerne die Hälfte der .pwn einnehmen kann.
Ist generell ekelig sich so ein Script anzugucken.Wenn ich schon sehe das dort überall tmp=strtok,cmd=strtok ... steht landet das Script im Papierkorb .Versteht man meist nur Bahnhof wenn man den Code nur überfliegt.Bei sscanf kann man trotz überfliegen den Command leicht und schnell verstehen.
Commands mit Parameter,was ist das?
An Beispielen wird euch das sicherlich deutlich,
Keine Paramter:
Zitat/lossantos - einfacher Teleport
/help
/time
Mit Paramtern:
Zitat/kick [playerid]
/announce [text]
/register [passwort] [password]
Natürlich ist den meisten hier im Forum die strtok variante sehr geläufig bei Commands mit Paramtern,eventuell
auch Commands mit strget zu erstellen.Doch es geht bei weitem einfacher und schneller
sowohl bei der Ausführung durch den Server als auch beim scripten.
Ich spreche von der Methode Commands zu erstellen in Verbindung von dcmd und sscanf.
Vorteile:
* Command ist viel besser strukturiert und besser lesbar
* CPU schonender als strtok oder strget (Code wird schneller ausgeführt durch CPU->Kann laggs vermindern)
* Bessere Gesamtstruktur des Scriptes (Es ist möglich die Commands in einem extra include aufzubewahren)
* DCMD enthält einen Filter (Command muss exakt eingegeben werden)
Hier ein einfaches Beispiel wie ein einfacher Command aussehen könnte mit einem extra Parameter,
/kick [playerid]
public OnPlayerCommandText(playerid, cmdtext[])
{
new
idx,
cmd[128];
cmd=strtok(cmdtext,idx);
if(!strcmp(cmd,"/kick",true,5)) {
new
sID[128],
pID;
sID=strtok(cmdtext,idx);
if(!strlen(sID)) {
return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid]");
}
pID=strval(sID);
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 0;
}
Natürlich funktioniert der Command auch so wunderbar,aber nur weil es funktioniert heisst nicht,dass es
so auch die beste Lösung ist.Sehr anläufig für viele Bugs.Was ist wenn wir einen String bestehend aus "gwefd23f%D" in einen Integer konvertieren wollen?Gut,dafür gibt es IsNumeric,aber wir werden später sehen,es geht besser.
Dazu kommt,dass man so auch euren Server crashen kann (Ja,das ist tatsächlich möglich mit dem Beispielcommand).
dcmd
Erfinder des dcmd's ist Dracoblue,vielleicht kennt ihr ihn eher von DINI,DUDB,Dutils oder djason.Das sind ebenfalls seine Werke.
Als erstes brauchen wir das dcmd-Macro.
#define dcmd(%1,%2,%3) if ((strcmp((%3)[1], #%1, true, (%2)) == 0) && ((((%3)[(%2) + 1] == 0) && (dcmd_%1(playerid, "")))||(((%3)[(%2) + 1] == 32) && (dcmd_%1(playerid, (%3)[(%2) + 2]))))) return 1
Der Command nun in der dcmd Form
public OnPlayerCommandText(playerid, cmdtext[])
{
dcmd(kick,4,cmdtext);
return 0;
}
dcmd_kick(playerid,params[]) {
if(!strlen(params)) {
return SendClientMessage(playerid,COLOR_RED,"USAGE: /kick [playerid]");
}
new
pID=strval(params);
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;
}
Auf den ersten Blick ist der Code nicht unbedingt viel kürzer,aber die länge ist nicht unbedingt ein wichtiges
Merkmal wie gut oder schlecht ein Code ist.Oft ist trotzdem kürzer besser ;P
Nun zu der Erklärung.Wie bereits erwähnt ist der Code lediglich etwas kürzer,dennoch wie Ich finde viel übersichtlicher
da das OnPlayerCommandText - Callback nicht voller endloslangen Codes ist.
Was bedeutet aber die Zeile in OnPlayerCommandText genau?
dcmd(kick,4,cmdtext);
kick,dass ist der Name des Commands den wir im 3 Paramter,cmdtext suchen.Es wird
überprüft ob ein Spieler /kick eingegeben hat.Die 4 steht dabei für die länge von kick.Das ganze muss man
ohne / angeben.Wieso ist relativ unwichtig,es sollte für den normalen gebrauch reichen.
Wichtig ist noch zu wissen,dass die Definitionszeile ( dcmd(<cmdname>,<cmdlänge>,<source>) ) immer unter das Callback OnPlayerCommandText(playerid,cmdtext[]) gehört.
So müsste als Beispiel die Definition von /ban aussehene:
dcmd(ban,3,cmdtext);
Kommen wir nun zu dem eigentlichen Command,dcmd_kick:
Wieso es dcmd_kick heisst sollte relativ klar sein,es ist einfach der Name des Commands.
Nun zu den Parametern.
dcmd_kick(playerid,params[])
Der erste Paramter,playerid ist wie der Name sagt die playerid von demjenigen der den Command ausgeführt hat.Der zweite Paramter wird meistens params genannt.Falls der Spieler nun /kick 34er2 eingegeben hat,würde params nun 34er2 enthalten.Sollte er auch nur /kick eingegeben hat,enthält params nicht.Ist also ein leerer String.
Wenn man das ganzes einmal verstanden hat,wird man merken das es so sehr sehr einfach ist.
Es gibt außerdem noch einen weitern Vorteil bei dcmd.Es enthält einen "Filter".Wer sich das ganze mal angucken möchte,nur zu: [HowTo] Fast command processor: DCMD
Allerdings müsste man auch strtok wieder benutzten,sobald man mehr als einen Paramter haben möchte in seinem Command,zB /kick [playerid] [grund].Jetzt kommt sscanf zum Einsatz.
Wenn die Funktion keine Parameter braucht, (zB bei Teleportcommands wie /sf (Teleportiert Spieler nach San Fierro)) kann man
folgende Warnung leicht unterdrücken.
Zitatwarning 203: symbol is never used: "params"
dcmd_info(playerid, params[]) {
#pragma unused params
//Do something here
}
Update 19.8.2010, Tutorial auf 2 ( 3 ) Post's aufgeteilt,da das Postlimit erreicht wurde ( Kein Edit mehr möglich ).
Überleg doch mal ein bischen...Wie soll man dir helfen wenn du nicht mal den Code zeigst wo es den Fehler gibt ? Am besten noch gleich die Zeilen daneben schreiben damit man aus der Fehlerlog sehen kann in welcher Zeile es Probleme gibt.
public OnPlayerCommandText(playerid, cmdtext[])
{ // Hier fehlte was
if(strcmp(cmdtext, "/me", true)==0)
{
new str[256], sname[256];
GetPlayerName(playerid, sname, 256);
format(str, 256, "%s %s", sname, cmdtext[4]);
SendClientMessageToAll(0x33CCFFAA, str);
return 1;
}
if (strcmp(cmdtext, "/heal", true)==0)
{
SetPlayerHealth(playerid, 100);
return 1;
}
// Hier weitere Commands einfügen oder auch nicht
return 0; // return musst du auch einfügen
} // Hier fehlte wieder etwas ;)
ZitatIsACopCar(modelid)
So wie ich das aber lese möchte er als Parameter schon die Model ID übergeben.
stock IsCopCar(modelid)
{
switch(modelid)
{
case 596:return 1; //Police Car (LSPD)
case 598:return 1; //Police Car (LVPD)
case 597:return 1; //Police Car (SFPD)
case 599:return 1; //Ranger
case 427:return 1; //Enforcer
case 523:return 1; //Cop Bike (HPV-1000)
}
return 0;
}
/* Oder mit vehicle ID */
stock IsCopCar(vehicleid)
{
switch(GetVehicleModel(vehicleid))
{
case 596:return 1; //Police Car (LSPD)
case 598:return 1; //Police Car (LVPD)
case 597:return 1; //Police Car (SFPD)
case 599:return 1; //Ranger
case 427:return 1; //Enforcer
case 523:return 1; //Cop Bike (HPV-1000)
}
return 0;
}
ZitatBei mir gibts nen eroor:
Wie wäre es wenn du mal zeigst was für ein Error?
public OnPlayerConnect(playerid)
{
new filename[256];
format(filename, sizeof(filename), "%s.ini",plname);
if(fexist(filename)) {
gPlayerAccount[playerid] = 1;
SendClientMessage(playerid, COLOR_YELLOW, "Einwohnermeldeamt: Daten gefunden ");
SendClientMessage(playerid, COLOR_WHITE, "Einwohnermeldeamt: Du kannst dich mit /Login [Passwort] anmelden ");
}
else {
gPlayerAccount[playerid] = 0;
SendClientMessage(playerid,COLOR_YELLOW," Einwohnermeldeamt: Fülle das Formular aus /register [passwort]");
}
return 1;
}
Du brauchst eine Variable pro Spieler,nicht eine Variable für alle.
new Text:drawAnzeige[MAX_PLAYERS];
new t_FuelTimer[MAX_PLAYERS];
Dann natürlich alle Variablen umändern
public OnPlayerConnect(playerid) {
drawAnzeige[playerid] = TextDrawCreate(0.0,434.0,"Benzin: 100");
//...
return 1;
}
Noch bessere wäre es du benutzt nur einen Timer für alle.
/* OnGameModeInit() */
SetTimer("FuelCheck",3*1000,true);
/* forward */
forward FuelCheck();
/* public */
public FuelCheck() {
for(new i;i<MAX_PLAYERS;i++) {
if(IsPlayerConnected(i)) {
if(IsPlayerInAnyVehicle(i)) {
//Update Draw Kram...
}
}
}
return 1;
}