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-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);
|
|
|
|
|
|
|
|
DOREPLIFETIME(UCombatComponent, EquippedWeapon);
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
if (EquippedWeapon && EquippedWeapon->IsEmpty() && EquippedWeapon->GetWeaponType() == WeaponType)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
if (bFireButtonPressed && EquippedWeapon)
|
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;
|
|
|
|
ServerFire(HitTarget);
|
2022-05-05 20:13:12 +00:00
|
|
|
if (EquippedWeapon)
|
|
|
|
{
|
2022-05-12 13:37:49 +00:00
|
|
|
CrosshairShootingFactor = .75f;
|
2022-05-05 20:13:12 +00:00
|
|
|
}
|
2022-05-06 20:54:23 +00:00
|
|
|
StartFireTimer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UCombatComponent::StartFireTimer()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr || Character == nullptr) return;
|
2022-05-12 13:37:49 +00:00
|
|
|
Character->GetWorldTimerManager().SetTimer(
|
|
|
|
FireTimer,
|
|
|
|
this,
|
|
|
|
&UCombatComponent::FireTimerFinished,
|
|
|
|
EquippedWeapon->FireDelay
|
|
|
|
);
|
2022-05-06 20:54:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UCombatComponent::FireTimerFinished()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return;
|
|
|
|
bCanFire = true;
|
|
|
|
if (bFireButtonPressed && EquippedWeapon->bAutomatic)
|
|
|
|
{
|
|
|
|
Fire();
|
|
|
|
}
|
2022-05-21 13:40:49 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return;
|
2022-05-21 13:40:49 +00:00
|
|
|
if (Character && CombatState == ECombatState::ECS_Reloading && EquippedWeapon->IsShotgun())
|
2022-05-20 23:33:02 +00:00
|
|
|
{
|
|
|
|
Character->PlayFireMontage(bAiming);
|
|
|
|
EquippedWeapon->Fire(TraceHitTarget);
|
|
|
|
CombatState = ECombatState::ECS_Unoccupied;
|
|
|
|
return;
|
|
|
|
}
|
2022-05-09 21:26:59 +00:00
|
|
|
if (Character && CombatState == ECombatState::ECS_Unoccupied)
|
2022-05-06 20:54:23 +00:00
|
|
|
{
|
|
|
|
Character->PlayFireMontage(bAiming);
|
|
|
|
EquippedWeapon->Fire(TraceHitTarget);
|
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-21 13:40:49 +00:00
|
|
|
|
|
|
|
DropEquippedWeapon();
|
|
|
|
EquippedWeapon = WeaponToEquip;
|
|
|
|
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
|
|
|
AttachActorToRightHand(EquippedWeapon);
|
|
|
|
EquippedWeapon->SetOwner(Character);
|
|
|
|
EquippedWeapon->SetHUDAmmo();
|
|
|
|
UpdateCarriedAmmo();
|
|
|
|
PlayEquipWeaponSound();
|
|
|
|
ReloadEmptyWeapon();
|
|
|
|
|
|
|
|
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
|
|
|
Character->bUseControllerRotationYaw = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UCombatComponent::DropEquippedWeapon()
|
|
|
|
{
|
2022-05-09 16:39:41 +00:00
|
|
|
if (EquippedWeapon)
|
|
|
|
{
|
|
|
|
EquippedWeapon->Dropped();
|
|
|
|
}
|
2022-05-21 13:40:49 +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)
|
|
|
|
{
|
2022-05-21 13:40:49 +00:00
|
|
|
HandSocket->AttachActor(ActorToAttach, Character->GetMesh());
|
2022-04-30 11:09:28 +00:00
|
|
|
}
|
2022-05-21 13:40:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UCombatComponent::AttachActorToLeftHand(AActor* ActorToAttach)
|
|
|
|
{
|
|
|
|
if (Character == nullptr || Character->GetMesh() == nullptr || ActorToAttach == nullptr || EquippedWeapon == nullptr) return;
|
|
|
|
bool bUsePistolSocket = EquippedWeapon->IsPistol() || EquippedWeapon->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-21 13:40:49 +00:00
|
|
|
void UCombatComponent::UpdateCarriedAmmo()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return;
|
2022-05-09 19:07:33 +00:00
|
|
|
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
|
|
|
{
|
|
|
|
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
|
|
|
}
|
|
|
|
|
|
|
|
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
|
|
|
if (Controller)
|
|
|
|
{
|
|
|
|
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
|
|
|
}
|
2022-05-21 13:40:49 +00:00
|
|
|
}
|
2022-05-09 22:35:33 +00:00
|
|
|
|
2022-05-21 13:40:49 +00:00
|
|
|
void UCombatComponent::PlayEquipWeaponSound()
|
|
|
|
{
|
|
|
|
if (Character && EquippedWeapon && EquippedWeapon->EquipSound)
|
2022-05-09 22:35:33 +00:00
|
|
|
{
|
2022-05-12 13:37:49 +00:00
|
|
|
UGameplayStatics::PlaySoundAtLocation(
|
|
|
|
this,
|
|
|
|
EquippedWeapon->EquipSound,
|
|
|
|
Character->GetActorLocation()
|
|
|
|
);
|
2022-05-09 22:35:33 +00:00
|
|
|
}
|
2022-05-21 13:40:49 +00:00
|
|
|
}
|
2022-05-09 22:45:30 +00:00
|
|
|
|
2022-05-21 13:40:49 +00:00
|
|
|
void UCombatComponent::ReloadEmptyWeapon()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon && EquippedWeapon->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-12 13:37:49 +00:00
|
|
|
void UCombatComponent::ServerReload_Implementation()
|
|
|
|
{
|
|
|
|
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
|
|
|
|
|
|
|
// return if weapon mag is at max capacity
|
|
|
|
if (EquippedWeapon->GetAmmo() == EquippedWeapon->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()
|
|
|
|
{
|
|
|
|
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
2022-05-12 13:37:49 +00:00
|
|
|
int32 ReloadAmount = AmountToReload();
|
2022-05-09 22:00:06 +00:00
|
|
|
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
|
|
|
{
|
|
|
|
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= ReloadAmount;
|
|
|
|
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
|
|
|
}
|
|
|
|
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
|
|
|
if (Controller)
|
|
|
|
{
|
|
|
|
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
|
|
|
}
|
|
|
|
EquippedWeapon->AddAmmo(-ReloadAmount);
|
|
|
|
}
|
|
|
|
|
2022-05-20 23:33:02 +00:00
|
|
|
void UCombatComponent::UpdateShotgunAmmoValues()
|
|
|
|
{
|
|
|
|
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
|
|
|
|
|
|
|
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
|
|
|
{
|
|
|
|
CarriedAmmoMap[EquippedWeapon->GetWeaponType()] -= 1;
|
|
|
|
CarriedAmmo = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
|
|
|
}
|
|
|
|
Controller = Controller == nullptr ? Cast<ABlasterPlayerController>(Character->Controller) : Controller;
|
|
|
|
if (Controller)
|
|
|
|
{
|
|
|
|
Controller->SetHUDCarriedAmmo(CarriedAmmo);
|
|
|
|
}
|
|
|
|
EquippedWeapon->AddAmmo(-1);
|
|
|
|
bCanFire = true;
|
|
|
|
if (EquippedWeapon->IsFull() || CarriedAmmo == 0)
|
|
|
|
{
|
|
|
|
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-21 13:40:49 +00:00
|
|
|
AttachActorToRightHand(EquippedWeapon);
|
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-21 13:40:49 +00:00
|
|
|
AttachActorToLeftHand(EquippedWeapon);
|
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()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return 0;
|
2022-05-12 13:37:49 +00:00
|
|
|
int32 RoomInMag = EquippedWeapon->GetMagCapacity() - EquippedWeapon->GetAmmo();
|
2022-05-09 22:00:06 +00:00
|
|
|
|
|
|
|
if (CarriedAmmoMap.Contains(EquippedWeapon->GetWeaponType()))
|
|
|
|
{
|
2022-05-12 13:37:49 +00:00
|
|
|
int32 AmountCarried = CarriedAmmoMap[EquippedWeapon->GetWeaponType()];
|
|
|
|
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-22 12:11:35 +00:00
|
|
|
if (CombatState != ECombatState::ECS_Unoccupied || EquippedWeapon == nullptr) return;
|
2022-05-21 10:13:03 +00:00
|
|
|
CombatState = ECombatState::ECS_ThrowingGrenade;
|
|
|
|
if (Character)
|
|
|
|
{
|
|
|
|
Character->PlayThrowGrenadeMontage();
|
2022-05-21 13:40:49 +00:00
|
|
|
AttachActorToLeftHand(EquippedWeapon);
|
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-21 13:40:49 +00:00
|
|
|
AttachActorToLeftHand(EquippedWeapon);
|
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-08 17:31:58 +00:00
|
|
|
void UCombatComponent::OnRep_EquippedWeapon()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon && Character)
|
|
|
|
{
|
|
|
|
EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped);
|
2022-05-21 13:40:49 +00:00
|
|
|
AttachActorToRightHand(EquippedWeapon);
|
2022-05-12 13:37:49 +00:00
|
|
|
Character->GetCharacterMovement()->bOrientRotationToMovement = false;
|
|
|
|
Character->bUseControllerRotationYaw = true;
|
2022-05-21 13:40:49 +00:00
|
|
|
PlayEquipWeaponSound();
|
2022-05-08 17:31:58 +00:00
|
|
|
}
|
2022-05-09 20:19:20 +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)
|
|
|
|
{
|
|
|
|
if (EquippedWeapon)
|
|
|
|
{
|
|
|
|
HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter;
|
|
|
|
HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft;
|
|
|
|
HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight;
|
|
|
|
HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom;
|
|
|
|
HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop;
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return;
|
|
|
|
|
|
|
|
if (bAiming)
|
|
|
|
{
|
|
|
|
CurrentFOV = FMath::FInterpTo(CurrentFOV, EquippedWeapon->GetZoomedFOV(), DeltaTime, EquippedWeapon->GetZoomInterpSpeed());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CurrentFOV = FMath::FInterpTo(CurrentFOV, DefaultFOV, DeltaTime, ZoomInterpSpeed);
|
|
|
|
}
|
|
|
|
if (Character && Character->GetFollowCamera())
|
|
|
|
{
|
|
|
|
Character->GetFollowCamera()->SetFieldOfView(CurrentFOV);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UCombatComponent::SetAiming(bool bIsAiming)
|
|
|
|
{
|
2022-05-20 14:12:12 +00:00
|
|
|
if (Character == nullptr || EquippedWeapon == nullptr) return;
|
2022-05-12 13:37:49 +00:00
|
|
|
bAiming = bIsAiming;
|
|
|
|
ServerSetAiming(bIsAiming);
|
2022-05-21 13:40:49 +00:00
|
|
|
if (Character)
|
|
|
|
{
|
|
|
|
Character->GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? AimWalkSpeed : BaseWalkSpeed;
|
|
|
|
}
|
|
|
|
if (Character->IsLocallyControlled() && EquippedWeapon->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()
|
|
|
|
{
|
|
|
|
if (EquippedWeapon == nullptr) return false;
|
2022-05-20 23:33:02 +00:00
|
|
|
if (EquippedWeapon->IsEmpty()) return false;
|
|
|
|
if (!bCanFire) return false;
|
|
|
|
if (CombatState == ECombatState::ECS_Reloading && EquippedWeapon->GetWeaponType() == EWeaponType::EWT_Shotgun) return true;
|
|
|
|
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 &&
|
|
|
|
EquippedWeapon != nullptr &&
|
|
|
|
EquippedWeapon->GetWeaponType() == EWeaponType::EWT_Shotgun &&
|
|
|
|
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
|
|
|
}
|