|
| 1 | +#include "weapon_logic.h" |
| 2 | +#include "extdll.h" |
| 3 | +#include "util.h" |
| 4 | +#include "cbase.h" |
| 5 | +#include "player.h" |
| 6 | +#include "monsters.h" |
| 7 | +#include "weapons.h" |
| 8 | +#include "nodes.h" |
| 9 | +#include "soundent.h" |
| 10 | +#include "decals.h" |
| 11 | +#include "gamerules.h" |
| 12 | + |
| 13 | +BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) |
| 14 | +{ |
| 15 | + return ( attack_time <= curtime ) ? TRUE : FALSE; |
| 16 | +} |
| 17 | + |
| 18 | +CBaseWeaponLogic::CBaseWeaponLogic(IWeaponLogicFuncs *funcs) : |
| 19 | + m_pFuncs(funcs), |
| 20 | + m_pPlayer(nullptr) |
| 21 | +{ |
| 22 | +} |
| 23 | + |
| 24 | +CBaseWeaponLogic::~CBaseWeaponLogic() |
| 25 | +{ |
| 26 | + if (m_pFuncs) { |
| 27 | + delete m_pFuncs; |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +void CBaseWeaponLogic::ItemPostFrame() |
| 32 | +{ |
| 33 | + if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= gpGlobals->time )) |
| 34 | + { |
| 35 | + // complete the reload. |
| 36 | + int j = Q_min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); |
| 37 | + |
| 38 | + // Add them to the clip |
| 39 | + m_iClip += j; |
| 40 | + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; |
| 41 | + |
| 42 | + m_fInReload = FALSE; |
| 43 | + } |
| 44 | + |
| 45 | + if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) |
| 46 | + { |
| 47 | + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) |
| 48 | + { |
| 49 | + m_fFireOnEmpty = TRUE; |
| 50 | + } |
| 51 | + |
| 52 | + SecondaryAttack(); |
| 53 | + m_pPlayer->pev->button &= ~IN_ATTACK2; |
| 54 | + } |
| 55 | + else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) |
| 56 | + { |
| 57 | + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) |
| 58 | + { |
| 59 | + m_fFireOnEmpty = TRUE; |
| 60 | + } |
| 61 | + |
| 62 | + PrimaryAttack(); |
| 63 | + } |
| 64 | + else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) |
| 65 | + { |
| 66 | + // reload when reload is pressed, or if no buttons are down and weapon is empty. |
| 67 | + Reload(); |
| 68 | + } |
| 69 | + else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) |
| 70 | + { |
| 71 | + // no fire buttons down |
| 72 | + |
| 73 | + m_fFireOnEmpty = FALSE; |
| 74 | + |
| 75 | + if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) |
| 76 | + { |
| 77 | + // weapon isn't useable, switch. |
| 78 | + if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) |
| 79 | + { |
| 80 | + m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; |
| 81 | + return; |
| 82 | + } |
| 83 | + } |
| 84 | + else |
| 85 | + { |
| 86 | + // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing |
| 87 | + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) |
| 88 | + { |
| 89 | + Reload(); |
| 90 | + return; |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + WeaponIdle( ); |
| 95 | + return; |
| 96 | + } |
| 97 | + |
| 98 | + // catch all |
| 99 | + if ( ShouldWeaponIdle() ) |
| 100 | + { |
| 101 | + WeaponIdle(); |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +void CBaseWeaponLogic::Holster( void ) |
| 106 | +{ |
| 107 | + m_fInReload = FALSE; // cancel any reload in progress. |
| 108 | + m_pPlayer->pev->viewmodel = 0; |
| 109 | + m_pPlayer->pev->weaponmodel = 0; |
| 110 | +} |
| 111 | + |
| 112 | +//========================================================= |
| 113 | +// IsUseable - this function determines whether or not a |
| 114 | +// weapon is useable by the player in its current state. |
| 115 | +// (does it have ammo loaded? do I have any ammo for the |
| 116 | +// weapon?, etc) |
| 117 | +//========================================================= |
| 118 | +BOOL CBaseWeaponLogic :: IsUseable( void ) |
| 119 | +{ |
| 120 | + if ( m_iClip <= 0 ) |
| 121 | + { |
| 122 | + if ( m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] <= 0 && iMaxAmmo1() != -1 ) |
| 123 | + { |
| 124 | + // clip is empty (or nonexistant) and the player has no more ammo of this type. |
| 125 | + return FALSE; |
| 126 | + } |
| 127 | + } |
| 128 | + |
| 129 | + return TRUE; |
| 130 | +} |
| 131 | + |
| 132 | +BOOL CBaseWeaponLogic :: CanDeploy( void ) |
| 133 | +{ |
| 134 | + BOOL bHasAmmo = 0; |
| 135 | + |
| 136 | + if ( !pszAmmo1() ) |
| 137 | + { |
| 138 | + // this weapon doesn't use ammo, can always deploy. |
| 139 | + return TRUE; |
| 140 | + } |
| 141 | + |
| 142 | + if ( pszAmmo1() ) |
| 143 | + { |
| 144 | + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); |
| 145 | + } |
| 146 | + if ( pszAmmo2() ) |
| 147 | + { |
| 148 | + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); |
| 149 | + } |
| 150 | + if (m_iClip > 0) |
| 151 | + { |
| 152 | + bHasAmmo |= 1; |
| 153 | + } |
| 154 | + if (!bHasAmmo) |
| 155 | + { |
| 156 | + return FALSE; |
| 157 | + } |
| 158 | + |
| 159 | + return TRUE; |
| 160 | +} |
| 161 | + |
| 162 | +BOOL CBaseWeaponLogic :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) |
| 163 | +{ |
| 164 | + if (!CanDeploy( )) |
| 165 | + return FALSE; |
| 166 | + |
| 167 | + m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); |
| 168 | + m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); |
| 169 | + strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); |
| 170 | + SendWeaponAnim( iAnim, skiplocal, body ); |
| 171 | + |
| 172 | + m_pPlayer->m_flNextAttack = gpGlobals->time + 0.5; |
| 173 | + m_flTimeWeaponIdle = gpGlobals->time + 1.0; |
| 174 | + |
| 175 | + return TRUE; |
| 176 | +} |
| 177 | + |
| 178 | +BOOL CBaseWeaponLogic :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) |
| 179 | +{ |
| 180 | + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) |
| 181 | + return FALSE; |
| 182 | + |
| 183 | + int j = Q_min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); |
| 184 | + |
| 185 | + if (j == 0) |
| 186 | + return FALSE; |
| 187 | + |
| 188 | + m_pPlayer->m_flNextAttack = gpGlobals->time + fDelay; |
| 189 | + |
| 190 | + //!!UNDONE -- reload sound goes here !!! |
| 191 | + SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); |
| 192 | + |
| 193 | + m_fInReload = TRUE; |
| 194 | + |
| 195 | + m_flTimeWeaponIdle = gpGlobals->time + 3; |
| 196 | + return TRUE; |
| 197 | +} |
| 198 | + |
| 199 | +void CBaseWeaponLogic::SendWeaponAnim( int iAnim, int skiplocal, int body ) |
| 200 | +{ |
| 201 | + if ( UseDecrement() ) |
| 202 | + skiplocal = 1; |
| 203 | + else |
| 204 | + skiplocal = 0; |
| 205 | + |
| 206 | + m_pPlayer->pev->weaponanim = iAnim; |
| 207 | + |
| 208 | + MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); |
| 209 | + WRITE_BYTE( iAnim ); // sequence number |
| 210 | + WRITE_BYTE( m_pFuncs->GetWeaponBodygroup() ); // weaponmodel bodygroup. |
| 211 | + MESSAGE_END(); |
| 212 | +} |
| 213 | + |
| 214 | +BOOL CBaseWeaponLogic :: PlayEmptySound( void ) |
| 215 | +{ |
| 216 | + if (m_iPlayEmptySound) |
| 217 | + { |
| 218 | + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); |
| 219 | + m_iPlayEmptySound = 0; |
| 220 | + return 0; |
| 221 | + } |
| 222 | + return 0; |
| 223 | +} |
| 224 | + |
| 225 | +void CBaseWeaponLogic :: ResetEmptySound( void ) |
| 226 | +{ |
| 227 | + m_iPlayEmptySound = 1; |
| 228 | +} |
| 229 | + |
| 230 | +int CBaseWeaponLogic::PrimaryAmmoIndex( void ) |
| 231 | +{ |
| 232 | + return m_iPrimaryAmmoType; |
| 233 | +} |
| 234 | + |
| 235 | +int CBaseWeaponLogic::SecondaryAmmoIndex( void ) |
| 236 | +{ |
| 237 | + return -1; |
| 238 | +} |
| 239 | + |
| 240 | +int CBaseWeaponLogic::iItemSlot(void) { return 0; } // return 0 to MAX_ITEMS_SLOTS, used in hud |
| 241 | +int CBaseWeaponLogic::iItemPosition( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iPosition; } |
| 242 | +const char *CBaseWeaponLogic::pszAmmo1( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszAmmo1; } |
| 243 | +int CBaseWeaponLogic::iMaxAmmo1( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxAmmo1; } |
| 244 | +const char *CBaseWeaponLogic::pszAmmo2( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszAmmo2; } |
| 245 | +int CBaseWeaponLogic::iMaxAmmo2( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxAmmo2; } |
| 246 | +const char *CBaseWeaponLogic::pszName( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].pszName; } |
| 247 | +int CBaseWeaponLogic::iMaxClip( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iMaxClip; } |
| 248 | +int CBaseWeaponLogic::iWeight( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iWeight; } |
| 249 | +int CBaseWeaponLogic::iFlags( void ) { return CBasePlayerItem::ItemInfoArray[ m_iId ].iFlags; } |
0 commit comments