From 722a6ac5cd55abe34a1b32f5abf6e4f616d9f87b Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Sat, 9 Jul 2022 16:45:52 -0700 Subject: [PATCH] Server: Implemented basic respawning. --- src/server/gamerules.h | 2 + src/server/gamerules.qc | 32 ++--- src/server/info_tfgoal.qc | 12 +- src/server/spawn.qc | 250 +------------------------------------- src/shared/defs.h | 41 +++++++ src/shared/include.src | 7 +- src/shared/player.qc | 238 ++++++++++++++++++++++++++++++++++++ 7 files changed, 315 insertions(+), 267 deletions(-) create mode 100644 src/shared/defs.h diff --git a/src/server/gamerules.h b/src/server/gamerules.h index dc05847..d38638e 100644 --- a/src/server/gamerules.h +++ b/src/server/gamerules.h @@ -23,6 +23,8 @@ class TFCGameRules:CGameRules virtual void(NSClientPlayer) PlayerPostFrame; virtual void(NSClientPlayer) PlayerSpawn; virtual void(NSClientPlayer) PlayerKill; + virtual void(NSClientPlayer) PlayerRespawn; + virtual void(NSClientPlayer) PlayerDeath; virtual void(void) LevelNewParms; }; diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc index 66113d7..184a025 100644 --- a/src/server/gamerules.qc +++ b/src/server/gamerules.qc @@ -55,6 +55,14 @@ TFCGameRules::PlayerDisconnect(NSClientPlayer pl) pl.SendFlags = PLAYER_MODELINDEX; } +void +TFCGameRules::PlayerDeath(NSClientPlayer pp) +{ + player pl = (player)pp; + pp.think = PlayerRespawn; + pp.nextthink = time + 4.0f; +} + void TFCGameRules::PlayerKill(NSClientPlayer pp) { @@ -62,30 +70,26 @@ TFCGameRules::PlayerKill(NSClientPlayer pp) Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); } +void +TFCGameRules::PlayerRespawn(NSClientPlayer pp) +{ + player pl = (player)pp; + pl.MakeClass(pl.classtype); + pl.SpawnIntoGame(); +} + void TFCGameRules::PlayerSpawn(NSClientPlayer pp) { player pl = (player)pp; - pl.classname = "unspawned"; - pl.health = 0; - pl.armor = 0; - pl.takedamage = DAMAGE_NO; - pl.solid = SOLID_NOT; - pl.movetype = MOVETYPE_NOCLIP; -// pl.SendEntity = Player_SendEntity; - pl.flags = FL_CLIENT; - pl.weapon = 0; - pl.viewzoom = 1.0f; - pl.model = 0; - setsize (pl, [-16,-16,-16], [16,16,16]); - pl.view_ofs = pl.velocity = [0,0,0]; - forceinfokey(pl, "*spec", "2"); + pl.MakeTempSpectator(); /* replace this with a non-spectator ghost */ Spawn_ObserverCam(pl); } void TFCGameRules::TFCGameRules(void) { + /* TODO: Make this depend on the actual spawn types */ forceinfokey(world, "teams", "2"); forceinfokey(world, "team_1", "Blue"); forceinfokey(world, "teamscore_1", "0"); diff --git a/src/server/info_tfgoal.qc b/src/server/info_tfgoal.qc index b9e96e6..e41a6f1 100644 --- a/src/server/info_tfgoal.qc +++ b/src/server/info_tfgoal.qc @@ -109,20 +109,20 @@ class info_tfgoal:NSRenderableEntity string m_voxNonOwnerTeams; /* non-owner team */ void(void) info_tfgoal; - virtual void(void) touch; + virtual void(entity) Touch; virtual void(void) Respawn; virtual void(string, string) SpawnKey; }; void -info_tfgoal::touch(void) +info_tfgoal::Touch(entity eToucher) { item_tfgoal findme = __NULL__; - if (other.classname != "player") { + if (eToucher.classname != "player") { return; } - player pl = (player)other; + player pl = (player)eToucher; /* check for state */ if (m_tfgState != TFGOAL_INACTIVE) @@ -130,7 +130,7 @@ info_tfgoal::touch(void) /* check for team eligibility */ if (m_iTeamUses) - if (other.team != m_iTeamUses) + if (eToucher.team != m_iTeamUses) return; /* check for the must-have carry */ @@ -163,7 +163,7 @@ info_tfgoal::touch(void) } sound(this, CHAN_ITEM, m_strActivatedSound, 1.0f, ATTN_NORM); - Logging_Pickup(other, this, m_strName); + Logging_Pickup(eToucher, this, m_strName); /* here we increase/decrease funstuff */ pl.health += m_iHealth; diff --git a/src/server/spawn.qc b/src/server/spawn.qc index 616a7b8..44822ee 100644 --- a/src/server/spawn.qc +++ b/src/server/spawn.qc @@ -14,50 +14,15 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -enum -{ - CLASS_SCOUT = 1, - CLASS_SNIPER, - CLASS_SOLDIER, - CLASS_DEMO, - CLASS_MEDIC, - CLASS_HVYWEAPON, - CLASS_PYRO, - CLASS_SPY, - CLASS_ENGINEER -}; - -string g_teammodels[] = { - "", - "models/player/scout/scout2.mdl", - "models/player/sniper/sniper2.mdl", - "models/player/soldier/soldier2.mdl", - "models/player/demo/demo.mdl", - "models/player/medic/medic2.mdl", - "models/player/hvyweapon/hvyweapon2.mdl", - "models/player/pyro/pyro2.mdl", - "models/player/spy/spy2.mdl", - "models/player/engineer/engineer2.mdl" -}; - void CSEv_TeamJoin_f(float f) { if (self.classname != "player") { spawnfunc_player(); } + player pl = (player)self; - entity spot = world; - pl.classname = "player"; - pl.health = self.max_health = 100; - - pl.takedamage = DAMAGE_YES; - pl.solid = SOLID_SLIDEBOX; - pl.movetype = MOVETYPE_WALK; - pl.flags = FL_CLIENT; - pl.viewzoom = 1.0; - /* mess, do it better */ if (f < 10) { pl.team = 1; /* Blue */ @@ -80,213 +45,10 @@ CSEv_TeamJoin_f(float f) forceinfokey(pl, "bottomcolor", "0x3bff00"); } - forceinfokey(pl, "*team", ftos(pl.team)); - pl.model = g_teammodels[f]; - setmodel(pl, pl.model); - setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); - pl.velocity = [0,0,0]; - pl.gravity = __NULL__; - pl.frame = 1; -// pl.SendEntity = Player_SendEntity; - pl.SendFlags = UPDATE_ALL; - pl.armor = pl.activeweapon = pl.g_items = 0; + /* assign our class type for safe keeping */ + pl.classtype = f; - pl.customphysics = Empty; - pl.iBleeds = TRUE; - forceinfokey(pl, "*spec", "0"); - forceinfokey(self, "*deaths", ftos(self.deaths)); - - switch (pl.team) { - case 1: - spot = Spawn_SelectRandom("info_teamspawn_blue"); - break; - case 2: - spot = Spawn_SelectRandom("info_teamspawn_red"); - break; - case 3: - spot = Spawn_SelectRandom("info_teamspawn_yellow"); - break; - case 4: - spot = Spawn_SelectRandom("info_teamspawn_green"); - break; - } - - setorigin(pl, spot.origin); - pl.angles = spot.angles; - pl.fixangle = TRUE; - - switch (f) { - case CLASS_SCOUT: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_NAILGUN, -1); - pl.m_iAmmoShells = 17; - pl.m_iAmmoNails = 100; - - pl.m_iMaxHealth = 75; - pl.m_iMaxArmor = 50; - pl.health = pl.m_iMaxHealth; - pl.armor = 25; - - pl.m_iMaxShells = 50; - pl.m_iMaxNails = 200; - pl.m_iMaxCells = 100; - pl.m_iMaxRockets = 25; - env_message_single(pl, "HELP_SCOUT"); - break; - case CLASS_SNIPER: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SNIPER, -1); - Weapons_AddItem(pl, WEAPON_AUTORIFLE, -1); - Weapons_AddItem(pl, WEAPON_NAILGUN, -1); - pl.m_iAmmoShells = 60; /* sniper rifles use shells */ - pl.m_iAmmoNails = 50; - - pl.m_iMaxHealth = 90; - pl.m_iMaxArmor = 50; - pl.health = pl.m_iMaxHealth; - pl.armor = 0; - - pl.m_iMaxShells = 75; - pl.m_iMaxNails = 100; - pl.m_iMaxCells = 50; - pl.m_iMaxRockets = 25; - env_message_single(pl, "HELP_SNIPER"); - break; - case CLASS_SOLDIER: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_DBS, -1); - Weapons_AddItem(pl, WEAPON_RPG, -1); - pl.m_iAmmoShells = 26; - pl.m_iAmmoRockets = 6; - - pl.m_iMaxHealth = 100; - pl.m_iMaxArmor = 200; - pl.health = pl.m_iMaxHealth; - pl.armor = 100; - - pl.m_iMaxShells = 100; - pl.m_iMaxNails = 100; - pl.m_iMaxCells = 50; - pl.m_iMaxRockets = 50; - env_message_single(pl, "HELP_SOLDIER"); - break; - case CLASS_DEMO: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_GLAUNCHER, -1); - Weapons_AddItem(pl, WEAPON_PIPEBOMB, -1); - pl.m_iAmmoShells = 22; - pl.m_iAmmoRockets = 14; - - pl.m_iMaxHealth = 90; - pl.m_iMaxArmor = 100; - pl.health = pl.m_iMaxHealth; - pl.armor = 50; - - pl.m_iMaxShells = 75; - pl.m_iMaxNails = 50; - pl.m_iMaxCells = 50; - pl.m_iMaxRockets = 50; - env_message_single(pl, "HELP_DEMOMAN"); - break; - case CLASS_MEDIC: - Weapons_AddItem(pl, WEAPON_MEDKIT, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_DBS, -1); - Weapons_AddItem(pl, WEAPON_SUPERNAIL, -1); - pl.m_iAmmoShells = 26; - pl.m_iAmmoNails = 50; - - pl.m_iMaxHealth = 90; - pl.m_iMaxArmor = 100; - pl.health = pl.m_iMaxHealth; - pl.armor = 50; - - pl.m_iMaxShells = 75; - pl.m_iMaxNails = 150; - pl.m_iMaxCells = 50; - pl.m_iMaxRockets = 25; - env_message_single(pl, "HELP_MEDIC"); - break; - case CLASS_HVYWEAPON: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_DBS, -1); - Weapons_AddItem(pl, WEAPON_ASSCAN, -1); - pl.m_iAmmoShells = 176; /* all of the heavy's weapons use shells */ - - pl.m_iMaxHealth = 100; - pl.m_iMaxArmor = 250; - pl.health = pl.m_iMaxHealth; - pl.armor = 150; - - pl.m_iMaxShells = 200; - pl.m_iMaxNails = 200; - pl.m_iMaxCells = 50; - pl.m_iMaxRockets = 25; - env_message_single(pl, "HELP_HWGUY"); - break; - case CLASS_PYRO: - Weapons_AddItem(pl, WEAPON_CROWBAR, -1); - Weapons_AddItem(pl, WEAPON_SBS, -1); - Weapons_AddItem(pl, WEAPON_FLAMER, -1); - Weapons_AddItem(pl, WEAPON_INCENDIARY, -1); - pl.m_iAmmoShells = 12; - pl.m_iAmmoCells = 120; - pl.m_iAmmoRockets = 5; - - pl.m_iMaxHealth = 100; - pl.m_iMaxArmor = 150; - pl.health = pl.m_iMaxHealth; - pl.armor = 50; - - pl.m_iMaxShells = 40; - pl.m_iMaxNails = 50; - pl.m_iMaxCells = 200; - pl.m_iMaxRockets = 60; - env_message_single(pl, "HELP_PYRO"); - break; - case CLASS_SPY: - Weapons_AddItem(pl, WEAPON_KNIFE, -1); - Weapons_AddItem(pl, WEAPON_TRANQUIL, -1); - Weapons_AddItem(pl, WEAPON_DBS, -1); - Weapons_AddItem(pl, WEAPON_NAILGUN, -1); - pl.m_iAmmoShells = 24; /* tranquil and dbs use shells */ - pl.m_iAmmoNails = 50; - - pl.m_iMaxHealth = 90; - pl.m_iMaxArmor = 100; - pl.health = pl.m_iMaxHealth; - pl.armor = 25; - - pl.m_iMaxShells = 40; - pl.m_iMaxNails = 50; - pl.m_iMaxCells = 30; - pl.m_iMaxRockets = 15; - env_message_single(pl, "HELP_SPY"); - break; - case CLASS_ENGINEER: - Weapons_AddItem(pl, WEAPON_WRENCH, -1); - Weapons_AddItem(pl, WEAPON_RAILGUN, -1); - Weapons_AddItem(pl, WEAPON_DBS, -1); - pl.m_iAmmoCells = 100; - pl.m_iAmmoNails = 25; - pl.m_iAmmoShells = 4; - - pl.m_iMaxHealth = 80; - pl.m_iMaxArmor = 50; - pl.health = pl.m_iMaxHealth; - pl.armor = 25; - - pl.m_iMaxShells = 50; - pl.m_iMaxNails = 50; - pl.m_iMaxCells = 200; - pl.m_iMaxRockets = 30; - env_message_single(pl, "HELP_ENGINEER"); - break; - } - - pl.g_items |= ITEM_SUIT; + /* turn the player into the class of his choice */ + pl.MakeClass(f); + pl.SpawnIntoGame(); } diff --git a/src/shared/defs.h b/src/shared/defs.h new file mode 100644 index 0000000..295cf04 --- /dev/null +++ b/src/shared/defs.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-2022 Marco Cawthorne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +typedef enum +{ + CLASS_SCOUT = 1, + CLASS_SNIPER, + CLASS_SOLDIER, + CLASS_DEMO, + CLASS_MEDIC, + CLASS_HVYWEAPON, + CLASS_PYRO, + CLASS_SPY, + CLASS_ENGINEER +} classtype_e; + +string g_teammodels[] = { + "", + "models/player/scout/scout2.mdl", + "models/player/sniper/sniper2.mdl", + "models/player/soldier/soldier2.mdl", + "models/player/demo/demo.mdl", + "models/player/medic/medic2.mdl", + "models/player/hvyweapon/hvyweapon2.mdl", + "models/player/pyro/pyro2.mdl", + "models/player/spy/spy2.mdl", + "models/player/engineer/engineer2.mdl" +}; diff --git a/src/shared/include.src b/src/shared/include.src index 8fa5637..3aaf10c 100644 --- a/src/shared/include.src +++ b/src/shared/include.src @@ -1,4 +1,8 @@ #includelist +defs.h +items.h +weapons.h + ../../../valve/src/shared/flags.h ../../../valve/src/shared/events.h player.qc @@ -17,9 +21,6 @@ player.qc ../../../valve/src/shared/fx_impact.qc ../../../base/src/shared/fx_corpse.qc -items.h -weapons.h - ../../../base/src/shared/weapon_basesemi.qc ../../../base/src/shared/weapon_basemelee.qc ../../../base/src/shared/weapon_baseshotgun.qc diff --git a/src/shared/player.qc b/src/shared/player.qc index 1fd261d..3711a8a 100644 --- a/src/shared/player.qc +++ b/src/shared/player.qc @@ -44,6 +44,9 @@ enumflags class player:NSClientPlayer { + /* class info */ + PREDICTED_INT(classtype); + /* animation */ PREDICTED_INT(anim_top); PREDICTED_FLOAT(anim_top_time); @@ -87,6 +90,9 @@ class player:NSClientPlayer virtual void(void) EvaluateEntity; virtual float(entity, float) SendEntity; + + virtual void(void) SpawnIntoGame; + virtual void(classtype_e) MakeClass; #endif }; @@ -133,6 +139,7 @@ player::ReceiveEntity(float new, float fl) if (fl & PLAYER_AMMO3) { mode_tempstate = readbyte(); + classtype = readbyte(); } setorigin(this, origin); @@ -168,6 +175,7 @@ player::PredictPreFrame(void) { /* the generic client attributes */ NSClientPlayer::PredictPreFrame(); + SAVE_STATE(classtype); SAVE_STATE(anim_top); SAVE_STATE(anim_top_delay); @@ -201,6 +209,7 @@ player::PredictPostFrame(void) { /* the generic client attributes */ NSClientPlayer::PredictPostFrame(); + ROLL_BACK(classtype); ROLL_BACK(anim_top); ROLL_BACK(anim_top_delay); @@ -260,6 +269,9 @@ player::EvaluateEntity(void) if (ATTR_CHANGED(mode_tempstate)) SendFlags |= PLAYER_AMMO3; + if (ATTR_CHANGED(classtype)) + SendFlags |= PLAYER_AMMO3; + SAVE_STATE(mag_sbs); SAVE_STATE(mag_dbs); SAVE_STATE(mag_rpg); @@ -278,6 +290,231 @@ player::EvaluateEntity(void) SAVE_STATE(anim_top_time); SAVE_STATE(anim_bottom); SAVE_STATE(anim_bottom_time); + SAVE_STATE(classtype); +} + +void +player::SpawnIntoGame(void) +{ + entity spot = world; + + /* spawn into the world */ + switch (team) { + case 1: + spot = Spawn_SelectRandom("info_teamspawn_blue"); + break; + case 2: + spot = Spawn_SelectRandom("info_teamspawn_red"); + break; + case 3: + spot = Spawn_SelectRandom("info_teamspawn_yellow"); + break; + case 4: + spot = Spawn_SelectRandom("info_teamspawn_green"); + break; + } + + setorigin(this, spot.origin); + angles = spot.angles; + fixangle = TRUE; +} + +void +player::MakeClass(classtype_e class) +{ + health = self.max_health = 100; + takedamage = DAMAGE_YES; + solid = SOLID_SLIDEBOX; + movetype = MOVETYPE_WALK; + flags = FL_CLIENT; + viewzoom = 1.0; + + /* select our class model */ + model = g_teammodels[classtype]; + setmodel(this, model); + setsize(this, VEC_HULL_MIN, VEC_HULL_MAX); + velocity = [0,0,0]; + gravity = __NULL__; + + armor = activeweapon = g_items = 0; + iBleeds = TRUE; + forceinfokey(this, "*spec", "0"); + forceinfokey(this, "*team", ftos(team)); + + switch (classtype) { + case CLASS_SCOUT: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_NAILGUN, -1); + m_iAmmoShells = 17; + m_iAmmoNails = 100; + + m_iMaxHealth = 75; + m_iMaxArmor = 50; + health = m_iMaxHealth; + armor = 25; + + m_iMaxShells = 50; + m_iMaxNails = 200; + m_iMaxCells = 100; + m_iMaxRockets = 25; + env_message_single(this, "HELP_SCOUT"); + break; + case CLASS_SNIPER: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SNIPER, -1); + Weapons_AddItem(this, WEAPON_AUTORIFLE, -1); + Weapons_AddItem(this, WEAPON_NAILGUN, -1); + m_iAmmoShells = 60; /* sniper rifles use shells */ + m_iAmmoNails = 50; + + m_iMaxHealth = 90; + m_iMaxArmor = 50; + health = m_iMaxHealth; + armor = 0; + + m_iMaxShells = 75; + m_iMaxNails = 100; + m_iMaxCells = 50; + m_iMaxRockets = 25; + env_message_single(this, "HELP_SNIPER"); + break; + case CLASS_SOLDIER: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_DBS, -1); + Weapons_AddItem(this, WEAPON_RPG, -1); + m_iAmmoShells = 26; + m_iAmmoRockets = 6; + + m_iMaxHealth = 100; + m_iMaxArmor = 200; + health = m_iMaxHealth; + armor = 100; + + m_iMaxShells = 100; + m_iMaxNails = 100; + m_iMaxCells = 50; + m_iMaxRockets = 50; + env_message_single(this, "HELP_SOLDIER"); + break; + case CLASS_DEMO: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_GLAUNCHER, -1); + Weapons_AddItem(this, WEAPON_PIPEBOMB, -1); + m_iAmmoShells = 22; + m_iAmmoRockets = 14; + + m_iMaxHealth = 90; + m_iMaxArmor = 100; + health = m_iMaxHealth; + armor = 50; + + m_iMaxShells = 75; + m_iMaxNails = 50; + m_iMaxCells = 50; + m_iMaxRockets = 50; + env_message_single(this, "HELP_DEMOMAN"); + break; + case CLASS_MEDIC: + Weapons_AddItem(this, WEAPON_MEDKIT, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_DBS, -1); + Weapons_AddItem(this, WEAPON_SUPERNAIL, -1); + m_iAmmoShells = 26; + m_iAmmoNails = 50; + + m_iMaxHealth = 90; + m_iMaxArmor = 100; + health = m_iMaxHealth; + armor = 50; + + m_iMaxShells = 75; + m_iMaxNails = 150; + m_iMaxCells = 50; + m_iMaxRockets = 25; + env_message_single(this, "HELP_MEDIC"); + break; + case CLASS_HVYWEAPON: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_DBS, -1); + Weapons_AddItem(this, WEAPON_ASSCAN, -1); + m_iAmmoShells = 176; /* all of the heavy's weapons use shells */ + + m_iMaxHealth = 100; + m_iMaxArmor = 250; + health = m_iMaxHealth; + armor = 150; + + m_iMaxShells = 200; + m_iMaxNails = 200; + m_iMaxCells = 50; + m_iMaxRockets = 25; + env_message_single(this, "HELP_HWGUY"); + break; + case CLASS_PYRO: + Weapons_AddItem(this, WEAPON_CROWBAR, -1); + Weapons_AddItem(this, WEAPON_SBS, -1); + Weapons_AddItem(this, WEAPON_FLAMER, -1); + Weapons_AddItem(this, WEAPON_INCENDIARY, -1); + m_iAmmoShells = 12; + m_iAmmoCells = 120; + m_iAmmoRockets = 5; + + m_iMaxHealth = 100; + m_iMaxArmor = 150; + health = m_iMaxHealth; + armor = 50; + + m_iMaxShells = 40; + m_iMaxNails = 50; + m_iMaxCells = 200; + m_iMaxRockets = 60; + env_message_single(this, "HELP_PYRO"); + break; + case CLASS_SPY: + Weapons_AddItem(this, WEAPON_KNIFE, -1); + Weapons_AddItem(this, WEAPON_TRANQUIL, -1); + Weapons_AddItem(this, WEAPON_DBS, -1); + Weapons_AddItem(this, WEAPON_NAILGUN, -1); + m_iAmmoShells = 24; /* tranquil and dbs use shells */ + m_iAmmoNails = 50; + + m_iMaxHealth = 90; + m_iMaxArmor = 100; + health = m_iMaxHealth; + armor = 25; + + m_iMaxShells = 40; + m_iMaxNails = 50; + m_iMaxCells = 30; + m_iMaxRockets = 15; + env_message_single(this, "HELP_SPY"); + break; + case CLASS_ENGINEER: + Weapons_AddItem(this, WEAPON_WRENCH, -1); + Weapons_AddItem(this, WEAPON_RAILGUN, -1); + Weapons_AddItem(this, WEAPON_DBS, -1); + m_iAmmoCells = 100; + m_iAmmoNails = 25; + m_iAmmoShells = 4; + + m_iMaxHealth = 80; + m_iMaxArmor = 50; + health = m_iMaxHealth; + armor = 25; + + m_iMaxShells = 50; + m_iMaxNails = 50; + m_iMaxCells = 200; + m_iMaxRockets = 30; + env_message_single(this, "HELP_ENGINEER"); + break; + } + + g_items |= ITEM_SUIT; } /* @@ -338,6 +575,7 @@ player::SendEntity(entity ePEnt, float fChanged) if (fChanged & PLAYER_AMMO3) { WriteByte(MSG_ENTITY, mode_tempstate); + WriteByte(MSG_ENTITY, classtype); } return (1);