2022-12-17 13:32:43 +01:00
|
|
|
/***
|
2021-03-16 21:26:03 +01:00
|
|
|
*
|
|
|
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
|
|
|
*
|
|
|
|
* This product contains software technology licensed from Id
|
|
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
|
|
* without written permission from Valve LLC.
|
|
|
|
*
|
|
|
|
****/
|
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "weapons.h"
|
|
|
|
#include "gamerules.h"
|
|
|
|
|
|
|
|
// Precaches the ammo and queues the ammo info for sending to clients
|
2022-07-20 13:09:57 +02:00
|
|
|
void AddAmmoNameToAmmoRegistry(const char* szAmmoname, const char* weaponName)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
// make sure it's not already in the registry
|
|
|
|
for (int i = 0; i < MAX_AMMO_SLOTS; i++)
|
|
|
|
{
|
|
|
|
if (!CBasePlayerItem::AmmoInfoArray[i].pszName)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (stricmp(CBasePlayerItem::AmmoInfoArray[i].pszName, szAmmoname) == 0)
|
|
|
|
return; // ammo already in registry, just quite
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
giAmmoIndex++;
|
|
|
|
ASSERT(giAmmoIndex < MAX_AMMO_SLOTS);
|
|
|
|
if (giAmmoIndex >= MAX_AMMO_SLOTS)
|
|
|
|
giAmmoIndex = 0;
|
|
|
|
|
2022-07-20 13:09:57 +02:00
|
|
|
auto& ammoType = CBasePlayerItem::AmmoInfoArray[giAmmoIndex];
|
|
|
|
|
|
|
|
ammoType.pszName = szAmmoname;
|
|
|
|
ammoType.iId = giAmmoIndex; // yes, this info is redundant
|
|
|
|
ammoType.WeaponName = weaponName;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
2021-11-19 14:31:11 +01:00
|
|
|
bool CBasePlayerWeapon::CanDeploy()
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
bool bHasAmmo = false;
|
2021-03-16 21:26:03 +01:00
|
|
|
|
|
|
|
if (!pszAmmo1())
|
|
|
|
{
|
|
|
|
// this weapon doesn't use ammo, can always deploy.
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pszAmmo1())
|
|
|
|
{
|
|
|
|
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0);
|
|
|
|
}
|
|
|
|
if (pszAmmo2())
|
|
|
|
{
|
|
|
|
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0);
|
|
|
|
}
|
|
|
|
if (m_iClip > 0)
|
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
bHasAmmo |= true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
if (!bHasAmmo)
|
|
|
|
{
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
2021-11-19 14:31:11 +01:00
|
|
|
bool CBasePlayerWeapon::DefaultReload(int iClipSize, int iAnim, float fDelay, int body)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2021-03-16 21:26:03 +01:00
|
|
|
|
|
|
|
int j = V_min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
|
|
|
|
if (j == 0)
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2021-03-16 21:26:03 +01:00
|
|
|
|
|
|
|
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay;
|
|
|
|
|
|
|
|
//!!UNDONE -- reload sound goes here !!!
|
2021-10-21 14:00:29 +02:00
|
|
|
SendWeaponAnim(iAnim, body);
|
2021-03-16 21:26:03 +01:00
|
|
|
|
2021-11-19 13:45:16 +01:00
|
|
|
m_fInReload = true;
|
2021-03-16 21:26:03 +01:00
|
|
|
|
|
|
|
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CBasePlayerWeapon::ResetEmptySound()
|
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
m_iPlayEmptySound = true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
2021-11-19 14:31:11 +01:00
|
|
|
bool CanAttack(float attack_time, float curtime, bool isPredicted)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
#if defined(CLIENT_WEAPONS)
|
2021-03-16 21:26:03 +01:00
|
|
|
if (!isPredicted)
|
|
|
|
#else
|
|
|
|
if (1)
|
|
|
|
#endif
|
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
return (attack_time <= curtime) ? true : false;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
return ((static_cast<int>(std::floor(attack_time * 1000.0)) * 1000.0) <= 0.0) ? true : false;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBasePlayerWeapon::ItemPostFrame()
|
|
|
|
{
|
|
|
|
if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase()))
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// complete the reload.
|
2021-03-16 21:26:03 +01:00
|
|
|
int j = V_min(iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
|
|
|
|
|
|
|
|
// Add them to the clip
|
|
|
|
m_iClip += j;
|
|
|
|
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
|
|
|
|
|
|
|
|
m_pPlayer->TabulateAmmo();
|
|
|
|
|
2021-11-19 13:43:33 +01:00
|
|
|
m_fInReload = false;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((m_pPlayer->pev->button & IN_ATTACK) == 0)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
m_flLastFireTime = 0.0f;
|
|
|
|
}
|
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((m_pPlayer->pev->button & IN_ATTACK2) != 0 && CanAttack(m_flNextSecondaryAttack, gpGlobals->time, UseDecrement()))
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
if (pszAmmo2() && 0 == m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()])
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
m_fFireOnEmpty = true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
m_pPlayer->TabulateAmmo();
|
|
|
|
SecondaryAttack();
|
|
|
|
m_pPlayer->pev->button &= ~IN_ATTACK2;
|
|
|
|
}
|
2021-11-28 15:32:26 +01:00
|
|
|
else if ((m_pPlayer->pev->button & IN_ATTACK) != 0 && CanAttack(m_flNextPrimaryAttack, gpGlobals->time, UseDecrement()))
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && 0 == m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()]))
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
m_fFireOnEmpty = true;
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
m_pPlayer->TabulateAmmo();
|
|
|
|
PrimaryAttack();
|
|
|
|
}
|
2021-11-28 15:32:26 +01:00
|
|
|
else if ((m_pPlayer->pev->button & IN_RELOAD) != 0 && iMaxClip() != WEAPON_NOCLIP && !m_fInReload)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
// reload when reload is pressed, or if no buttons are down and weapon is empty.
|
|
|
|
Reload();
|
|
|
|
}
|
2021-11-28 15:32:26 +01:00
|
|
|
else if ((m_pPlayer->pev->button & (IN_ATTACK | IN_ATTACK2)) == 0)
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
// no fire buttons down
|
|
|
|
|
2021-11-19 13:43:33 +01:00
|
|
|
m_fFireOnEmpty = false;
|
2021-03-16 21:26:03 +01:00
|
|
|
|
|
|
|
if (!IsUseable() && m_flNextPrimaryAttack < (UseDecrement() ? 0.0 : gpGlobals->time))
|
|
|
|
{
|
2023-04-12 14:33:06 +02:00
|
|
|
#ifndef CLIENT_DLL
|
2021-03-16 21:26:03 +01:00
|
|
|
// weapon isn't useable, switch.
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) == 0 && g_pGameRules->GetNextBestWeapon(m_pPlayer, this))
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
m_flNextPrimaryAttack = (UseDecrement() ? 0.0 : gpGlobals->time) + 0.3;
|
|
|
|
return;
|
|
|
|
}
|
2023-04-12 14:33:06 +02:00
|
|
|
#endif
|
2021-03-16 21:26:03 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
|
2021-11-28 15:32:26 +01:00
|
|
|
if (m_iClip == 0 && (iFlags() & ITEM_FLAG_NOAUTORELOAD) == 0 && m_flNextPrimaryAttack < (UseDecrement() ? 0.0 : gpGlobals->time))
|
2021-03-16 21:26:03 +01:00
|
|
|
{
|
|
|
|
Reload();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WeaponIdle();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// catch all
|
|
|
|
if (ShouldWeaponIdle())
|
|
|
|
{
|
|
|
|
WeaponIdle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CBasePlayer::SelectLastItem()
|
|
|
|
{
|
|
|
|
if (!m_pLastItem)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_pActiveItem && !m_pActiveItem->CanHolster())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ResetAutoaim();
|
|
|
|
|
|
|
|
// FIX, this needs to queue them up and delay
|
|
|
|
if (m_pActiveItem)
|
|
|
|
m_pActiveItem->Holster();
|
|
|
|
|
|
|
|
CBasePlayerItem* pTemp = m_pActiveItem;
|
|
|
|
m_pActiveItem = m_pLastItem;
|
|
|
|
m_pLastItem = pTemp;
|
2022-07-20 17:28:02 +02:00
|
|
|
|
2022-07-22 18:46:04 +02:00
|
|
|
auto weapon = m_pActiveItem->GetWeaponPtr();
|
2022-07-20 17:28:02 +02:00
|
|
|
|
|
|
|
if (weapon)
|
|
|
|
{
|
|
|
|
weapon->m_ForceSendAnimations = true;
|
|
|
|
}
|
|
|
|
|
2021-03-16 21:26:03 +01:00
|
|
|
m_pActiveItem->Deploy();
|
2022-07-20 17:28:02 +02:00
|
|
|
|
|
|
|
if (weapon)
|
|
|
|
{
|
|
|
|
weapon->m_ForceSendAnimations = false;
|
|
|
|
}
|
|
|
|
|
2021-03-16 21:26:03 +01:00
|
|
|
m_pActiveItem->UpdateItemInfo();
|
|
|
|
}
|