De/Creating A Class System

==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 man an Codedateien braucht:
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 muss man die Deklarationen machen.
Was man braucht sind einige Variablen und einige Funktionen.
Als Erstes erstellt man ein Enum das die Werte der Klassen enthält!
Das enum kommt in die player.h über class CBasePlayer;
Das Enum macht man erstmal so:
 enum
 {
 	Unassigned = 0,
 	Assaulter,
 	Supporter,
 	Medic,
 };
Später braucht man das für die Vergleiche!
Jetzt widme man sich der Klasse CBasePlayer.
 
Zum Beginn erstellt man einen neuen public und einen neuen private Bereich am Ende von CBasePlayer in der player.h.
Dort schreibt man den gesamten Code für das Klassensystem rein!
 // Die neuen Bereiche für das Klassensystem!
 public:
 private:
Hier nun alles was man an Methoden deklarieren muss 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 zur Erklärung, von oben nach unten.
==public==
 // Methode zum Klassenwechseln
 virtual void ChangeClass(int NewClass); 
Diese Methode braucht man, damit der Client(Spieler) per Menu/Konsole seine Klasse wechselt.
 virtual int GetClass();
Braucht man, wenn man noch Sachen wie Munition, Leben und Rüstungsinkrementierung für den Supporter/Medic einbauen will.
 // 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 ist man dann schlauer.
 // Überprüft ob man keinen ungültigen wert setzt für die Klassenvariablen:
 void CheckAllClassConVars();
Diese Methode prüft, ob man einen gültigen Wert eingegeben hat.
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 man die Klasse gewechselt hat:
 void OnClassChange();
Diese Methode wird in der Thinkmethode gebraucht.
Falls man die Klasse wechselt wird man gekillt und ein Punkt addiert sonst würde man 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 muss man selber ä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 den Wert der Klasse die man hat.
 // 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 muss man leider noch machen!).
 // Legt das Leben für die Klasse fest:
 int GetClassHealth()const;
Diese Methode holt das Leben, das man im Moment hat.
 // Diese Methoden setzt für jede Klasse das Leben und die Armor
 int GetClassMaxHealth()const;
Die Methode holt das Maximale Leben, das die Klasse haben kann.
 // Legt die Armor für die Klasse Fest:
 int GetClassArmor()const;
Diese Methode holt die Rüstung, die man im Moment hat.
 // Diese Methoden holt für jede Klasse das Leben und die Armor
 int GetClassMaxArmor()const;
Diese Methode holt die Maximale Rüstung der 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 Auskunft ob man das Erste mal gespawnt wird.
 // Welche Klasse hat man(enum):
 int m_iClass;
Diese Variable speichert den Wert der Klasse:
 // Prüft, ob man die Klasse gewechselt hat:
 int m_iCurrentClass;
Das ist die Prüfungsvariable, die den Wert der Momentanen Klasse enthält.
Der Wert wird dann geändert wenn die Klasse gewechselt wird.
 // Hier setzt man 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 die Methoden zum verteilen aller wichtigen Sachen einer Klasse.
(Leben, Maximalleben, Rüstung, Maximalrüstung, Waffen usw.)
 // Integer für Rüstung:
 int m_iArmor;
 int m_iMaxArmor;
Das sind die Variablen für Rüstung und Maximalrüstung.
Jetzt wei0 man was man alles braucht und wieso.
Nun kommt man zum Teil in dem man alles Einbaut.
==Die Implementation==
Da man nun alles hat was man braucht muss man nurnoch alles einbauen!
Alles kommt in die player.cpp ganz ans Ende.
Hier der Code mit Erklärung:
Added im Konstruktor:
 	// Erster Spawn?
 	m_bFirstSpawn = true;
 
 	// Startklasse festlegen:
 	m_iClass = default_class.GetInt();
 
 	m_iCurrentClass = m_iClass;
 	// Die Standardklasse setzen!
 	m_iDefaultClass = default_class.GetInt();
 
 	// Standartwerte 100 für Leben/Armor:
 	m_iHealth = 100;
 	m_iArmor = 100;
 
 	// Maximal Leben/Armor für jede Klasse:
 	m_iMaxHealth = 100;
 	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 setzt man 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 man nicht die selbe Klasse hat!
 		m_iCurrentClass = m_iClass;
 	}
 }
 
 void CBasePlayer::CheckAllClassConVars()
 {
 	// Hat man 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 die 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 man ja schon weiß, wofür die ganzen Methoden sind, man nurnoch schauen 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 kann man dann über die Konsole ändern :)
Man kann 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 muss man aber selbst implementieren!
Nun muss man nur noch dem Spieler die Möglichkeit zum Ändern der Klasse geben!
Und dann muss man noch die Prüfungen der Klassen einbauen!
Dazu muss man einfach in der Methode OnClientCommand folgendes am Ende einbauen:
 	else if ( !stricmp( cmd, "class" ) )
 	{
 		if ( engine->Cmd_Argc() < 2 )
 			return true;
 
 		int iClass = atoi( engine->Cmd_Argv(1) );
 		ChangeClass(iClass);
 
 		return true;
 	}
Hiermit wird eine ConVar simuliert.
Aber man kann durch Class und dann die Klassennummer, also Class 1, die Klasse ändern!
Nun muss man aber die Prüfungsmethode aufrufen und dann hat man es schon!
Das macht man in der Methode PostThink();
Dort setzt man am Ende einfach folgendes ein:
 OnClassChange();
Das wars :) wenn alles stimmt dann dürfte das Klassensystem funktionieren ;)
==Wichtiges zum Code==
Damit der Code ohne Probleme läuft, muss man noch einiges fixen!
Erstmal muss man 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 kann man 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 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!
==Klassenmenu öffnen==
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 kann man sich noch einen Spaß erlauben und jeder Klasse eine bestimmte Geschwindigkeit zuweisen.
Dazu braucht man die hl2_player.cpp und die player.h/.cpp
Als erstes muss man 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 muss man eine Steuerung bauen für den Speed!
Dazu muss man nur eine Kleinigkeit zum Basisspieler hinzufügen.
player.h öffnen und folgendes im letzten Public-bereich hinzufügen:
 // Hier wird die Spielergeschwindigkeit gesetzt:
 void SetWalkSpeed(int WalkSpeed);
 void SetNormSpeed(int NormSpeed);
 void SetSprintSpeed(int SprintSpeed);
Damit kann man die Werte setzen, aber nun braucht man 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 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 muss man nur noch 2 Sachen tun!
Als erstes muss man sagen, dass die Get Methoden die Geschwindigkeit steuern.
Das macht man 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 muss man nurnoch definieren welche Geschwindigkeit eure Klasse haben soll.
Dazu mmuss man nur in den SetClass Methoden die neuen SetSpeed Methoden einbauen.
Dann kann man 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 ;)