halflife-photomode/dlls/weapons_shared.cpp

242 lines
5.3 KiB
C++

/***
*
* 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
void AddAmmoNameToAmmoRegistry(const char* szAmmoname, const char* weaponName)
{
// 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;
auto& ammoType = CBasePlayerItem::AmmoInfoArray[giAmmoIndex];
ammoType.pszName = szAmmoname;
ammoType.iId = giAmmoIndex; // yes, this info is redundant
ammoType.WeaponName = weaponName;
}
bool CBasePlayerWeapon::CanDeploy()
{
bool bHasAmmo = false;
if (!pszAmmo1())
{
// this weapon doesn't use ammo, can always deploy.
return true;
}
if (pszAmmo1())
{
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0);
}
if (pszAmmo2())
{
bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0);
}
if (m_iClip > 0)
{
bHasAmmo |= true;
}
if (!bHasAmmo)
{
return false;
}
return true;
}
bool CBasePlayerWeapon::DefaultReload(int iClipSize, int iAnim, float fDelay, int body)
{
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
return false;
int j = V_min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
if (j == 0)
return false;
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay;
//!!UNDONE -- reload sound goes here !!!
SendWeaponAnim(iAnim, body);
m_fInReload = true;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
return true;
}
void CBasePlayerWeapon::ResetEmptySound()
{
m_iPlayEmptySound = true;
}
bool CanAttack(float attack_time, float curtime, bool isPredicted)
{
#if defined(CLIENT_WEAPONS)
if (!isPredicted)
#else
if (1)
#endif
{
return (attack_time <= curtime) ? true : false;
}
else
{
return ((static_cast<int>(std::floor(attack_time * 1000.0)) * 1000.0) <= 0.0) ? true : false;
}
}
void CBasePlayerWeapon::ItemPostFrame()
{
if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase()))
{
// complete the reload.
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();
m_fInReload = false;
}
if ((m_pPlayer->pev->button & IN_ATTACK) == 0)
{
m_flLastFireTime = 0.0f;
}
if ((m_pPlayer->pev->button & IN_ATTACK2) != 0 && CanAttack(m_flNextSecondaryAttack, gpGlobals->time, UseDecrement()))
{
if (pszAmmo2() && 0 == m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()])
{
m_fFireOnEmpty = true;
}
m_pPlayer->TabulateAmmo();
SecondaryAttack();
m_pPlayer->pev->button &= ~IN_ATTACK2;
}
else if ((m_pPlayer->pev->button & IN_ATTACK) != 0 && CanAttack(m_flNextPrimaryAttack, gpGlobals->time, UseDecrement()))
{
if ((m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && 0 == m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()]))
{
m_fFireOnEmpty = true;
}
m_pPlayer->TabulateAmmo();
PrimaryAttack();
}
else if ((m_pPlayer->pev->button & IN_RELOAD) != 0 && iMaxClip() != WEAPON_NOCLIP && !m_fInReload)
{
// reload when reload is pressed, or if no buttons are down and weapon is empty.
Reload();
}
else if ((m_pPlayer->pev->button & (IN_ATTACK | IN_ATTACK2)) == 0)
{
// no fire buttons down
m_fFireOnEmpty = false;
if (!IsUseable() && m_flNextPrimaryAttack < (UseDecrement() ? 0.0 : gpGlobals->time))
{
#ifndef CLIENT_DLL
// weapon isn't useable, switch.
if ((iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) == 0 && g_pGameRules->GetNextBestWeapon(m_pPlayer, this))
{
m_flNextPrimaryAttack = (UseDecrement() ? 0.0 : gpGlobals->time) + 0.3;
return;
}
#endif
}
else
{
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
if (m_iClip == 0 && (iFlags() & ITEM_FLAG_NOAUTORELOAD) == 0 && m_flNextPrimaryAttack < (UseDecrement() ? 0.0 : gpGlobals->time))
{
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;
auto weapon = m_pActiveItem->GetWeaponPtr();
if (weapon)
{
weapon->m_ForceSendAnimations = true;
}
m_pActiveItem->Deploy();
if (weapon)
{
weapon->m_ForceSendAnimations = false;
}
m_pActiveItem->UpdateItemInfo();
}