158 lines
4.9 KiB
C++
158 lines
4.9 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
|
|
#include "Shotgun.h"
|
|
|
|
#include "Blaster/Character/BlasterCharacter.h"
|
|
#include "Blaster/Components/LagCompensationComponent.h"
|
|
#include "Blaster/PlayerController/BlasterPlayerController.h"
|
|
#include "Engine/SkeletalMeshSocket.h"
|
|
#include "Kismet/GameplayStatics.h"
|
|
#include "Kismet/KismetMathLibrary.h"
|
|
|
|
void AShotgun::FireShotgun(const TArray<FVector_NetQuantize>& HitTargets)
|
|
{
|
|
AWeapon::Fire(FVector());
|
|
APawn* OwnerPawn = Cast<APawn>(GetOwner());
|
|
if (OwnerPawn == nullptr) return;
|
|
AController* InstigatorController = OwnerPawn->GetController();
|
|
|
|
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
|
|
if (MuzzleFlashSocket)
|
|
{
|
|
const FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
|
|
const FVector Start = SocketTransform.GetLocation();
|
|
|
|
// Maps hit character to number of times hit
|
|
TMap<ABlasterCharacter*, uint32> HitMap;
|
|
TMap<ABlasterCharacter*, uint32> HeadShotHitMap;
|
|
|
|
for (FVector_NetQuantize HitTarget : HitTargets)
|
|
{
|
|
FHitResult FireHit;
|
|
WeaponTraceHit(Start, HitTarget, FireHit);
|
|
|
|
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(FireHit.GetActor());
|
|
if (BlasterCharacter)
|
|
{
|
|
const bool bHeadShot = FireHit.BoneName.ToString() == FString("head");
|
|
|
|
if (bHeadShot)
|
|
{
|
|
if (HeadShotHitMap.Contains(BlasterCharacter)) HeadShotHitMap[BlasterCharacter]++;
|
|
else HeadShotHitMap.Emplace(BlasterCharacter, 1);
|
|
}
|
|
else
|
|
{
|
|
if (HitMap.Contains(BlasterCharacter)) HitMap[BlasterCharacter]++;
|
|
else HitMap.Emplace(BlasterCharacter, 1);
|
|
}
|
|
|
|
if (ImpactParticles)
|
|
{
|
|
UGameplayStatics::SpawnEmitterAtLocation(
|
|
GetWorld(),
|
|
ImpactParticles,
|
|
FireHit.ImpactPoint,
|
|
FireHit.ImpactNormal.Rotation()
|
|
);
|
|
}
|
|
if (HitSound)
|
|
{
|
|
UGameplayStatics::PlaySoundAtLocation(
|
|
this,
|
|
HitSound,
|
|
FireHit.ImpactPoint,
|
|
.5f,
|
|
FMath::FRandRange(-.5f, .5f)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
TArray<ABlasterCharacter*> HitCharacters;
|
|
|
|
// Maps Character hit to total damage
|
|
TMap<ABlasterCharacter*, uint32> DamageMap;
|
|
|
|
// Calculate body shot damage by multiplying times hit x Damage - Stored in DamageMap
|
|
for (auto HitPair : HitMap)
|
|
{
|
|
if (HitPair.Key)
|
|
{
|
|
DamageMap.Emplace(HitPair.Key, HitPair.Value * Damage);
|
|
|
|
HitCharacters.AddUnique(HitPair.Key);
|
|
}
|
|
}
|
|
// Calculate head shot damage by multiplying times hit x HeadShotDamage - Stored in DamageMap
|
|
for (auto HeadShotHitPair : HeadShotHitMap)
|
|
{
|
|
if (HeadShotHitPair.Key)
|
|
{
|
|
if (DamageMap.Contains(HeadShotHitPair.Key)) DamageMap[HeadShotHitPair.Key] += HeadShotHitPair.Value * HeadShotDamage;
|
|
else DamageMap.Emplace(HeadShotHitPair.Key, HeadShotHitPair.Value * HeadShotDamage);
|
|
|
|
HitCharacters.AddUnique(HeadShotHitPair.Key);
|
|
}
|
|
}
|
|
|
|
// Loop trough DamageMap to get total damage for each character
|
|
for (auto DamagePair : DamageMap)
|
|
{
|
|
if (DamagePair.Key && InstigatorController)
|
|
{
|
|
bool bCauseAuthDamage = !bUseServerSideRewind || OwnerPawn->IsLocallyControlled();
|
|
if (HasAuthority() && bCauseAuthDamage)
|
|
{
|
|
UGameplayStatics::ApplyDamage(
|
|
DamagePair.Key, // Character that was hit
|
|
DamagePair.Value, // Damage calculated in the two loops above
|
|
InstigatorController,
|
|
this,
|
|
UDamageType::StaticClass()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!HasAuthority() && bUseServerSideRewind)
|
|
{
|
|
OwnerCharacter = OwnerCharacter == nullptr ? Cast<ABlasterCharacter>(OwnerPawn) : OwnerCharacter;
|
|
OwnerController = OwnerController == nullptr ? Cast<ABlasterPlayerController>(InstigatorController) : OwnerController;
|
|
|
|
if (OwnerCharacter && OwnerController && OwnerCharacter->GetLagCompensation() && OwnerCharacter->IsLocallyControlled())
|
|
{
|
|
OwnerCharacter->GetLagCompensation()->ShotgunServerScoreRequest(
|
|
HitCharacters,
|
|
Start,
|
|
HitTargets,
|
|
OwnerController->GetServerTime() - OwnerController->SingleTripTime
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AShotgun::ShotgunTraceEndWithScatter(const FVector& HitTarget, TArray<FVector_NetQuantize>& HitTargets)
|
|
{
|
|
const USkeletalMeshSocket* MuzzleFlashSocket = GetWeaponMesh()->GetSocketByName("MuzzleFlash");
|
|
if (MuzzleFlashSocket == nullptr) return;
|
|
|
|
const FTransform SocketTransform = MuzzleFlashSocket->GetSocketTransform(GetWeaponMesh());
|
|
const FVector TraceStart = SocketTransform.GetLocation();
|
|
|
|
const FVector ToTargetNormalized = (HitTarget - TraceStart).GetSafeNormal();
|
|
const FVector SphereCenter = TraceStart + ToTargetNormalized * DistanceToSphere;
|
|
|
|
for (uint32 i = 0; i < NumberOfPellets; i++)
|
|
{
|
|
const FVector RandVec = UKismetMathLibrary::RandomUnitVector() * FMath::FRandRange(0.f, SphereRadius);
|
|
const FVector EndLoc = SphereCenter + RandVec;
|
|
FVector ToEndLoc = EndLoc - TraceStart;
|
|
ToEndLoc = FVector(TraceStart + ToEndLoc * TRACE_LENGTH / ToEndLoc.Size());
|
|
|
|
HitTargets.Add(ToEndLoc);
|
|
}
|
|
}
|