From 44479cd637fe8962ba04f05c1b348eb0c9343026 Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Sat, 7 Sep 2019 21:01:05 +0200 Subject: [PATCH] Networking improvements. Make player entities and NPC networking conditional. Only changed fields are networked. This is because the overall design seems mature enough. --- src/client/entry.c | 5 +- src/client/npc.c | 59 ++++-- src/client/valve/player.c | 106 +++++----- src/server/cstrike/item_suit.cpp | 32 +-- src/server/scihunt/client.c | 100 ++++++++- src/server/scihunt/monster_scientist.cpp | 95 +++++++-- src/server/valve/client.c | 170 ++++++++++++--- src/server/valve/player.c | 92 ++++++--- src/shared/entities.h | 40 ++++ src/shared/scihunt/player.cpp | 18 ++ src/shared/valve/player.cpp | 18 ++ src/shared/valve/w_crowbar.c | 250 +++++++++++++---------- 12 files changed, 708 insertions(+), 277 deletions(-) diff --git a/src/client/entry.c b/src/client/entry.c index 3538a20e..c9243843 100644 --- a/src/client/entry.c +++ b/src/client/entry.c @@ -99,7 +99,6 @@ CSQC_Init(float apilevel, string enginename, float engineversion) /* Game specific inits */ HUD_Init(); - Scores_Init(); Client_Init(apilevel, enginename, engineversion); DSP_Init(); @@ -210,6 +209,10 @@ CSQC_UpdateView(float w, float h, float focus) } else { setsensitivityscaler(pl.viewzoom); } + + if (pl.viewzoom <= 0.0f) { + setsensitivityscaler(1.0f); + } pl.viewzoom = oldzoom; diff --git a/src/client/npc.c b/src/client/npc.c index 722a4833..9e7f64a1 100644 --- a/src/client/npc.c +++ b/src/client/npc.c @@ -17,7 +17,6 @@ class monster_npc { int body; - int inited; float frame_last; virtual float() predraw; @@ -26,12 +25,6 @@ class monster_npc float monster_npc::predraw(void) { - /* Only do this once whenever the ent pops into view */ - if (!inited) { - setcustomskin(this, "", sprintf("geomset 1 %i\n", body)); - inited = TRUE; - } - if (lerpfrac > 0) { lerpfrac -= frametime * 5; if (lerpfrac < 0) { @@ -58,28 +51,50 @@ monster_npc::predraw(void) void NPC_ReadEntity(float new) { + float fl; monster_npc pl = (monster_npc)self; - if (new == TRUE) { + + if (new) { spawnfunc_monster_npc(); pl.classname = "npc"; pl.solid = SOLID_SLIDEBOX; + pl.movetype = MOVETYPE_NONE; pl.drawmask = MASK_ENGINE; pl.customphysics = Empty; - setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX ); + setsize(pl, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]); } - /* TODO: make these conditional */ - pl.modelindex = readshort(); - pl.origin[0] = readcoord(); - pl.origin[1] = readcoord(); - pl.origin[2] = readcoord(); - pl.angles[1] = readfloat(); - pl.angles[2] = readfloat(); - pl.velocity[0] = readcoord(); - pl.velocity[1] = readcoord(); - pl.velocity[2] = readcoord(); - pl.frame = readbyte(); - pl.skin = readbyte(); - pl.body = readbyte(); + fl = readshort(); + + if (fl & NPC_MODELINDEX) + pl.modelindex = readshort(); + if (fl & NPC_ORIGIN_X) + pl.origin[0] = readcoord(); + if (fl & NPC_ORIGIN_Y) + pl.origin[1] = readcoord(); + if (fl & NPC_ORIGIN_Z) + pl.origin[2] = readcoord(); + if (fl & NPC_ANGLES_X) + pl.angles[0] = readfloat(); + if (fl & NPC_ANGLES_Y) + pl.angles[1] = readfloat(); + if (fl & NPC_ANGLES_Z) + pl.angles[2] = readfloat(); + if (fl & NPC_VELOCITY_X) + pl.velocity[0] = readcoord(); + if (fl & NPC_VELOCITY_Y) + pl.velocity[1] = readcoord(); + if (fl & NPC_VELOCITY_Z) + pl.velocity[2] = readcoord(); + if (fl & NPC_FRAME) + pl.frame = readbyte(); + if (fl & NPC_SKIN) + pl.skin = readbyte(); + if (fl & NPC_BODY) + pl.body = readbyte(); + + if (new) { + setcustomskin(pl, "", sprintf("geomset 1 %i\n", pl.body)); + } } diff --git a/src/client/valve/player.c b/src/client/valve/player.c index 8821c9f8..8e9aed3c 100644 --- a/src/client/valve/player.c +++ b/src/client/valve/player.c @@ -14,29 +14,19 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -//FOR DEBUGGING ONLY, remove when prediction is trusted (along with the extra network bloat). -static void warnifdiff(string name, __inout float expected, float got) -{ - //this should only fire from prediction misses. - //this hopefully only happens when the server's anti-time-banking logic does its thing, or for things caused by other players/ents getting in the way. - - //if (expected != got) - //print(sprintf("%s differs, expected %g, got %g\n", name, expected, got)); - - //enable the following line if you want to see if it actually makes a difference. - //expected = got; -} - -void Player_ReadEntity(float flIsNew) +void +Player_ReadEntity(float new) { + float fl; player pl = (player)self; - if ( flIsNew == TRUE ) { + + if (new == TRUE) { spawnfunc_player(); pl.classname = "player"; pl.solid = SOLID_SLIDEBOX; pl.drawmask = MASK_ENGINE; pl.customphysics = Empty; - setsize( pl, VEC_HULL_MIN, VEC_HULL_MAX ); + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); } else { int i; //FIXME: splitscreen @@ -56,36 +46,58 @@ void Player_ReadEntity(float flIsNew) } } - pl.sequence = servercommandframe; - pl.modelindex = readshort(); // TODO: make conditional - pl.origin[0] = readcoord(); - pl.origin[1] = readcoord(); - pl.origin[2] = readcoord(); // TODO: make conditional - pl.pitch = readfloat(); - pl.angles[1] = readfloat(); - pl.angles[2] = readfloat(); - pl.velocity[0] = readcoord(); - pl.velocity[1] = readcoord(); - pl.velocity[2] = readcoord(); - pl.flags = readfloat(); //make mostly conditional - pl.activeweapon = readbyte(); // TODO: make conditional - warnifdiff("weapontime", pl.weapontime, readfloat()); //remove - pl.g_items = readfloat(); // TODO: make conditional - pl.health = readbyte(); // TODO: make conditional - pl.armor = readbyte(); // TODO: make conditional - pl.movetype = readbyte(); // TODO: make conditional - pl.view_ofs[2] = readfloat(); // TODO: make conditional - pl.viewzoom = readfloat(); //remove? or make conditional - warnifdiff("jumptime", pl.jumptime, readfloat()); //remove - warnifdiff("teletime", pl.teleport_time, readfloat()); //remove - - pl.baseframe = readbyte(); // TODO: make conditional - pl.frame = readbyte(); // TODO: make conditional + pl.sequence = servercommandframe; - pl.a_ammo1 = readbyte(); // TODO: make conditional - pl.a_ammo2 = readbyte(); // TODO: make conditional - pl.a_ammo3 = readbyte(); // TODO: make conditional - warnifdiff("attack_next", pl.w_attack_next, readfloat()); //remove - warnifdiff("idle_next", pl.w_idle_next, readfloat()); //remove - setorigin( pl, pl.origin ); + fl = readfloat(); + + if (fl & PLAYER_MODELINDEX) + pl.modelindex = readshort(); + + if (fl & PLAYER_ORIGIN) { + pl.origin[0] = readcoord(); + pl.origin[1] = readcoord(); + } + + if (fl & PLAYER_ORIGIN_Z) + pl.origin[2] = readcoord(); + if (fl & PLAYER_ANGLES_X) + pl.pitch = readfloat(); + if (fl & PLAYER_ANGLES_Y) + pl.angles[1] = readfloat(); + if (fl & PLAYER_ANGLES_Z) + pl.angles[2] = readfloat(); + + if (fl & PLAYER_VELOCITY) { + pl.velocity[0] = readcoord(); + pl.velocity[1] = readcoord(); + } + + if (fl & PLAYER_VELOCITY_Z) + pl.velocity[2] = readcoord(); + if (fl & PLAYER_FLAGS) + pl.flags = readfloat(); + if (fl & PLAYER_WEAPON) + pl.activeweapon = readbyte(); + if (fl & PLAYER_ITEMS) + pl.g_items = readfloat(); + if (fl & PLAYER_HEALTH) + pl.health = readbyte(); + if (fl & PLAYER_ARMOR) + pl.armor = readbyte(); + if (fl & PLAYER_MOVETYPE) + pl.movetype = readbyte(); + if (fl & PLAYER_VIEWOFS) + pl.view_ofs[2] = readfloat(); + if (fl & PLAYER_BASEFRAME) + pl.baseframe = readbyte(); + if (fl & PLAYER_FRAME) + pl.frame = readbyte(); + if (fl & PLAYER_AMMO1) + pl.a_ammo1 = readbyte(); + if (fl & PLAYER_AMMO2) + pl.a_ammo2 = readbyte(); + if (fl & PLAYER_AMMO3) + pl.a_ammo3 = readbyte(); + + setorigin(pl, pl.origin); } diff --git a/src/server/cstrike/item_suit.cpp b/src/server/cstrike/item_suit.cpp index 823eab7c..1d7387e8 100644 --- a/src/server/cstrike/item_suit.cpp +++ b/src/server/cstrike/item_suit.cpp @@ -24,23 +24,24 @@ class item_suit:CBaseTrigger void item_suit::touch(void) { - if (other.classname == "player") { - player pl = (player)other; - /*if (pl.g_items & ITEM_SUIT) { - return; - }*/ - sound(other, CHAN_ITEM, "items/tr_kevlar.wav", 1, ATTN_NORM); - /*pl.g_items |= ITEM_SUIT;*/ + if (other.classname != "player") { + return; + } + player pl = (player)other; + /*if (pl.g_items & ITEM_SUIT) { + return; + }*/ + sound(other, CHAN_ITEM, "items/tr_kevlar.wav", 1, ATTN_NORM); + /*pl.g_items |= ITEM_SUIT;*/ - CBaseTrigger::UseTargets(); + CBaseTrigger::UseTargets(); - if (cvar("sv_playerslots") == 1) { - remove(self); - } else { - Hide(); - think = Respawn; - nextthink = time + 30.0f; - } + if (cvar("sv_playerslots") == 1) { + remove(self); + } else { + Hide(); + think = Respawn; + nextthink = time + 30.0f; } } @@ -54,7 +55,6 @@ void item_suit::Respawn(void) think = __NULL__; nextthink = -1; - sound(this, CHAN_ITEM, "items/suitchargeok1.wav", 1, ATTN_NORM, 150); } void item_suit::item_suit(void) diff --git a/src/server/scihunt/client.c b/src/server/scihunt/client.c index 6104d918..3d1b51f8 100644 --- a/src/server/scihunt/client.c +++ b/src/server/scihunt/client.c @@ -55,8 +55,70 @@ void Game_PlayerPreThink(void) } void Game_PlayerPostThink(void) { + player pl = (player)self; Animation_PlayerUpdate(); - self.SendFlags = 1; + + if (pl.old_modelindex != pl.modelindex) + pl.SendFlags |= PLAYER_MODELINDEX; + if (pl.old_origin[0] != pl.origin[0]) + pl.SendFlags |= PLAYER_ORIGIN; + if (pl.old_origin[1] != pl.origin[1]) + pl.SendFlags |= PLAYER_ORIGIN; + if (pl.old_origin[2] != pl.origin[2]) + pl.SendFlags |= PLAYER_ORIGIN_Z; + if (pl.old_angles[0] != pl.angles[0]) + pl.SendFlags |= PLAYER_ANGLES_X; + if (pl.old_angles[1] != pl.angles[1]) + pl.SendFlags |= PLAYER_ANGLES_Y; + if (pl.old_angles[2] != pl.angles[2]) + pl.SendFlags |= PLAYER_ANGLES_Z; + if (pl.old_velocity[0] != pl.velocity[0]) + pl.SendFlags |= PLAYER_VELOCITY; + if (pl.old_velocity[1] != pl.velocity[1]) + pl.SendFlags |= PLAYER_VELOCITY; + if (pl.old_velocity[2] != pl.velocity[2]) + pl.SendFlags |= PLAYER_VELOCITY_Z; + if (pl.old_flags != pl.flags) + pl.SendFlags |= PLAYER_FLAGS; + if (pl.old_activeweapon != pl.activeweapon) + pl.SendFlags |= PLAYER_WEAPON; + if (pl.old_items != pl.g_items) + pl.SendFlags |= PLAYER_ITEMS; + if (pl.old_health != pl.health) + pl.SendFlags |= PLAYER_HEALTH; + if (pl.old_armor != pl.armor) + pl.SendFlags |= PLAYER_ARMOR; + if (pl.old_movetype != pl.movetype) + pl.SendFlags |= PLAYER_MOVETYPE; + if (pl.old_viewofs != pl.view_ofs[2]) + pl.SendFlags |= PLAYER_VIEWOFS; + if (pl.old_baseframe != pl.baseframe) + pl.SendFlags |= PLAYER_BASEFRAME; + if (pl.old_frame != pl.frame) + pl.SendFlags |= PLAYER_FRAME; + if (pl.old_a_ammo1 != pl.a_ammo1) + pl.SendFlags |= PLAYER_AMMO1; + if (pl.old_a_ammo2 != pl.a_ammo2) + pl.SendFlags |= PLAYER_AMMO2; + if (pl.old_a_ammo3 != pl.a_ammo3) + pl.SendFlags |= PLAYER_AMMO3; + + pl.old_modelindex = pl.modelindex; + pl.old_origin = pl.origin; + pl.old_angles = pl.angles; + pl.old_velocity = pl.velocity; + pl.old_flags = pl.flags; + pl.old_activeweapon = pl.activeweapon; + pl.old_items = pl.g_items; + pl.old_health = pl.health; + pl.old_armor = pl.armor; + pl.old_movetype = pl.movetype; + pl.old_viewofs = pl.view_ofs[2]; + pl.old_baseframe = pl.baseframe; + pl.old_frame = pl.frame; + pl.old_a_ammo1 = pl.a_ammo1; + pl.old_a_ammo2 = pl.a_ammo2; + pl.old_a_ammo3 = pl.a_ammo3; } void Game_RunClientCommand(void) { @@ -106,7 +168,6 @@ void Game_PutClientInServer(void) pl.classname = "player"; pl.health = self.max_health = 100; - //forceinfokey(self, "*dead", "0"); pl.takedamage = DAMAGE_YES; pl.solid = SOLID_SLIDEBOX; pl.movetype = MOVETYPE_WALK; @@ -115,19 +176,40 @@ void Game_PutClientInServer(void) pl.model = "models/player.mdl"; string mymodel = infokey(pl, "model"); - if (mymodel) { - mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); - if (whichpack(mymodel)) { - pl.model = mymodel; - } - } - setmodel(pl, pl.model); + if (mymodel) { + mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); + if (whichpack(mymodel)) { + pl.model = mymodel; + } + } + setmodel(pl, pl.model); setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); pl.view_ofs = VEC_PLAYER_VIEWPOS; pl.velocity = [0,0,0]; pl.frame = 1; pl.SendEntity = Player_SendEntity; + pl.SendFlags = PLAYER_MODELINDEX | + PLAYER_ORIGIN | + PLAYER_ORIGIN_Z | + PLAYER_ANGLES_X | + PLAYER_ANGLES_Y | + PLAYER_ANGLES_Z | + PLAYER_VELOCITY | + PLAYER_VELOCITY_Z | + PLAYER_FLAGS | + PLAYER_WEAPON | + PLAYER_ITEMS | + PLAYER_HEALTH | + PLAYER_ARMOR | + PLAYER_MOVETYPE | + PLAYER_VIEWOFS | + PLAYER_BASEFRAME | + PLAYER_FRAME | + PLAYER_AMMO1 | + PLAYER_AMMO2 | + PLAYER_AMMO3; + pl.customphysics = Empty; pl.vPain = Player_Pain; pl.vDeath = Player_Death; diff --git a/src/server/scihunt/monster_scientist.cpp b/src/server/scihunt/monster_scientist.cpp index 998af4cf..968c78da 100644 --- a/src/server/scihunt/monster_scientist.cpp +++ b/src/server/scihunt/monster_scientist.cpp @@ -301,7 +301,7 @@ string sci_sndidle[] = { class monster_scientist:CBaseEntity { - int m_iBody; + int body; vector m_vecLastUserPos; entity m_eUser; entity m_eRescuer; @@ -313,6 +313,15 @@ class monster_scientist:CBaseEntity float m_flTraceTime; float m_flPitch; int m_iFlags; + + int old_modelindex; + vector old_origin; + vector old_angles; + vector old_velocity; + int old_frame; + int old_skin; + int old_body; + void() monster_scientist; virtual void() touch; @@ -337,18 +346,35 @@ float monster_scientist::SendEntity(entity ePEnt, float fChanged) } WriteByte(MSG_ENTITY, ENT_NPC); - WriteShort(MSG_ENTITY, modelindex); - WriteCoord(MSG_ENTITY, origin[0]); - WriteCoord(MSG_ENTITY, origin[1]); - WriteCoord(MSG_ENTITY, origin[2]); - WriteFloat(MSG_ENTITY, angles[1]); - WriteFloat(MSG_ENTITY, angles[2]); - WriteCoord(MSG_ENTITY, velocity[0]); - WriteCoord(MSG_ENTITY, velocity[1]); - WriteCoord(MSG_ENTITY, velocity[2]); - WriteByte(MSG_ENTITY, frame); - WriteByte(MSG_ENTITY, skin); - WriteByte(MSG_ENTITY, m_iBody); + WriteShort(MSG_ENTITY, fChanged); + + if (fChanged & NPC_MODELINDEX) + WriteShort(MSG_ENTITY, modelindex); + if (fChanged & NPC_ORIGIN_X) + WriteCoord(MSG_ENTITY, origin[0]); + if (fChanged & NPC_ORIGIN_Y) + WriteCoord(MSG_ENTITY, origin[1]); + if (fChanged & NPC_ORIGIN_Z) + WriteCoord(MSG_ENTITY, origin[2]); + if (fChanged & NPC_ANGLES_X) + WriteFloat(MSG_ENTITY, angles[0]); + if (fChanged & NPC_ANGLES_Y) + WriteFloat(MSG_ENTITY, angles[1]); + if (fChanged & NPC_ANGLES_Z) + WriteFloat(MSG_ENTITY, angles[2]); + if (fChanged & NPC_VELOCITY_X) + WriteCoord(MSG_ENTITY, velocity[0]); + if (fChanged & NPC_VELOCITY_Y) + WriteCoord(MSG_ENTITY, velocity[1]); + if (fChanged & NPC_VELOCITY_Z) + WriteCoord(MSG_ENTITY, velocity[2]); + if (fChanged & NPC_FRAME) + WriteByte(MSG_ENTITY, frame); + if (fChanged & NPC_SKIN) + WriteByte(MSG_ENTITY, skin); + if (fChanged & NPC_BODY) + WriteByte(MSG_ENTITY, body); + return TRUE; } @@ -546,7 +572,41 @@ void monster_scientist::Physics(void) runstandardplayerphysics(this); Footsteps_Update(); - SendFlags = 1; + + if (modelindex != old_modelindex) + SendFlags |= NPC_MODELINDEX; + if (origin[0] != old_origin[0]) + SendFlags |= NPC_ORIGIN_X; + if (origin[1] != old_origin[1]) + SendFlags |= NPC_ORIGIN_Y; + if (origin[2] != old_origin[2]) + SendFlags |= NPC_ORIGIN_Z; + if (angles[0] != old_angles[0]) + SendFlags |= NPC_ANGLES_X; + if (angles[1] != old_angles[1]) + SendFlags |= NPC_ANGLES_Y; + if (angles[2] != old_angles[2]) + SendFlags |= NPC_ANGLES_Z; + if (velocity[0] != old_velocity[0]) + SendFlags |= NPC_VELOCITY_X; + if (velocity[1] != old_velocity[1]) + SendFlags |= NPC_VELOCITY_Y; + if (velocity[2] != old_velocity[2]) + SendFlags |= NPC_VELOCITY_Z; + if (frame != old_frame) + SendFlags |= NPC_FRAME; + if (skin != old_skin) + SendFlags |= NPC_SKIN; + if (body != old_body) + SendFlags |= NPC_BODY; + + old_modelindex = modelindex; + old_origin = origin; + old_angles = angles, + old_velocity = velocity, + old_frame = frame; + old_skin = skin; + old_body = body; if (!(flags & FL_ONGROUND) && velocity[2] < -100) { if (!(m_iFlags & SCIF_FALLING)) { @@ -624,7 +684,7 @@ void monster_scientist::vDeath(int iHitBody) think = Respawn; nextthink = time + 10.0f; - SendFlags = 1; + SendFlags |= NPC_FRAME; m_eUser = world; customphysics = __NULL__; m_iFlags = 0x0; @@ -676,6 +736,7 @@ void monster_scientist::Respawn(void) health = 50; velocity = [0,0,0]; m_iFlags = 0x0; + SendFlags = 0xff; if (autocvar_sh_scialert) { m_iFlags |= SCIF_FEAR; @@ -713,8 +774,8 @@ void monster_scientist::monster_scientist(void) /* This stuff needs to be persistent because we can't guarantee that * the client-side geomset refresh happens. Don't shove this into Respawn */ - m_iBody = floor(random(1,5)); - switch (m_iBody) { + body = floor(random(1,5)); + switch (body) { case 1: m_flPitch = 105; netname = "Walter"; diff --git a/src/server/valve/client.c b/src/server/valve/client.c index 5708d173..4ef7bc5b 100644 --- a/src/server/valve/client.c +++ b/src/server/valve/client.c @@ -14,25 +14,30 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -void Game_ClientConnect(void) +var int autocvar_sv_networkeverything = FALSE; + +void +Game_ClientConnect(void) { + entity a; bprint(PRINT_HIGH, sprintf("%s connected\n", self.netname)); int playercount = 0; - for (entity eFind = world; (eFind = find(eFind, classname, "player"));) { + for (a = world; (a = find(a, classname, "player"));) { playercount++; } - /* We're the first. */ + /* we're the first. respawn all entities? */ if (playercount == 0) { - for (entity a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) { - CBaseEntity caw = (CBaseEntity)a; - caw.Respawn(); - } + for (a = world; (a = findfloat(a, gflags, GF_CANRESPAWN));) { + CBaseEntity caw = (CBaseEntity)a; + caw.Respawn(); + } } } -void Game_ClientDisconnect(void) +void +Game_ClientDisconnect(void) { bprint(PRINT_HIGH, sprintf("%s disconnected\n", self.netname)); @@ -45,28 +50,117 @@ void Game_ClientDisconnect(void) self.SendFlags = 1; } -void Game_ClientKill(void) +void +Game_ClientKill(void) { Damage_Apply(self, self, self.health, self.origin, TRUE); } -void Game_PlayerPreThink(void) +void +Game_PlayerPreThink(void) { } -void Game_PlayerPostThink(void) +void +Game_PlayerPostThink(void) { + player pl = (player)self; Animation_PlayerUpdate(); - self.SendFlags = 1; + + if (pl.old_modelindex != pl.modelindex) { + pl.SendFlags |= PLAYER_MODELINDEX; + } + if (pl.old_origin[0] != pl.origin[0]) { + pl.SendFlags |= PLAYER_ORIGIN; + } + if (pl.old_origin[1] != pl.origin[1]) { + pl.SendFlags |= PLAYER_ORIGIN; + } + if (pl.old_origin[2] != pl.origin[2]) { + pl.SendFlags |= PLAYER_ORIGIN_Z; + } + if (pl.old_angles[0] != pl.angles[0]) { + pl.SendFlags |= PLAYER_ANGLES_X; + } + if (pl.old_angles[1] != pl.angles[1]) { + pl.SendFlags |= PLAYER_ANGLES_Y; + } + if (pl.old_angles[2] != pl.angles[2]) { + pl.SendFlags |= PLAYER_ANGLES_Z; + } + if (pl.old_velocity[0] != pl.velocity[0]) { + pl.SendFlags |= PLAYER_VELOCITY; + } + if (pl.old_velocity[1] != pl.velocity[1]) { + pl.SendFlags |= PLAYER_VELOCITY; + } + if (pl.old_velocity[2] != pl.velocity[2]) { + pl.SendFlags |= PLAYER_VELOCITY_Z; + } + if (pl.old_flags != pl.flags) { + pl.SendFlags |= PLAYER_FLAGS; + } + if (pl.old_activeweapon != pl.activeweapon) { + pl.SendFlags |= PLAYER_WEAPON; + } + if (pl.old_items != pl.g_items) { + pl.SendFlags |= PLAYER_ITEMS; + } + if (pl.old_health != pl.health) { + pl.SendFlags |= PLAYER_HEALTH; + } + if (pl.old_armor != pl.armor) { + pl.SendFlags |= PLAYER_ARMOR; + } + if (pl.old_movetype != pl.movetype) { + pl.SendFlags |= PLAYER_MOVETYPE; + } + if (pl.old_viewofs != pl.view_ofs[2]) { + pl.SendFlags |= PLAYER_VIEWOFS; + } + if (pl.old_baseframe != pl.baseframe) { + pl.SendFlags |= PLAYER_BASEFRAME; + } + if (pl.old_frame != pl.frame) { + pl.SendFlags |= PLAYER_FRAME; + } + if (pl.old_a_ammo1 != pl.a_ammo1) { + pl.SendFlags |= PLAYER_AMMO1; + } + if (pl.old_a_ammo2 != pl.a_ammo2) { + pl.SendFlags |= PLAYER_AMMO2; + } + if (pl.old_a_ammo3 != pl.a_ammo3) { + pl.SendFlags |= PLAYER_AMMO3; + } + + pl.old_modelindex = pl.modelindex; + pl.old_origin = pl.origin; + pl.old_angles = pl.angles; + pl.old_velocity = pl.velocity; + pl.old_flags = pl.flags; + pl.old_activeweapon = pl.activeweapon; + pl.old_items = pl.g_items; + pl.old_health = pl.health; + pl.old_armor = pl.armor; + pl.old_movetype = pl.movetype; + pl.old_viewofs = pl.view_ofs[2]; + pl.old_baseframe = pl.baseframe; + pl.old_frame = pl.frame; + pl.old_a_ammo1 = pl.a_ammo1; + pl.old_a_ammo2 = pl.a_ammo2; + pl.old_a_ammo3 = pl.a_ammo3; } -void Game_RunClientCommand(void) +void +Game_RunClientCommand(void) { Footsteps_Update(); QPhysics_Run(self); } -void Game_DecodeChangeParms(void) +void +Game_DecodeChangeParms(void) { player pl = (player)self; g_landmarkpos[0] = parm1; @@ -81,7 +175,8 @@ void Game_DecodeChangeParms(void) pl.g_items = parm10; pl.activeweapon = parm11; } -void Game_SetChangeParms(void) +void +Game_SetChangeParms(void) { player pl = (player)self; parm1 = g_landmarkpos[0]; @@ -97,7 +192,8 @@ void Game_SetChangeParms(void) parm11 = pl.activeweapon; } -void Game_PutClientInServer(void) +void +Game_PutClientInServer(void) { if (self.classname != "player") { spawnfunc_player(); @@ -107,7 +203,7 @@ void Game_PutClientInServer(void) entity spot; pl.classname = "player"; pl.health = self.max_health = 100; - //forceinfokey(self, "*dead", "0"); + pl.takedamage = DAMAGE_YES; pl.solid = SOLID_SLIDEBOX; pl.movetype = MOVETYPE_WALK; @@ -116,7 +212,7 @@ void Game_PutClientInServer(void) pl.model = "models/player.mdl"; string mymodel = infokey(pl, "model"); - + if (mymodel) { mymodel = sprintf("models/player/%s/%s.mdl", mymodel, mymodel); if (whichpack(mymodel)) { @@ -124,7 +220,7 @@ void Game_PutClientInServer(void) } } setmodel(pl, pl.model); - + setsize(pl, VEC_HULL_MIN, VEC_HULL_MAX); pl.view_ofs = VEC_PLAYER_VIEWPOS; pl.velocity = [0,0,0]; @@ -141,7 +237,6 @@ void Game_PutClientInServer(void) Game_DecodeChangeParms(); if (startspot != "") { - print(sprintf("[LEVEL] Startspot is \"%s\"\n", startspot)); setorigin(pl, Landmark_GetSpot()); } else { spot = find(world, classname, "info_player_start"); @@ -162,40 +257,48 @@ void Game_PutClientInServer(void) } } -void SV_SendChat(entity eSender, string sMessage, entity eEnt, float fType) +void +SV_SendChat(entity sender, string msg, entity eEnt, float fType) { WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET); WriteByte(MSG_MULTICAST, fType == 0 ? EV_CHAT:EV_CHAT_TEAM); - WriteByte(MSG_MULTICAST, num_for_edict(eSender) - 1); - WriteByte(MSG_MULTICAST, eSender.team); - WriteString(MSG_MULTICAST, sMessage); + WriteByte(MSG_MULTICAST, num_for_edict(sender) - 1); + WriteByte(MSG_MULTICAST, sender.team); + WriteString(MSG_MULTICAST, msg); if (eEnt) { msg_entity = eEnt; multicast([0,0,0], MULTICAST_ONE); } else { multicast([0,0,0], MULTICAST_ALL); } + + localcmd(sprintf("echo [SERVER] %s: %s\n", sender.netname, msg)); } -void Game_ParseClientCommand(string cmd) +void +Game_ParseClientCommand(string cmd) { tokenize(cmd); if (argv(1) == "timeleft") { - float fTimeLeft = cvar("mp_timelimit") - (time / 60); - Vox_Singlecast(self, sprintf("we have %s minutes remaining", Vox_TimeToString(fTimeLeft))); + string msg; + string timestring; + float timeleft; + timeleft = cvar("mp_timelimit") - (time / 60); + timestring = Vox_TimeToString(timeleft); + msg = sprintf("we have %s minutes remaining", timestring); + Vox_Singlecast(self, msg); return; } if (argv(0) == "say") { - localcmd(sprintf("echo [SERVER] %s: %s\n", self.netname, argv(1))); SV_SendChat(self, argv(1), world, 0); return; } else if (argv(0) == "say_team") { - localcmd(sprintf("echo [TEAM %d] %s: %s\n", self.team, self.netname, argv(1))); - for (entity eFind = world; (eFind = find(eFind, classname, "player"));) { - if (eFind.team == self.team) { - SV_SendChat(self, argv(1), eFind, 1); + entity a; + for (a = world; (a = find(a, classname, "player"));) { + if (a.team == self.team) { + SV_SendChat(self, argv(1), a, 1); } } return; @@ -204,7 +307,8 @@ void Game_ParseClientCommand(string cmd) clientcommand(self, cmd); } -void Game_SetNewParms(void) +void +Game_SetNewParms(void) { } diff --git a/src/server/valve/player.c b/src/server/valve/player.c index 7b791daf..404f9e9d 100644 --- a/src/server/valve/player.c +++ b/src/server/valve/player.c @@ -120,36 +120,72 @@ float Player_SendEntity(entity ePEnt, float fChanged) } WriteByte(MSG_ENTITY, ENT_PLAYER); - WriteShort(MSG_ENTITY, pl.modelindex); - WriteCoord(MSG_ENTITY, pl.origin[0]); - WriteCoord(MSG_ENTITY, pl.origin[1]); - WriteCoord(MSG_ENTITY, pl.origin[2]); - WriteFloat(MSG_ENTITY, pl.v_angle[0]); - WriteFloat(MSG_ENTITY, pl.angles[1]); - WriteFloat(MSG_ENTITY, pl.angles[2]); - WriteCoord(MSG_ENTITY, pl.velocity[0]); - WriteCoord(MSG_ENTITY, pl.velocity[1]); - WriteCoord(MSG_ENTITY, pl.velocity[2]); - WriteFloat(MSG_ENTITY, pl.flags); - WriteByte(MSG_ENTITY, pl.activeweapon); - WriteFloat(MSG_ENTITY, pl.weapontime); - WriteFloat(MSG_ENTITY, pl.g_items); - WriteByte(MSG_ENTITY, pl.health); - WriteByte(MSG_ENTITY, pl.armor); - WriteByte(MSG_ENTITY, pl.movetype); - WriteFloat(MSG_ENTITY, pl.view_ofs[2]); - WriteFloat(MSG_ENTITY, pl.viewzoom); - WriteFloat(MSG_ENTITY, pl.jumptime); - WriteFloat(MSG_ENTITY, pl.teleport_time); + WriteFloat(MSG_ENTITY, fChanged); - WriteByte(MSG_ENTITY, pl.baseframe); - WriteByte(MSG_ENTITY, pl.frame); + /* really trying to get our moneys worth with 23 bits of mantissa */ + if (fChanged & PLAYER_MODELINDEX) { + WriteShort(MSG_ENTITY, pl.modelindex); + } + if (fChanged & PLAYER_ORIGIN) { + WriteCoord(MSG_ENTITY, pl.origin[0]); + WriteCoord(MSG_ENTITY, pl.origin[1]); + } + if (fChanged & PLAYER_ORIGIN_Z) { + WriteCoord(MSG_ENTITY, pl.origin[2]); + } + if (fChanged & PLAYER_ANGLES_X) { + WriteFloat(MSG_ENTITY, pl.v_angle[0]); + } + if (fChanged & PLAYER_ANGLES_Y) { + WriteFloat(MSG_ENTITY, pl.angles[1]); + } + if (fChanged & PLAYER_ANGLES_Z) { + WriteFloat(MSG_ENTITY, pl.angles[2]); + } + if (fChanged & PLAYER_VELOCITY) { + WriteCoord(MSG_ENTITY, pl.velocity[0]); + WriteCoord(MSG_ENTITY, pl.velocity[1]); + } + if (fChanged & PLAYER_VELOCITY_Z) { + WriteCoord(MSG_ENTITY, pl.velocity[2]); + } + if (fChanged & PLAYER_FLAGS) { + WriteFloat(MSG_ENTITY, pl.flags); + } + if (fChanged & PLAYER_WEAPON) { + WriteByte(MSG_ENTITY, pl.activeweapon); + } + if (fChanged & PLAYER_ITEMS) { + WriteFloat(MSG_ENTITY, pl.g_items); + } + if (fChanged & PLAYER_HEALTH) { + WriteByte(MSG_ENTITY, pl.health); + } + if (fChanged & PLAYER_ARMOR) { + WriteByte(MSG_ENTITY, pl.armor); + } + if (fChanged & PLAYER_MOVETYPE) { + WriteByte(MSG_ENTITY, pl.movetype); + } + if (fChanged & PLAYER_VIEWOFS) { + WriteFloat(MSG_ENTITY, pl.view_ofs[2]); + } + if (fChanged & PLAYER_BASEFRAME) { + WriteByte(MSG_ENTITY, pl.baseframe); + } + if (fChanged & PLAYER_FRAME) { + WriteByte(MSG_ENTITY, pl.frame); + } + if (fChanged & PLAYER_AMMO1) { + WriteByte(MSG_ENTITY, pl.a_ammo1); + } + if (fChanged & PLAYER_AMMO2) { + WriteByte(MSG_ENTITY, pl.a_ammo2); + } + if (fChanged & PLAYER_AMMO3) { + WriteByte(MSG_ENTITY, pl.a_ammo3); + } - WriteByte(MSG_ENTITY, pl.a_ammo1); - WriteByte(MSG_ENTITY, pl.a_ammo2); - WriteByte(MSG_ENTITY, pl.a_ammo3); - WriteFloat(MSG_ENTITY, pl.w_attack_next); - WriteFloat(MSG_ENTITY, pl.w_idle_next); return TRUE; } diff --git a/src/shared/entities.h b/src/shared/entities.h index 0be4527a..94a1abaa 100644 --- a/src/shared/entities.h +++ b/src/shared/entities.h @@ -25,3 +25,43 @@ enum { #endif ENT_DECAL }; + +/* entity update flags */ +enumflags { + NPC_MODELINDEX, + NPC_ORIGIN_X, + NPC_ORIGIN_Y, + NPC_ORIGIN_Z, + NPC_ANGLES_X, + NPC_ANGLES_Y, + NPC_ANGLES_Z, + NPC_VELOCITY_X, + NPC_VELOCITY_Y, + NPC_VELOCITY_Z, + NPC_FRAME, + NPC_SKIN, + NPC_BODY +}; + +enumflags { + PLAYER_MODELINDEX, + PLAYER_ORIGIN, + PLAYER_ORIGIN_Z, + PLAYER_ANGLES_X, + PLAYER_ANGLES_Y, + PLAYER_ANGLES_Z, + PLAYER_VELOCITY, + PLAYER_VELOCITY_Z, + PLAYER_FLAGS, + PLAYER_WEAPON, + PLAYER_ITEMS, + PLAYER_HEALTH, + PLAYER_ARMOR, + PLAYER_MOVETYPE, + PLAYER_VIEWOFS, + PLAYER_BASEFRAME, + PLAYER_FRAME, + PLAYER_AMMO1, + PLAYER_AMMO2, + PLAYER_AMMO3 +}; diff --git a/src/shared/scihunt/player.cpp b/src/shared/scihunt/player.cpp index 7529643b..b79a030e 100644 --- a/src/shared/scihunt/player.cpp +++ b/src/shared/scihunt/player.cpp @@ -91,5 +91,23 @@ class player int ammo_tripmine; int ammo_snark; int ammo_hornet; + + /* conditional networking */ + int old_modelindex; + vector old_origin; + vector old_angles; + vector old_velocity; + int old_flags; + int old_activeweapon; + int old_items; + int old_health; + int old_armor; + int old_movetype; + int old_viewofs; + int old_baseframe; + int old_frame; + int old_a_ammo1; + int old_a_ammo2; + int old_a_ammo3; #endif }; diff --git a/src/shared/valve/player.cpp b/src/shared/valve/player.cpp index 5d16c435..3263ff2c 100644 --- a/src/shared/valve/player.cpp +++ b/src/shared/valve/player.cpp @@ -89,6 +89,24 @@ class player int ammo_tripmine; int ammo_snark; int ammo_hornet; + + /* conditional networking */ + int old_modelindex; + vector old_origin; + vector old_angles; + vector old_velocity; + int old_flags; + int old_activeweapon; + int old_items; + int old_health; + int old_armor; + int old_movetype; + int old_viewofs; + int old_baseframe; + int old_frame; + int old_a_ammo1; + int old_a_ammo2; + int old_a_ammo3; #endif }; diff --git a/src/shared/valve/w_crowbar.c b/src/shared/valve/w_crowbar.c index eb92e893..6de4b927 100644 --- a/src/shared/valve/w_crowbar.c +++ b/src/shared/valve/w_crowbar.c @@ -16,18 +16,19 @@ enum { - CROWBAR_IDLE, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT + CBAR_IDLE, + CBAR_DRAW, + CBAR_HOLSTER, + CBAR_ATTACK1HIT, + CBAR_ATTACK1MISS, + CBAR_ATTACK2MISS, + CBAR_ATTACK2HIT, + CBAR_ATTACK3MISS, + CBAR_ATTACK3HIT }; -void w_crowbar_precache(void) +void +w_crowbar_precache(void) { precache_sound("weapons/cbar_miss1.wav"); precache_sound("weapons/cbar_hit1.wav"); @@ -40,162 +41,203 @@ void w_crowbar_precache(void) precache_model("models/p_crowbar.mdl"); } -void w_crowbar_updateammo(player pl) +void +w_crowbar_updateammo(player pl) { #ifdef SSQC Weapons_UpdateAmmo(pl, __NULL__, __NULL__, __NULL__); #endif } -string w_crowbar_wmodel(void) + +string +w_crowbar_wmodel(void) { return "models/w_crowbar.mdl"; } -string w_crowbar_pmodel(void) +string +w_crowbar_pmodel(void) { return "models/p_crowbar.mdl"; } -string w_crowbar_deathmsg(void) + +string +w_crowbar_deathmsg(void) { return "%s was assaulted by %s's Crowbar."; } -void w_crowbar_draw(void) +void +w_CBAR_DRAW(void) { Weapons_SetModel("models/v_crowbar.mdl"); - Weapons_ViewAnimation(CROWBAR_DRAW); + Weapons_ViewAnimation(CBAR_DRAW); } -void w_crowbar_holster(void) +void +w_CBAR_HOLSTER(void) { - Weapons_ViewAnimation(CROWBAR_HOLSTER); + Weapons_ViewAnimation(CBAR_HOLSTER); } -void w_crowbar_primary(void) + +void +w_crowbar_primary(void) { + int anim = 0; + vector src; player pl = (player)self; - + if (pl.w_attack_next) { return; } Weapons_MakeVectors(); - vector src = pl.origin + pl.view_ofs; - traceline(src, src + (v_forward * 32), FALSE, pl); + src = pl.origin + pl.view_ofs; + traceline(src, src + (v_forward * 32), FALSE, pl); - int r = (float)input_sequence%3; - switch (r) { - case 0: - Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK1MISS:CROWBAR_ATTACK1HIT); - break; - case 1: - Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK2MISS:CROWBAR_ATTACK2HIT); - break; - default: - Weapons_ViewAnimation(trace_fraction >= 1 ? CROWBAR_ATTACK3MISS:CROWBAR_ATTACK3HIT); - } - - if (trace_fraction >= 1.0) { - pl.w_attack_next = 0.5f; - } else { - pl.w_attack_next = 0.25f; - } - -#ifdef SSQC - if (pl.flags & FL_CROUCHING) - Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f); - else - Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f); - - Weapons_PlaySound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM); + int r = (float)input_sequence % 3; + switch (r) { + case 0: + anim = trace_fraction >= 1 ? CBAR_ATTACK1MISS:CBAR_ATTACK1HIT; + break; + case 1: + anim = trace_fraction >= 1 ? CBAR_ATTACK2MISS:CBAR_ATTACK2HIT; + break; + default: + anim = trace_fraction >= 1 ? CBAR_ATTACK3MISS:CBAR_ATTACK3HIT; + } + Weapons_ViewAnimation(anim); if (trace_fraction >= 1.0) { + pl.w_attack_next = 0.5f; + } else { + pl.w_attack_next = 0.25f; + } + + pl.w_idle_next = 2.5f; + +#ifdef SSQC + if (pl.flags & FL_CROUCHING) { + Animation_PlayerTopTemp(ANIM_SHOOTCROWBAR, 0.5f); + } else { + Animation_PlayerTopTemp(ANIM_CR_SHOOTCROWBAR, 0.42f); + } + + sound(pl, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM); + + if (trace_fraction >= 1.0) { + return; + } + + /* don't bother with decals, we got squibs */ + if (trace_ent.iBleeds) { + Effect_CreateBlood(trace_endpos, [0,0,0]); } else { Effect_Impact(IMPACT_MELEE, trace_endpos, trace_plane_normal); - - if (trace_ent.takedamage) { - Damage_Apply(trace_ent, self, 10, trace_endpos, FALSE ); - - // TODO: Better way to find if it bleeds? - if (trace_ent.iBleeds == 1) { - if (random() < 0.33) { - Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); - } else if (random() < 0.66) { - Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); - } else { - Weapons_PlaySound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); - } - } + } + + if (trace_ent.takedamage) { + Damage_Apply(trace_ent, self, 10, trace_endpos, FALSE ); + + if (!trace_ent.iBleeds) { + return; + } + + if (random() < 0.33) { + sound(pl, 8, "weapons/cbar_hitbod1.wav", 1, ATTN_NORM); + } else if (random() < 0.66) { + sound(pl, 8, "weapons/cbar_hitbod2.wav", 1, ATTN_NORM); } else { - if (random() < 0.5) { - Weapons_PlaySound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM); - } else { - Weapons_PlaySound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM); - } + sound(pl, 8, "weapons/cbar_hitbod3.wav", 1, ATTN_NORM); + } + } else { + if (random() < 0.5) { + sound(pl, 8, "weapons/cbar_hit1.wav", 1, ATTN_NORM); + } else { + sound(pl, 8, "weapons/cbar_hit2.wav", 1, ATTN_NORM); } } #endif - pl.w_idle_next = 2.5f; } -void w_crowbar_secondary(void) -{ - -} -void w_crowbar_reload(void) -{ - -} -void w_crowbar_release(void) + +void +w_crowbar_release(void) { player pl = (player)self; + if (pl.w_idle_next) { return; } - Weapons_ViewAnimation(CROWBAR_IDLE); + Weapons_ViewAnimation(CBAR_IDLE); pl.w_idle_next = 15.0f; } -float w_crowbar_aimanim(void) +float +w_crowbar_aimanim(void) { return self.flags & FL_CROUCHING ? ANIM_CR_AIMCROWBAR : ANIM_AIMCROWBAR; } -void w_crowbar_hudpic(int s, vector pos) + +void +w_crowbar_hudpic(int selected, vector pos) { #ifdef CSQC - if (s) { - drawsubpic(pos, [170,45], "sprites/640hud4.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE); + if (selected) { + drawsubpic( + pos, + [170,45], + "sprites/640hud4.spr_0.tga", + [0,0], + [170/256,45/256], + g_hud_color, + 1.0f, + DRAWFLAG_ADDITIVE + ); } else { - drawsubpic(pos, [170,45], "sprites/640hud1.spr_0.tga", [0,0], [170/256,45/256], g_hud_color, 1, DRAWFLAG_ADDITIVE); + drawsubpic( + pos, + [170,45], + "sprites/640hud1.spr_0.tga", + [0,0], + [170/256,45/256], + g_hud_color, + 1.0f, + DRAWFLAG_ADDITIVE + ); } #endif } weapon_t w_crowbar = { - ITEM_CROWBAR, - 0, - 0, - "sprites/640hud1.spr_0.tga", - [48,16], - [192,0], - w_crowbar_draw, - w_crowbar_holster, - w_crowbar_primary, - w_crowbar_secondary, - w_crowbar_reload, - w_crowbar_release, - __NULL__, - w_crowbar_precache, - __NULL__, - w_crowbar_updateammo, - w_crowbar_wmodel, - w_crowbar_pmodel, - w_crowbar_deathmsg, - w_crowbar_aimanim, - w_crowbar_hudpic + .id = ITEM_CROWBAR, + .slot = 0, + .slot_pos = 0, + .ki_spr = "sprites/640hud1.spr_0.tga", + .ki_size = [48,16], + .ki_xy = [192,0], + .draw = w_CBAR_DRAW, + .holster = w_CBAR_HOLSTER, + .primary = w_crowbar_primary, + .secondary = __NULL__, + .reload = __NULL__, + .release = w_crowbar_release, + .crosshair = __NULL__, + .precache = w_crowbar_precache, + .pickup = __NULL__, + .updateammo = w_crowbar_updateammo, + .wmodel = w_crowbar_wmodel, + .pmodel = w_crowbar_pmodel, + .deathmsg = w_crowbar_deathmsg, + .aimanim = w_crowbar_aimanim, + .hudpic = w_crowbar_hudpic }; +/* entity definitions for pickups */ #ifdef SSQC -void weapon_crowbar(void) { +void +weapon_crowbar(void) +{ Weapons_InitItem(WEAPON_CROWBAR); } #endif