Hallo, und willkommen zu meinem ersten Tutorial! Ich möchte in diesem Tutorial zeigen, wie man einen simpelen TDM-Gamemode scriptet. Dieses Tutorial ist vorallem an Anfänger gerichtet, die noch keinen richtigen Gamemode gescriptet haben sondern jediglich die Grundlagen kennen. Also, fangen wir an!
Das Grundgerüst
Zuallererst erstellen wie einen neuen Gamemode. Die Callbacks "OnFilterScriptInit()" und "OnFilterScriptExit()" können wir problemlos entfernen, da es sich ja um einen Gamemode handelt. Der Code, der bei "OnGameModeInit()" miterstellt wird, kann bis auf das "return 1;" entfernt werden. Dort fügen wir zuerst unsere "Spielerklassen" ein, also die Figuren, die man dann im Spiel auswählen kann. Dazu benötigen wir zuerst die Postion, an der die Spielerfigur spawnen; also wo man nach der Figurauswahl steht; soll. Diese können wir ingame mit dem Befehl "/save", der auf jedem Server vorhanden ist, abspeichern. Es empfiehlt sich, nach "/save" noch zu schreiben, um was es sich für eine Postion handelt. Dies ist bei größeren Mengen an gespeicherten Postionen natürlich von Vorteil. Also z. B. "/save Ballas Spawn". Die Postionen werden dann in eurem GTA San Andreas Ordner in der Datei savedpositions.txt gespeichert. Wenn ihr die Datei nun öffnet, könnte es so aussehen:
AddPlayerClass(288,1939.2563,-1117.9183,26.4455,179.6119,0,0,0,0,0,0); // Ballas Spawn
Beim 2.,3. und 4. Parameter kann man die Koordinaten ablesen. Beim 5. Parameter kann man die Richtung ablesen. Nun haben wir also die Koordinaten + Richtung. Nun kehren wir wieder zu unserem Pawn-Editor zurück und fügen bei OnGameModeInit folgende Zeilen ein:
AddPlayerClass(105,2511.2092,-1688.0992,13.5621,44.2817,24,60,26,100,18,8); // grove1
AddPlayerClass(106,2512.6931,-1672.5791,13.5036,66.8167,6,1,31,400,22,80); // grove2
AddPlayerClass(107,2517.3416,-1661.4232,14.2167,100.0303,32,550,23,50,4,1); // grove3
AddPlayerClass(102,1910.1559,-1123.0077,25.5906,183.7904,24,60,26,100,18,8); // ballas1
AddPlayerClass(103,1939.0726,-1114.7036,27.4523,178.7263,6,1,31,400,22,80); // ballas2
AddPlayerClass(104,2002.9470,-1115.9773,27.1250,181.3781,32,550,23,50,4,1); // ballas3
Wie ihr seht, habe ich ein bisschen vorgearbeitet und schon viele Postionen gesaved. Ihr seht, dass beim ersten Parameter verschiedene Zahlen sind. Es handelt sich hierbei um SkinIDs. Jeder Skin (=Spielerfigur) hat eine eigene ID, mit der man sie bestimmen kann. Alle SkinIDs findet ihr hier. Aber wofür sind die 6 letzten Parameter? Sie sind dafür da, um den Spielerfiguren Waffen zu geben! Somit wissen wir nun, wie AddPlayerClass aufgebaut ist, nämlich so:
AddPlayerClass(SkinID,x,y,z,richtung,WaffenID1,Munition1,WaffenID2,Munition2,WaffenID3,Munition3);
Aber woher bekommen wir nun die WaffenIDs? Genauso einfach wie bei den SkinIDs!Nämlich hier! Wenn ihr also wollt, dass der Spieler eine 9mm mit 20 Schuss bekommt, ist WaffenID1 = 22 und Munition1 = 20! Nun haben wir schon verschiedene Spielerklassen. Das einzige Problem: Wir sehen bei der Spielerauswahl unseren Skin nicht! Das ist natürlich ein wenig blöd. Wir entfernen also nun den vorgefertigten Code beim Callback "OnPlayerRequestClass()" bis auf das "return 1;" und fügen nun folgende Abfragen ein:
if (classid == 0) //grove1
{
}
if (classid == 1)//grove2
{
}
if (classid == 2)//grove3
{
}
if (classid == 3)//ballas4
{
}
if (classid == 4)//ballas5
{
}
if (classid == 5)//ballas6
{
}
"Wozu brauche ich für jede classid eine Abfrage?", fragt ihr euch vielleicht. Wenn ihr meine Spielerklassen verwendet, werdet ihr sicherlich bemerkt haben, dass jede Spielerfigur eine andere Postion hat. Somit muss die Kamera ihre Position/Richtung auch jedesmal ändern, damit wir unsere ausgewählte Spielerklasse sehen. Dies macht SAMP allerdings nicht von alleine. Deshalb gibt es die Funktionen SetPlayerCameraPos(playerid, x,y,z) (Ändert die Postion der Kamera auf x,y,z) und SetPlayerCameraLookAt(playerid,x,y,z); (Lässt die Kamera auf die Postion x,y,z gucken). Ich habe eine kleine Grafik erstellt, um das ganze etwas anschaulicher zu erklären. Diese findet ihr hier. Kümmern wir uns zuerst um die erste if-Abfrage, also grove1:
if (classid == 0) //grove1
{
SetPlayerPos(playerid, 2511.2092,-1688.0992,13.5621);
SetPlayerFacingAngle(playerid,44.2817);
SetPlayerCameraPos(playerid, 2508.6785,-1685.8330,13.5628);
SetPlayerCameraLookAt(playerid, 2511.2092,-1688.0992,13.5621);
}
Eventuell etwas verständlicher:
if (classid == 0) //grove1
{
SetPlayerPos(playerid, x,y,z); //x,y,z = Postion auf der der Spielerskin steht
SetPlayerFacingAngle(playerid,richtung); //richtung = Richtung, in die der Spielerskin steht
SetPlayerCameraPos(playerid, x,y,z); //x,y,z = Postion der Kamera
SetPlayerCameraLookAt(playerid, x,y,z); //x,y,z = Position vom Skin, auf den die Kamera guckt
}
Genau so geht das auch bei den anderen if-Abfragen! Bei mir sehen diese jetzt so aus:
if (classid == 0) //grove
{
SetPlayerPos(playerid, 2511.2092,-1688.0992,13.5621);
SetPlayerFacingAngle(playerid,44.2817);
SetPlayerCameraPos(playerid, 2508.6785,-1685.8330,13.5628);
SetPlayerCameraLookAt(playerid, 2511.2092,-1688.0992,13.5621);
}
if (classid == 1)//grove
{
SetPlayerPos(playerid, 2518.0532,-1677.3661,14.3649);
SetPlayerFacingAngle(playerid,48.3784);
SetPlayerCameraPos(playerid, 2515.3792,-1674.7891,13.7942);
SetPlayerCameraLookAt(playerid, 2518.0532,-1677.3661,14.3649);
}
if (classid == 2)//grove
{
SetPlayerPos(playerid, 2518.9741,-1661.5500,14.3701);
SetPlayerFacingAngle(playerid,95.8370);
SetPlayerCameraPos(playerid, 2516.1572,-1662.0303,14.0208);
SetPlayerCameraLookAt(playerid, 2518.9741,-1661.5500,14.3701);
}
if (classid == 3)//ballas
{
SetPlayerPos(playerid, 1910.1559,-1123.0077,25.5906);
SetPlayerFacingAngle(playerid,183.7904);
SetPlayerCameraPos(playerid, 1910.4298,-1126.7048,24.7416);
SetPlayerCameraLookAt(playerid, 1910.1559,-1123.0077,25.5906);
}
if (classid == 4)//ballas
{
SetPlayerPos(playerid, 1939.0726,-1114.7036,27.4523);
SetPlayerFacingAngle(playerid,178.7263);
SetPlayerCameraPos(playerid, 1938.8990,-1116.4243,26.9467);
SetPlayerCameraLookAt(playerid, 1939.0726,-1114.7036,27.4523);
}
if (classid == 5)//ballas
{
SetPlayerPos(playerid, 2002.9470,-1115.9773,27.1250);
SetPlayerFacingAngle(playerid,181.3781);
SetPlayerCameraPos(playerid, 2002.8882,-1118.4071,26.7813);
SetPlayerCameraLookAt(playerid, 2002.9470,-1115.9773,27.1250);
}
So... Das war's für diesen Abschnitt.
Verschiedene Teams
Mittlerweile haben wir nun ein Grundgerüst. Dieses ist jedoch noch sehr mager. Deshalb möchten wir uns mit einem der wichtigsten Sachen eines TDM-Gamemodes beschäftigen - den Teams. Wie ihr es (hoffentlich) mitbekommen habt, habe ich in meinem Gamemode 2 Teams bzw. Gangs: Ballas und Grove Street. Es ist nun wichtig zu wissen, welcher Spieler welcher Gang angehört. Dazu erstellen wir ein Array:
new Gang[MAX_PLAYERS];
Nun editieren wir die if-Abfragen bei OnPlayerRequestClass():
if (classid == 0) //grove
{
...
Gang[playerid] = 1;
}
if (classid == 1)//grove
{
{
...
Gang[playerid] = 1;
}
if (classid == 2)//grove
{
{
...
Gang[playerid] = 1;
}
if (classid == 3)//ballas
{
...
Gang[playerid] = 2;
}
if (classid == 4)//ballas
{
...
Gang[playerid] = 2;
}
if (classid == 5)//ballas
{
...
Gang[playerid] = 2;
}
Ihr erkennt vermutlich sofort, dass wenn man classid 0 - 2 nimmt, gang[playerid] = 1 (1 = Grove) ist und wenn die classid 3 - 5 ist, gang[playerid] = 2 (2 = Ballas) ist. Nun können wir jederzeit herausfinden, wer welchem Team gehört. Jetzt bauen wir eine Überprüfung ein, die prüft, wieviele Teamkills jemand gemacht hat. Sind es über 4, wird die Person gekickt. Dazu brauchen wir wiedermal ein Array:
new teamkills[MAX_PLAYERS];
Wichtig ist, dass wir den Wert des Arrays auf 0 Setzen, wenn jemand auf den Server kommt. Wieso? Stellt euch vor, jemand hat 2 Teamkills und verlässt den Server. Wenn nun jemand auf den Server kommt und die gleiche Playerid wie der vorherige Spieler hat, der ja schon 2 Teamkills hat, hat der Spieler der den Server gerade betreten hat schon 2 Teamkills, obwohl er ja noch nicht mal gespawnt ist. Um dies zu umgehen, genügt es, folgende Zeile beim Callback OnPlayerConnect() hinzuzufügen:
teamkills[playerid] = 0;
Aber nun zum Wichtigsten: Dem Zählen der Teamkills. Um herauszufinden, wer jemanden aus seinem eigenen Team gekillt hat, benutzen wir OnPlayerDeath(). Wir prüfen dabei einfach, ob gang[playerid] den gleichen Wert hat wie gang[killerid]. Wenn beide den gleichen Wert haben, bekommt killerid einen Teamkill. Das OnPlayerDeaht()-Callback in Code gefasst:
public OnPlayerDeath(playerid, killerid, reason)
{
if (gang[playerid] == gang[killerid])
{
teamkills[killerid] = teamkills[killerid] + 1;
if (teamkills[killerid] > 4)
{
Kick(killerid);
}
}
return 1;
}
Wenn killerid mehr als 4 Teamkills hat, wird er gekickt.