void AAWeapon::HandleFiring() { if (CurrentAmmoInClip > 0 && CanFire()) { if (GetNetMode() != NM_DedicatedServer) { SimulateWeaponFire(); } if (MyPawn && MyPawn->IsLocallyControlled()) { FireWeapon(); UseAmmo(); BurstCounter++; } } else if (CanReload()) { StartReload(); } else if (MyPawn && MyPawn->IsLocallyControlled()) { if (GetCurrentAmmo() == 0 && !bRefiring) { PlayWeaponSound(OutOfAmmoSound); } /* Reload after firing last round */ if (CurrentAmmoInClip <= 0 && CanReload()) { StartReload(); } /* Stop weapon fire FX, but stay in firing state */ if (BurstCounter > 0) { OnBurstFinished(); } } if (MyPawn && MyPawn->IsLocallyControlled()) { if (Role < ROLE_Authority) { ServerHandleFiring(); } /* Retrigger HandleFiring on a delay for automatic weapons */ bRefiring = (CurrentState == EWeaponState::Firing && TimeBetweenShots > 0.0f); if (bRefiring) { GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AAWeapon::HandleFiring, TimeBetweenShots, false); } } LastFireTime = GetWorld()->GetTimeSeconds(); }
void AWeapon::HandleFiring() { if ((CurrentAmmoInClip > 0 || HasInfiniteClip() || HasInfiniteAmmo()) && CanFire()) { if (GetNetMode() != NM_DedicatedServer) { SimulateWeaponFire(); } if (MyPawn && MyPawn->IsLocallyControlled()) { FireWeapon(); UseAmmo(); // update firing FX on remote clients if function was called on server BurstCounter++; } } else if (CanReload()) { StartReload(); } else if (MyPawn && MyPawn->IsLocallyControlled()) { // stop weapon fire FX, but stay in Firing state if (BurstCounter > 0) { OnBurstFinished(); } } if (MyPawn && MyPawn->IsLocallyControlled()) { // local client will notify server if (Role < ROLE_Authority) { ServerHandleFiring(); } // reload after firing last round if (CurrentAmmoInClip <= 0 && CanReload()) { StartReload(); } // setup refire timer bRefiring = (CurrentState == EWeaponState::Firing && WeaponConfig.TimeBetweenShots > 0.0f); if (bRefiring) { GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &AWeapon::HandleFiring, WeaponConfig.TimeBetweenShots, false); } } LastFireTime = GetWorld()->GetTimeSeconds(); }
void AShooterWeapon::DetermineWeaponState() { EWeaponState::Type NewState = EWeaponState::Idle; if (bIsEquipped) { if( bPendingReload ) { if( CanReload() == false ) { NewState = CurrentState; } else { NewState = EWeaponState::Reloading; } } else if ( (bPendingReload == false ) && ( bWantsToFire == true ) && ( CanFire() == true )) { NewState = EWeaponState::Firing; } } else if (bPendingEquip) { NewState = EWeaponState::Equipping; } SetWeaponState(NewState); }
void AShooterWeapon::StartReload(bool bFromReplication) { if (!bFromReplication && Role < ROLE_Authority) { ServerStartReload(); } if (bFromReplication || CanReload()) { bPendingReload = true; DetermineWeaponState(); float AnimDuration = PlayWeaponAnimation(ReloadAnim); if (AnimDuration <= 0.0f) { AnimDuration = WeaponConfig.NoAnimReloadDuration; } GetWorldTimerManager().SetTimer(TimerHandle_StopReload, this, &AShooterWeapon::StopReload, AnimDuration, false); if (Role == ROLE_Authority) { GetWorldTimerManager().SetTimer(TimerHandle_ReloadWeapon, this, &AShooterWeapon::ReloadWeapon, FMath::Max(0.1f, AnimDuration - 0.1f), false); } if (MyPawn && MyPawn->IsLocallyControlled()) { PlayWeaponSound(ReloadSound); } } }
void ASWeapon::StartReload(bool bFromReplication) { /* Push the request to server */ if (!bFromReplication && Role < ROLE_Authority) { ServerStartReload(); } /* If local execute requested or we are running on the server */ if (bFromReplication || CanReload()) { bPendingReload = true; DetermineWeaponState(); float AnimDuration = PlayWeaponAnimation(ReloadAnim); if (AnimDuration <= 0.0f) { AnimDuration = NoAnimReloadDuration; } GetWorldTimerManager().SetTimer(TimerHandle_StopReload, this, &ASWeapon::StopSimulateReload, AnimDuration, false); if (Role == ROLE_Authority) { GetWorldTimerManager().SetTimer(TimerHandle_ReloadWeapon, this, &ASWeapon::ReloadWeapon, FMath::Max(0.1f, AnimDuration - 0.1f), false); } if (MyPawn && MyPawn->IsLocallyControlled()) { PlayWeaponSound(ReloadSound); } } }
void ASWeapon::DetermineWeaponState() { EWeaponState NewState = EWeaponState::Idle; if (bIsEquipped) { if (bPendingReload) { if (CanReload()) { NewState = EWeaponState::Reloading; } else { NewState = CurrentState; } } else if (!bPendingReload && bWantsToFire && CanFire()) { NewState = EWeaponState::Firing; } } else if (bPendingEquip) { NewState = EWeaponState::Equipping; } SetWeaponState(NewState); }
// Pre Fire void AWeapon::PreFire() { // BP Pre Fire BP_PreFire(); if (!ThePlayer)return; // If player stopped shooting stop event if (!bShooting ) { ThePlayer->GetWorldTimerManager().ClearTimer(PreFireTimeHandle); return; } // Currently Equiping this weapon, delay a bit if (ThePlayer->IsAnimState(EAnimState::Equip)) { // try after a small delay FTimerHandle MyHandle; ThePlayer->GetWorldTimerManager().SetTimer(MyHandle, this, &AWeapon::PreFire, 0.2, false); return; } // Wrong Weapon or Player Anim State if (!CanShoot())return; // Ammo Check if (!MainFire.CanFire()) { // BP No Ammo BP_NoAmmo(); // if have ammo, start reloading if (CanReload())ReloadWeaponStart(); return; } // The real fire event Fire(); // Use Ammo if (bUseAmmo)UseMainFireAmmo(); // Set Player Anim State ThePlayer->ServerSetAnimID(EAnimState::Fire); // Decrease move speed when shooting ThePlayer->ResetMoveSpeed(); /// Stop Fire Anim FTimerHandle MyHandle; ThePlayer->GetWorldTimerManager().SetTimer(MyHandle, this, &AWeapon::StopFireAnim, 0.1, false); }
int32 ASWeapon::GiveAmmo(int32 AddAmount) { const int32 MissingAmmo = FMath::Max(0, MaxAmmo - CurrentAmmo); AddAmount = FMath::Min(AddAmount, MissingAmmo); CurrentAmmo += AddAmount; /* Push reload request to client */ if (GetCurrentAmmoInClip() <= 0 && CanReload() && MyPawn->GetCurrentWeapon() == this) { ClientStartReload(); } /* Return the unused ammo when weapon is filled up */ return FMath::Max(0, AddAmount - MissingAmmo); }
void AAWeapon::OnEquipFinished() { AttachMeshToPawn(); bIsEquipped = true; bPendingEquip = false; DetermineWeaponState(); if (MyPawn) { if (MyPawn->IsLocallyControlled() && CurrentAmmoInClip <= 0 && CanReload()) { StartReload(); } } }
void AWeapon::StartReload(bool bFromReplication) { if (!bFromReplication && Role < ROLE_Authority) { ServerStartReload(); } if (bFromReplication || CanReload()) { bPendingReload = true; DetermineWeaponState(); GetWorldTimerManager().SetTimer(TimerHandle_StopReload, this, &AWeapon::StopReload, ReloadDuration, false); if (Role == ROLE_Authority) { GetWorldTimerManager().SetTimer(TimerHandle_ReloadWeapon, this, &AWeapon::ReloadWeapon, FMath::Max(0.1f, ReloadDuration - 0.1f), false); } } }
void AShooterWeapon::GiveAmmo(int AddAmount) { const int32 MissingAmmo = FMath::Max(0, WeaponConfig.MaxAmmo - CurrentAmmo); AddAmount = FMath::Min(AddAmount, MissingAmmo); CurrentAmmo += AddAmount; AShooterAIController* BotAI = MyPawn ? Cast<AShooterAIController>(MyPawn->GetController()) : NULL; if (BotAI) { BotAI->CheckAmmo(this); } // start reload if clip was empty if (GetCurrentAmmoInClip() <= 0 && CanReload() && MyPawn->GetWeapon() == this) { ClientStartReload(); } }
void AShooterWeapon::OnEquipFinished() { AttachMeshToPawn(); bIsEquipped = true; bPendingEquip = false; // Determine the state so that the can reload checks will work DetermineWeaponState(); if (MyPawn) { // try to reload empty clip if (MyPawn->IsLocallyControlled() && CurrentAmmoInClip <= 0 && CanReload()) { StartReload(); } } }
void ASWeapon::HandleFiring() { if (CurrentAmmoInClip > 0 && CanFire()) { if (GetNetMode() != NM_DedicatedServer) { SimulateWeaponFire(); } if (MyPawn && MyPawn->IsLocallyControlled()) { FireWeapon(); UseAmmo(); // Update firing FX on remote clients if this is called on server BurstCounter++; } } else if (CanReload()) { StartReload(); } else if (MyPawn && MyPawn->IsLocallyControlled()) { if (GetCurrentAmmo() == 0 && !bRefiring) { PlayWeaponSound(OutOfAmmoSound); } /* Reload after firing last round */ if (CurrentAmmoInClip <= 0 && CanReload()) { StartReload(); } /* Stop weapon fire FX, but stay in firing state */ if (BurstCounter > 0) { OnBurstFinished(); } } if (MyPawn && MyPawn->IsLocallyControlled()) { if (Role < ROLE_Authority) { ServerHandleFiring(); } /* Retrigger HandleFiring on a delay for automatic weapons */ bRefiring = (CurrentState == EWeaponState::Firing && TimeBetweenShots > 0.0f); if (bRefiring) { GetWorldTimerManager().SetTimer(TimerHandle_HandleFiring, this, &ASWeapon::HandleFiring, TimeBetweenShots, false); } } /* Make Noise on every shot. The data is managed by the PawnNoiseEmitterComponent created in SBaseCharacter and used by PawnSensingComponent in SZombieCharacter */ if (MyPawn) { MyPawn->MakePawnNoise(1.0f); } LastFireTime = GetWorld()->GetTimeSeconds(); }
/* ===================== CBasePlayerWeapon::ItemPostFrame Handles weapon firing, reloading, etc. ===================== */ void CBasePlayerWeapon::ItemPostFrame( void ) { WeaponTick(); if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { #ifdef SERVER_DLL // FIXME, need ammo on client to make this work right // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ); // Add them to the clip m_iClip += j; m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] -= j; #else m_iClip += 10; #endif m_fInReload = false; } #ifdef SERVER_DLL if( !m_pPlayer->GetButtons().Any( IN_ATTACK ) ) { m_flLastFireTime = 0.0f; } #endif if( m_pPlayer->GetButtons().Any( IN_ATTACK2 ) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, IsPredicted() ) ) { if( pszAmmo2() && !m_pPlayer->m_rgAmmo[ SecondaryAmmoIndex() ] ) { m_bFireOnEmpty = true; } SecondaryAttack(); m_pPlayer->GetButtons().ClearFlags( IN_ATTACK2 ); } else if( m_pPlayer->GetButtons().Any( IN_ATTACK ) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, IsPredicted() ) ) { if( ( m_iClip == 0 && pszAmmo1() ) || ( iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ) ) { m_bFireOnEmpty = true; } PrimaryAttack(); } else if( m_pPlayer->GetButtons().Any( IN_RELOAD ) && 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->GetButtons().Any( IN_ATTACK | IN_ATTACK2 ) ) { // no fire buttons down m_bFireOnEmpty = false; //Only the server checks for weapon switching. - Solokiller #ifdef SERVER_DLL if( !IsUseable() && m_flNextPrimaryAttack < ( IsPredicted() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if( !( iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY ) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { m_flNextPrimaryAttack = ( IsPredicted() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else #endif { // 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 ) && CanReload( m_flNextPrimaryAttack, gpGlobals->time, IsPredicted() ) ) { Reload(); return; } } WeaponIdle(); return; } // catch all if( ShouldWeaponIdle() ) { WeaponIdle(); } }