#include "MyGame.h" #include "weapon_pistol.h" Aweapon_pistol::Aweapon_pistol(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP) { } void Aweapon_pistol::PrimaryFire() { Super::PrimaryFire(); checkSlow(InstantHitInfo.IsValidIndex(CurrentFireMode)); const int32 RandomSeed = FMath::Rand(); const FVector SpawnLocation = GetFireStartLoc(); const FRotator SpawnRotation = GetAdjustedAim(SpawnLocation); const FVector FireDir = SpawnRotation.Vector(); const FVector EndTrace = SpawnLocation + FireDir * InstantHitInfo[CurrentFireMode].TraceRange; FHitResult Hit; if (!GetWorld()->LineTraceSingle(Hit, SpawnLocation, EndTrace, COLLISION_TRACE_WEAPON, FCollisionQueryParams(GetClass()->GetFName(), false, MyPawn))) { Hit.Location = EndTrace; } if (Role == ROLE_Authority) { //MyPawn->SetFlashLocation(Hit.Location, CurrentFireMode); } //if (Hit.Actor != NULL && Hit.Actor->bCanBeDamaged /*&& bDealDamage*/) //{ // Hit.Actor->TakeDamage(InstantHitInfo[CurrentFireMode].Damage, FPointDamageEvent(InstantHitInfo[CurrentFireMode].Damage, Hit, FireDir, InstantHitInfo[CurrentFireMode].DamageType/*, FireDir * InstantHitInfo[CurrentFireMode].Momentum*/), MyPawn->Controller, this); //} ProcessInstantHit(Hit, SpawnLocation, FireDir, RandomSeed, 0.f); //if (OutHit != NULL) //{ // *OutHit = Hit; //} } void Aweapon_pistol::ProcessInstantHit(const FHitResult& Impact, const FVector& Origin, const FVector& ShootDir, int32 RandomSeed, float ReticleSpread) { if (MyPawn && MyPawn->IsLocallyControlled() && GetNetMode() == NM_Client) { // if we're a client and we've hit something that is being controlled by the server if (Impact.GetActor() && Impact.GetActor()->GetRemoteRole() == ROLE_Authority) { // notify the server of the hit GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("trying to call ServerNotifyHit()")); ServerNotifyHit(Impact, ShootDir, RandomSeed, ReticleSpread); } else if (Impact.GetActor() == NULL) { if (Impact.bBlockingHit) { // notify the server of the hit GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("trying to call ServerNotifyHit()")); ServerNotifyHit(Impact, ShootDir, RandomSeed, ReticleSpread); } else { // notify server of the miss //ServerNotifyMiss(ShootDir, RandomSeed, ReticleSpread); } } } // process a confirmed hit ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread); } bool Aweapon_pistol::ServerNotifyHit_Validate(const FHitResult Impact, FVector_NetQuantizeNormal ShootDir, int32 RandomSeed, float ReticleSpread) { return true; } void Aweapon_pistol::ServerNotifyHit_Implementation(const FHitResult Impact, FVector_NetQuantizeNormal ShootDir, int32 RandomSeed, float ReticleSpread) { GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString("in ServerNotifyHit_Implementation")); const float WeaponAngleDot = FMath::Abs(FMath::Sin(ReticleSpread * PI / 180.f)); // if we have an instigator, calculate dot between the view and the shot if (Instigator && (Impact.GetActor() || Impact.bBlockingHit)) { const FVector Origin = GetMuzzleLocation(); const FVector ViewDir = (Impact.Location - Origin).SafeNormal(); // is the angle between the hit and the view within allowed limits (limit + weapon max angle) const float ViewDotHitDir = FVector::DotProduct(Instigator->GetViewRotation().Vector(), ViewDir); if (ViewDotHitDir > InstantHitInfo[CurrentFireMode].AllowedViewDotHitDir - WeaponAngleDot) { if (1==1 /*CurrentState != EWeaponState::Idle*/) { if (Impact.GetActor() == NULL) { if (Impact.bBlockingHit) { ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread); } } // assume it told the truth about static things because the don't move and the hit // usually doesn't have significant gameplay implications else if (Impact.GetActor()->IsRootComponentStatic() || Impact.GetActor()->IsRootComponentStationary()) { ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread); } else { // Get the component bounding box const FBox HitBox = Impact.GetActor()->GetComponentsBoundingBox(); // calculate the box extent, and increase by a leeway FVector BoxExtent = 0.5 * (HitBox.Max - HitBox.Min); BoxExtent *= InstantHitInfo[CurrentFireMode].ClientSideHitLeeway; // avoid precision errors with really thin objects BoxExtent.X = FMath::Max(20.0f, BoxExtent.X); BoxExtent.Y = FMath::Max(20.0f, BoxExtent.Y); BoxExtent.Z = FMath::Max(20.0f, BoxExtent.Z); // Get the box center const FVector BoxCenter = (HitBox.Min + HitBox.Max) * 0.5; // if we are within client tolerance if (FMath::Abs(Impact.Location.Z - BoxCenter.Z) < BoxExtent.Z && FMath::Abs(Impact.Location.X - BoxCenter.X) < BoxExtent.X && FMath::Abs(Impact.Location.Y - BoxCenter.Y) < BoxExtent.Y) { ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread); } else { //UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s (outside bounding box tolerance)"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor())); } } } } else if (ViewDotHitDir <= InstantHitInfo[CurrentFireMode].AllowedViewDotHitDir) { //UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s (facing too far from the hit direction)"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor())); } else { //UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor())); } } } void Aweapon_pistol::ProcessInstantHit_Confirmed(const FHitResult& Impact, const FVector& Origin, const FVector& ShootDir, int32 RandomSeed, float ReticleSpread) { // handle damage //if (ShouldDealDamage(Impact.GetActor())) { if (Impact.Actor != NULL)// != NULL && Impact.Actor->bCanBeDamaged /*&& bDealDamage*/) { FPointDamageEvent PointDmg; PointDmg.DamageTypeClass = InstantHitInfo[CurrentFireMode].DamageType; PointDmg.HitInfo = Impact; PointDmg.ShotDirection = ShootDir; PointDmg.Damage = InstantHitInfo[CurrentFireMode].Damage; Impact.Actor->TakeDamage(PointDmg.Damage, PointDmg, MyPawn->Controller, this); } } } bool Aweapon_pistol::ShouldDealDamage(AActor* TestActor) const { // if we're an actor on the server, or the actor's role is authoritative, we should register damage if (TestActor) { if (GetNetMode() != NM_Client || TestActor->Role == ROLE_Authority || TestActor->bTearOff) { return true; } } return false; }