void CASW_Weapon::FinishReload( void ) { CASW_Marine *pOwner = GetMarine(); if (pOwner) { // If I use primary clips, reload primary if ( UsesClipsForAmmo1() ) { // asw: throw away what's in the clip currently m_iClip1 = 0; int primary = MIN( GetMaxClip1() - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType)); m_iClip1 += primary; pOwner->RemoveAmmo( primary, m_iPrimaryAmmoType); } // If I use secondary clips, reload secondary if ( UsesClipsForAmmo2() ) { int secondary = MIN( GetMaxClip2() - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType)); m_iClip2 += secondary; pOwner->RemoveAmmo( secondary, m_iSecondaryAmmoType ); } if ( m_bReloadsSingly ) { m_bInReload = false; } #ifdef GAME_DLL if ( !m_bFastReloadSuccess ) { pOwner->m_nFastReloadsInARow = 0; } #endif m_bFastReloadSuccess = false; m_bFastReloadFailure = false; } }
bool CASW_Weapon::ASWReload( int iClipSize1, int iClipSize2, int iActivity ) { if ( m_bInReload ) // we're already reloading! { Msg("ASWReload already reloading\n"); Assert(false); return true; } CASW_Marine *pMarine = GetMarine(); if ( !pMarine || !ASWGameRules() ) return false; bool bReload = false; if ( m_bIsFiring ) { OnStoppedFiring(); } // If you don't have clips, then don't try to reload them. if ( UsesClipsForAmmo1() ) { // need to reload primary clip? int primary = MIN( iClipSize1 - m_iClip1, pMarine->GetAmmoCount( m_iPrimaryAmmoType ) ); if ( primary != 0 ) { bReload = true; } else { // check if we have an ammo bag we can take a clip from instead CASW_Weapon_Ammo_Bag* pAmmoBag = dynamic_cast<CASW_Weapon_Ammo_Bag*>( pMarine->GetASWWeapon( 0 ) ); if ( !pAmmoBag ) { pAmmoBag = dynamic_cast<CASW_Weapon_Ammo_Bag*>( pMarine->GetASWWeapon( 1 ) ); } if ( pAmmoBag && pAmmoBag->CanGiveAmmoToWeapon( this ) ) { #ifdef CLIENT_DLL bReload = true; #else pAmmoBag->GiveClipTo(pMarine, m_iPrimaryAmmoType, true); // now we've given a clip, check if we can reload primary = MIN(iClipSize1 - m_iClip1, pMarine->GetAmmoCount(m_iPrimaryAmmoType)); if ( primary != 0 ) { bReload = true; } #endif } } } if ( UsesClipsForAmmo2() ) { // need to reload secondary clip? int secondary = MIN( iClipSize2 - m_iClip2, pMarine->GetAmmoCount( m_iSecondaryAmmoType ) ); if ( secondary != 0 ) { bReload = true; } } if ( !bReload ) return false; m_bFastReloadSuccess = false; m_bFastReloadFailure = false; #ifndef CLIENT_DLL if ( GetMaxClip1() > 1 ) { // Fire event when a player reloads a weapon with more than a bullet per clip IGameEvent * event = gameeventmanager->CreateEvent( "weapon_reload" ); if ( event ) { CASW_Player *pPlayer = NULL; pPlayer = pMarine->GetCommander(); int nClipSize = GetMaxClip1(); int nClips = pMarine->GetAmmoCount( m_iPrimaryAmmoType ) / nClipSize; CASW_Weapon_Ammo_Bag *pAmmoBag = dynamic_cast< CASW_Weapon_Ammo_Bag* >( pMarine->GetASWWeapon( 0 ) ); if ( !pAmmoBag ) { pAmmoBag = dynamic_cast< CASW_Weapon_Ammo_Bag* >( pMarine->GetASWWeapon( 1 ) ); } if ( pAmmoBag && this != pAmmoBag ) { nClips += pAmmoBag->NumClipsForWeapon( this ); } event->SetInt( "userid", ( pPlayer ? pPlayer->GetUserID() : 0 ) ); event->SetInt( "marine", pMarine->entindex() ); event->SetInt( "lost", m_iClip1 ); event->SetInt( "clipsize", nClipSize ); event->SetInt( "clipsremaining", nClips - 1 ); event->SetInt( "clipsmax", GetAmmoDef()->MaxCarry( m_iPrimaryAmmoType, pMarine ) / nClipSize ); gameeventmanager->FireEvent( event ); } } #endif m_fReloadClearFiringTime = gpGlobals->curtime + GetFireRate(); float fReloadTime = GetReloadTime(); float flSequenceEndTime = gpGlobals->curtime + fReloadTime; pMarine->SetNextAttack( flSequenceEndTime ); m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime; //Msg(" Setting nextprimary attack time to %f from aswreload\n", m_flNextPrimaryAttack); m_bInReload = true; // set fast reload timings // assuming 2.8 base reload time // ~0.29 RandomSeed( CBaseEntity::GetPredictionRandomSeed() & 255 ); float flStartFraction = random->RandomFloat( 0.29f, 0.35f ); // set width by difficulty float flFastReloadWidth = 0.12f; switch( ASWGameRules()->GetSkillLevel() ) { default: case 1: case 2: flFastReloadWidth = random->RandomFloat( 0.10f, 0.1f ); break; // easy/normal case 3: flFastReloadWidth = random->RandomFloat( 0.08f, 0.12f ); break; // hard case 4: flFastReloadWidth = random->RandomFloat( 0.06f, 0.10f ); break; // insane case 5: flFastReloadWidth = random->RandomFloat( 0.055f, 0.09f ); break; // imba } // scale by marine skills flFastReloadWidth *= MarineSkills()->GetSkillBasedValueByMarine( pMarine, ASW_MARINE_SKILL_RELOADING, ASW_MARINE_SUBSKILL_RELOADING_FAST_WIDTH_SCALE ); m_fReloadStart = gpGlobals->curtime; m_fFastReloadStart = gpGlobals->curtime + flStartFraction * fReloadTime; m_fFastReloadEnd = m_fFastReloadStart + flFastReloadWidth * fReloadTime; SendReloadEvents(); #ifdef GAME_DLL pMarine->RemoveWeaponPowerup( this ); #endif return true; }
// check player or marine commander's buttons for firing/reload/etc void CASW_Weapon::ItemPostFrame( void ) { //CBasePlayer *pOwner = GetCommander(); CASW_Marine* pOwner = GetMarine(); if (!pOwner) return; bool bThisActive = ( pOwner && pOwner->GetActiveWeapon() == this ); bool bAttack1, bAttack2, bReload, bOldReload, bOldAttack1; GetButtons(bAttack1, bAttack2, bReload, bOldReload, bOldAttack1 ); if ( pOwner->IsHacking() ) { bThisActive = bAttack1 = bAttack2 = bReload = false; } // check for clearing our weapon switching bool if (m_bSwitchingWeapons && gpGlobals->curtime > m_flNextPrimaryAttack) { m_bSwitchingWeapons = false; } // check for clearing our firing bool from reloading if (m_bInReload && gpGlobals->curtime > m_fReloadClearFiringTime) { ClearIsFiring(); } if ( m_bShotDelayed && gpGlobals->curtime > m_flDelayedFire ) { DelayedAttack(); } if ( UsesClipsForAmmo1() ) { CheckReload(); } bool bFired = false; if ( bThisActive ) { //Track the duration of the fire //FIXME: Check for IN_ATTACK2 as well? //FIXME: What if we're calling ItemBusyFrame? m_fFireDuration = bAttack1 ? ( m_fFireDuration + gpGlobals->frametime ) : 0.0f; if (bAttack2 && (m_flNextSecondaryAttack <= gpGlobals->curtime) && gpGlobals->curtime > pOwner->m_fFFGuardTime) { if ( SecondaryAttackUsesPrimaryAmmo() ) { if ( !IsMeleeWeapon() && (( UsesClipsForAmmo1() && !(this->PrimaryAmmoLoaded())) || ( !UsesClipsForAmmo1() && pOwner->GetAmmoCount(m_iPrimaryAmmoType)<=0 )) ) { HandleFireOnEmpty(); } else { bFired = true; SecondaryAttack(); #ifndef CLIENT_DLL if ( pOwner->IsInhabited() ) { IGameEvent * event = gameeventmanager->CreateEvent( "player_alt_fire" ); if ( event ) { CASW_Player *pPlayer = pOwner->GetCommander(); event->SetInt( "userid", ( pPlayer ? pPlayer->GetUserID() : 0 ) ); gameeventmanager->FireEvent( event ); } } #endif } } else if ( UsesSecondaryAmmo() && ( ( UsesClipsForAmmo2() && m_iClip2 <= 0 ) || ( !UsesClipsForAmmo2() && pOwner->GetAmmoCount( m_iSecondaryAmmoType ) <= 0 ) ) ) { if ( m_flNextEmptySoundTime < gpGlobals->curtime ) { WeaponSound( EMPTY ); m_flNextSecondaryAttack = m_flNextEmptySoundTime = gpGlobals->curtime + 0.5; } } else { bFired = true; SecondaryAttack(); #ifndef CLIENT_DLL if ( pOwner->IsInhabited() ) { IGameEvent * event = gameeventmanager->CreateEvent( "player_alt_fire" ); if ( event ) { CASW_Player *pPlayer = pOwner->GetCommander(); event->SetInt( "userid", ( pPlayer ? pPlayer->GetUserID() : 0 ) ); gameeventmanager->FireEvent( event ); } } #endif // Secondary ammo doesn't have a reload animation // this code makes secondary ammo come from nowhere! /* if ( UsesClipsForAmmo2() ) { // reload clip2 if empty if (m_iClip2 < 1) { pOwner->RemoveAmmo( 1, m_iSecondaryAmmoType ); m_iClip2 = m_iClip2 + 1; } }*/ } } if ( !bFired && bAttack1 && (m_flNextPrimaryAttack <= gpGlobals->curtime) && gpGlobals->curtime > pOwner->m_fFFGuardTime) { // Clip empty? Or out of ammo on a no-clip weapon? if ( !IsMeleeWeapon() && (( UsesClipsForAmmo1() && !(this->PrimaryAmmoLoaded())) || ( !UsesClipsForAmmo1() && pOwner->GetAmmoCount(m_iPrimaryAmmoType)<=0 )) ) { HandleFireOnEmpty(); } else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false) { // This weapon doesn't fire underwater WeaponSound(EMPTY); m_flNextPrimaryAttack = gpGlobals->curtime + 0.2; return; } else { //NOTENOTE: There is a bug with this code with regards to the way machine guns catch the leading edge trigger // on the player hitting the attack key. It relies on the gun catching that case in the same frame. // However, because the player can also be doing a secondary attack, the edge trigger may be missed. // We really need to hold onto the edge trigger and only clear the condition when the gun has fired its // first shot. Right now that's too much of an architecture change -- jdw // If the firing button was just pressed, reset the firing time if ( pOwner && bAttack1 ) { #ifdef CLIENT_DLL //Msg("[Client] setting nextprimaryattack to now %f\n", gpGlobals->curtime); #else //Msg("[Server] setting nextprimaryattack to now %f\n", gpGlobals->curtime); #endif m_flNextPrimaryAttack = gpGlobals->curtime; } PrimaryAttack(); } } } if (!bAttack1) // clear our firing var if we don't have the attack button held down (not totally accurate since firing could continue for some time after pulling the trigger, but it's good enough for our purposes) { m_bIsFiring = false; // NOTE: Only want to clear primary fire IsFiring bool here (i.e. don't call ClearIsFiring as that'll clear secondary fire too, in subclasses that have it) if ( bOldAttack1 ) { OnStoppedFiring(); } } // ----------------------- // Reload pressed / Clip Empty // ----------------------- if ( bReload && UsesClipsForAmmo1()) { if ( m_bInReload ) { // todo: check for a fast reload //Msg("Check for fast reload\n"); } else { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); m_fFireDuration = 0.0f; } } // ----------------------- // No buttons down // ----------------------- if (!(bAttack1 || bAttack2 || bReload)) { // no fire buttons down or reloading if ( !ReloadOrSwitchWeapons() && ( m_bInReload == false ) ) { WeaponIdle(); } } }
bool CWeaponDODBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity ) { CBaseCombatCharacter *pOwner = GetOwner(); if (!pOwner) return false; // If I don't have any spare ammo, I can't reload if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 ) return false; bool bReload = false; // If you don't have clips, then don't try to reload them. if ( UsesClipsForAmmo1() ) { // need to reload primary clip? int primary = min(iClipSize1 - m_iClip1, pOwner->GetAmmoCount(m_iPrimaryAmmoType)); if ( primary != 0 ) { bReload = true; } } if ( UsesClipsForAmmo2() ) { // need to reload secondary clip? int secondary = min(iClipSize2 - m_iClip2, pOwner->GetAmmoCount(m_iSecondaryAmmoType)); if ( secondary != 0 ) { bReload = true; } } if ( !bReload ) return false; CDODPlayer *pPlayer = GetDODPlayerOwner(); if ( pPlayer ) { #ifdef CLIENT_DLL PlayWorldReloadSound( pPlayer ); #else pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD ); #endif } SendWeaponAnim( iActivity ); // Play the player's reload animation if ( pOwner->IsPlayer() ) { ( ( CBasePlayer * )pOwner)->SetAnimation( PLAYER_RELOAD ); } float flSequenceEndTime = gpGlobals->curtime + SequenceDuration(); pOwner->SetNextAttack( flSequenceEndTime ); m_flNextPrimaryAttack = m_flNextSecondaryAttack = flSequenceEndTime; m_bInReload = true; return true; }
void CASW_Weapon_Assault_Shotgun::SecondaryAttack() { // Only the player fires this way so we can cast CASW_Player *pPlayer = GetCommander(); if (!pPlayer) return; CASW_Marine *pMarine = GetMarine(); if (!pMarine) return; //Must have ammo bool bUsesSecondary = UsesSecondaryAmmo(); bool bUsesClips = UsesClipsForAmmo2(); int iAmmoCount = pMarine->GetAmmoCount(m_iSecondaryAmmoType); bool bInWater = ( pMarine->GetWaterLevel() == 3 ); if ( (bUsesSecondary && ( ( bUsesClips && m_iClip2 <= 0) || ( !bUsesClips && iAmmoCount<=0 ) ) ) || bInWater || m_bInReload ) { SendWeaponAnim( ACT_VM_DRYFIRE ); BaseClass::WeaponSound( EMPTY ); m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; return; } BaseClass::WeaponSound( SPECIAL1 ); #ifndef CLIENT_DLL pMarine->GetMarineSpeech()->Chatter(CHATTER_GRENADE); Vector vecSrc = pMarine->Weapon_ShootPosition(); Vector vecThrow; // check for turning on lag compensation if (pPlayer && pMarine->IsInhabited()) { CASW_Lag_Compensation::RequestLagCompensation( pPlayer, pPlayer->GetCurrentUserCommand() ); } vecThrow = UTIL_LaunchVector(vecSrc, pPlayer->GetCrosshairTracePos(), asw_vindicator_grenade_gravity.GetFloat()) * 8.0f * asw_vindicator_grenade_velocity.GetFloat(); QAngle angAiming = pPlayer->EyeAnglesWithCursorRoll(); float fGrenadeDamage = MarineSkills()->GetSkillBasedValueByMarine(pMarine, ASW_MARINE_SKILL_GRENADES, ASW_MARINE_SUBSKILL_GRENADE_INCENDIARY_DMG); float fGrenadeRadius = MarineSkills()->GetSkillBasedValueByMarine(pMarine, ASW_MARINE_SKILL_GRENADES, ASW_MARINE_SUBSKILL_GRENADE_RADIUS); if (asw_debug_marine_damage.GetBool()) { Msg("Grenade damage = %f radius = %f\n", fGrenadeDamage, fGrenadeRadius); } // check the grenade fits where we want to spawn it Ray_t ray; trace_t pm; ray.Init( pMarine->WorldSpaceCenter(), vecSrc, -Vector(4,4,4), Vector(4,4,4) ); UTIL_TraceRay( ray, MASK_SOLID, pMarine, COLLISION_GROUP_PROJECTILE, &pm ); if (pm.fraction < 1.0f) vecSrc = pm.endpos; CASW_Grenade_Vindicator::Vindicator_Grenade_Create( fGrenadeDamage, fGrenadeRadius, vecSrc, angAiming, vecThrow, AngularImpulse(0,0,0), pMarine, this ); pMarine->OnWeaponFired( this, 1, true ); #endif SendWeaponAnim( GetPrimaryAttackActivity() ); pMarine->DoAnimationEvent( PLAYERANIMEVENT_FIRE_GUN_PRIMARY ); // Decrease ammo if ( bUsesClips ) { m_iClip2 -= 1; } else { pMarine->RemoveAmmo( 1, m_iSecondaryAmmoType ); } #ifndef CLIENT_DLL ASWFailAdvice()->OnMarineUsedSecondary(); CEffectData data; data.m_vOrigin = GetAbsOrigin(); //data.m_vNormal = dir; //data.m_flScale = (float)amount; CPASFilter filter( data.m_vOrigin ); filter.SetIgnorePredictionCull(true); DispatchParticleEffect( "muzzleflash_grenadelauncher_main", PATTACH_POINT_FOLLOW, this, "muzzle", false, -1, &filter ); #endif // Can shoot again immediately m_flNextPrimaryAttack = gpGlobals->curtime + 0.5f; // Can blow up after a short delay (so have time to release mouse button) m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f; }