// 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& HitTargets) { AWeapon::Fire(FVector()); APawn* OwnerPawn = Cast(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 HitMap; TMap HeadShotHitMap; for (FVector_NetQuantize HitTarget : HitTargets) { FHitResult FireHit; WeaponTraceHit(Start, HitTarget, FireHit); ABlasterCharacter* BlasterCharacter = Cast(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 HitCharacters; // Maps Character hit to total damage TMap 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(OwnerPawn) : OwnerCharacter; OwnerController = OwnerController == nullptr ? Cast(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& 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); } }