diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp index 9ce1be12..ffe37c74 100644 --- a/cl_dll/ammo.cpp +++ b/cl_dll/ammo.cpp @@ -35,6 +35,8 @@ WEAPON* gpLastSel; // Last weapon menu selection client_sprite_t* GetSpriteList(client_sprite_t* pList, const char* psz, int iRes, int iCount); +void HUD_WeaponList(const int iId, const int iAmmoType, const int iAmmoType2); + WeaponsResource gWR; int g_weaponselect = 0; @@ -492,6 +494,11 @@ bool CHudAmmo::MsgFunc_AmmoX(const char* pszName, int iSize, void* pbuf) int iIndex = READ_BYTE(); int iCount = READ_BYTE(); + return Update_AmmoX(iIndex, iCount); +} + +bool CHudAmmo::Update_AmmoX(const int iIndex, const int iCount) +{ gWR.SetAmmo(iIndex, abs(iCount)); return true; @@ -563,15 +570,20 @@ bool CHudAmmo::MsgFunc_HideWeapon(const char* pszName, int iSize, void* pbuf) // bool CHudAmmo::MsgFunc_CurWeapon(const char* pszName, int iSize, void* pbuf) { - static Rect nullrc; - bool fOnTarget = false; - BEGIN_READ(pbuf, iSize); int iState = READ_BYTE(); int iId = READ_CHAR(); int iClip = READ_CHAR(); + return Update_CurWeapon(iState, iId, iClip); +} + +bool CHudAmmo::Update_CurWeapon(const int iState, const int iId, const int iClip) +{ + static Rect nullrc; + bool fOnTarget = false; + // detect if we're also on target if (iState > 1) { @@ -685,6 +697,9 @@ bool CHudAmmo::MsgFunc_WeaponList(const char* pszName, int iSize, void* pbuf) gWR.AddWeapon(&Weapon); + // Tell the predicted weapons which ammo types to use + HUD_WeaponList(Weapon.iId, Weapon.iAmmoType, Weapon.iAmmo2Type); + return true; } diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index 55727b31..1199ae3f 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -99,15 +99,20 @@ bool CHudHealth::MsgFunc_Health(const char* pszName, int iSize, void* pbuf) { // TODO: update local health data BEGIN_READ(pbuf, iSize); - int x = READ_SHORT(); + int iHealth = READ_SHORT(); + return Update_Health(iHealth); +} + +bool CHudHealth::Update_Health(const int iHealth) +{ m_iFlags |= HUD_ACTIVE; // Only update the fade if we've changed health - if (x != m_iHealth) + if (iHealth != m_iHealth) { m_fFade = FADE_TIME; - m_iHealth = x; + m_iHealth = iHealth; } return true; diff --git a/cl_dll/health.h b/cl_dll/health.h index 71dcc1d7..7761767d 100644 --- a/cl_dll/health.h +++ b/cl_dll/health.h @@ -52,6 +52,7 @@ class CHudHealth : public CHudBase void Reset() override; bool MsgFunc_Health(const char* pszName, int iSize, void* pbuf); bool MsgFunc_Damage(const char* pszName, int iSize, void* pbuf); + bool Update_Health(const int iHealth); int m_iHealth; int m_HUD_dmg_bio; int m_HUD_cross; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index d0d36e4e..043a7719 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -271,8 +271,6 @@ void CBasePlayer::ItemPreFrame() {} void CBasePlayer::ItemPostFrame() {} int CBasePlayer::AmmoInventory(int iAmmoIndex) { return -1; } int CBasePlayer::GetAmmoIndex(const char* psz) { return -1; } -void CBasePlayer::SendAmmoUpdate() {} -void CBasePlayer::UpdateClientData() {} bool CBasePlayer::FBecomeProne() { return true; } void CBasePlayer::BarnacleVictimBitten(entvars_t* pevBarnacle) {} void CBasePlayer::BarnacleVictimReleased() {} @@ -321,7 +319,6 @@ void CBasePlayerItem::Holster() {} void CBasePlayerItem::AttachToPlayer(CBasePlayer* pPlayer) {} bool CBasePlayerWeapon::AddDuplicate(CBasePlayerItem* pOriginal) { return false; } void CBasePlayerWeapon::AddToPlayer(CBasePlayer* pPlayer) {} -bool CBasePlayerWeapon::UpdateClientData(CBasePlayer* pPlayer) { return false; } bool CBasePlayerWeapon::IsUseable() { return true; } int CBasePlayerWeapon::PrimaryAmmoIndex() { return m_iPrimaryAmmoType; } int CBasePlayerWeapon::SecondaryAmmoIndex() { return m_iSecondaryAmmoType; } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 84dfea46..e254334d 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -30,6 +30,10 @@ #include "../com_weapons.h" #include "../demo.h" +#include "hud.h" + +#include + extern int g_iUser1; // Pool of client side entities/entvars_t @@ -65,6 +69,8 @@ CSatchel g_Satchel; CTripmine g_Tripmine; CSqueak g_Snark; +void HUD_InitClientWeapons(); + /* ====================== @@ -116,13 +122,15 @@ void HUD_PrepEntity(CBaseEntity* pEntity, CBasePlayer* pWeaponOwner) if (pWeaponOwner) { + CBasePlayerWeapon* const pWeapon = (CBasePlayerWeapon*)pEntity; + ItemInfo info; memset(&info, 0, sizeof(info)); - ((CBasePlayerWeapon*)pEntity)->m_pPlayer = pWeaponOwner; + pWeapon->m_pPlayer = pWeaponOwner; - ((CBasePlayerWeapon*)pEntity)->GetItemInfo(&info); + pWeapon->GetItemInfo(&info); CBasePlayerItem::ItemInfoArray[info.iId] = info; @@ -138,10 +146,30 @@ void HUD_PrepEntity(CBaseEntity* pEntity, CBasePlayer* pWeaponOwner) AddAmmoNameToAmmoRegistry(info.pszAmmo2, weaponName); } - g_pWpns[info.iId] = (CBasePlayerWeapon*)pEntity; + // Add to the list before extracting ammo so weapon ownership checks work properly. + pWeapon->m_pNext = pWeaponOwner->m_rgpPlayerItems[info.iSlot]; + pWeaponOwner->m_rgpPlayerItems[info.iSlot] = pWeapon; + + g_pWpns[info.iId] = pWeapon; } } +void HUD_WeaponList(const int iId, const int iAmmoType, const int iAmmoType2) +{ + // This may be called prior to the first weapon prediction frame + HUD_InitClientWeapons(); + + const auto pWeapon = g_pWpns[iId]; + + if (pWeapon == nullptr) + { + return; + } + + pWeapon->m_iPrimaryAmmoType = iAmmoType; + pWeapon->m_iSecondaryAmmoType = iAmmoType2; +} + /* ===================== CBaseEntity:: Killed @@ -220,6 +248,57 @@ void CBasePlayerWeapon::SendWeaponAnim(int iAnim, int body) HUD_SendWeaponAnim(iAnim, body, false); } +bool CBasePlayerWeapon::UpdateClientData(CBasePlayer* pPlayer) +{ + bool bSend = false; + int state = 0; + if (pPlayer->m_pActiveItem == this) + { + if (pPlayer->m_fOnTarget) + state = WEAPON_IS_ONTARGET; + else + state = 1; + } + + // Forcing send of all data! + if (!pPlayer->m_fWeapon) + { + bSend = true; + } + + // This is the current or last weapon, so the state will need to be updated + if (this == pPlayer->m_pActiveItem || + this == pPlayer->m_pClientActiveItem) + { + if (pPlayer->m_pActiveItem != pPlayer->m_pClientActiveItem) + { + bSend = true; + } + } + + // If the ammo, state, or fov has changed, update the weapon + if (m_iClip != m_iClientClip || + state != m_iClientWeaponState || + pPlayer->m_iFOV != pPlayer->m_iClientFOV) + { + bSend = true; + } + + if (bSend) + { + gHUD.m_Ammo.Update_CurWeapon(state, m_iId, m_iClip); + + m_iClientClip = m_iClip; + m_iClientWeaponState = state; + pPlayer->m_fWeapon = true; + } + + if (m_pNext) + m_pNext->UpdateClientData(pPlayer); + + return true; +} + /* ===================== CBaseEntity::FireBulletsPlayer @@ -312,12 +391,108 @@ CBasePlayer::Spawn */ void CBasePlayer::Spawn() { + m_iClientFOV = -1; // make sure fov reset is sent + + m_iClientHealth = -1; + m_iClientBattery = -1; + m_pClientActiveItem = nullptr; + m_fWeapon = false; + + // reset all ammo values to 0 + for (int i = 0; i < MAX_AMMO_SLOTS; i++) + { + m_rgAmmoLast[i] = -1; // client ammo values also have to be reset + } + + for (int i = 0; i < MAX_WEAPONS; i++) + { + const auto pWeapon = g_pWpns[i]; + + if (pWeapon != nullptr) + { + pWeapon->m_iClientClip = 0; + pWeapon->m_iClientWeaponState = 0; + } + } + if (m_pActiveItem) m_pActiveItem->Deploy(); g_irunninggausspred = false; } +void CBasePlayer::SendAmmoUpdate() +{ + for (int i = 0; i < MAX_AMMO_SLOTS; i++) + { + InternalSendSingleAmmoUpdate(i); + } +} + +void CBasePlayer::SendSingleAmmoUpdate(int ammoIndex) +{ + if (ammoIndex < 0 || ammoIndex >= MAX_AMMO_SLOTS) + { + return; + } + + InternalSendSingleAmmoUpdate(ammoIndex); +} + +void CBasePlayer::InternalSendSingleAmmoUpdate(int ammoIndex) +{ + if (m_rgAmmo[ammoIndex] != m_rgAmmoLast[ammoIndex]) + { + m_rgAmmoLast[ammoIndex] = m_rgAmmo[ammoIndex]; + + // send "Ammo" update message + gHUD.m_Ammo.Update_AmmoX(ammoIndex, m_rgAmmo[ammoIndex]); + } +} + +void CBasePlayer::UpdateClientData() +{ + if (m_iFOV != m_iClientFOV) + { + gHUD.Update_SetFOV(m_iFOV); + + // cache FOV change at end of function, so weapon updates can see that FOV has changed + } + + if (pev->health != m_iClientHealth) + { + int iHealth = std::clamp(pev->health, 0.f, (float)(std::numeric_limits::max())); // make sure that no negative health values are sent + if (pev->health > 0.0f && pev->health <= 1.0f) + iHealth = 1; + + // send "health" update message + gHUD.m_Health.Update_Health(iHealth); + + m_iClientHealth = pev->health; + } + + SendAmmoUpdate(); + + // Update all the items + for (int i = 0; i < MAX_ITEM_TYPES; i++) + { + if (m_rgpPlayerItems[i]) // each item updates it's successors + m_rgpPlayerItems[i]->UpdateClientData(this); + } + + //Active item is becoming null, or we're sending all HUD state to client + //Only if we're not in Observer mode, which uses the target player's weapon + if (!m_pActiveItem && m_pClientActiveItem != m_pActiveItem) + { + //Tell ammo hud that we have no weapon selected + gHUD.m_Ammo.Update_CurWeapon(0, 0, 0); + } + + // Cache and client weapon change + m_pClientActiveItem = m_pActiveItem; + m_iClientFOV = m_iFOV; +} + /* ===================== UTIL_TraceLine @@ -609,10 +784,6 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd lasthealth = to->client.health; } - // We are not predicting the current weapon, just bow out here. - if (!pWeapon) - return; - for (i = 0; i < MAX_WEAPONS; i++) { pCurrent = g_pWpns[i]; @@ -637,14 +808,15 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd pCurrent->m_fInAttack = pfrom->iuser2; pCurrent->m_fireState = pfrom->iuser3; - pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2]; - pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0]; - player.m_rgAmmo[pCurrent->m_iPrimaryAmmoType] = (int)from->client.vuser4[1]; - player.m_rgAmmo[pCurrent->m_iSecondaryAmmoType] = (int)from->client.vuser4[2]; - pCurrent->SetWeaponData(*pfrom); } + // Stores all our ammo info, so the client side weapons can use them. + for (i = 0; i < MAX_AMMO_SLOTS; i++) + { + player.m_rgAmmo[i] = from->weapondata[i].iuser4; + } + // For random weapon events, use this seed to seed random # generator player.random_seed = random_seed; @@ -668,6 +840,7 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd player.pev->velocity = from->client.velocity; player.pev->flags = from->client.flags; + player.pev->health = from->client.health; player.pev->deadflag = from->client.deadflag; player.pev->waterlevel = from->client.waterlevel; player.pev->maxspeed = from->client.maxspeed; @@ -678,37 +851,33 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd player.m_flNextAmmoBurn = from->client.fuser2; player.m_flAmmoStartCharge = from->client.fuser3; - //Stores all our ammo info, so the client side weapons can use them. - player.ammo_9mm = (int)from->client.vuser1[0]; - player.ammo_357 = (int)from->client.vuser1[1]; - player.ammo_argrens = (int)from->client.vuser1[2]; - player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... - player.ammo_buckshot = (int)from->client.ammo_shells; - player.ammo_uranium = (int)from->client.ammo_cells; - player.ammo_hornets = (int)from->client.vuser2[0]; - player.ammo_rockets = (int)from->client.ammo_rockets; - - // Point to current weapon object if (WEAPON_NONE != from->client.m_iId) { player.m_pActiveItem = g_pWpns[from->client.m_iId]; } - - if (player.m_pActiveItem->m_iId == WEAPON_RPG) + else { - ((CRpg*)player.m_pActiveItem)->m_fSpotActive = static_cast(from->client.vuser2[1]); - ((CRpg*)player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[2]; + player.m_pActiveItem = nullptr; } - // Don't go firing anything if we have died or are spectating - // Or if we don't have a weapon model deployed - if ((player.pev->deadflag != (DEAD_DISCARDBODY + 1)) && - !CL_IsDead() && 0 != player.pev->viewmodel && 0 == g_iUser1) + if (player.m_pActiveItem != nullptr) { - if (player.m_flNextAttack <= 0) + if (player.m_pActiveItem->m_iId == WEAPON_RPG) + { + ((CRpg*)player.m_pActiveItem)->m_fSpotActive = static_cast(from->client.vuser2[1]); + ((CRpg*)player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[2]; + } + + // Don't go firing anything if we have died or are spectating + // Or if we don't have a weapon model deployed + if ((player.pev->deadflag != (DEAD_DISCARDBODY + 1)) && + !CL_IsDead() && 0 != player.pev->viewmodel && 0 == g_iUser1) { - pWeapon->ItemPostFrame(); + if (player.m_flNextAttack <= 0) + { + pWeapon->ItemPostFrame(); + } } } @@ -753,31 +922,25 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd to->client.maxspeed = player.pev->maxspeed; //HL Weapons - to->client.vuser1[0] = player.ammo_9mm; - to->client.vuser1[1] = player.ammo_357; - to->client.vuser1[2] = player.ammo_argrens; - to->client.ammo_nails = player.ammo_bolts; - to->client.ammo_shells = player.ammo_buckshot; - to->client.ammo_cells = player.ammo_uranium; - to->client.vuser2[0] = player.ammo_hornets; - to->client.ammo_rockets = player.ammo_rockets; - - if (player.m_pActiveItem->m_iId == WEAPON_RPG) + if (player.m_pActiveItem != nullptr) { - to->client.vuser2[1] = static_cast(((CRpg*)player.m_pActiveItem)->m_fSpotActive); - to->client.vuser2[2] = ((CRpg*)player.m_pActiveItem)->m_cActiveRockets; - } + if (player.m_pActiveItem->m_iId == WEAPON_RPG) + { + to->client.vuser2[1] = static_cast(((CRpg*)player.m_pActiveItem)->m_fSpotActive); + to->client.vuser2[2] = ((CRpg*)player.m_pActiveItem)->m_cActiveRockets; + } - // Make sure that weapon animation matches what the game .dll is telling us - // over the wire ( fixes some animation glitches ) - if (g_runfuncs && (HUD_GetWeaponAnim() != to->client.weaponanim)) - { - //Make sure the 357 has the right body - g_Python.pev->body = bIsMultiplayer() ? 1 : 0; + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + if (g_runfuncs && (HUD_GetWeaponAnim() != to->client.weaponanim)) + { + //Make sure the 357 has the right body + g_Python.pev->body = bIsMultiplayer() ? 1 : 0; - // Force a fixed anim down to viewmodel - HUD_SendWeaponAnim(to->client.weaponanim, pWeapon->pev->body, true); + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim(to->client.weaponanim, pWeapon->pev->body, true); + } } for (i = 0; i < MAX_WEAPONS; i++) @@ -814,11 +977,6 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; pto->fuser1 -= cmd->msec / 1000.0; - to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; - to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; - to->client.vuser4[1] = player.m_rgAmmo[pCurrent->m_iPrimaryAmmoType]; - to->client.vuser4[2] = player.m_rgAmmo[pCurrent->m_iSecondaryAmmoType]; - pCurrent->DecrementTimers(); pCurrent->GetWeaponData(*pto); @@ -861,6 +1019,11 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd } } + for (i = 0; i < MAX_AMMO_SLOTS; i++) + { + to->weapondata[i].iuser4 = player.m_rgAmmo[i]; + } + // m_flNextAttack is now part of the weapons, but is part of the player instead to->client.m_flNextAttack -= cmd->msec / 1000.0; if (to->client.m_flNextAttack < -0.001) @@ -880,6 +1043,9 @@ void HUD_WeaponsPostThink(local_state_s* from, local_state_s* to, usercmd_t* cmd to->client.fuser3 = -0.001; } + // Check if new client data (for HUD and view control) needs to be updated + player.UpdateClientData(); + // Store off the last position from the predicted state. HUD_SetLastOrg(); diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index c5050096..52bd8c84 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -634,7 +634,13 @@ bool CHud::MsgFunc_SetFOV(const char* pszName, int iSize, void* pbuf) { BEGIN_READ(pbuf, iSize); - int newfov = READ_BYTE(); + int iFOV = READ_BYTE(); + + return Update_SetFOV(iFOV); +} + +bool CHud::Update_SetFOV(const int iFOV) +{ int def_fov = CVAR_GET_FLOAT("default_fov"); //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). @@ -644,15 +650,15 @@ bool CHud::MsgFunc_SetFOV(const char* pszName, int iSize, void* pbuf) return 1; */ - g_lastFOV = newfov; + g_lastFOV = iFOV; - if (newfov == 0) + if (iFOV == 0) { m_iFOV = def_fov; } else { - m_iFOV = newfov; + m_iFOV = iFOV; } // the clients fov is actually set in the client data update section of the hud @@ -666,7 +672,7 @@ bool CHud::MsgFunc_SetFOV(const char* pszName, int iSize, void* pbuf) else { // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = IN_GetMouseSensitivity() * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + m_flMouseSensitivity = IN_GetMouseSensitivity() * ((float)iFOV / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); } return true; diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 4506d1f4..4bc70ff6 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -111,6 +111,8 @@ class CHudAmmo : public CHudBase bool MsgFunc_WeapPickup(const char* pszName, int iSize, void* pbuf); bool MsgFunc_ItemPickup(const char* pszName, int iSize, void* pbuf); bool MsgFunc_HideWeapon(const char* pszName, int iSize, void* pbuf); + bool Update_CurWeapon(const int iState, const int iId, const int iClip); + bool Update_AmmoX(const int iIndex, const int iCount); void SlotInput(int iSlot); void UserCmd_Slot1(); @@ -592,6 +594,7 @@ class CHud bool MsgFunc_SetFOV(const char* pszName, int iSize, void* pbuf); bool MsgFunc_Concuss(const char* pszName, int iSize, void* pbuf); bool MsgFunc_Weapons(const char* pszName, int iSize, void* pbuf); + bool Update_SetFOV(const int iFOV); // Screen information SCREENINFO m_scrinfo; diff --git a/dlls/client.cpp b/dlls/client.cpp index 50bdb701..99fd82fc 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -1749,6 +1749,11 @@ int GetWeaponData(struct edict_s* player, struct weapon_data_s* info) if (!pl) return 1; + for (i = 0; i < MAX_AMMO_SLOTS; i++) + { + info[i].iuser4 = pl->m_rgAmmo[i]; + } + // go through all of the weapons and make a list of the ones to pack for (i = 0; i < MAX_ITEM_TYPES; i++) { @@ -1877,15 +1882,6 @@ void UpdateClientData(const edict_t* ent, int sendweapons, struct clientdata_s* cd->m_flNextAttack = pl->m_flNextAttack; cd->fuser2 = pl->m_flNextAmmoBurn; cd->fuser3 = pl->m_flAmmoStartCharge; - cd->vuser1.x = pl->ammo_9mm; - cd->vuser1.y = pl->ammo_357; - cd->vuser1.z = pl->ammo_argrens; - cd->ammo_nails = pl->ammo_bolts; - cd->ammo_shells = pl->ammo_buckshot; - cd->ammo_rockets = pl->ammo_rockets; - cd->ammo_cells = pl->ammo_uranium; - cd->vuser2.x = pl->ammo_hornets; - if (pl->m_pActiveItem) { @@ -1898,11 +1894,6 @@ void UpdateClientData(const edict_t* ent, int sendweapons, struct clientdata_s* cd->m_iId = II.iId; - cd->vuser3.z = gun->m_iSecondaryAmmoType; - cd->vuser4.x = gun->m_iPrimaryAmmoType; - cd->vuser4.y = pl->m_rgAmmo[gun->m_iPrimaryAmmoType]; - cd->vuser4.z = pl->m_rgAmmo[gun->m_iSecondaryAmmoType]; - if (pl->m_pActiveItem->m_iId == WEAPON_RPG) { cd->vuser2.y = static_cast(((CRpg*)pl->m_pActiveItem)->m_fSpotActive); diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 8e90a37c..5cc8e32d 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -436,7 +436,7 @@ void CCrossbow::SecondaryAttack() void CCrossbow::Reload() { - if (m_pPlayer->ammo_bolts <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return; if (m_pPlayer->m_iFOV != 0) diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 2931edff..f72bfb97 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -118,7 +118,7 @@ float CEgon::GetDischargeInterval() bool CEgon::HasAmmo() { - if (m_pPlayer->ammo_uranium <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return false; return true; diff --git a/dlls/glock.cpp b/dlls/glock.cpp index 64552cbf..6e7e3208 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -158,7 +158,7 @@ void CGlock::GlockFire(float flSpread, float flCycleTime, bool fUseAutoAim) void CGlock::Reload() { - if (m_pPlayer->ammo_9mm <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return; bool iResult = DefaultReload(17, m_iClip > 0 ? GLOCK_RELOAD_NOT_EMPTY : GLOCK_RELOAD, 1.5); diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index ebabbba2..715cd459 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -123,7 +123,7 @@ void CHgun::PrimaryAttack() { Reload(); - if (m_pPlayer->ammo_hornets <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { return; } @@ -177,7 +177,7 @@ void CHgun::SecondaryAttack() { Reload(); - if (m_pPlayer->ammo_hornets <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) { return; } diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index ed399b06..a0bb8784 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -218,7 +218,7 @@ void CMP5::SecondaryAttack() void CMP5::Reload() { - if (m_pPlayer->ammo_9mm <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return; DefaultReload(MP5_MAX_CLIP, MP5_RELOAD, 1.5); diff --git a/dlls/player.cpp b/dlls/player.cpp index 9efa12d6..7259cd01 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1087,14 +1087,6 @@ all the ammo we have into the ammo vars. */ void CBasePlayer::TabulateAmmo() { - ammo_9mm = AmmoInventory(GetAmmoIndex("9mm")); - ammo_357 = AmmoInventory(GetAmmoIndex("357")); - ammo_argrens = AmmoInventory(GetAmmoIndex("ARgrenades")); - ammo_bolts = AmmoInventory(GetAmmoIndex("bolts")); - ammo_buckshot = AmmoInventory(GetAmmoIndex("buckshot")); - ammo_rockets = AmmoInventory(GetAmmoIndex("rockets")); - ammo_uranium = AmmoInventory(GetAmmoIndex("uranium")); - ammo_hornets = AmmoInventory(GetAmmoIndex("Hornets")); } @@ -3009,7 +3001,6 @@ void CBasePlayer::Spawn() for (int i = 0; i < MAX_AMMO_SLOTS; i++) { m_rgAmmo[i] = 0; - m_rgAmmoLast[i] = 0; // client ammo values also have to be reset (the death hud clear messages does on the client side) } m_lastx = m_lasty = 0; @@ -3017,6 +3008,11 @@ void CBasePlayer::Spawn() m_flNextChatTime = gpGlobals->time; g_pGameRules->PlayerSpawn(this); + + for (int i = 0; i < MAX_AMMO_SLOTS; i++) + { + m_rgAmmoLast[i] = -1; + } } @@ -4075,6 +4071,10 @@ void CBasePlayer::UpdateClientData() { const bool fullHUDInitRequired = m_fInitHUD != false; +#if defined(CLIENT_WEAPONS) + const bool updateData = fullHUDInitRequired || m_bRestored || !ENGINE_CANSKIP(edict()); +#endif + if (m_fInitHUD) { m_fInitHUD = false; @@ -4114,7 +4114,11 @@ void CBasePlayer::UpdateClientData() m_iClientHideHUD = m_iHideHUD; } - if (m_iFOV != m_iClientFOV) + if ( +#if defined(CLIENT_WEAPONS) + updateData && +#endif + m_iFOV != m_iClientFOV) { MESSAGE_BEGIN(MSG_ONE, gmsgSetFOV, NULL, pev); WRITE_BYTE(m_iFOV); @@ -4133,7 +4137,11 @@ void CBasePlayer::UpdateClientData() gDisplayTitle = false; } - if (pev->health != m_iClientHealth) + if ( +#if defined(CLIENT_WEAPONS) + updateData && +#endif + pev->health != m_iClientHealth) { int iHealth = std::clamp(pev->health, 0.f, (float)(std::numeric_limits::max())); // make sure that no negative health values are sent if (pev->health > 0.0f && pev->health <= 1.0f) @@ -4316,30 +4324,35 @@ void CBasePlayer::UpdateClientData() } - SendAmmoUpdate(); - - // Update all the items - for (int i = 0; i < MAX_ITEM_TYPES; i++) +#if defined(CLIENT_WEAPONS) + if (updateData) +#endif { - if (m_rgpPlayerItems[i]) // each item updates it's successors - m_rgpPlayerItems[i]->UpdateClientData(this); - } + SendAmmoUpdate(); - //Active item is becoming null, or we're sending all HUD state to client - //Only if we're not in Observer mode, which uses the target player's weapon - if (pev->iuser1 == OBS_NONE && !m_pActiveItem && ((m_pClientActiveItem != m_pActiveItem) || fullHUDInitRequired)) - { - //Tell ammo hud that we have no weapon selected - MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, NULL, pev); - WRITE_BYTE(0); - WRITE_BYTE(0); - WRITE_BYTE(0); - MESSAGE_END(); - } + // Update all the items + for (int i = 0; i < MAX_ITEM_TYPES; i++) + { + if (m_rgpPlayerItems[i]) // each item updates it's successors + m_rgpPlayerItems[i]->UpdateClientData(this); + } - // Cache and client weapon change - m_pClientActiveItem = m_pActiveItem; - m_iClientFOV = m_iFOV; + //Active item is becoming null, or we're sending all HUD state to client + //Only if we're not in Observer mode, which uses the target player's weapon + if (pev->iuser1 == OBS_NONE && !m_pActiveItem && ((m_pClientActiveItem != m_pActiveItem) || fullHUDInitRequired)) + { + //Tell ammo hud that we have no weapon selected + MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, NULL, pev); + WRITE_BYTE(0); + WRITE_BYTE(0); + WRITE_BYTE(0); + MESSAGE_END(); + } + + // Cache and client weapon change + m_pClientActiveItem = m_pActiveItem; + m_iClientFOV = m_iFOV; + } // Update Status Bar if (m_flNextSBarUpdateTime < gpGlobals->time) diff --git a/dlls/python.cpp b/dlls/python.cpp index 962b054e..4d43ebd1 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -189,7 +189,7 @@ void CPython::PrimaryAttack() void CPython::Reload() { - if (m_pPlayer->ammo_357 <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return; if (m_pPlayer->m_iFOV != 0) diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index 28b9830d..631d08b3 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -314,7 +314,7 @@ void CRpg::Reload() return; } - if (m_pPlayer->ammo_rockets <= 0) + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) return; // because the RPG waits to autoreload when no missiles are active while the LTD is on, the diff --git a/network/delta.lst b/network/delta.lst index 7d3a9fdf..43cbc5e5 100644 --- a/network/delta.lst +++ b/network/delta.lst @@ -16,11 +16,6 @@ clientdata_t none DEFINE_DELTA( origin[2], DT_SIGNED | DT_FLOAT, 21, 128.0 ), DEFINE_DELTA( velocity[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), - DEFINE_DELTA( ammo_nails, DT_SIGNED | DT_INTEGER, 10, 1.0 ), - DEFINE_DELTA( ammo_shells, DT_SIGNED | DT_INTEGER, 10, 1.0 ), - DEFINE_DELTA( ammo_cells, DT_SIGNED | DT_INTEGER, 10, 1.0 ), - DEFINE_DELTA( ammo_rockets, DT_SIGNED | DT_INTEGER, 10, 1.0 ), - DEFINE_DELTA( m_iId, DT_INTEGER, 6, 1.0 ), DEFINE_DELTA( punchangle[2], DT_SIGNED | DT_FLOAT, 16, 8.0 ), @@ -47,21 +42,11 @@ clientdata_t none DEFINE_DELTA( iuser1, DT_INTEGER, 3, 1.0 ), DEFINE_DELTA( iuser2, DT_INTEGER, 6, 1.0 ), - DEFINE_DELTA( vuser1[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - DEFINE_DELTA( vuser1[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - DEFINE_DELTA( vuser1[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - - DEFINE_DELTA( vuser2[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), DEFINE_DELTA( vuser2[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), DEFINE_DELTA( vuser2[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), DEFINE_DELTA( vuser3[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), DEFINE_DELTA( vuser3[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - DEFINE_DELTA( vuser3[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - - DEFINE_DELTA( vuser4[0], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - DEFINE_DELTA( vuser4[1], DT_SIGNED | DT_FLOAT, 10, 1.0 ), - DEFINE_DELTA( vuser4[2], DT_SIGNED | DT_FLOAT, 10, 1.0 ), DEFINE_DELTA( fuser1, DT_SIGNED | DT_FLOAT, 22, 128.0 ), DEFINE_DELTA( fuser2, DT_SIGNED | DT_FLOAT, 10, 128.0 ), @@ -244,6 +229,7 @@ weapon_data_t none DEFINE_DELTA( iuser1, DT_SIGNED | DT_INTEGER, 10, 1.0 ), DEFINE_DELTA( iuser2, DT_SIGNED | DT_INTEGER, 10, 1.0 ), DEFINE_DELTA( iuser3, DT_SIGNED | DT_INTEGER, 10, 1.0 ), + DEFINE_DELTA( iuser4, DT_INTEGER, 8, 1.0 ), DEFINE_DELTA( fuser1, DT_SIGNED | DT_FLOAT, 22, 1000.0 ), DEFINE_DELTA( fuser2, DT_SIGNED | DT_FLOAT, 22, 128.0 ), DEFINE_DELTA( fuser3, DT_SIGNED | DT_FLOAT, 22, 128.0 )