/* * Copyright (c) 2016-2021 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. */ #ifdef CLIENT /* Here's a list of bone names that we are aware of on HL player models. Usually we'd use skeletalobjects to share the same skeleton/anim with another model - but because FTEQW does not support that for HLMDL we are forced to manually position the bones of our attachnment by iterating over them and manually setting their position in 3D-space. */ string g_pbones[] = { "Bip01", "Bip01 Footsteps", "Bip01 Pelvis", "Bip01 L Leg", "Bip01 L Leg1", "Bip01 L Foot", "Bip01 L Toe0", "Bip01 L Toe01", "Bip01 L Toe02", "Dummy16", "Bip01 R Leg", "Bip01 R Leg1", "Bip01 R Foot", "Bip01 R Toe0", "Bip01 R Toe01", "Bip01 R Toe02", "Dummy11", "Bip01 Spine", "Bip01 Spine1", "Bip01 Spine2", "Bip01 Spine3", "Bip01 Neck", "Bip01 Head", "Dummy21", "Dummy08", "Bone02", "Bone03", "Bone04", "Dummy05", "Bone09", "Bone10", "Dummy04", "Bone05", "Bone06", "Dummy03", "Bone07", "Bone08", "Dummy09", "Bone11", "Bone12", "Dummy10", "Bone13", "Bone14", "Bone15", "Bip01 L Arm", "Bip01 L Arm1", "Bip01 L Arm2", "Bip01 L Hand", "Bip01 L Finger0", "Bip01 L Finger01", "Bip01 L Finger02", "Dummy06", "Bip01 L Finger1", "Bip01 L Finger11", "Bip01 L Finger12", "Dummy07", "Bip01 R Arm", "Bip01 R Arm1", "Bip01 R Arm2", "Bip01 R Hand", "Bip01 R Finger0", "Bip01 R Finger01", "Bip01 R Finger02", "Dummy01", "Bip01 R Finger1", "Bip01 R Finger11", "Bip01 R Finger12", "Dummy02", "Box02", "Bone08", "Bone15" }; #endif /* all potential SendFlags bits we can possibly send */ enumflags { PLAYER_TOPFRAME = PLAYER_CUSTOMFIELDSTART, PLAYER_BOTTOMFRAME, PLAYER_AMMO1, PLAYER_AMMO2, PLAYER_AMMO3, PLAYER_UNUSED5, PLAYER_UNUSED6, PLAYER_UNUSED7 }; class player:NSClientPlayer { /* class info */ PREDICTED_INT(classtype) /* animation */ PREDICTED_INT(anim_top) PREDICTED_FLOAT(anim_top_time) PREDICTED_FLOAT(anim_top_delay) PREDICTED_INT(anim_bottom) PREDICTED_FLOAT(anim_bottom_time) /* ammo 1 */ PREDICTED_INT(mag_sbs) PREDICTED_INT(mag_dbs) PREDICTED_INT(mag_rpg) PREDICTED_INT(mag_glauncher) /* ammo 2 */ PREDICTED_INT(m_iAmmoRockets) PREDICTED_INT(m_iAmmoNails) PREDICTED_INT(m_iAmmoCells) PREDICTED_INT(m_iAmmoShells) PREDICTED_INT(m_iAmmoDetpack) PREDICTED_INT(m_iAmmoMedikit) /* ammo 3 */ PREDICTED_INT(mode_tempstate) virtual void Physics_Jump(void); virtual float Physics_MaxSpeed(void); virtual void ProcessInput(void); nonvirtual void TFC_CookGren1(void); nonvirtual void TFC_CookGren2(void); nonvirtual void TFC_ReleaseGren1(void); nonvirtual void TFC_ReleaseGren2(void); virtual void UpdatePlayerAnimation(float); #ifdef CLIENT virtual void ReceiveEntity(float,float); virtual void PredictPreFrame(void); virtual void PredictPostFrame(void); virtual void UpdateAliveCam(void); virtual void UpdatePlayerAttachments(bool); #else NSTimer gren1; NSTimer gren2; int m_iMaxHealth; int m_iMaxArmor; int m_iMaxShells; int m_iMaxNails; int m_iMaxRockets; int m_iMaxCells; int m_iMaxDetpack; int m_iMaxMedikit; virtual void EvaluateEntity(void); virtual float SendEntity(entity, float); virtual void SpawnIntoGame(void); virtual void MakeClass(classtype_e); virtual void ServerInputFrame(void); nonvirtual void TFC_FragSelf(void); nonvirtual void TFC_FragSelf(void); #endif }; void Animation_PlayerUpdate(player); void Animation_TimerUpdate(player, float); void player::UpdatePlayerAnimation(float timelength) { /* calculate our skeletal progression */ Animation_PlayerUpdate(this); /* advance animation timers */ Animation_TimerUpdate(this, timelength); } #ifdef SERVER void TFCNade_ThrowCaltrop(player); void TFCNade_ThrowHandGrenade(player); void TFCNade_ThrowSecondary(player); void TFCNade_SelfExplode(player); void player::TFC_FragSelf(void) { print("Primary exploded in your hand!\n"); TFCNade_SelfExplode(this); } void player::TFC_ThrowSecondary(void) { print("Secondary exploded in your hand!\n"); TFCNade_ThrowSecondary(this); } #endif void player::TFC_CookGren1(void) { /* we're already cooking it */ if (gflags & GF_GREN1COOK) return; if (classtype == CLASS_SCOUT) { /* caltrop sound */ #ifdef SERVER StartSound("weapons/tink1.wav", CHAN_AUTO, 0, true); #endif } else { /* grenade timer sound */ #ifdef SERVER StartSound("weapons/timer.wav", CHAN_AUTO, 0, true); gren1 = gren1.SetupTimer(this, TFC_FragSelf, 3.75f, false); gren1.RunTimer(); #endif } gflags |= GF_GREN1COOK; } void player::TFC_ReleaseGren1(void) { if (!(gflags & GF_GREN1COOK)) return; if (classtype == CLASS_SCOUT) { /* release caltrop */ #ifdef SERVER TFCNade_ThrowCaltrop(this); #endif } else { /* release the nade! */ #ifdef SERVER TFCNade_ThrowHandGrenade(this); gren1.StopTimer(); #endif } gflags &= ~GF_GREN1COOK; } void player::TFC_CookGren2(void) { if (gflags & GF_GREN2COOK) return; if (classtype == CLASS_SNIPER) return; #ifdef SERVER StartSound("weapons/timer.wav", CHAN_AUTO, 0, true); gren2 = gren2.SetupTimer(this, TFC_ThrowSecondary, 3.75f, false); gren2.RunTimer(); #endif gflags |= GF_GREN2COOK; } void player::TFC_ReleaseGren2(void) { if (!(gflags & GF_GREN2COOK)) return; #ifdef SERVER TFCNade_ThrowSecondary(this); gren2.StopTimer(); #endif gflags &= ~GF_GREN2COOK; } void player::ProcessInput(void) { super::ProcessInput(); if (input_buttons & INPUT_BUTTON6) TFC_CookGren1(); else TFC_ReleaseGren1(); if (input_buttons & INPUT_BUTTON7) TFC_CookGren2(); else TFC_ReleaseGren2(); } #ifdef CLIENT .string oldmodel; string Weapons_GetPlayermodel(player, int); void player::UpdatePlayerAttachments(bool visible) { /* draw the flashlight */ if (gflags & GF_FLASHLIGHT) { vector src; vector ang; if (entnum != player_localentnum) { src = origin + view_ofs; ang = v_angle; } else { src = pSeat->m_vecPredictedOrigin + [0,0,-8]; ang = view_angles; } makevectors(ang); traceline(src, src + (v_forward * 8096), MOVE_NORMAL, this); if (serverkeyfloat("*bspversion") == BSPVER_HL) { dynamiclight_add(trace_endpos + (v_forward * -2), 128, [1,1,1]); } else { float p = dynamiclight_add(src, 512, [1,1,1], 0, "textures/flashlight"); dynamiclight_set(p, LFIELD_ANGLES, ang); dynamiclight_set(p, LFIELD_FLAGS, 3); } } /* FIXME: this needs to be incorporated and simplified, now that we can handle it all in-class */ if (!visible) return; /* what's the current weapon model supposed to be anyway? */ p_model.oldmodel = Weapons_GetPlayermodel(this, activeweapon); /* we changed weapons, update skeletonindex */ if (p_model.model != p_model.oldmodel) { /* free memory */ if (p_model.skeletonindex) skel_delete(p_model.skeletonindex); /* set the new model and mark us updated */ setmodel(p_model, p_model.oldmodel); p_model.model = p_model.oldmodel; /* set the new skeletonindex */ p_model.skeletonindex = skel_create(p_model.modelindex); /* hack this thing in here FIXME: this should be done when popping in/out of a pvs */ if (autocvar(cl_himodels, 1, "Use high-quality thisayer models over lower-definition ones")) setcustomskin(this, "", "geomset 0 2\n"); else setcustomskin(this, "", "geomset 0 1\n"); } /* follow thisayer at all times */ setorigin(p_model, origin); p_model.angles = angles; skel_build(p_model.skeletonindex, p_model, p_model.modelindex,0, 0, -1); /* we have to loop through all valid bones of the weapon model and match them * to the thisayer one */ for (float i = 0; i < g_pbones.length; i++) { vector bpos; float pbone = gettagindex(this, g_pbones[i]); float wbone = gettagindex(p_model, g_pbones[i]); /* if the bone doesn't ignore in either skeletal mesh, ignore */ if (wbone <= 0 || pbone <= 0) continue; bpos = gettaginfo(this, pbone); /* the most expensive bit */ skel_set_bone_world(p_model, wbone, bpos, v_forward, v_right, v_up); } } void Weapons_AmmoUpdate(entity); void HUD_AmmoNotify_Check(player pl); void HUD_ItemNotify_Check(player pl); void Camera_RunPosBob(vector angles, __inout vector camera_pos); void Camera_StrafeRoll(__inout vector camera_angle); void Shake_Update(NSClientPlayer); void player::UpdateAliveCam(void) { vector cam_pos = GetEyePos(); Camera_RunPosBob(view_angles, cam_pos); g_view.SetCameraOrigin(cam_pos); Camera_StrafeRoll(view_angles); g_view.SetCameraAngle(view_angles); if (vehicle) { NSVehicle veh = (NSVehicle)vehicle; if (veh.UpdateView) veh.UpdateView(); } else if (health) { if (autocvar_pm_thirdPerson == TRUE) { makevectors(view_angles); vector vStart = [pSeat->m_vecPredictedOrigin[0], pSeat->m_vecPredictedOrigin[1], pSeat->m_vecPredictedOrigin[2] + 16] + (v_right * 4); vector vEnd = vStart + (v_forward * -48) + [0,0,16] + (v_right * 4); traceline(vStart, vEnd, FALSE, this); g_view.SetCameraOrigin(trace_endpos + (v_forward * 5)); } } Shake_Update(this); g_view.AddPunchAngle(punchangle); } /* ================= player::ReceiveEntity ================= */ void player::ReceiveEntity(float new, float fl) { /* the generic client attributes */ NSClientPlayer::ReceiveEntity(new, fl); /* animation */ if (fl & PLAYER_TOPFRAME) { anim_top = readbyte(); anim_top_time = readfloat(); anim_top_delay = readfloat(); } if (fl & PLAYER_BOTTOMFRAME) { anim_bottom = readbyte(); anim_bottom_time = readfloat(); } if (fl & PLAYER_AMMO1) { mag_sbs = readbyte(); mag_dbs = readbyte(); mag_rpg = readbyte(); mag_glauncher = readbyte(); } if (fl & PLAYER_AMMO2) { m_iAmmoRockets = readbyte(); m_iAmmoNails = readbyte(); m_iAmmoCells = readbyte(); m_iAmmoShells = readbyte(); m_iAmmoDetpack = readbyte(); m_iAmmoMedikit = readbyte(); } if (fl & PLAYER_AMMO3) { mode_tempstate = readbyte(); classtype = readbyte(); } setorigin(this, origin); /* these only concern the current player */ CSQC_UpdateSeat(); if (this != pSeat->m_ePlayer) return; /* do not notify us of updates when spawning initially */ if (fl == UPDATE_ALL) PredictPreFrame(); if (fl & PLAYER_AMMO1 || fl & PLAYER_AMMO2 || fl & PLAYER_AMMO3) { Weapons_AmmoUpdate(this); HUD_AmmoNotify_Check(this); } if (fl & PLAYER_ITEMS || fl & PLAYER_HEALTH) HUD_ItemNotify_Check(this); } /* ================= player::PredictPostFrame Save the last valid server values away in the _net variants of each field so we can roll them back later. ================= */ void player::PredictPreFrame(void) { /* the generic client attributes */ NSClientPlayer::PredictPreFrame(); SAVE_STATE(anim_top); SAVE_STATE(anim_top_delay); SAVE_STATE(anim_top_time); SAVE_STATE(anim_bottom); SAVE_STATE(anim_bottom_time); SAVE_STATE(mag_sbs); SAVE_STATE(mag_dbs); SAVE_STATE(mag_rpg); SAVE_STATE(mag_glauncher); SAVE_STATE(m_iAmmoRockets); SAVE_STATE(m_iAmmoNails); SAVE_STATE(m_iAmmoCells); SAVE_STATE(m_iAmmoShells); SAVE_STATE(m_iAmmoDetpack); SAVE_STATE(m_iAmmoMedikit); SAVE_STATE(mode_tempstate); SAVE_STATE(classtype); } /* ================= player::PredictPostFrame Where we roll back our values to the ones last sent/verified by the server. ================= */ void player::PredictPostFrame(void) { /* the generic client attributes */ NSClientPlayer::PredictPostFrame(); ROLL_BACK(anim_top); ROLL_BACK(anim_top_delay); ROLL_BACK(anim_top_time); ROLL_BACK(anim_bottom); ROLL_BACK(anim_bottom_time); ROLL_BACK(mag_sbs); ROLL_BACK(mag_dbs); ROLL_BACK(mag_rpg); ROLL_BACK(mag_glauncher); ROLL_BACK(m_iAmmoRockets); ROLL_BACK(m_iAmmoNails); ROLL_BACK(m_iAmmoCells); ROLL_BACK(m_iAmmoShells); ROLL_BACK(m_iAmmoDetpack); ROLL_BACK(m_iAmmoMedikit); ROLL_BACK(mode_tempstate); ROLL_BACK(classtype); } #else void player::ServerInputFrame(void) { super::ServerInputFrame(); gflags &= ~GF_NOBUILDZONE; gflags &= ~GF_NOGRENADEZONE; } void player::EvaluateEntity(void) { /* the generic client attributes */ NSClientPlayer::EvaluateEntity(); /* animation */ if (ATTR_CHANGED(anim_bottom) || ATTR_CHANGED(anim_bottom_time)) SendFlags |= PLAYER_BOTTOMFRAME; if (ATTR_CHANGED(anim_top) || ATTR_CHANGED(anim_top_time) || ATTR_CHANGED(anim_top_delay)) SendFlags |= PLAYER_TOPFRAME; /* ammo 1 type updates */ if (ATTR_CHANGED(mag_sbs)) SendFlags |= PLAYER_AMMO1; else if (ATTR_CHANGED(mag_dbs)) SendFlags |= PLAYER_AMMO1; else if (ATTR_CHANGED(mag_rpg)) SendFlags |= PLAYER_AMMO1; else if (ATTR_CHANGED(mag_glauncher)) SendFlags |= PLAYER_AMMO1; /* ammo 2 type updates */ if (ATTR_CHANGED(m_iAmmoRockets)) SendFlags |= PLAYER_AMMO2; else if (ATTR_CHANGED(m_iAmmoNails)) SendFlags |= PLAYER_AMMO2; else if (ATTR_CHANGED(m_iAmmoCells)) SendFlags |= PLAYER_AMMO2; else if (ATTR_CHANGED(m_iAmmoShells)) SendFlags |= PLAYER_AMMO2; else if (ATTR_CHANGED(m_iAmmoDetpack)) SendFlags |= PLAYER_AMMO2; else if (ATTR_CHANGED(m_iAmmoMedikit)) SendFlags |= PLAYER_AMMO2; 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); SAVE_STATE(mag_glauncher); SAVE_STATE(m_iAmmoRockets); SAVE_STATE(m_iAmmoNails); SAVE_STATE(m_iAmmoCells); SAVE_STATE(m_iAmmoShells); SAVE_STATE(m_iAmmoDetpack); SAVE_STATE(m_iAmmoMedikit); SAVE_STATE(mode_tempstate); SAVE_STATE(classtype); SAVE_STATE(anim_top); SAVE_STATE(anim_top_delay); SAVE_STATE(anim_top_time); SAVE_STATE(anim_bottom); SAVE_STATE(anim_bottom_time); } 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 = 300; 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; } /* ================= player::SendEntity ================= */ float player::SendEntity(entity ePEnt, float flChanged) { /* don't broadcast invisible players */ if (IsFakeSpectator() && ePEnt != this) return (0); if (!GetModelindex() && ePEnt != this) return (0); flChanged = OptimiseChangedFlags(ePEnt, flChanged); WriteByte(MSG_ENTITY, ENT_PLAYER); WriteFloat(MSG_ENTITY, flChanged); /* the generic client attributes */ NSClientPlayer::SendEntity(ePEnt, flChanged); if (flChanged & PLAYER_TOPFRAME) { WriteByte(MSG_ENTITY, anim_top); WriteFloat(MSG_ENTITY, anim_top_time); WriteFloat(MSG_ENTITY, anim_top_delay); } if (flChanged & PLAYER_BOTTOMFRAME) { WriteByte(MSG_ENTITY, anim_bottom); WriteFloat(MSG_ENTITY, anim_bottom_time); } if (flChanged & PLAYER_AMMO1) { WriteByte(MSG_ENTITY, mag_sbs); WriteByte(MSG_ENTITY, mag_dbs); WriteByte(MSG_ENTITY, mag_rpg); WriteByte(MSG_ENTITY, mag_glauncher); } if (flChanged & PLAYER_AMMO2) { WriteByte(MSG_ENTITY, m_iAmmoRockets); WriteByte(MSG_ENTITY, m_iAmmoNails); WriteByte(MSG_ENTITY, m_iAmmoCells); WriteByte(MSG_ENTITY, m_iAmmoShells); WriteByte(MSG_ENTITY, m_iAmmoDetpack); WriteByte(MSG_ENTITY, m_iAmmoMedikit); } if (flChanged & PLAYER_AMMO3) { WriteByte(MSG_ENTITY, mode_tempstate); WriteByte(MSG_ENTITY, classtype); } return (1); } #endif