einfach per Befehl die Nametags für den Spieler anzuschalten der sie eingegeben hat
Was meinst du damit?
einfach per Befehl die Nametags für den Spieler anzuschalten der sie eingegeben hat
Was meinst du damit?
@Trooper[Y]
1. Da hast du Recht, ist halt schade für die, die wirklich was sinnvolles hinzufügen wollen.
2. Ok.
3. Ja, mehrmals.
Sieht so aus:
4. Ok.
Das sind "nur" Warnungen, keine Errors, die sollte man aber auch nicht ignorieren.
Wie sieht denn das enum aus?
Zu Punkt 1:
Die Warnung sagt aus, dass du im Code zwei mal ein #define OnPlayerRequestClass hast. Es sollte eigentlich nur in dem Code vorhanden sein, den ich dir gegeben habe, es sei denn es wird bereits ein Hook verwendet auf dieses Callback, der nicht nach diesem System aufgebaut ist.
Zu Punkt 2:
Die Funktion Hook_OnPlayerRequestClass existiert "virtuell".
Durch diese Zeile
sagen wir dem Compiler, dass von jetzt an (alles was danach folgt) alle "OnPlayerRequestClass" mit "Hook_OnPlayerRequestClass" ersetzt werden sollen (siehst du nicht, das macht der Compiler beim kompilieren). Das bedeutet, dass das OnPlayerRequestClass im Gamemode (kommt ja nach der Include) zu Hook_OnPlayerRequestClass umbeannt wird.
Stellt dann den Funktionskopf, damit die Funktion Hook_OnPlayerRequestClass auch deklariert ist.
Was also passiert ist:
Compiler geht in die Include -> kompiliert dort das OnPlayerRequestClass -> benennt danach alle folgenden OnPlayerRequestClass um zu Hook_OnPlayerRequestClass -> geht in den Gamemode zurück -> kompiliert OnPlayerRequestClass im Gamemode, welches Hook_OnPlayerRequestClass heißt.
Im Betrieb: OnPlayerRequestClass wird aufgerufen (befindet sich nur in der Include, weil im Gamemode wurde es ja zu Hook_OnPlayerRequestClass umbenannt) -> Am Ende von OnPlayerRequestClass in der Include wird mit CallLocalFunktion dann Hook_OnPlayerRequestClass aufgerufen -> OnPlayerRequestClass im Gamemode wird ausgeführt (vom Compiler als Hook_OnPlayerRequestClass bekannt).
Zu Punkt 3:
Es ist egal was dafür definiert wurde, es geht nur darum, ob es definiert wurde.
Das ist in diesem Code hier:
//Wenn _ALS_OnPlayerRequestClass definiert ist
#if defined _ALS_OnPlayerRequestClass
//dann ent-definiere OnPlayerRequestClass, damit es später wieder definiert werden kann.
#undef OnPlayerRequestClass
#else
//ansonsten definiere _ALS_OnPlayerRequestClass
#define _ALS_OnPlayerRequestClass
#endif
Genau genommen wird es als '' definiert, also nichts. Es ist aber definiert, nur halt als nichts. Daher reicht die Abfrage so. Du kannst es auch als Apfelkuchen definieren, das spielt keine Rolle, da es ohnehin nirgends verwendet wird, außer in der Abfrage, ob bereits gehookt wurde, also ob _ALS_OnPlayerRequestClass definiert ist.
Prinzipiell kann man diesen Teil auch komplett weg lassen, nur kommt es dann zu Problemen, wenn man das Callback in einer anderen Include bereits gehookt hat (das wäre dann genau die Warnung aus Punkt 1).
Diese #define-Struktur brauchst du eigentlich nicht auswendig zu können, ich kopiere die auch immer nur und ersetze die entsprechenden Teile mit den neuen Bezeichnungen, weil es schneller geht.
Welchen Teil von dem Code willst du denn erklärt haben? Einen bestimmten, oder alles davon?
Gute Sache!
Aber ein paar Fragen/Dinge dazu:
1) Kann ich eine Erklärung bearbeiten, wenn ja, wie?
2) Kann ich irgendwo meine gesendeten Erklärungen sehen?
3) WDas Profil Bild wird bei mir nicht angezeigt.
4) Kann man PWN Codes formatiert einfügen, oder den <img> Tag nutzen? (Hätte es probiert, wusste aber nicht ob ich es nochmal editieren kann).
Alle Befehle per Print? Das ist von der Performance her kein Problem.
Welchen Code? Pauschal kann man das nicht sagen, unter Umständen geht es manchmal, und manchmal nicht.
Ersteres ist vom Speicher her minimal besser, da es minimal weniger benötigt, und von der CPU Last ebenfalls etwas besser, da der Zugriff auf mehrdimensionale Arrays etwas langsamer ist.
Das sind aber jeweils minimale Unterschiede, die du unter normalen Umständen nicht bemerken wirst.
Schreibe deinen SetSkin stock so:
stock SetSkin(playerid,skin[])
{
new Spielerdatei[64];
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid,name,sizeof(name));
format(Spielerdatei,sizeof(Spielerdatei),"/Spieler-Dateien/%s.css",name);
SetPVarInt(playerid, "Skin", strval(skin));
SetPlayerSkin(playerid, strval(skin));
SpielerSpeichern(playerid);
return 1;
}
Alles anzeigen
Der Code ist aber ziemlich abenteuerlich.
OnPlayerStateChange kannst du so machen:
if(newstate == PLAYER_STATE_DRIVER)
{
if(!IsANoTachoVehicle(GetPlayerVehicleID(playerid)))
{
TextDrawShowForPlayer(playerid, Speedo[playerid]);
//SetTimerEx("Speedometer", 100, 1, "d", playerid);
//Ich habe diesen Timer auskommentiert, da er jedes mal gestartet würde,
//wenn du in ein Fahrzeug einsteigst, das einen Tacho hat, sprich irgendwann
//hast du 1000 Timer am Laufen, von denen jeder 10x pro Sekunde aufgerufen
//wird. Deine CPU wird dir das nicht danken ;)
//Also besser so:
speedoTimer[playerid] = SetTimerEx("Speedometer", 100, 1, "d", playerid);
//Und den Timer auch wieder beenden, wenn der Speedometer nicht mehr angezeigt wird.
//Oder noch besser ist es, einen einzigen globalen Timer mit einer Schleife durch
//alle Spieler zu machen, der Timer wird dann bei OnGameModeInit gestartet.
if(IsABike(GetPlayerVehicleID(playerid)))
{
timer2[playerid] = SetTimerEx("TankTimer",60000,1,"i",playerid);
}
else
{
timer2[playerid] = SetTimerEx("TankTimer",20000,1,"i",playerid);
}
}
//Hier der Code für die Roller:
new veh = GetPlayerVehicleID(playerid);
for(new i=0; i<sizeof(rentroller); i++)
{
if(veh == rentroller[i])
{
SendClientMessage(playerid,0xF60000F6,"Dieses Fahrzeug kannst du mieten! Tippe /rentcar, wenn du nicht möchtest, dann /verlassen.");
SendClientMessage(playerid,0xF60000F6,"Das Auto wird nach 30 Minuten respawnt.");
TogglePlayerControllable(playerid,0);
break;
}
}
}
Alles anzeigen
Den /rentcar Befehl kannst du dann so machen:
if(!strcmp("/rentcar", cmdtext, true))
{
new veh = GetPlayerVehicleID(playerid);
for(new i=0; i<sizeof(rentroller); i++)
{
if(veh == rentroller[i])
{
new kosten;
switch(i)
{
case 0: kosten = 100;
case 1: kosten = 250;
case 2: kosten = 2000;
//...
default: kosten = 500;
}
if(GetPlayerMoney(playerid) <= kosten) return SendClientMessage(playerid,0xF60000F6,"Du hast nicht genügend Geld!");
SendClientMessage(playerid,0xF60000F6,"Du hast dieses Auto gemietet!");
TogglePlayerControllable(playerid,1);
GivePlayerMoney(playerid,kosten);
return 1;
}
}
return SendClientMessage(playerid, 0xFF0000FF, "Error: Dies ist kein Auto, das gemietet werden kann.");
}
Alles anzeigen
Der /verlassen Befehl bleibt weitgehend gleich.
Wenn du es nun anpassen willst, dass das Fahrzeug für genau 30 Minuten aktiv ist, dann musst du eine Spielervariable anlegen, in der du den Wert speicherst, wann die Zeit vorbei ist und eine Variable die die Index ID beinhaltet, unter den Includes:
Sowie eine Variable um das Fahrzeug als gemietet zu markieren (-1 = nicht vermietet):
Unter OnGameModeInit startest du einen Prüf-Timer:
[wiki]SetTimer[/wiki]
Und der Code dazu:
forward CheckRentCars();
public CheckRentCars()
{
for(new i=0; i<MAX_PLAYERS; i++)
{
if(IsPlayerConnected(i) && rentTime[i] != 0 && rentTime[i] < gettime())
{
new idx = rentIdx[playerid];
SetVehicleToRespawn(rentroller[idx]);
SendClientMessage(i, 0xFF0000FF, "Zeit vorbei.");
rentTime[i] = 0;
}
}
return 1;
}
Alles anzeigen
Den /rentcar Befehl musst du dann so anpassen:
if(!strcmp("/rentcar", cmdtext, true))
{
if(rentTime[playerid] != 0) return SendClientMessage(playerid, 0xFF0000FF, "Error: Du hast bereits ein Auto gemietet.");
new veh = GetPlayerVehicleID(playerid);
for(new i=0; i<sizeof(rentroller); i++)
{
if(veh == rentroller[i])
{
new kosten;
switch(i)
{
case 0: kosten = 100;
case 1: kosten = 250;
case 2: kosten = 2000;
//...
default: kosten = 500;
}
if(GetPlayerMoney(playerid) <= kosten) return SendClientMessage(playerid,0xF60000F6,"Du hast nicht genügend Geld!");
SendClientMessage(playerid,0xF60000F6,"Du hast dieses Auto gemietet!");
TogglePlayerControllable(playerid,1);
GivePlayerMoney(playerid,kosten);
rentTime[playerid] = gettime() + 30 * 60 * 1000; //30 Minuten zu je 60 Sekunden und 1000ms.
rentIdx[playerid] = i;
rentBlocked[i] = playerid;
return 1;
}
}
return SendClientMessage(playerid, 0xFF0000FF, "Error: Dies ist kein Auto, das gemietet werden kann.");
}
Alles anzeigen
Bei OnPlayerDisconnect zum Beispiel:
if(rentTime[playerid] != 0)
{
new idx = rentIdx[playerid];
SetVehicleToRespawn(rentroller[idx]);
rentTime[playerid] = 0;
rentBlocked[idx] = -1;
}
Und das OnPlayerStateChange sieht dann so aus:
if(newstate == PLAYER_STATE_DRIVER)
{
if(!IsANoTachoVehicle(GetPlayerVehicleID(playerid)))
{
TextDrawShowForPlayer(playerid, Speedo[playerid]);
//SetTimerEx("Speedometer", 100, 1, "d", playerid);
//Ich habe diesen Timer auskommentiert, da er jedes mal gestartet würde,
//wenn du in ein Fahrzeug einsteigst, das einen Tacho hat, sprich irgendwann
//hast du 1000 Timer am Laufen, von denen jeder 10x pro Sekunde aufgerufen
//wird. Deine CPU wird dir das nicht danken ;)
//Also besser so:
speedoTimer[playerid] = SetTimerEx("Speedometer", 100, 1, "d", playerid);
//Und den Timer auch wieder beenden, wenn der Speedometer nicht mehr angezeigt wird.
//Oder noch besser ist es, einen einzigen globalen Timer mit einer Schleife durch
//alle Spieler zu machen, der Timer wird dann bei OnGameModeInit gestartet.
if(IsABike(GetPlayerVehicleID(playerid)))
{
timer2[playerid] = SetTimerEx("TankTimer",60000,1,"i",playerid);
}
else
{
timer2[playerid] = SetTimerEx("TankTimer",20000,1,"i",playerid);
}
}
//Hier der Code für die Roller:
new veh = GetPlayerVehicleID(playerid);
for(new i=0; i<sizeof(rentroller); i++)
{
if(veh == rentroller[i])
{
if(rentBlocked[i] == -1)
{
SendClientMessage(playerid,0xF60000F6,"Dieses Fahrzeug kannst du mieten! Tippe /rentcar, wenn du nicht möchtest, dann /verlassen.");
SendClientMessage(playerid,0xF60000F6,"Das Auto wird nach 30 Minuten respawnt.");
TogglePlayerControllable(playerid,0);
}
else
{
SendClientMessage(playerid,0xF60000F6,"Dieses Fahrzeug gehört bereits einem Spieler.");
RemovePlayerFromVehicle(playerid);
}
break;
}
}
}
Alles anzeigen
Beachte bitte die Kommentare im Code und passie die Stellen entsprechend an.
Wie sieht denn dein Code aus, und was klappt denn nicht?
Du musst den Code nicht im Detail verstehen, das ist einfach nur eine Hin-und-her-Definition. Man schält sich praktisch vor das Callback im Gamemode, definiert es um, und ruft es nach der Ausführung in der Include wieder im Gamemode, unter neuem Name, auf.
Callbacks sind Funktionsbausteine (public's) die unter bestimmten Umständen (OnPlayerConnect -> Verbindung hergestellt) aufgerufen werden.
Forwards sind dazu da, um selbst erstellte public's du instanziieren, da der Compiler sonst eine Fehlermeldung ausgibt, dass die forward-Funktion zu dem public fehlt (lacks forward definition ...). In manchen Fällen werden forwards aber auch anderweitig verwendet, zum Beispiel wenn du einen stock hast, der einen getaggten (Float:) Rückgabewert hat, dann muss der entweder vor der ersten Verwendung stehen (sprich in einer Include oder ganz oben im Code), oder ein forward enthalten.
Das ist eine Bahnschranke, die öffnet sich automatisch und schließt, wenn ein Zug vorbei kommt, daher steht sie so schräg.
Nutze das Objekt: 968
Ja, du musst den Download bestätigen (unterer Bildschirmrand).
Oder nimm die .zip aus meinem Post. Die musst du gegebenenfalls aber auch bestätigen, je nach dem wie dein Browser eingestellt ist. Das ist eine gewisse Sicherheit, damit nicht aus Versehen etwas heruntergeladen wird.