De/Creating A Class System: Difference between revisions
m (→Einleitung) |
(fixed a bunch of clerical errors) |
||
Line 5: | Line 5: | ||
Notizen (/Überlegungen): | Notizen (/Überlegungen): | ||
*Es | *Es gibt 3 Klassen (Supporter, Medic und Assaulter) | ||
*Beim ersten Spawn bekommt man eine Standardklasse. | *Beim ersten Spawn bekommt man eine Standardklasse. | ||
*Wechselt man die Klasse, stirbt man und | *Wechselt man die Klasse, stirbt man und spawnt mit der neuen Klasse. | ||
==Daten die gebraucht werden== | ==Daten, die gebraucht werden== | ||
Als erstes eine Auflistung was wir | Als erstes eine Auflistung was wir an Codedateien brauchen: | ||
Header: | Header: | ||
Line 19: | Line 19: | ||
Das Klassensystem wird zu 100% | Das Klassensystem wird zu 100% serverseitig sein, der Client kann die Klassen aber wechseln. | ||
==Die Deklarationen== | ==Die Deklarationen== | ||
Line 131: | Line 131: | ||
virtual void ChangeClass(int NewClass); | virtual void ChangeClass(int NewClass); | ||
Diese Methode brauchen wir damit der Client(Spieler) per Menu/Konsole seine Klasse wechselt. | Diese Methode brauchen wir, damit der Client(Spieler) per Menu/Konsole seine Klasse wechselt. | ||
virtual int GetClass(); | virtual int GetClass(); | ||
Brauchen wir wenn wir noch | Brauchen wir, wenn wir noch Sachen wie Munition, Leben und Rüstungsinkrementierung für den Supporter/Medic einbauen wollen. | ||
// Initalisierung des Klassensystems! | // Initalisierung des Klassensystems! | ||
Line 147: | Line 147: | ||
void CheckAllClassConVars(); | void CheckAllClassConVars(); | ||
Diese Methode prüft ob wir einen gültigen Wert eingegeben haben | Diese Methode prüft, ob wir einen gültigen Wert eingegeben haben. | ||
Falls wir das nicht Prüfen würden dann würde eure Mod crashen | Falls wir das nicht Prüfen würden, dann würde eure Mod crashen! | ||
Falls der Wert nicht | Falls der Wert nicht stimmt, dann müsst ihr einen Wert für die Klasse setzen. | ||
// Hier wird geprüft ob wir die Klasse gewechselt haben: | // Hier wird geprüft ob wir die Klasse gewechselt haben: | ||
Line 161: | Line 161: | ||
Diese Methode setzt für jede Klasse den Wert für das Leben, Maximal Leben und Rüstung. | Diese Methode setzt für jede Klasse den Wert für das Leben, Maximal Leben und Rüstung. | ||
Leider wird die Rüstung über den Code der Recharger festgelegt | Leider wird die Rüstung über den Code der Recharger festgelegt, diesen müsst ihr ändern. | ||
// Setzt den neuen wert für die Check Variable: | // Setzt den neuen wert für die Check Variable: | ||
void SetCurrentClassValue(); | void SetCurrentClassValue(); | ||
Diese Methode ändert den Wert der CheckVariable für die Klassen sonst würde man immer wieder sterben! | Diese Methode ändert den Wert der CheckVariable für die Klassen, sonst würde man immer wieder sterben! | ||
// Die Klasse holen: | // Die Klasse holen: | ||
Line 176: | Line 176: | ||
int GetDefaultClassValue()const; | int GetDefaultClassValue()const; | ||
Diese Methode holt | Diese Methode holt vom Server die Standardklasse damit man im Falle einer ungültigen Klasse diese bekommt. | ||
// Schaltmethode die Klassen verteilt: | // Schaltmethode die Klassen verteilt: | ||
Line 185: | Line 185: | ||
// Legt das Leben für unsere | // Legt das Leben für unsere Klasse fest: | ||
int GetClassHealth()const; | int GetClassHealth()const; | ||
Diese Methode holt das Leben das ihr im Moment habt. | Diese Methode holt das Leben, das ihr im Moment habt. | ||
// Diese Methoden setzen für jede Klasse das Leben und die Armor | // Diese Methoden setzen für jede Klasse das Leben und die Armor | ||
int GetClassMaxHealth()const; | int GetClassMaxHealth()const; | ||
Die Methode holt das Maximale Leben das eure Klasse haben kann. | Die Methode holt das Maximale Leben, das eure Klasse haben kann. | ||
// Legt die Armor für die Klasse Fest: | // Legt die Armor für die Klasse Fest: | ||
int GetClassArmor()const; | int GetClassArmor()const; | ||
Diese Methode holt euch die Rüstung die ihr im | Diese Methode holt euch die Rüstung, die ihr im Moment habt. | ||
// Diese Methoden holen für jede Klasse das Leben und die Armor | // Diese Methoden holen für jede Klasse das Leben und die Armor | ||
int GetClassMaxArmor()const; | int GetClassMaxArmor()const; | ||
Diese Methode holt die Maximale Rüstung eurer Klasse( | Diese Methode holt die Maximale Rüstung eurer Klasse (ist leider noch unbrauchbar wegen dem Recharger Code!) | ||
==private== | ==private== | ||
Line 210: | Line 210: | ||
bool m_bFirstSpawn; | bool m_bFirstSpawn; | ||
Diese Variable ist für die | Diese Variable ist für die Abfrage für den ersten Spawn nötig. | ||
bool IsFirstSpawn(); | bool IsFirstSpawn(); | ||
Diese Methode gibt uns | Diese Methode gibt uns Auskunft ob wir das erstemal gespawnt sind. | ||
// Welche Klasse haben wir(enum): | // Welche Klasse haben wir(enum): | ||
Line 221: | Line 221: | ||
Diese Variable speichert den Wert unserer Klasse: | Diese Variable speichert den Wert unserer Klasse: | ||
// Prüft ob wir die Klasse gewechselt haben: | // Prüft, ob wir die Klasse gewechselt haben: | ||
int m_iCurrentClass; | int m_iCurrentClass; | ||
Das ist die Prüfungsvariable die den Wert unserer Momentanen Klasse enthält. | Das ist die Prüfungsvariable, die den Wert unserer Momentanen Klasse enthält. | ||
Der Wert wird dann geändert wqenn wie die Klasse wechseln. | Der Wert wird dann geändert wqenn wie die Klasse wechseln. | ||
// Hier setzen wir die | // Hier setzen wir die Standardklasse! | ||
int m_iDefaultClass; | int m_iDefaultClass; | ||
Diese Variable holt die Klasse des Servers und ist gleichzeitig die erste Klasse die man beim ersten | Diese Variable holt die Klasse des Servers und ist gleichzeitig die erste Klasse, die man beim ersten Spawn | ||
bekommt | bekommt. | ||
// Waffen, Leben und Armor der Klassen verteilen: | // Waffen, Leben und Armor der Klassen verteilen: | ||
Line 254: | Line 254: | ||
Da wir nun alles haben was wir brauchen müssen wir nur alles einbauen! | Da wir nun alles haben was wir brauchen müssen wir nur alles einbauen! | ||
Alles kommt in die ''player.cpp'' ganz ans Ende | Alles kommt in die ''player.cpp'' ganz ans Ende. | ||
Hier der Code mit | Hier der Code mit Erklärung: | ||
Added im Konstruktor: | Added im Konstruktor: | ||
Line 266: | Line 266: | ||
int m_iCurrentClass = m_iClass; | int m_iCurrentClass = m_iClass; | ||
// Die | // Die Standardklasse setzen! | ||
int m_iDefaultClass = default_class.GetInt(); | int m_iDefaultClass = default_class.GetInt(); | ||
// Standartwerte 100 für | // Standartwerte 100 für Leben/Armor: | ||
int m_iHealth = 100; | int m_iHealth = 100; | ||
int m_iArmor = 100; | int m_iArmor = 100; | ||
// Maximal Leben/Armor für | // Maximal Leben/Armor für jede Klasse: | ||
int m_iMaxHealth = 100; | int m_iMaxHealth = 100; | ||
int m_iMaxArmor = 100; | int m_iMaxArmor = 100; | ||
Line 308: | Line 308: | ||
m_iClass = m_iDefaultClass; | m_iClass = m_iDefaultClass; | ||
} | } | ||
// Jetzt werden die | // Jetzt werden die Klassen verteilt: | ||
switch(m_iClass) | switch(m_iClass) | ||
{ | { | ||
Line 322: | Line 322: | ||
//case Invalid: | //case Invalid: | ||
// Muss noch eingebaut werden! | // Muss noch eingebaut werden! | ||
// Hier bekommt man nur die | // Hier bekommt man nur die Standardwaffen! | ||
case Unassigned: | case Unassigned: | ||
// Hier setzen wir die | // Hier setzen wir die Standardklasse! | ||
default: | default: | ||
SetClassDefault(); | SetClassDefault(); | ||
Line 335: | Line 335: | ||
if( m_iClass != m_iCurrentClass ) | if( m_iClass != m_iCurrentClass ) | ||
{ | { | ||
// Spieler killen und | // Spieler killen und Punkte um 1 erhöhen (wegen Selbstmord)! | ||
CommitSuicide(); | CommitSuicide(); | ||
IncrementFragCount(1); | IncrementFragCount(1); | ||
// Setzen damit wir nicht die | // Setzen, damit wir nicht die selbe Klassen haben! | ||
m_iCurrentClass = m_iClass; | m_iCurrentClass = m_iClass; | ||
} | } | ||
Line 346: | Line 346: | ||
void CBasePlayer::CheckAllClassConVars() | void CBasePlayer::CheckAllClassConVars() | ||
{ | { | ||
// Haben wir eine Klasse die zwischen Spec-Ops und der letzen Klasse liegt? | // Haben wir eine Klasse, die zwischen Spec-Ops und der letzen Klasse liegt? | ||
if( m_iClass < Assaulter || m_iClass > Medic ) | if( m_iClass < Assaulter || m_iClass > Medic ) | ||
{ | { | ||
Line 369: | Line 369: | ||
void CBasePlayer::SetClassGroundUnit() | void CBasePlayer::SetClassGroundUnit() | ||
{ | { | ||
// | // Standardwerte für Leben/Armor: | ||
m_iHealth = 125; | m_iHealth = 125; | ||
m_iArmor = 125; | m_iArmor = 125; | ||
// Maximal Leben/Armor für | // Maximal Leben/Armor für jede Klasse: | ||
m_iMaxHealth = 125; | m_iMaxHealth = 125; | ||
m_iMaxArmor = 125; | m_iMaxArmor = 125; | ||
Line 420: | Line 420: | ||
void CBasePlayer::SetClassMedic() | void CBasePlayer::SetClassMedic() | ||
{ | { | ||
// | // Standardwerte für Leben/Armor: | ||
m_iHealth = 100; | m_iHealth = 100; | ||
m_iArmor = 75; | m_iArmor = 75; | ||
Line 445: | Line 445: | ||
} | } | ||
// Legt die Armor für die Klasse | // Legt die Armor für die Klasse fest: | ||
int CBasePlayer::GetClassArmor()const | int CBasePlayer::GetClassArmor()const | ||
{ | { | ||
Line 471: | Line 471: | ||
// Variable gehört nicht zu CBasePlayer!!! | // Variable gehört nicht zu CBasePlayer!!! | ||
// TODO: Das ist eine Private Variable die ich ändern muss! | // TODO: Das ist eine Private Variable, die ich ändern muss! | ||
SetArmorValue(GetClassArmor()); | SetArmorValue(GetClassArmor()); | ||
// SetMaxArmorValue(GetClassMaxArmor()); | // SetMaxArmorValue(GetClassMaxArmor()); | ||
} | } | ||
// Klasse per ConVar | // Klasse per ConVar Wechsel für Client: | ||
void CBasePlayer::ChangeClass(int NewClass) | void CBasePlayer::ChangeClass(int NewClass) | ||
{ | { | ||
Line 482: | Line 482: | ||
} | } | ||
Da ihr ja schon wisst wofür die ganzen Methoden sind müsst ihr nur noch gucken wie alles läuft :) | Da ihr ja schon wisst, wofür die ganzen Methoden sind, müsst ihr nur noch gucken wie alles läuft :) | ||
Aber nun mal zum | Aber nun mal zum Einbauen der ConVars, die man braucht: | ||
// Der Server hat für alle die selbe | // Der Server hat für alle die selbe Standardklasse! | ||
// Der Admin kann die Standartklasse ändern! | // Der Admin kann die Standartklasse ändern! | ||
ConVar default_class("default_class", "3", FCVAR_ARCHIVE, "Variable für | ConVar default_class("default_class", "3", FCVAR_ARCHIVE, "Variable für Standardklasse!"); | ||
Nun hat der Server seine Default Klasse die jeder Spieler beim | Nun hat der Server seine Default-Klasse, die jeder Spieler beim Spawnen bekommt. | ||
Diese könnt ihr dann über die Konsole ändern :) | Diese könnt ihr dann über die Konsole ändern :) | ||
Ihr könnt auch noch mehr Settings für den Admin zur | Ihr könnt auch noch mehr Settings für den Admin zur Verfügung stellen: | ||
// Maximale Klassen erlauben(Admins!) | // Maximale Klassen erlauben(Admins!) | ||
Line 509: | Line 509: | ||
Diese müsst ihr aber selbst implementieren! | Diese müsst ihr aber selbst implementieren! | ||
Nun müssen wir nur noch dem Spieler die | Nun müssen wir nur noch dem Spieler die Möglichkeit zum Ändern der Klasse geben! | ||
Und dann muss man noch die Prüfungen der Klassen einbauen! | Und dann muss man noch die Prüfungen der Klassen einbauen! | ||
Dazu müssen wir einfach in der Methode OnClientCommand folgendes einbauen am | Dazu müssen wir einfach in der Methode OnClientCommand folgendes einbauen am Ende: | ||
else if ( !stricmp( cmd, "class" ) ) | else if ( !stricmp( cmd, "class" ) ) | ||
Line 525: | Line 525: | ||
} | } | ||
Hier mit wird eine ConVar | Hier mit wird eine ConVar simuliert. | ||
Aber man kann durch Class und dann die Klassennummer also Class 1 die Klasse ändern! | Aber man kann durch Class und dann die Klassennummer, also Class 1, die Klasse ändern! | ||
Nun müssen wir aber die Prüfungsmethode aufrufen und dann haben wirs schon! | Nun müssen wir aber die Prüfungsmethode aufrufen und dann haben wirs schon! | ||
Das machen wir in der Methode PostThink(); | Das machen wir in der Methode PostThink(); | ||
Dort setzen wir am | Dort setzen wir am Ende einfach folgendes ein: | ||
OnClassChange(); | OnClassChange(); | ||
Das wars :) wenn alles stimmt dann dürfte euer Klassensystem | Das wars :) wenn alles stimmt dann dürfte euer Klassensystem funktionieren ;) | ||
==Wichtiges zum Code== | ==Wichtiges zum Code== | ||
Damit der Code ohne Probleme läuft müsst ihr noch einiges | Damit der Code ohne Probleme läuft, müsst ihr noch einiges fixen! | ||
Erstmal müsst ihr noch folgende Methoden | Erstmal müsst ihr noch folgende Methoden im Public-bereich hinzufügen: | ||
// Deklarationen: | // Deklarationen: | ||
Line 587: | Line 587: | ||
} | } | ||
Damit könnt ihr die Armor und das Health setzen( | Damit könnt ihr die Armor und das Health setzen (je nachdem, wieviel die Klassen haben sollen). | ||
Aber auch Medic und Supporter können so ihr Leben/Rüstung regenerieren! | Aber auch Medic und Supporter können so ihr Leben/Rüstung regenerieren! | ||
Line 597: | Line 597: | ||
Die Magazinsdefinitionen: | Die Magazinsdefinitionen: | ||
// Nur verändern wenn man die Munition der Waffenmagazine im script/code ändert! | // Nur verändern, wenn man die Munition der Waffenmagazine im script/code ändert! | ||
// Legt die Magazine fest(Magazin und dann größe in Kugeln)! | // Legt die Magazine fest(Magazin und dann größe in Kugeln)! | ||
#define Magazin_None 0 | #define Magazin_None 0 | ||
Line 630: | Line 630: | ||
#endif //_Magazin_H | #endif //_Magazin_H | ||
Ich würde euch zur zweiten Methode raten da man hier auch die Munitionsdefinitions in den gamerules.cpp ändern kann und die maximale Munition einbinden kann! | Ich würde euch zur zweiten Methode raten, da man hier auch die Munitionsdefinitions in den gamerules.cpp ändern kann und die maximale Munition einbinden kann! | ||
Und man sollte die Default Klasse per CooVars setzen oder die Default Klasse aus dem Coden komplett entfernen! | Und man sollte die Default Klasse per CooVars setzen oder die Default Klasse aus dem Coden komplett entfernen! | ||
Line 638: | Line 638: | ||
==Klassenmenu öffnen== | ==Klassenmenu öffnen== | ||
Damit man das Klassen system später aufrufen kann solte man in der baseviewport.cpp | Damit man das Klassen system später aufrufen kann, solte man in der baseviewport.cpp dieses eintragen: | ||
dieses eintragen: | |||
// sub dialogs | // sub dialogs | ||
Line 652: | Line 651: | ||
#include "NavProgress.h" | #include "NavProgress.h" | ||
jetzt | jetzt den Befehl zum Aufrufen: | ||
CON_COMMAND( chooseclass, "Opens a menu for class choose" ) | CON_COMMAND( chooseclass, "Opens a menu for class choose" ) | ||
Line 662: | Line 661: | ||
} | } | ||
Etwas weiter unten das hier: | |||
void CBaseViewport::CreateDefaultPanels( void ) | void CBaseViewport::CreateDefaultPanels( void ) | ||
Line 698: | Line 697: | ||
==Bonus== | ==Bonus== | ||
Nun werden wir uns noch einen Spaß erlauben und jeder Klasse eine bestimmte | Nun werden wir uns noch einen Spaß erlauben und jeder Klasse eine bestimmte Geschwindigkeit zuweisen. | ||
Dazu brauchen wir die hl2_player.cpp und die player.h/.cpp | Dazu brauchen wir die hl2_player.cpp und die player.h/.cpp | ||
Als erstes müssen wir ausfindig machen wo der Spieler seine Laufgeschwindigkeit | Als erstes müssen wir ausfindig machen, wo der Spieler seine Laufgeschwindigkeit einstellt! | ||
Das macht man hier: | Das macht man hier: | ||
Line 717: | Line 716: | ||
#endif | #endif | ||
Die | Die Erklärung ist simpel. | ||
Wenn HL2MP definiert ist dann werden | Wenn HL2MP definiert ist, dann werden Standardwerte gesetzt: | ||
#ifdef HL2MP | #ifdef HL2MP | ||
Line 725: | Line 724: | ||
#define HL2_SPRINT_SPEED 320 | #define HL2_SPRINT_SPEED 320 | ||
Ansonsten kann man alles über die ConVars machen, aber in HL2DM geht das nur über die Standardwerte! | |||
#else | #else | ||
Line 735: | Line 734: | ||
Aber nun müssen wir uns eine Steuerung bauen für den Speed! | Aber nun müssen wir uns eine Steuerung bauen für den Speed! | ||
Dazu müssen wir nur eine | Dazu müssen wir nur eine Kleinigkeit zum Basisspieler hinzufügen. | ||
Öffnet nun die player.h und added folgendes im letzten Public-bereich: | |||
// Hier wird die Spielergeschwindigkeit gesetzt: | // Hier wird die Spielergeschwindigkeit gesetzt: | ||
Line 743: | Line 742: | ||
void SetSprintSpeed(int SprintSpeed); | void SetSprintSpeed(int SprintSpeed); | ||
Damit können wir die Werte setzen aber nun brauchen wir noch die Variablen der Klasse: | Damit können wir die Werte setzen, aber nun brauchen wir noch die Variablen der Klasse: | ||
// Spielergeschwindigkeit: | // Spielergeschwindigkeit: | ||
Line 756: | Line 755: | ||
int GetSprintSpeed(); | int GetSprintSpeed(); | ||
Jetzt kommen wir zur | Jetzt kommen wir zur Implementierung: | ||
void CBasePlayer::SetWalkSpeed(int WalkSpeed) | void CBasePlayer::SetWalkSpeed(int WalkSpeed) | ||
Line 788: | Line 787: | ||
} | } | ||
Jetzt müssen wir nur noch 2 | Jetzt müssen wir nur noch 2 Sachen tun! | ||
Als erstes müssen wir sagen | Als erstes müssen wir sagen, dass die Get Methoden die Geschwindigkeit steuern. | ||
Das machen wir wie folgt: | Das machen wir wie folgt: | ||
Line 798: | Line 797: | ||
#define HL2_SPRINT_SPEED CBasePlayer::GetSprintSpeed() | #define HL2_SPRINT_SPEED CBasePlayer::GetSprintSpeed() | ||
Das | Das wars auch schon fast. | ||
Jetzt müsst ihr nur noch sagen welche Geschwindigkeit eure Klasse haben soll. | Jetzt müsst ihr nur noch sagen welche Geschwindigkeit eure Klasse haben soll. | ||
Line 806: | Line 805: | ||
Dann könnt ihr eine Klasse schnell einbauen. | Dann könnt ihr eine Klasse schnell einbauen. | ||
Hier mal ein Beispiel meiner | Hier mal ein Beispiel meiner Supportunit-Klasse: | ||
<code cpp n> | <code cpp n> | ||
// Supporter | // Supporter | ||
Line 855: | Line 854: | ||
} | } | ||
</code> | </code> | ||
Ich habe auch schon die Waffenverteilung auf die Teams gesetzt aber das kann ich auch noch erklären ;) sobald ich das verbessert hab(z.b. mit einer Team | Ich habe auch schon die Waffenverteilung auf die Teams gesetzt aber das kann ich auch noch erklären ;) sobald ich das verbessert hab(z.b. mit einer Team-Variable) ;) | ||
Also viel Spaß und schreibt mir falls es Probleme oder Kritik gibt ;) | Also viel Spaß und schreibt mir falls es Probleme oder Kritik gibt ;) | ||
[[Category:Programming:de]][[Category:Tutorials:de]] | [[Category:Programming:de]][[Category:Tutorials:de]] |
Revision as of 11:19, 29 August 2008
Template:Language:de Template:TutPOV:de
Einleitung
Dieses Coding Tutorial befasst sich mit dem Erstellen eines Klassensystems.
Notizen (/Überlegungen):
- Es gibt 3 Klassen (Supporter, Medic und Assaulter)
- Beim ersten Spawn bekommt man eine Standardklasse.
- Wechselt man die Klasse, stirbt man und spawnt mit der neuen Klasse.
Daten, die gebraucht werden
Als erstes eine Auflistung was wir an Codedateien brauchen:
Header:
dlls/player.h
Quellcodedateien
dlls/player.cpp
Das Klassensystem wird zu 100% serverseitig sein, der Client kann die Klassen aber wechseln.
Die Deklarationen
Als erstes müssen wir uns an die Deklarationen machen. Was wir brauchen sind einige Variablen und einige Funktionen. Aber als erstes werden wir ein Enum erstellen das die Werte unserer Klassen enthält! Das enum kommt in die player.h über class CBasePlayer;
Das Enum machen wir erstmal so:
enum { Unassigned = 0, Assaulter, Supporter, Medic, };
Später brauchen wir das für die Vergleiche!
Jetzt werden wir uns der Klasse CBasePlayer widmen.
Zum Beginn werden wir einen neuen public und einen neuen private Bereich am Ende von CBasePlayer in der player.h hinzufügen. Dort schreiben wir den gesamten Code für das Klassensystem rein!
// Die neuen Bereiche für das Klassensystem! public: private:
Hier nun alles was wir an Methoden deklarieren müssen und natürlich auch die Variablen:
/* ******************************************** **Klassensystem: **Hier werden die Klassen verteilt! **Es wird auch auf die richtigen Klassen geprüft! ******************************************** */ public: // Methode zum Klassenwechseln virtual void ChangeClass(int NewClass); virtual int GetClass(); // Initalisierung des Klassensystems! void InitClassSystem(); // Überprüft ob wir keinen ungültigen wert setzen für die Klassenvariablen: void CheckAllClassConVars(); // Hier wird geprüft ob wir die Klasse gewechselt haben: void OnClassChange(); // Setzt Leben und Armor für den Spieler! void SetClassStuff(); // Setzt den neuen wert für die Check Variable: void SetCurrentClassValue(); // Die Klasse holen: int GetClassValue()const; // Die Standartklasse holen: int GetDefaultClassValue()const; // Schaltmethode die Klassen verteilt: void SetPlayerClass(); // Legt das Leben für unsere klasse fest: int GetClassHealth()const; // Diese Methoden setzen für jede Klasse das Leben und die Armor int GetClassMaxHealth()const; // Legt die Armor für die Klasse Fest: int GetClassArmor()const; // Diese Methoden holen für jede Klasse das Leben und die Armor int GetClassMaxArmor()const; private: // Wichtige Prüfung auf ersten Spawn: bool m_bFirstSpawn; bool IsFirstSpawn(); // Welche Klasse haben wir(enum): int m_iClass; // Prüft ob wir die Klasse gewechselt haben: int m_iCurrentClass; // Hier setzen wir die Standartklasse! int m_iDefaultClass; // Waffen, Leben und Armor der Klassen verteilen: void SetClassDefault(); void SetClassGroundUnit(); void SetClassSupportUnit(); void SetClassMedic(); void SetHealthValue( int value );
/* ******************************************** **Spielereigenschaften: **Hier werden Eigenschaften wie Speed, Condition **und maximale Klassen festgelegt! ******************************************** */ // Integer für Rüstung: int m_iArmor; int m_iMaxArmor;
Nun kommen wir zur Erklärung wofür wir das alles brauchen. Wir fangen oben an und arbeiten uns nach unten vor.
public
// Methode zum Klassenwechseln virtual void ChangeClass(int NewClass);
Diese Methode brauchen wir, damit der Client(Spieler) per Menu/Konsole seine Klasse wechselt.
virtual int GetClass();
Brauchen wir, wenn wir noch Sachen wie Munition, Leben und Rüstungsinkrementierung für den Supporter/Medic einbauen wollen.
// Initalisierung des Klassensystems! void InitClassSystem();
Diese Methode soll das Klassensystem aus der Spawn Methode von CBasePlayer starten. Damit werden die Methoden für die Klassenverteilung usw aufgerufen. Bei der Implementierung seid ihr dann schlauer.
// Überprüft ob wir keinen ungültigen wert setzen für die Klassenvariablen: void CheckAllClassConVars();
Diese Methode prüft, ob wir einen gültigen Wert eingegeben haben. Falls wir das nicht Prüfen würden, dann würde eure Mod crashen! Falls der Wert nicht stimmt, dann müsst ihr einen Wert für die Klasse setzen.
// Hier wird geprüft ob wir die Klasse gewechselt haben: void OnClassChange();
Diese Methode wird in der Thinkmethode gebraucht. Falls ihr die Klasse wechselt werdet ihr gekillt und einen Punkt sonst würdet ihr Punktabzug bekommen.
// Setzt Leben und Armor für den Spieler! void SetClassStuff();
Diese Methode setzt für jede Klasse den Wert für das Leben, Maximal Leben und Rüstung. Leider wird die Rüstung über den Code der Recharger festgelegt, diesen müsst ihr ändern.
// Setzt den neuen wert für die Check Variable: void SetCurrentClassValue();
Diese Methode ändert den Wert der CheckVariable für die Klassen, sonst würde man immer wieder sterben!
// Die Klasse holen: int GetClassValue()const;
Diese Methode holt uns den Wert der Klasse die wir haben.
// Die Standartklasse holen: int GetDefaultClassValue()const;
Diese Methode holt vom Server die Standardklasse damit man im Falle einer ungültigen Klasse diese bekommt.
// Schaltmethode die Klassen verteilt: void SetPlayerClass();
Diese Methode ist die Steuerzentrale unseres Klassensystems. Dort wird mit dem Wert der Klassenvariable alles gelenkt. Von der Waffen und Lebensverteilung bis zum setzen des Spielermodels(das müsst ihr leider noch machen!)
// Legt das Leben für unsere Klasse fest: int GetClassHealth()const;
Diese Methode holt das Leben, das ihr im Moment habt.
// Diese Methoden setzen für jede Klasse das Leben und die Armor int GetClassMaxHealth()const;
Die Methode holt das Maximale Leben, das eure Klasse haben kann.
// Legt die Armor für die Klasse Fest: int GetClassArmor()const;
Diese Methode holt euch die Rüstung, die ihr im Moment habt.
// Diese Methoden holen für jede Klasse das Leben und die Armor int GetClassMaxArmor()const;
Diese Methode holt die Maximale Rüstung eurer Klasse (ist leider noch unbrauchbar wegen dem Recharger Code!)
private
// Wichtige Prüfung auf ersten Spawn: bool m_bFirstSpawn;
Diese Variable ist für die Abfrage für den ersten Spawn nötig.
bool IsFirstSpawn();
Diese Methode gibt uns Auskunft ob wir das erstemal gespawnt sind.
// Welche Klasse haben wir(enum): int m_iClass;
Diese Variable speichert den Wert unserer Klasse:
// Prüft, ob wir die Klasse gewechselt haben: int m_iCurrentClass;
Das ist die Prüfungsvariable, die den Wert unserer Momentanen Klasse enthält. Der Wert wird dann geändert wqenn wie die Klasse wechseln.
// Hier setzen wir die Standardklasse! int m_iDefaultClass;
Diese Variable holt die Klasse des Servers und ist gleichzeitig die erste Klasse, die man beim ersten Spawn bekommt.
// Waffen, Leben und Armor der Klassen verteilen: void SetClassDefault(); void SetClassGroundUnit(); void SetClassSupportUnit(); void SetClassMedic();
Das sind unsere Methoden zum verteilen alle wichtigen Sachen einer Klasse. Also Leben, Maximalleben, Rüstung, Maximalrüstung, Waffen usw.
// Integer für Rüstung: int m_iArmor; int m_iMaxArmor;
Das sind unsere Variablen für Rüstung und Maximalrüstung.
Jetzt wisst ihr was wir alles brauchen und wieso.
Nun kommen wir zum Teil in dem wir alles Einbauen.
Die Implementation
Da wir nun alles haben was wir brauchen müssen wir nur alles einbauen! Alles kommt in die player.cpp ganz ans Ende.
Hier der Code mit Erklärung:
Added im Konstruktor:
// Erster Spawn? int m_bFirstSpawn = true; // Startklasse festlegen: int m_iClass = default_class.GetInt(); int m_iCurrentClass = m_iClass; // Die Standardklasse setzen! int m_iDefaultClass = default_class.GetInt(); // Standartwerte 100 für Leben/Armor: int m_iHealth = 100; int m_iArmor = 100; // Maximal Leben/Armor für jede Klasse: int m_iMaxHealth = 100; int m_iMaxArmor = 100;
void CBasePlayer::InitClassSystem() { DevMsg("Klassensystem wird initalisiert!\n"); CheckAllClassConVars(); SetPlayerClass(); SetClassStuff(); } int CBasePlayer::GetClassValue()const { return m_iClass; } int CBasePlayer::GetDefaultClassValue()const { return m_iDefaultClass; } bool CBasePlayer::IsFirstSpawn() { return m_bFirstSpawn; } // Soll die Waffen verteilen: // Hier ist irgend wo ein Bug! void CBasePlayer::SetPlayerClass() { if(IsFirstSpawn()) { m_iClass = m_iDefaultClass; } // Jetzt werden die Klassen verteilt: switch(m_iClass) { case Assaulter: SetClassGroundUnit(); break; case Supporter: SetClassSupportUnit(); break; case Medic: SetClassMedic(); break; //case Invalid: // Muss noch eingebaut werden! // Hier bekommt man nur die Standardwaffen! case Unassigned: // Hier setzen wir die Standardklasse! default: SetClassDefault(); break; } } void CBasePlayer::OnClassChange() { if( m_iClass != m_iCurrentClass ) { // Spieler killen und Punkte um 1 erhöhen (wegen Selbstmord)! CommitSuicide(); IncrementFragCount(1); // Setzen, damit wir nicht die selbe Klassen haben! m_iCurrentClass = m_iClass; } } void CBasePlayer::CheckAllClassConVars() { // Haben wir eine Klasse, die zwischen Spec-Ops und der letzen Klasse liegt? if( m_iClass < Assaulter || m_iClass > Medic ) { m_iClass = Assaulter; } if( m_iDefaultClass < Assaulter || m_iDefaultClass > Medic ) { m_iDefaultClass = Assaulter; } } void CBasePlayer::SetClassDefault() { Msg("Du hast die Klasse Default!\n"); CheckAllClassConVars(); SetPlayerClass(); } // Assault: void CBasePlayer::SetClassGroundUnit() { // Standardwerte für Leben/Armor: m_iHealth = 125; m_iArmor = 125; // Maximal Leben/Armor für jede Klasse: m_iMaxHealth = 125; m_iMaxArmor = 125; // Waffen verteilen: Msg("Du bist jetzt eine Ground Unit!\n"); CBasePlayer::GiveNamedItem( "weapon_357" ); CBasePlayer::GiveNamedItem( "weapon_smg1" ); CBasePlayer::GiveNamedItem( "weapon_frag" ); CBasePlayer::GiveAmmo( Magazin_357*3 , "357" ); CBasePlayer::GiveAmmo( Magazin_SMG1*3 , "SMG1"); CBasePlayer::GiveAmmo( Magazin_SMG1_Granates*1, "smg1_grenade"); CBasePlayer::GiveAmmo( Magazin_Frag*5 , "grenade" ); } // Supporter void CBasePlayer::SetClassSupportUnit() { // Standartwerte für leben/armor: m_iHealth = 100; m_iArmor = 300; // Maximal Leben/Armor für Klasse: m_iMaxHealth = 100; m_iMaxArmor = 300; // Waffen verteilen: Msg("Du bist jetzt eine Support Unit!\n"); CBasePlayer::GiveNamedItem( "weapon_ar2" ); CBasePlayer::GiveNamedItem( "weapon_frag" ); CBasePlayer::GiveNamedItem( "weapon_357" ); CBasePlayer::GiveAmmo( Magazin_AR2*3, "AR2" ); CBasePlayer::GiveAmmo( Magazin_AR2AltFire*2, "AR2AltFire" ); CBasePlayer::GiveAmmo( Magazin_Frag*3, "grenade" ); CBasePlayer::GiveAmmo( Magazin_357*3 , "357" ); // Eigenschaft des Supporter's aufrufen: // GetAmmo(); } // Medic: void CBasePlayer::SetClassMedic() { // Standardwerte für Leben/Armor: m_iHealth = 100; m_iArmor = 75; // Maximal Leben/Armor für Klasse: m_iMaxHealth = 100; m_iMaxArmor = 75; // Waffen verteilen: Msg("Du bist jetzt ein Medic!\n"); CBasePlayer::GiveNamedItem( "weapon_357" ); CBasePlayer::GiveNamedItem( "weapon_smg1" ); CBasePlayer::GiveAmmo( Magazin_357*2, "357" ); CBasePlayer::GiveAmmo( Magazin_SMG1*2 , "SMG1"); CBasePlayer::GiveAmmo( Magazin_SMG1_Granates*3, "smg1_grenade"); } // Legt das Leben für unsere klasse fest: int CBasePlayer::GetClassHealth()const { return m_iHealth; } // Legt die Armor für die Klasse fest: int CBasePlayer::GetClassArmor()const { return m_iArmor; } // Diese Methoden setzen für jede Klasse das Leben und die Armor int CBasePlayer::GetClassMaxHealth()const { return m_iMaxHealth; } // Diese Methoden holen für jede Klasse das Leben und die Armor int CBasePlayer::GetClassMaxArmor()const { return m_iMaxArmor; } // Setzt Leben und Armor für den Spieler! void CBasePlayer::SetClassStuff() { // Hier Leben setzen: SetHealthValue(GetClassHealth()); SetMaxHealthValue(GetClassMaxHealth()); // Variable gehört nicht zu CBasePlayer!!! // TODO: Das ist eine Private Variable, die ich ändern muss! SetArmorValue(GetClassArmor()); // SetMaxArmorValue(GetClassMaxArmor()); } // Klasse per ConVar Wechsel für Client: void CBasePlayer::ChangeClass(int NewClass) { m_iClass = NewClass; }
Da ihr ja schon wisst, wofür die ganzen Methoden sind, müsst ihr nur noch gucken wie alles läuft :)
Aber nun mal zum Einbauen der ConVars, die man braucht:
// Der Server hat für alle die selbe Standardklasse! // Der Admin kann die Standartklasse ändern! ConVar default_class("default_class", "3", FCVAR_ARCHIVE, "Variable für Standardklasse!");
Nun hat der Server seine Default-Klasse, die jeder Spieler beim Spawnen bekommt. Diese könnt ihr dann über die Konsole ändern :)
Ihr könnt auch noch mehr Settings für den Admin zur Verfügung stellen:
// Maximale Klassen erlauben(Admins!) // TODO: Muss noch aktiviert werden im Code! ConVar max_assaulter("max_assaulter", "3", FCVAR_ARCHIVE, "Variable für Maximale Assaulter!"); ConVar max_supporter("max_supporter", "3", FCVAR_ARCHIVE, "Variable für Maximale Supporter!"); ConVar max_medic("max_medic", "3", FCVAR_ARCHIVE, "Variable für Maximale Medics!");
// Klassen erlauben(Admins): // TODO: Muss noch aktiviert werden im Code! ConVar allow_assaulter("allow_assaulter", "1", FCVAR_ARCHIVE, "Erlaubt Klasse Ground Unit!"); ConVar allow_supporter("allow_supporter", "1", FCVAR_ARCHIVE, "Erlaubt Klasse Support Unit!"); ConVar allow_medic("allow_medic", "1", FCVAR_ARCHIVE, "Erlaubt Klasse Medic!");
Diese müsst ihr aber selbst implementieren!
Nun müssen wir nur noch dem Spieler die Möglichkeit zum Ändern der Klasse geben! Und dann muss man noch die Prüfungen der Klassen einbauen!
Dazu müssen wir einfach in der Methode OnClientCommand folgendes einbauen am Ende:
else if ( !stricmp( cmd, "class" ) ) { if ( engine->Cmd_Argc() < 2 ) return true; int iClass = atoi( engine->Cmd_Argv(1) ); ChangeClass(iClass); return true; }
Hier mit wird eine ConVar simuliert. Aber man kann durch Class und dann die Klassennummer, also Class 1, die Klasse ändern! Nun müssen wir aber die Prüfungsmethode aufrufen und dann haben wirs schon!
Das machen wir in der Methode PostThink();
Dort setzen wir am Ende einfach folgendes ein:
OnClassChange();
Das wars :) wenn alles stimmt dann dürfte euer Klassensystem funktionieren ;)
Wichtiges zum Code
Damit der Code ohne Probleme läuft, müsst ihr noch einiges fixen!
Erstmal müsst ihr noch folgende Methoden im Public-bereich hinzufügen:
// Deklarationen: // Added von mir: void SetHealthValue( int value ); int GetHealthValue(); void SetMaxHealthValue(int MaxValue); int GetMaxHealthValue(); void IncrementHealthValue( int nCount ); int GetArmorValue();
// Implementierung: void CBasePlayer::SetHealthValue( int value ) { m_iHealth = value; } void CBasePlayer::SetMaxHealthValue( int MaxValue ) { m_iMaxHealth = MaxValue; } int CBasePlayer::GetHealthValue() { return m_iHealth; } int CBasePlayer::GetMaxHealthValue() { return m_iMaxHealth; } void CBasePlayer::IncrementHealthValue( int nCount ) { m_iHealth += nCount; if (m_iMaxHealth > 0 && m_iHealth > m_iMaxHealth) m_iHealth = m_iMaxHealth; } int CBasePlayer::GetArmorValue() { return m_ArmorValue; }
Damit könnt ihr die Armor und das Health setzen (je nachdem, wieviel die Klassen haben sollen). Aber auch Medic und Supporter können so ihr Leben/Rüstung regenerieren!
Nun muss man noch die Munitionsverteilung ändern. Entweder man gibt die Munitionszahlen selber ein oder man erstellt eine Header wie folgt: Header definition starten:
#ifndef _Magazin_H #define _Magazin_H
Die Magazinsdefinitionen:
// Nur verändern, wenn man die Munition der Waffenmagazine im script/code ändert! // Legt die Magazine fest(Magazin und dann größe in Kugeln)! #define Magazin_None 0 #define Magazin_Pistole 20 #define Magazin_357 6 #define Magazin_SMG1 50 #define Magazin_SMG1_Granates 1 #define Magazin_AR2 100 #define Magazin_AR2AltFire 1 #define Magazin_RPG 1 #define Magazin_Slam 1 #define Magazin_Frag 1 #define Magazin_Shotgun 8 #define Magazin_Crossbow 1
Die maximale Definition eines Magazins:
// Legt die Mazimale Muntion/Magazine fest: #define Max_Magazin_None Magazin_None*0 #define Max_Magazin_Pistole Magazin_Pistole*16 #define Max_Magazin_357 Magazin_357*6 #define Max_Magazin_SMG1 Magazin_SMG1*8 #define Max_Magazin_SMG1_Granates Magazin_SMG1_Granates*7 #define Max_Magazin_AR2 Magazin_AR2*3 #define Max_Magazin_AR2AltFire Magazin_AR2AltFire*2 #define Max_Magazin_RPG Magazin_RPG*25 #define Max_Magazin_Slam Magazin_Slam*10 #define Max_Magazin_Frag Magazin_Frag*10 #define Max_Magazin_Shotgun Magazin_Shotgun*13 #define Max_Magazin_Crossbow Magazin_Crossbow*50
Die Magazinsdefinition beenden:
#endif //_Magazin_H
Ich würde euch zur zweiten Methode raten, da man hier auch die Munitionsdefinitions in den gamerules.cpp ändern kann und die maximale Munition einbinden kann!
Und man sollte die Default Klasse per CooVars setzen oder die Default Klasse aus dem Coden komplett entfernen!
Damit man das Klassen system später aufrufen kann, solte man in der baseviewport.cpp dieses eintragen:
// sub dialogs #include "clientscoreboarddialog.h" #include "spectatorgui.h" #include "teammenu.h" #include "classmenu.h" #include "vguitextwindow.h" #include "IGameUIFuncs.h" #include "mapoverview.h" #include "hud.h" #include "NavProgress.h"
jetzt den Befehl zum Aufrufen:
CON_COMMAND( chooseclass, "Opens a menu for class choose" ) { if ( !gViewPortInterface ) return; gViewPortInterface->ShowPanel( "class", true ); }
Etwas weiter unten das hier:
void CBaseViewport::CreateDefaultPanels( void ) { #ifndef _XBOX AddNewPanel( CreatePanelByName( PANEL_SCOREBOARD ) ); AddNewPanel( CreatePanelByName( PANEL_INFO ) ); AddNewPanel( CreatePanelByName( PANEL_SPECGUI ) ); AddNewPanel( CreatePanelByName( PANEL_SPECMENU ) ); AddNewPanel( CreatePanelByName( PANEL_NAV_PROGRESS ) ); AddNewPanel( CreatePanelByName( PANEL_TEAM ) ); AddNewPanel( CreatePanelByName( PANEL_CLASS ) ); // AddNewPanel( CreatePanelByName( PANEL_BUY ) ); #endif }
und zuletzt das hier:
IViewPortPanel* CBaseViewport::CreatePanelByName(const char *szPanelName) { ... else if ( Q_strcmp(PANEL_TEAM, szPanelName) == 0 ) { newpanel = new CTeamMenu( this ); } else if ( Q_strcmp(PANEL_CLASS, szPanelName) == 0 ) { newpanel = new CTeamMenu( this ); } ... }
Bonus
Nun werden wir uns noch einen Spaß erlauben und jeder Klasse eine bestimmte Geschwindigkeit zuweisen.
Dazu brauchen wir die hl2_player.cpp und die player.h/.cpp
Als erstes müssen wir ausfindig machen, wo der Spieler seine Laufgeschwindigkeit einstellt!
Das macht man hier:
#ifdef HL2MP #define HL2_WALK_SPEED 150 #define HL2_NORM_SPEED 190 #define HL2_SPRINT_SPEED 320 #else #define HL2_WALK_SPEED hl2_walkspeed.GetFloat() #define HL2_NORM_SPEED hl2_normspeed.GetFloat() #define HL2_SPRINT_SPEED hl2_sprintspeed.GetFloat() #endif
Die Erklärung ist simpel. Wenn HL2MP definiert ist, dann werden Standardwerte gesetzt:
#ifdef HL2MP #define HL2_WALK_SPEED 150 #define HL2_NORM_SPEED 190 #define HL2_SPRINT_SPEED 320
Ansonsten kann man alles über die ConVars machen, aber in HL2DM geht das nur über die Standardwerte!
#else #define HL2_WALK_SPEED hl2_walkspeed.GetFloat() #define HL2_NORM_SPEED hl2_normspeed.GetFloat() #define HL2_SPRINT_SPEED hl2_sprintspeed.GetFloat() #endif
Aber nun müssen wir uns eine Steuerung bauen für den Speed!
Dazu müssen wir nur eine Kleinigkeit zum Basisspieler hinzufügen. Öffnet nun die player.h und added folgendes im letzten Public-bereich:
// Hier wird die Spielergeschwindigkeit gesetzt: void SetWalkSpeed(int WalkSpeed); void SetNormSpeed(int NormSpeed); void SetSprintSpeed(int SprintSpeed);
Damit können wir die Werte setzen, aber nun brauchen wir noch die Variablen der Klasse:
// Spielergeschwindigkeit: int m_iWalkSpeed; int m_iNormSpeed; int m_iSprintSpeed;
Nun noch die Methoden zum holen der Werte:
int GetWalkSpeed(); int GetNormSpeed(); int GetSprintSpeed();
Jetzt kommen wir zur Implementierung:
void CBasePlayer::SetWalkSpeed(int WalkSpeed) { m_iWalkSpeed=WalkSpeed; } void CBasePlayer::SetNormSpeed(int NormSpeed) { m_iNormSpeed=NormSpeed; } void CBasePlayer::SetSprintSpeed(int SprintSpeed) { m_iSprintSpeed=SprintSpeed; } int CBasePlayer::GetWalkSpeed() { return m_iWalkSpeed; } int CBasePlayer::GetNormSpeed() { return m_iNormSpeed; } int CBasePlayer::GetSprintSpeed() { return m_iSprintSpeed; }
Jetzt müssen wir nur noch 2 Sachen tun!
Als erstes müssen wir sagen, dass die Get Methoden die Geschwindigkeit steuern.
Das machen wir wie folgt:
#define HL2_WALK_SPEED CBasePlayer::GetWalkSpeed() #define HL2_NORM_SPEED CBasePlayer::GetNormSpeed() #define HL2_SPRINT_SPEED CBasePlayer::GetSprintSpeed()
Das wars auch schon fast.
Jetzt müsst ihr nur noch sagen welche Geschwindigkeit eure Klasse haben soll.
Dazu müsst ihr nur in den SetClass Methoden die neuen SetSpeed Methoden einbauen.
Dann könnt ihr eine Klasse schnell einbauen.
Hier mal ein Beispiel meiner Supportunit-Klasse:
// Supporter
void CBasePlayer::SetClassSupportUnit()
{
// Code hier rein!
// m_szClassName = ClassNames[CLASS_SUPPORT];
// Standartwerte für leben/armor:
m_iHealth = 100;
m_iArmor = 300;
// Maximal Leben/Armor für Jede Klasse:
m_iMaxHealth = 100;
m_iMaxArmor = 300;
// Waffen verteilen:
Msg("Du bist jetzt eine Support Unit!\n");
switch(GetTeamNumber())
{
case TEAM_REBELS:
// Hier waffenverteilen:
// Rebelen:
CBasePlayer::GiveNamedItem( "weapon_reb_hmg" );
CBasePlayer::GiveNamedItem( "weapon_reb_frag" );
break;
case TEAM_COMBINE:
// Hier waffenverteilen:
// Combine:
CBasePlayer::GiveNamedItem( "weapon_com_hmg" );
CBasePlayer::GiveNamedItem( "weapon_com_frag" );
break;
default:
CBasePlayer::GiveNamedItem( "weapon_ar2" );
CBasePlayer::GiveNamedItem( "weapon_frag" );
break;
}
CBasePlayer::GiveNamedItem( "weapon_ammo_spawner" );
CBasePlayer::GiveAmmo( Magazin_AR2*3, "AR2" );
CBasePlayer::GiveAmmo( Magazin_Frag*3, "grenade" );
SetWalkSpeed(90);
SetNormSpeed(130);
SetSprintSpeed(200);
}
Ich habe auch schon die Waffenverteilung auf die Teams gesetzt aber das kann ich auch noch erklären ;) sobald ich das verbessert hab(z.b. mit einer Team-Variable) ;)
Also viel Spaß und schreibt mir falls es Probleme oder Kritik gibt ;)