blaster/Source/Blaster/Components/CombatComponent.cpp

811 lines
21 KiB
C++
Raw Normal View History

2022-04-30 11:09:28 +00:00
// Fill out your copyright notice in the Description page of Project Settings.
#include "CombatComponent.h"
#include "Blaster/Character/BlasterCharacter.h"
2022-05-05 15:57:57 +00:00
#include "Blaster/PlayerController/BlasterPlayerController.h"
2022-05-26 12:29:39 +00:00
#include "Blaster/Weapon/Shotgun.h"
2022-04-30 11:09:28 +00:00
#include "Blaster/Weapon/Weapon.h"
2022-05-05 19:56:31 +00:00
#include "Camera/CameraComponent.h"
2022-04-30 11:09:28 +00:00
#include "Engine/SkeletalMeshSocket.h"
2022-05-02 13:40:33 +00:00
#include "GameFramework/CharacterMovementComponent.h"
2022-05-04 22:39:17 +00:00
#include "Kismet/GameplayStatics.h"
2022-04-30 14:48:34 +00:00
#include "Net/UnrealNetwork.h"
2022-04-30 11:09:28 +00:00
UCombatComponent::UCombatComponent()
{
2022-05-04 22:39:17 +00:00
PrimaryComponentTick.bCanEverTick = true;
2022-05-03 17:50:47 +00:00
BaseWalkSpeed = 600.f;
2022-05-04 12:57:48 +00:00
AimWalkSpeed = 350.f;
2022-04-30 11:09:28 +00:00
}
2022-05-04 20:57:45 +00:00
void UCombatComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
2022-05-24 10:46:30 +00:00
DOREPLIFETIME(UCombatComponent, PrimaryWeapon);
DOREPLIFETIME(UCombatComponent, SecondaryWeapon);
2022-05-04 20:57:45 +00:00
DOREPLIFETIME(UCombatComponent, bAiming);
2022-05-12 13:37:49 +00:00
DOREPLIFETIME_CONDITION(UCombatComponent, CarriedAmmo, COND_OwnerOnly);
2022-05-09 21:16:55 +00:00
DOREPLIFETIME(UCombatComponent, CombatState);
2022-05-22 13:21:17 +00:00
DOREPLIFETIME(UCombatComponent, Grenades);
2022-05-04 20:57:45 +00:00
}
2022-05-22 20:56:28 +00:00
void UCombatComponent::PickupAmmo(EWeaponType WeaponType, int32 AmmoAmount)
{
if (CarriedAmmoMap.Contains(WeaponType))
{
CarriedAmmoMap[WeaponType] = FMath::Clamp(CarriedAmmoMap[WeaponType] + AmmoAmount, 0, MaxCarriedAmmo);
UpdateCarriedAmmo();
}
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon && PrimaryWeapon->IsEmpty() && PrimaryWeapon->GetWeaponType() == WeaponType)
2022-05-22 20:56:28 +00:00
{
Reload();
}
}
2022-04-30 11:09:28 +00:00
void UCombatComponent::BeginPlay()
{
Super::BeginPlay();
2022-05-03 17:50:47 +00:00
if (Character)
{
Character->GetCharacterMovement()->MaxWalkSpeed = BaseWalkSpeed;
2022-05-05 19:56:31 +00:00
if (Character->GetFollowCamera())
{
DefaultFOV = Character->GetFollowCamera()->FieldOfView;
CurrentFOV = DefaultFOV;
}
2022-05-09 19:07:33 +00:00
if (Character->HasAuthority())
{
InitializeCarriedAmmo();
}
2022-05-03 17:50:47 +00:00
}
2022-04-30 11:09:28 +00:00
}
2022-05-05 15:57:57 +00:00
void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
2022-05-05 20:46:35 +00:00
2022-05-05 18:14:17 +00:00
if (Character && Character->IsLocallyControlled())
{
FHitResult HitResult;
TraceUnderCrosshairs(HitResult);
HitTarget = HitResult.ImpactPoint;
2022-05-05 19:56:31 +00:00
SetHUDCrosshairs(DeltaTime);
InterpFOV(DeltaTime);
2022-05-05 18:14:17 +00:00
}
2022-05-05 15:57:57 +00:00
}
2022-05-12 13:37:49 +00:00
void UCombatComponent::FireButtonPressed(bool bPressed)
2022-05-03 17:50:47 +00:00
{
2022-05-12 13:37:49 +00:00
bFireButtonPressed = bPressed;
2022-05-24 10:46:30 +00:00
if (bFireButtonPressed && PrimaryWeapon)
2022-05-03 17:50:47 +00:00
{
2022-05-12 13:37:49 +00:00
Fire();
2022-05-03 17:50:47 +00:00
}
2022-04-30 15:38:03 +00:00
}
2022-05-20 23:33:02 +00:00
void UCombatComponent::ShotgunShellReload()
{
if (Character && Character->HasAuthority())
{
UpdateShotgunAmmoValues();
}
}
2022-05-06 20:54:23 +00:00
void UCombatComponent::Fire()
2022-05-04 20:13:31 +00:00
{
2022-05-09 16:48:14 +00:00
if (CanFire())
2022-05-04 20:57:45 +00:00
{
2022-05-06 20:54:23 +00:00
bCanFire = false;
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon)
2022-05-05 20:13:12 +00:00
{
2022-05-12 13:37:49 +00:00
CrosshairShootingFactor = .75f;
2022-05-26 12:03:51 +00:00
switch (PrimaryWeapon->FireType)
{
case EFireType::EFT_HitScan:
FireHitScanWeapon();
break;
case EFireType::EFT_Projectile:
FireProjectileWeapon();
break;
case EFireType::EFT_Shotgun:
FireShotgun();
break;
}
2022-05-05 20:13:12 +00:00
}
2022-05-06 20:54:23 +00:00
StartFireTimer();
}
}
2022-05-26 12:03:51 +00:00
void UCombatComponent::FireProjectileWeapon()
{
2022-05-26 13:06:27 +00:00
if (PrimaryWeapon && Character)
2022-05-26 12:29:39 +00:00
{
HitTarget = PrimaryWeapon->bUseScatter ? PrimaryWeapon->TraceEndWithScatter(HitTarget) : HitTarget;
2022-05-26 13:06:27 +00:00
if (!Character->HasAuthority()) LocalFire(HitTarget);
2022-05-26 12:29:39 +00:00
ServerFire(HitTarget);
}
2022-05-26 12:03:51 +00:00
}
void UCombatComponent::FireHitScanWeapon()
{
2022-05-26 13:06:27 +00:00
if (PrimaryWeapon && Character)
2022-05-26 12:03:51 +00:00
{
HitTarget = PrimaryWeapon->bUseScatter ? PrimaryWeapon->TraceEndWithScatter(HitTarget) : HitTarget;
2022-05-26 13:06:27 +00:00
if (!Character->HasAuthority()) LocalFire(HitTarget);
2022-05-26 12:03:51 +00:00
ServerFire(HitTarget);
}
}
void UCombatComponent::FireShotgun()
{
2022-05-26 13:06:27 +00:00
AShotgun* Shotgun = Cast<AShotgun>(PrimaryWeapon);
if (Shotgun && Character)
2022-05-26 12:29:39 +00:00
{
2022-05-26 13:06:27 +00:00
TArray<FVector_NetQuantize> HitTargets;
2022-05-26 12:29:39 +00:00
Shotgun->ShotgunTraceEndWithScatter(HitTarget, HitTargets);
2022-05-26 13:06:27 +00:00
if (!Character->HasAuthority()) ShotgunLocalFire(HitTargets);
ServerShotgunFire(HitTargets);
2022-05-26 12:29:39 +00:00
}
2022-05-26 12:03:51 +00:00
}
2022-05-06 20:54:23 +00:00
void UCombatComponent::StartFireTimer()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr || Character == nullptr) return;
2022-05-12 13:37:49 +00:00
Character->GetWorldTimerManager().SetTimer(
FireTimer,
this,
&UCombatComponent::FireTimerFinished,
2022-05-24 10:46:30 +00:00
PrimaryWeapon->FireDelay
2022-05-12 13:37:49 +00:00
);
2022-05-06 20:54:23 +00:00
}
void UCombatComponent::FireTimerFinished()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return;
2022-05-06 20:54:23 +00:00
bCanFire = true;
2022-05-24 10:46:30 +00:00
if (bFireButtonPressed && PrimaryWeapon->bAutomatic)
2022-05-06 20:54:23 +00:00
{
Fire();
}
ReloadEmptyWeapon();
2022-05-06 20:54:23 +00:00
}
void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
{
MulticastFire(TraceHitTarget);
}
void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget)
2022-05-26 11:29:49 +00:00
{
if (Character && Character->IsLocallyControlled() && !Character->HasAuthority()) return;
LocalFire(TraceHitTarget);
}
2022-05-26 13:06:27 +00:00
void UCombatComponent::ServerShotgunFire_Implementation(const TArray<FVector_NetQuantize>& TraceHitTargets)
{
MulticastShotgunFire(TraceHitTargets);
}
void UCombatComponent::MulticastShotgunFire_Implementation(const TArray<FVector_NetQuantize>& TraceHitTargets)
{
if (Character && Character->IsLocallyControlled() && !Character->HasAuthority()) return;
ShotgunLocalFire(TraceHitTargets);
}
2022-05-26 11:29:49 +00:00
void UCombatComponent::LocalFire(const FVector_NetQuantize& TraceHitTarget)
2022-05-06 20:54:23 +00:00
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return;
2022-05-26 13:06:27 +00:00
if (Character && CombatState == ECombatState::ECS_Unoccupied)
2022-05-20 23:33:02 +00:00
{
Character->PlayFireMontage(bAiming);
2022-05-24 10:46:30 +00:00
PrimaryWeapon->Fire(TraceHitTarget);
2022-05-20 23:33:02 +00:00
}
2022-05-26 13:06:27 +00:00
}
void UCombatComponent::ShotgunLocalFire(const TArray<FVector_NetQuantize>& TraceHitTargets)
{
AShotgun* Shotgun = Cast<AShotgun>(PrimaryWeapon);
if (Shotgun == nullptr || Character == nullptr) return;
if (CombatState == ECombatState::ECS_Reloading || CombatState == ECombatState::ECS_Unoccupied)
2022-05-06 20:54:23 +00:00
{
Character->PlayFireMontage(bAiming);
2022-05-26 13:06:27 +00:00
Shotgun->FireShotgun(TraceHitTargets);
CombatState = ECombatState::ECS_Unoccupied;
2022-05-04 20:57:45 +00:00
}
}
2022-04-30 11:09:28 +00:00
void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip)
{
if (Character == nullptr || WeaponToEquip == nullptr) return;
2022-05-21 10:13:03 +00:00
if (CombatState != ECombatState::ECS_Unoccupied) return;
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon != nullptr && SecondaryWeapon == nullptr)
{
EquipSecondaryWeapon(WeaponToEquip);
}
else
{
EquipPrimaryWeapon(WeaponToEquip);
}
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
}
2022-05-25 13:24:29 +00:00
void UCombatComponent::SwapWeapons()
{
2022-05-26 11:29:49 +00:00
if (CombatState != ECombatState::ECS_Unoccupied) return;
2022-05-25 13:24:29 +00:00
AWeapon* TempWeapon = PrimaryWeapon;
PrimaryWeapon = SecondaryWeapon;
SecondaryWeapon = TempWeapon;
PrimaryWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
AttachActorToRightHand(PrimaryWeapon);
PrimaryWeapon->SetHUDAmmo();
UpdateCarriedAmmo();
PlayEquipWeaponSound(PrimaryWeapon);
SecondaryWeapon->SetWeaponState(EWeaponState::EWS_EquippedSecondary);
AttachActorToBackpack(SecondaryWeapon);
}
bool UCombatComponent::ShouldSwapWeapons()
{
return PrimaryWeapon != nullptr && SecondaryWeapon != nullptr;
}
2022-05-24 10:46:30 +00:00
void UCombatComponent::EquipPrimaryWeapon(AWeapon* WeaponToEquip)
{
if (WeaponToEquip == nullptr) return;
2022-05-24 10:46:30 +00:00
DropPrimaryWeapon();
PrimaryWeapon = WeaponToEquip;
PrimaryWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
AttachActorToRightHand(PrimaryWeapon);
PrimaryWeapon->SetOwner(Character);
PrimaryWeapon->SetHUDAmmo();
UpdateCarriedAmmo();
2022-05-24 10:46:30 +00:00
PlayEquipWeaponSound(PrimaryWeapon);
ReloadEmptyWeapon();
2022-05-24 10:46:30 +00:00
}
void UCombatComponent::EquipSecondaryWeapon(AWeapon* WeaponToEquip)
{
if (WeaponToEquip == nullptr) return;
SecondaryWeapon = WeaponToEquip;
2022-05-25 13:24:29 +00:00
SecondaryWeapon->SetWeaponState(EWeaponState::EWS_EquippedSecondary);
2022-05-24 10:46:30 +00:00
AttachActorToBackpack(WeaponToEquip);
PlayEquipWeaponSound(SecondaryWeapon);
2022-05-25 13:24:29 +00:00
SecondaryWeapon->SetOwner(Character);
}
void UCombatComponent::OnRep_PrimaryWeapon()
{
if (PrimaryWeapon && Character)
{
PrimaryWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
AttachActorToRightHand(PrimaryWeapon);
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
Character->bUseControllerRotationYaw = true;
PlayEquipWeaponSound(PrimaryWeapon);
PrimaryWeapon->SetHUDAmmo();
}
}
void UCombatComponent::OnRep_SecondaryWeapon()
{
if (SecondaryWeapon && Character)
{
SecondaryWeapon->SetWeaponState(EWeaponState::EWS_EquippedSecondary);
AttachActorToBackpack(SecondaryWeapon);
PlayEquipWeaponSound(SecondaryWeapon);
}
}
2022-05-24 10:46:30 +00:00
void UCombatComponent::DropPrimaryWeapon()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon)
2022-05-09 16:39:41 +00:00
{
2022-05-24 10:46:30 +00:00
PrimaryWeapon->Dropped();
2022-05-09 16:39:41 +00:00
}
}
void UCombatComponent::AttachActorToRightHand(AActor* ActorToAttach)
{
if (Character == nullptr || Character->GetMesh() == nullptr|| ActorToAttach == nullptr) return;
2022-04-30 11:09:28 +00:00
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket"));
if (HandSocket)
{
HandSocket->AttachActor(ActorToAttach, Character->GetMesh());
2022-04-30 11:09:28 +00:00
}
}
void UCombatComponent::AttachActorToLeftHand(AActor* ActorToAttach)
{
2022-05-24 10:46:30 +00:00
if (Character == nullptr || Character->GetMesh() == nullptr || ActorToAttach == nullptr || PrimaryWeapon == nullptr) return;
bool bUsePistolSocket = PrimaryWeapon->IsPistol() || PrimaryWeapon->IsSMG();
FName SocketName = bUsePistolSocket ? FName("LeftHandPistolSocket") : FName("LeftHandSocket");
const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(SocketName);
if (HandSocket)
{
HandSocket->AttachActor(ActorToAttach, Character->GetMesh());
}
}
2022-05-09 19:07:33 +00:00
2022-05-24 10:46:30 +00:00
void UCombatComponent::AttachActorToBackpack(AActor* ActorToAttach)
{
if (Character == nullptr || Character->GetMesh() == nullptr|| ActorToAttach == nullptr) return;
const USkeletalMeshSocket* BackpackSocket = Character->GetMesh()->GetSocketByName(FName("BackpackSocket"));
if (BackpackSocket)
{
BackpackSocket->AttachActor(ActorToAttach, Character->GetMesh());
}
}
void UCombatComponent::UpdateCarriedAmmo()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return;
if (CarriedAmmoMap.Contains(PrimaryWeapon->GetWeaponType()))
2022-05-09 19:07:33 +00:00
{
2022-05-24 10:46:30 +00:00
CarriedAmmo = CarriedAmmoMap[PrimaryWeapon->GetWeaponType()];
2022-05-09 19:07:33 +00:00
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
}
2022-05-09 22:35:33 +00:00
2022-05-24 10:46:30 +00:00
void UCombatComponent::PlayEquipWeaponSound(const AWeapon* Weapon)
{
2022-05-24 10:46:30 +00:00
if (Character && Weapon && Weapon->EquipSound)
2022-05-09 22:35:33 +00:00
{
2022-05-12 13:37:49 +00:00
UGameplayStatics::PlaySoundAtLocation(
this,
2022-05-24 10:46:30 +00:00
Weapon->EquipSound,
2022-05-12 13:37:49 +00:00
Character->GetActorLocation()
);
2022-05-09 22:35:33 +00:00
}
}
2022-05-09 22:45:30 +00:00
void UCombatComponent::ReloadEmptyWeapon()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon && PrimaryWeapon->IsEmpty())
2022-05-09 22:45:30 +00:00
{
Reload();
}
2022-04-30 11:09:28 +00:00
}
2022-05-08 17:31:58 +00:00
2022-05-09 20:19:20 +00:00
void UCombatComponent::Reload()
{
2022-05-21 10:13:03 +00:00
if (CarriedAmmo > 0 && CombatState == ECombatState::ECS_Unoccupied)
2022-05-09 20:19:20 +00:00
{
ServerReload();
}
}
2022-05-25 13:49:51 +00:00
void UCombatComponent::DropWeapons()
{
if (PrimaryWeapon) PrimaryWeapon->Dropped();
if (SecondaryWeapon) SecondaryWeapon->Dropped();
}
2022-05-12 13:37:49 +00:00
void UCombatComponent::ServerReload_Implementation()
{
2022-05-24 10:46:30 +00:00
if (Character == nullptr || PrimaryWeapon == nullptr) return;
2022-05-12 13:37:49 +00:00
// return if weapon mag is at max capacity
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon->GetAmmo() == PrimaryWeapon->GetMagCapacity()) return;
2022-05-20 23:33:02 +00:00
2022-05-12 13:37:49 +00:00
CombatState = ECombatState::ECS_Reloading;
HandleReload();
}
2022-05-09 21:16:55 +00:00
void UCombatComponent::FinishedReloading()
{
if (Character == nullptr) return;
if (Character->HasAuthority())
{
2022-05-09 22:00:06 +00:00
CombatState = ECombatState::ECS_Unoccupied;
UpdateAmmoValues();
2022-05-09 21:16:55 +00:00
}
2022-05-09 21:26:59 +00:00
if (bFireButtonPressed)
{
Fire();
}
2022-05-09 21:16:55 +00:00
}
2022-05-09 22:00:06 +00:00
void UCombatComponent::UpdateAmmoValues()
{
2022-05-24 10:46:30 +00:00
if (Character == nullptr || PrimaryWeapon == nullptr) return;
2022-05-12 13:37:49 +00:00
int32 ReloadAmount = AmountToReload();
2022-05-24 10:46:30 +00:00
if (CarriedAmmoMap.Contains(PrimaryWeapon->GetWeaponType()))
2022-05-09 22:00:06 +00:00
{
2022-05-24 10:46:30 +00:00
CarriedAmmoMap[PrimaryWeapon->GetWeaponType()] -= ReloadAmount;
CarriedAmmo = CarriedAmmoMap[PrimaryWeapon->GetWeaponType()];
2022-05-09 22:00:06 +00:00
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
2022-05-26 14:37:53 +00:00
PrimaryWeapon->AddAmmo(ReloadAmount);
2022-05-09 22:00:06 +00:00
}
2022-05-20 23:33:02 +00:00
void UCombatComponent::UpdateShotgunAmmoValues()
{
2022-05-24 10:46:30 +00:00
if (Character == nullptr || PrimaryWeapon == nullptr) return;
2022-05-20 23:33:02 +00:00
2022-05-24 10:46:30 +00:00
if (CarriedAmmoMap.Contains(PrimaryWeapon->GetWeaponType()))
2022-05-20 23:33:02 +00:00
{
2022-05-24 10:46:30 +00:00
CarriedAmmoMap[PrimaryWeapon->GetWeaponType()] -= 1;
CarriedAmmo = CarriedAmmoMap[PrimaryWeapon->GetWeaponType()];
2022-05-20 23:33:02 +00:00
}
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
2022-05-26 14:37:53 +00:00
PrimaryWeapon->AddAmmo(1);
2022-05-20 23:33:02 +00:00
bCanFire = true;
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon->IsFull() || CarriedAmmo == 0)
2022-05-20 23:33:02 +00:00
{
JumpToShotgunEnd();
}
}
void UCombatComponent::JumpToShotgunEnd()
{
// Jump to ShotgunEnd section
UAnimInstance* AnimInstance = Character->GetMesh()->GetAnimInstance();
if (AnimInstance && Character->GetReloadMontage())
{
AnimInstance->Montage_JumpToSection(FName("ShotgunEnd"));
}
}
2022-05-21 10:13:03 +00:00
void UCombatComponent::ThrowGrenadeFinished()
{
CombatState = ECombatState::ECS_Unoccupied;
2022-05-24 10:46:30 +00:00
AttachActorToRightHand(PrimaryWeapon);
2022-05-21 10:13:03 +00:00
}
2022-05-21 15:03:30 +00:00
void UCombatComponent::LaunchGrenade()
{
ShowAttachedGrenade(false);
2022-05-22 12:26:02 +00:00
if (Character && Character->IsLocallyControlled())
{
ServerLaunchGrenade(HitTarget);
}
}
void UCombatComponent::ServerLaunchGrenade_Implementation(const FVector_NetQuantize& Target)
{
if (Character && GrenadeClass && Character->GetAttachedGrenade())
2022-05-22 12:11:35 +00:00
{
const FVector StartingLocation = Character->GetAttachedGrenade()->GetComponentLocation();
2022-05-22 12:26:02 +00:00
FVector ToTarget = Target - StartingLocation;
2022-05-22 12:11:35 +00:00
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = Character;
SpawnParams.Instigator = Character;
UWorld* World = GetWorld();
if (World)
{
World->SpawnActor<AProjectile>(
GrenadeClass,
StartingLocation + 10.f,
ToTarget.Rotation(),
SpawnParams
);
}
}
2022-05-21 15:03:30 +00:00
}
2022-05-09 21:16:55 +00:00
void UCombatComponent::OnRep_CombatState()
{
switch (CombatState)
{
case ECombatState::ECS_Reloading:
HandleReload();
break;
2022-05-09 21:26:59 +00:00
case ECombatState::ECS_Unoccupied:
if (bFireButtonPressed)
{
Fire();
}
break;
2022-05-21 10:13:03 +00:00
case ECombatState::ECS_ThrowingGrenade:
if (Character && !Character->IsLocallyControlled())
{
Character->PlayThrowGrenadeMontage();
2022-05-24 10:46:30 +00:00
AttachActorToLeftHand(PrimaryWeapon);
2022-05-21 15:03:30 +00:00
ShowAttachedGrenade(true);
2022-05-21 10:13:03 +00:00
}
break;
2022-05-09 21:16:55 +00:00
}
}
void UCombatComponent::HandleReload()
{
2022-05-09 20:19:20 +00:00
Character->PlayReloadMontage();
}
2022-05-09 22:00:06 +00:00
int32 UCombatComponent::AmountToReload()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return 0;
int32 RoomInMag = PrimaryWeapon->GetMagCapacity() - PrimaryWeapon->GetAmmo();
2022-05-09 22:00:06 +00:00
2022-05-24 10:46:30 +00:00
if (CarriedAmmoMap.Contains(PrimaryWeapon->GetWeaponType()))
2022-05-09 22:00:06 +00:00
{
2022-05-24 10:46:30 +00:00
int32 AmountCarried = CarriedAmmoMap[PrimaryWeapon->GetWeaponType()];
2022-05-12 13:37:49 +00:00
int32 Least = FMath::Min(RoomInMag, AmountCarried);
2022-05-09 22:00:06 +00:00
return FMath::Clamp(RoomInMag, 0, Least);
}
return 0;
}
2022-05-21 10:13:03 +00:00
void UCombatComponent::ThrowGrenade()
{
2022-05-22 13:21:17 +00:00
if (Grenades == 0) return;
2022-05-24 10:46:30 +00:00
if (CombatState != ECombatState::ECS_Unoccupied || PrimaryWeapon == nullptr) return;
2022-05-21 10:13:03 +00:00
CombatState = ECombatState::ECS_ThrowingGrenade;
if (Character)
{
Character->PlayThrowGrenadeMontage();
2022-05-24 10:46:30 +00:00
AttachActorToLeftHand(PrimaryWeapon);
2022-05-21 15:03:30 +00:00
ShowAttachedGrenade(true);
2022-05-21 10:13:03 +00:00
}
if (Character && !Character->HasAuthority())
{
ServerThrowGrenade();
}
2022-05-22 13:21:17 +00:00
if (Character && Character->HasAuthority())
{
Grenades = FMath::Clamp(Grenades -1, 0, MaxGrenades);
UpdateHUDGrenades();
}
2022-05-21 10:13:03 +00:00
}
void UCombatComponent::ServerThrowGrenade_Implementation()
{
2022-05-22 13:21:17 +00:00
if (Grenades == 0) return;
2022-05-21 10:13:03 +00:00
CombatState = ECombatState::ECS_ThrowingGrenade;
if (Character)
{
Character->PlayThrowGrenadeMontage();
2022-05-24 10:46:30 +00:00
AttachActorToLeftHand(PrimaryWeapon);
2022-05-21 15:03:30 +00:00
ShowAttachedGrenade(true);
}
2022-05-22 13:21:17 +00:00
Grenades = FMath::Clamp(Grenades -1, 0, MaxGrenades);
UpdateHUDGrenades();
}
void UCombatComponent::OnRep_Grenades()
{
UpdateHUDGrenades();
}
void UCombatComponent::UpdateHUDGrenades()
{
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDGrenades(Grenades);
}
2022-05-21 15:03:30 +00:00
}
void UCombatComponent::ShowAttachedGrenade(bool bShowGrenade)
{
if (Character && Character->GetAttachedGrenade())
{
Character->GetAttachedGrenade()->SetVisibility(bShowGrenade);
2022-05-21 10:13:03 +00:00
}
}
2022-05-12 13:37:49 +00:00
void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult)
{
FVector2D ViewportSize;
if (GEngine && GEngine->GameViewport)
{
GEngine->GameViewport->GetViewportSize(ViewportSize);
}
FVector2D CrosshairLocation(ViewportSize.X / 2.f, ViewportSize.Y / 2.f);
FVector CrosshairWorldPosition;
FVector CrosshairWorldDirection;
bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld(
UGameplayStatics::GetPlayerController(this, 0),
CrosshairLocation,
CrosshairWorldPosition,
CrosshairWorldDirection
);
if (bScreenToWorld)
{
FVector Start = CrosshairWorldPosition;
if (Character)
{
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
Start += CrosshairWorldDirection * (DistanceToCharacter + 100.f);
}
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
GetWorld()->LineTraceSingleByChannel(
TraceHitResult,
Start,
End,
ECollisionChannel::ECC_Visibility
);
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
{
HUDPackage.CrosshairsColor = FLinearColor::Red;
}
else
{
HUDPackage.CrosshairsColor = FLinearColor::White;
}
if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End;
}
}
void UCombatComponent::SetHUDCrosshairs(float DeltaTime)
{
if (Character == nullptr || Character->Controller == nullptr) return;
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
HUD = HUD == nullptr ? Cast<ABlasterHUD>(Controller->GetHUD()) : HUD;
if (HUD)
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon)
2022-05-12 13:37:49 +00:00
{
2022-05-24 10:46:30 +00:00
HUDPackage.CrosshairsCenter = PrimaryWeapon->CrosshairsCenter;
HUDPackage.CrosshairsLeft = PrimaryWeapon->CrosshairsLeft;
HUDPackage.CrosshairsRight = PrimaryWeapon->CrosshairsRight;
HUDPackage.CrosshairsBottom = PrimaryWeapon->CrosshairsBottom;
HUDPackage.CrosshairsTop = PrimaryWeapon->CrosshairsTop;
2022-05-12 13:37:49 +00:00
}
else
{
HUDPackage.CrosshairsCenter = nullptr;
HUDPackage.CrosshairsLeft = nullptr;
HUDPackage.CrosshairsRight = nullptr;
HUDPackage.CrosshairsBottom = nullptr;
HUDPackage.CrosshairsTop = nullptr;
}
// Calculate crosshair spread
// [0, 600] -> [0, 1]
FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed);
FVector2D VelocityMultiplierRange(0.f, 1.f);
FVector Velocity = Character->GetVelocity();
Velocity.Z = 0.f;
CrosshairVelocityFactor = FMath::GetMappedRangeValueClamped(WalkSpeedRange, VelocityMultiplierRange, Velocity.Size());
if (Character->GetCharacterMovement()->IsFalling())
{
CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 2.25f, DeltaTime, 2.25f);
}
else
{
CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 0.f, DeltaTime, 30.f);
}
if (bAiming)
{
CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.58f, DeltaTime, 30.f);
}
else
{
CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.f, DeltaTime, 30.f);
}
CrosshairShootingFactor = FMath::FInterpTo(CrosshairShootingFactor, 0.f, DeltaTime, 40.f);
HUDPackage.CrosshairSpread =
0.5f +
CrosshairVelocityFactor +
CrosshairInAirFactor -
CrosshairAimFactor +
CrosshairShootingFactor;
HUD->SetHUDPackage(HUDPackage);
}
}
}
void UCombatComponent::InterpFOV(float DeltaTime)
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return;
2022-05-12 13:37:49 +00:00
if (bAiming)
{
2022-05-24 10:46:30 +00:00
CurrentFOV = FMath::FInterpTo(CurrentFOV, PrimaryWeapon->GetZoomedFOV(), DeltaTime, PrimaryWeapon->GetZoomInterpSpeed());
2022-05-12 13:37:49 +00:00
}
else
{
CurrentFOV = FMath::FInterpTo(CurrentFOV, DefaultFOV, DeltaTime, ZoomInterpSpeed);
}
if (Character && Character->GetFollowCamera())
{
Character->GetFollowCamera()->SetFieldOfView(CurrentFOV);
}
}
void UCombatComponent::SetAiming(bool bIsAiming)
{
2022-05-24 10:46:30 +00:00
if (Character == nullptr || PrimaryWeapon == nullptr) return;
2022-05-12 13:37:49 +00:00
bAiming = bIsAiming;
ServerSetAiming(bIsAiming);
if (Character)
{
Character->GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? AimWalkSpeed : BaseWalkSpeed;
}
2022-05-24 10:46:30 +00:00
if (Character->IsLocallyControlled() && PrimaryWeapon->IsSniper())
2022-05-12 13:37:49 +00:00
{
2022-05-20 14:12:12 +00:00
Character->ShowSniperScopeWidget(bIsAiming);
2022-05-12 13:37:49 +00:00
}
}
void UCombatComponent::ServerSetAiming_Implementation(bool bIsAiming)
{
bAiming = bIsAiming;
if (Character)
{
Character->GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? AimWalkSpeed : BaseWalkSpeed;
}
}
bool UCombatComponent::CanFire()
{
2022-05-24 10:46:30 +00:00
if (PrimaryWeapon == nullptr) return false;
if (PrimaryWeapon->IsEmpty()) return false;
2022-05-20 23:33:02 +00:00
if (!bCanFire) return false;
2022-05-24 10:46:30 +00:00
if (CombatState == ECombatState::ECS_Reloading && PrimaryWeapon->GetWeaponType() == EWeaponType::EWT_Shotgun) return true;
2022-05-20 23:33:02 +00:00
return CombatState == ECombatState::ECS_Unoccupied;
2022-05-12 13:37:49 +00:00
}
void UCombatComponent::OnRep_CarriedAmmo()
{
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
if (Controller)
{
Controller->SetHUDCarriedAmmo(CarriedAmmo);
}
2022-05-20 23:33:02 +00:00
bool bJumpToShotgunEnd = CombatState == ECombatState::ECS_Reloading &&
2022-05-24 10:46:30 +00:00
PrimaryWeapon != nullptr &&
PrimaryWeapon->GetWeaponType() == EWeaponType::EWT_Shotgun &&
2022-05-20 23:33:02 +00:00
CarriedAmmo == 0;
if (bJumpToShotgunEnd)
{
JumpToShotgunEnd();
}
2022-05-12 13:37:49 +00:00
}
void UCombatComponent::InitializeCarriedAmmo()
{
CarriedAmmoMap.Emplace(EWeaponType::EWT_AssaultRifle, StartingARAmmo);
2022-05-18 12:44:39 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_RocketLauncher, StartingRocketAmmo);
2022-05-19 17:13:21 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_Pistol, StartingPistolAmmo);
2022-05-19 18:51:50 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_SubmachineGun, StartingSMGAmmo);
2022-05-20 10:10:21 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_Shotgun, StartingShotgunAmmo);
2022-05-20 12:59:40 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_SniperRifle, StartingSniperAmmo);
2022-05-20 14:29:14 +00:00
CarriedAmmoMap.Emplace(EWeaponType::EWT_GrenadeLauncher, StartingGrenadeLauncherAmmo);
2022-05-12 13:37:49 +00:00
}