Merge branch 'dev' into Stealth-AI

# Conflicts:
#	EndlessVendetta/Content/FirstPerson/Blueprints/BP_FirstPersonCharacter.uasset
#	EndlessVendetta/Content/FirstPerson/Input/IMC_Default.uasset
#	EndlessVendetta/Source/EndlessVendetta/EndlessVendettaCharacter.cpp
#	EndlessVendetta/Source/EndlessVendetta/EndlessVendettaCharacter.h
This commit is contained in:
Philip W 2023-10-09 11:09:32 +01:00
commit d9cdf94757
62 changed files with 1065 additions and 181 deletions

View File

@ -5,4 +5,7 @@ SimpleMapName=/Game/FirstPerson/Maps/FirstPersonExampleMap
bAllowClassAndBlueprintPinMatching=true
bReplaceBlueprintWithClass= true
bDontLoadBlueprintOutsideEditor= true
bBlueprintIsNotBlueprintType= true
bBlueprintIsNotBlueprintType= true
[/Script/AdvancedPreviewScene.SharedProfiles]

View File

@ -85,3 +85,6 @@ ConnectionType=USBOnly
bUseManualIPAddress=False
ManualIPAddress=
[CoreRedirects]
+PropertyRedirects=(OldName="/Script/EndlessVendetta.BaseWeaponClass.player",NewName="/Script/EndlessVendetta.BaseWeaponClass.playerInWorld")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
EndlessVendetta/Content/Gadgets/BP_DeadEnemy.uasset (Stored with Git LFS) Normal file

Binary file not shown.

BIN
EndlessVendetta/Content/Gadgets/BP_Grenade.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -91,7 +91,12 @@ void AEndlessVendettaCharacter::SetupPlayerInputComponent(class UInputComponent*
EnhancedInputComponent->BindAction(EquipSecondaryWeapon, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::EquipSecondary);
//Weapon Shooting
EnhancedInputComponent->BindAction(TapShootAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::TapFireCaller);
EnhancedInputComponent->BindAction(TapShootAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::FireCaller);
EnhancedInputComponent->BindAction(GunAimInAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::GunRightClick);
EnhancedInputComponent->BindAction(GunAimInAction, ETriggerEvent::Completed, this, &AEndlessVendettaCharacter::StopGunRightClick);
//Weapon Reloading
EnhancedInputComponent->BindAction(GunReloadAction, ETriggerEvent::Triggered, this, &AEndlessVendettaCharacter::GunReload);
//Crouching
EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Started, this, &AEndlessVendettaCharacter::SetCrouch);
@ -168,6 +173,7 @@ void AEndlessVendettaCharacter::EquipPrimary()
if (IsValid(PrimaryWeapon))
{
PrimaryWeapon->Destroy();
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
PrimaryWeapon = nullptr;
bHasRifle = false;
return;
@ -175,11 +181,9 @@ void AEndlessVendettaCharacter::EquipPrimary()
if (IsValid(SecondaryWeapon)) EquipSecondary();
// Marcel I respect you, like you and what not, please for the love of god don't touch these two guard clauses
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (GadgetManager->IsReconEquipped() && !GadgetManager->TryToUnequipRecon()) return; /////////////////////////
if (GadgetManager->IsCombatEquipped() && !GadgetManager->TryToUnequipCombat()) return; ///////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (GadgetManager->IsReconEquipped() && !GadgetManager->TryToUnequipRecon()) return;
if (GadgetManager->IsCombatEquipped() && !GadgetManager->TryToUnequipCombat()) return;
FActorSpawnParameters spawnParams;
spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
@ -193,34 +197,6 @@ void AEndlessVendettaCharacter::EquipPrimary()
//We do this because we need to check if PrimaryWeapon is equipped and we want primaryweapon to be ABaseWeapon type and not a generic AActor
PrimaryWeapon = Cast<ABaseWeaponClass>(PrimaryWeaponActor);
//If primary weapon is not there but secondary weapon is it will call equipSecondary.
//EquipSecondary checks and sees that secondary is there so it will call to destroy itself
//Code goes back and sees primary weapon is not there anymore and spawns it in.
//Same thing for the EquipSecondary()
// if (!IsValid(PrimaryWeapon))
// {
// if (IsValid(SecondaryWeapon)) EquipSecondary();
//
// UE_LOG(LogTemp, Display, TEXT("Primary equipped"));
// bHasRifle = true;
// FActorSpawnParameters spawnParams;
// spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
// //Creating a new actor object called PrimaryWeapon that is based off primaryweaponClass
// AActor* PrimaryWeaponActor = GetWorld()->SpawnActor<AActor>(PrimaryWeaponClass, spawnParams);
// PrimaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
// //Changing PrimaryWeaponActor to ABaseWeaponClass type instead of actor and storing it into PrimaryWeapon which is a ABaseClass Object
// //We do this because we need to check if PrimaryWeapon is equipped and we want primaryweapon to be ABaseWeapon type and not a generic AActor
// PrimaryWeapon = Cast<ABaseWeaponClass>(PrimaryWeaponActor);
//
// }
// else if (IsValid(PrimaryWeapon))
// {
// PrimaryWeapon->Destroy();
// bHasRifle = false;
// }
}
void AEndlessVendettaCharacter::EquipSecondary()
@ -228,6 +204,7 @@ void AEndlessVendettaCharacter::EquipSecondary()
if (IsValid(SecondaryWeapon))
{
SecondaryWeapon->Destroy();
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
SecondaryWeapon = nullptr;
bHasRifle = false;
return;
@ -235,11 +212,9 @@ void AEndlessVendettaCharacter::EquipSecondary()
if (IsValid(PrimaryWeapon)) EquipPrimary();
// Marcel I respect you, like you and what not, please for the love of god don't touch these two guard clauses
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (GadgetManager->IsReconEquipped() && !GadgetManager->TryToUnequipRecon()) return; /////////////////////////
if (GadgetManager->IsCombatEquipped() && !GadgetManager->TryToUnequipCombat()) return; ///////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (GadgetManager->IsReconEquipped() && !GadgetManager->TryToUnequipRecon()) return;
if (GadgetManager->IsCombatEquipped() && !GadgetManager->TryToUnequipCombat()) return;
FActorSpawnParameters spawnParams;
spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
@ -249,73 +224,81 @@ void AEndlessVendettaCharacter::EquipSecondary()
AActor* SecondaryWeaponActor = GetWorld()->SpawnActor<AActor>(SecondaryWeaponClass, spawnParams);
SecondaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
SecondaryWeapon = Cast<ABaseWeaponClass>(SecondaryWeaponActor);
// if (!IsValid(SecondaryWeapon))
// {
// if (IsValid(PrimaryWeapon)) EquipPrimary();
//
// UE_LOG(LogTemp, Display, TEXT("Secondary equipped"));
// bHasRifle = true;
// FActorSpawnParameters spawnParams;
// spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
// FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
// AActor* SecondaryWeaponActor = GetWorld()->SpawnActor<AActor>(SecondaryWeaponClass, spawnParams);
// SecondaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
// SecondaryWeapon = Cast<ABaseWeaponClass>(SecondaryWeaponActor);
// }
// else if (IsValid(SecondaryWeapon))
// {
// SecondaryWeapon->Destroy();
// bHasRifle = false;
// }
}
//Calls the fire function in the baseWeaponClass
void AEndlessVendettaCharacter::TapFireCaller()
void AEndlessVendettaCharacter::FireCaller()
{
UE_LOG(LogTemp, Warning, TEXT("Tap Fire"));
// if (IsValid(PrimaryWeapon) || IsValid(SecondaryWeapon))
// {
// PrimaryWeaponClass.GetDefaultObject()->TapFire();
// }
if (IsValid(PrimaryWeapon))
{
PrimaryWeapon->Fire();
}
if (IsValid(SecondaryWeapon))
{
SecondaryWeapon->Fire();
}
}
//POTENTIAL PICKUP SYSTEM NEEDS CHANGING BUT YES
//Called from Player BluePrints
/*void AEndlessVendettaCharacter::WeaponPickUpSystem(AActor* PickedUpWeapon)
void AEndlessVendettaCharacter::GunRightClick()
{
ABaseWeaponClass* WeaponInWorld = Cast<ABaseWeaponClass>(PickedUpWeapon);
if(WeaponInWorld->IsA(ABaseWeaponClass::StaticClass()))
if (IsValid(PrimaryWeapon) && !bIsScoped)
{
if(PrimaryWeapon)
for (UActorComponent* actorComp : this->GetComponentsByTag(UArrowComponent::StaticClass(), FName("ScopedLocationArrow")))
{
UE_LOG(LogTemp, Display, TEXT("Primary Weapon Picked up"));
bHasRifle = true;
FVector loc = GetActorLocation() + FVector(-50, 0, 0);
FRotator rot = GetActorRotation();
FActorSpawnParameters spawnParams;
spawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
//WeaponInWorld = Cast<ABaseWeaponClass>(GetWorld()->SpawnActor<AActor>(PrimaryWeapon, loc, rot, spawnParams));
WeaponInWorld->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
WeaponInWorld->Destroy();
//for some reason the spawning of the weapon is broken to the players hand so need to fix this.
// potentially add a varibable to check if its a secondary or priamry weapon being picked up
// add this in the baseweaponclass variable
ScopedLocationArrow = Cast<UArrowComponent>(actorComp);
break;
}
if (!IsValid(ScopedLocationArrow)) return;
PrimaryWeapon->SetActorLocation(ScopedLocationArrow->GetComponentLocation());
bIsScoped = true;
PrimaryWeapon->WeaponScopedFire();
this->GetFirstPersonCameraComponent()->SetFieldOfView(50); //change this number to a number you can change in editor eventually
}
if(WeaponInWorld->IsA(ABaseWeaponClass::StaticClass()))
if (IsValid(SecondaryWeapon) && !bIsScoped)
{
if(SecondaryWeapon)
for (UActorComponent* actorComp : this->GetComponentsByTag(UArrowComponent::StaticClass(), FName("ScopedLocationArrow")))
{
UE_LOG(LogTemp, Display, TEXT("Secondary Weapon Picked up"));
ScopedLocationArrow = Cast<UArrowComponent>(actorComp);
break;
}
if (!IsValid(ScopedLocationArrow)) return;
bIsScoped = true;
SecondaryWeapon->WeaponScopedFire();
SecondaryWeapon->SetActorLocation(ScopedLocationArrow->GetComponentLocation());
this->GetFirstPersonCameraComponent()->SetFieldOfView(50); //change this number to a number you can change in editor eventually
}
}*/
}
void AEndlessVendettaCharacter::StopGunRightClick()
{
if (IsValid(PrimaryWeapon))
{
bIsScoped = false;
PrimaryWeapon->WeaponScopedFire();
PrimaryWeapon->SetActorRelativeLocation(FVector(0,0,0));
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
}
if (IsValid(SecondaryWeapon))
{
bIsScoped = false;
SecondaryWeapon->WeaponScopedFire();
SecondaryWeapon->SetActorRelativeLocation(FVector(0,0,0));
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
}
}
void AEndlessVendettaCharacter::GunReload()
{
if (IsValid(PrimaryWeapon))
{
PrimaryWeapon->WeaponReload();
}
if (IsValid(SecondaryWeapon))
{
SecondaryWeapon->WeaponReload();
}
}
void AEndlessVendettaCharacter::Move(const FInputActionValue& Value)

View File

@ -57,12 +57,15 @@ class AEndlessVendettaCharacter : public ACharacter
UInputAction* EquipSecondaryWeapon;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
UInputAction* TapShootAction;
class UInputAction* TapShootAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* GunAimInAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
UInputAction* HoldShootAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = ( AllowPrivateAccess = "true" ))
class UInputAction* GunReloadAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true"))
UInputAction* CrouchAction;
public:
@ -109,7 +112,21 @@ public:
ABaseWeaponClass* SecondaryWeapon;
UFUNCTION(BlueprintCallable, Category = "Weapons")
void TapFireCaller();
void FireCaller();
UFUNCTION(BlueprintCallable, Category = "Weapons")
void GunRightClick();
UFUNCTION(BlueprintCallable, Category = "Weapons")
void StopGunRightClick();
UFUNCTION(BlueprintCallable, Category = "Weapons")
void GunReload();
UArrowComponent* ScopedLocationArrow;
UPROPERTY(EditAnywhere, Category = "Dont Touch")
bool bIsScoped;
protected:
/** Called for movement input */
@ -124,20 +141,18 @@ protected:
void EquipPrimary();
void EquipSecondary();
//Called from Player BluePrints
//UFUNCTION(BlueprintCallable, Category = "Weapons")
//void WeaponPickUpSystem(AActor* PickedUpWeapon);
protected:
// APawn interface
virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override;
// End of APawn interface
public:
UFUNCTION(BlueprintCallable, Category = "Stealth")
void SetCrouch();
UFUNCTION(BlueprintCallable, Category = "Stealth")
void SetUnCrouch();
public:
/** Returns Mesh1P Sub-object **/
USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
/** Returns FirstPersonCameraComponent Sub-object **/

View File

@ -0,0 +1,87 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Explosive.h"
#include "CollisionDebugDrawingPublic.h"
#include "Kismet/KismetMathLibrary.h"
// Sets default values
AExplosive::AExplosive()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AExplosive::BeginPlay()
{
Super::BeginPlay();
if (ExplosionDelayInSeconds <= 0)
{
Explosion();
return;
}
FTimerHandle ExplosionHandle;
GetWorld()->GetTimerManager().SetTimer(ExplosionHandle, this, &AExplosive::Explosion, ExplosionDelayInSeconds);
}
// Called every frame
void AExplosive::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AExplosive::Explosion()
{
float PitchAngleIncrement = 180.f / ShrapnelPitchDensity;
float YawAngleIncrement = 360.f / ShrapnelYawDensity;
FHitResult OutHit;
FCollisionQueryParams QueryParams = FCollisionQueryParams::DefaultQueryParam;
QueryParams.bTraceComplex = false;
QueryParams.AddIgnoredActor(this);
FVector LT_Start = GetActorLocation();
for(int y = 1; y <= ShrapnelPitchDensity; y++)
{
for (int x = 1; x <= ShrapnelYawDensity; x++)
{
FRotator ShrapnelRotation = FRotator(-90.f + (y * PitchAngleIncrement), x * YawAngleIncrement, 0.f);
FVector LT_End = LT_Start + (UKismetMathLibrary::GetForwardVector(ShrapnelRotation) * ShrapnelTravelDistance);
bool HitSomething = GetWorld()->LineTraceSingleByChannel(OutHit, LT_Start, LT_End, ECC_Camera, QueryParams);
if (DrawDebugLines) DrawShrapnelDebugLines(HitSomething, LT_Start, LT_End, OutHit.ImpactPoint);
if (!HitSomething || !OutHit.GetActor()->ActorHasTag(FName("Enemy")) || OutHit.GetActor()->ActorHasTag(FName("Dead"))) continue;
float HitDistance = FVector::Distance(LT_Start, OutHit.ImpactPoint);
float DamageToApply = ShrapnelDamage;
if (HitDistance > ShrapnelDamageFalloffDistance)
{
// Damage linearly decrease from falloff distance to maximum travel distance, using straight line equation y = mx + c
float Magnitude = ShrapnelDamage / (ShrapnelDamageFalloffDistance - ShrapnelTravelDistance);
float DMG_Intercept = ShrapnelDamage - (Magnitude * ShrapnelDamageFalloffDistance);
DamageToApply = (Magnitude * HitDistance) + DMG_Intercept;
}
// When merged, call philips take damage function here
UE_LOG(LogTemp, Warning, TEXT("A shrapnel piece hit %s, dealing %f damage"), *OutHit.GetActor()->GetName(), DamageToApply);
}
}
PlayExplosionEffects();
}
void AExplosive::DrawShrapnelDebugLines(bool HitSomething, FVector StartVector, FVector EndVector, FVector ImpactPoint)
{
if (!HitSomething)
{
DrawDebugLine(GetWorld(), StartVector, EndVector, FColor::Green, false, 5, 0, 2);
return;
}
DrawDebugLine(GetWorld(), ImpactPoint, EndVector, FColor::Red, false, 5, 0, 2);
DrawDebugLine(GetWorld(), StartVector, ImpactPoint, FColor::Green, false, 5, 0, 2);
}

View File

@ -0,0 +1,63 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Explosive.generated.h"
UCLASS()
class ENDLESSVENDETTA_API AExplosive : public AActor
{
GENERATED_BODY()
void DrawShrapnelDebugLines(bool HitSomething, FVector StartVector, FVector EndVector, FVector ImpactPoint);
protected:
// Maximum amount of damage dealt by an individual piece of shrapnel
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
float ShrapnelDamage = 10;
// Number of shrapnel pieces uniformly spread around the Y axis
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
int ShrapnelPitchDensity = 40;
// Number of shrapnel pieces uniformly spread around the Z axis
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
int ShrapnelYawDensity = 40;
// How far shrapnel should travel from origin point, given its not obstructed along its path
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
float ShrapnelTravelDistance = 600;
// After what distance travelled should shrapnel damage start to decrease
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
float ShrapnelDamageFalloffDistance = 200;
// Delay from spawning in before explosion happens
UPROPERTY(EditDefaultsOnly, Category = "Explosion")
float ExplosionDelayInSeconds = 0;
/**
* Should debug lines be drawn to show planned travel trajectory of each
* shrapnel piece in red, and actual travelled shrapnel trajectory in green
*/
UPROPERTY(EditAnywhere, Category = "Explosion")
bool DrawDebugLines = false;
UFUNCTION(BlueprintImplementableEvent, Category = "Explosion")
void PlayExplosionEffects();
void Explosion();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Sets default values for this actor's properties
AExplosive();
// Called every frame
virtual void Tick(float DeltaTime) override;
};

View File

@ -0,0 +1,129 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "OverloadModule.h"
#include "Components/SphereComponent.h"
#include "GameFramework/Character.h"
void AOverloadModule::BeginPlay()
{
Super::BeginPlay();
this->SetActorTickInterval(0.2);
PlayerChar = GetWorld()->GetFirstPlayerController()->GetCharacter();
PlayerCam = Cast<UCameraComponent>(PlayerChar->GetComponentByClass(UCameraComponent::StaticClass()));
}
void AOverloadModule::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (GadgetCantBeUsed()) return;
CheckForPotentialHackTarget();
}
void AOverloadModule::CheckForPotentialHackTarget()
{
FHitResult OutHit;
FVector LT_Start = PlayerCam->GetComponentLocation();
FVector LT_End = PlayerCam->GetComponentLocation() + (PlayerCam->GetForwardVector() * DeadBodyCheckDistance);
//DrawDebugLine(GetWorld(), LT_Start, LT_End, FColor::Red, false, 0.2, 0, 1);
FCollisionQueryParams QueryParams = FCollisionQueryParams::DefaultQueryParam;
QueryParams.AddIgnoredActor(PlayerChar);
if (!GetWorld()->LineTraceSingleByChannel(OutHit, LT_Start, LT_End, ECC_Camera, QueryParams) || !(OutHit.GetActor()->ActorHasTag(FName("Enemy")) && OutHit.GetActor()->ActorHasTag(FName("Dead"))))
{
PotentialHackTarget = nullptr;
DisplayNeedADeadEnemy();
return;
}
if (HackedEnemies.Contains(OutHit.GetActor()->GetUniqueID()))
{
PotentialHackTarget = nullptr;
DisplayAlreadyHacked();
return;
}
//DrawDebugLine(GetWorld(), LT_Start, OutHit.ImpactPoint, FColor::Green, false, 0.2, 0, 1);
PotentialHackTarget = OutHit.GetActor();
DisplayFoundPotentialTarget();
}
void AOverloadModule::Activate()
{
if (GadgetCantBeUsed() || !IsValid(PotentialHackTarget)) return;
Super::Activate();
HackedEnemies.Add(PotentialHackTarget->GetUniqueID());
ExplodeClosestAliveEnemy();
PlayHackingAnim(GadgetMaxUptime);
}
void AOverloadModule::FinishedUsing()
{
IsValid(ClosestEnemy) ? DisplayHackingSuccess() : DisplayHackingFailure();
SpawnExplosiveOnActor(ClosestEnemy);
Super::FinishedUsing();
PlayRechargingAnim(CooldownTime);
}
void AOverloadModule::ExplodeClosestAliveEnemy()
{
FTransform EmptyTransform;
USphereComponent* SphereCollision = Cast<USphereComponent>(AddComponentByClass(USphereComponent::StaticClass(), false, EmptyTransform, false));
SphereCollision->SetSphereRadius(AreaOfEffectInMeters * 100, true);
TArray<AActor*> OverlappingActors;
TArray<AActor*> EnemiesInRadius;
// Find all living enemies within the radius
SphereCollision->GetOverlappingActors(OverlappingActors, ACharacter::StaticClass());
for (AActor* OverlappingActor : OverlappingActors)
{
if (OverlappingActor->ActorHasTag(FName("Enemy")) && !OverlappingActor->ActorHasTag(FName("Dead"))) EnemiesInRadius.Add(OverlappingActor);
}
if (EnemiesInRadius.IsEmpty())
{
ClosestEnemy = nullptr;
SphereCollision->DestroyComponent();
return;
}
// Find the closest Enemy in radius
ClosestEnemy = EnemiesInRadius[0];
float Dist = FVector::Distance(PlayerChar->GetActorLocation(), ClosestEnemy->GetActorLocation());
if (EnemiesInRadius.Num() < 2)
{
SphereCollision->DestroyComponent();
return;
}
for (int i = 1; i < EnemiesInRadius.Num(); i++)
{
float ConsideredDist = FVector::Distance(PlayerChar->GetActorLocation(), EnemiesInRadius[i]->GetActorLocation());
if (ConsideredDist <= Dist)
{
ClosestEnemy = EnemiesInRadius[i];
Dist = ConsideredDist;
}
}
SphereCollision->DestroyComponent();
}
void AOverloadModule::SpawnExplosiveOnActor(AActor* ActortoExplode)
{
if (!IsValid(ActortoExplode)) return;
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
GetWorld()->SpawnActor<AActor>(Explosive, ActortoExplode->GetActorLocation(), ActortoExplode->GetActorRotation(), SpawnParams);
}

View File

@ -0,0 +1,75 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraComponent.h"
#include "EndlessVendetta/GadgetSystem/CombatGadget.h"
#include "EndlessVendetta/GadgetSystem/GadgetClasses/Combat/Explosive.h"
#include "OverloadModule.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API AOverloadModule : public ACombatGadget
{
GENERATED_BODY()
ACharacter* PlayerChar;
UCameraComponent* PlayerCam;
AActor* PotentialHackTarget;
AActor* ClosestEnemy;
// An Array of previously hacked enemies, stops player from hacking the same Dead Enemy
TArray<uint32> HackedEnemies;
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void Activate() override;
virtual void FinishedUsing() override;
void CheckForPotentialHackTarget();
void ExplodeClosestAliveEnemy();
void SpawnExplosiveOnActor(AActor* ActortoExplode);
protected:
UPROPERTY(EditDefaultsOnly, Category = "Overload Module")
float AreaOfEffectInMeters = 20;
UPROPERTY(EditDefaultsOnly, Category = "Overload Module")
float DeadBodyCheckDistance = 250;
UPROPERTY(EditDefaultsOnly, Category = "Overload Module")
TSubclassOf<AExplosive> Explosive;
// --------------- Display Functions ---------------
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void DisplayAlreadyHacked();
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void DisplayNeedADeadEnemy();
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void DisplayFoundPotentialTarget();
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void PlayHackingAnim(float Loadingtime);
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void DisplayHackingFailure();
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void DisplayHackingSuccess();
UFUNCTION(BlueprintImplementableEvent, Category = "Overload Module")
void PlayRechargingAnim(float RechargingTime);
};

View File

@ -0,0 +1,27 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "PhoneRinging.h"
// Sets default values
APhoneRinging::APhoneRinging()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void APhoneRinging::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void APhoneRinging::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}

View File

@ -0,0 +1,26 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PhoneRinging.generated.h"
UCLASS()
class ENDLESSVENDETTA_API APhoneRinging : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
APhoneRinging();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};

View File

@ -0,0 +1,102 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "RingModule.h"
#include "Components/SphereComponent.h"
#include "GameFramework/Character.h"
void ARingModule::BeginPlay()
{
Super::BeginPlay();
this->SetActorTickInterval(0.2);
PlayerChar = GetWorld()->GetFirstPlayerController()->GetCharacter();
PlayerCam = Cast<UCameraComponent>(PlayerChar->GetComponentByClass(UCameraComponent::StaticClass()));
}
void ARingModule::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (GadgetCantBeUsed()) return;
CheckForPotentialHackTarget();
}
void ARingModule::CheckForPotentialHackTarget()
{
FHitResult OutHit;
FVector LT_Start = PlayerCam->GetComponentLocation();
FVector LT_End = PlayerCam->GetComponentLocation() + (PlayerCam->GetForwardVector() * DeadBodyCheckDistance);
//DrawDebugLine(GetWorld(), LT_Start, LT_End, FColor::Red, false, 0.2, 0, 1);
FCollisionQueryParams QueryParams = FCollisionQueryParams::DefaultQueryParam;
QueryParams.AddIgnoredActor(PlayerChar);
if (!GetWorld()->LineTraceSingleByChannel(OutHit, LT_Start, LT_End, ECC_Camera, QueryParams) || !(OutHit.GetActor()->ActorHasTag(FName("Enemy")) && OutHit.GetActor()->ActorHasTag(FName("Dead"))))
{
PotentialHackTarget = nullptr;
DisplayNeedADeadEnemy();
return;
}
if (HackedEnemies.Contains(OutHit.GetActor()->GetUniqueID()))
{
PotentialHackTarget = nullptr;
DisplayAlreadyHacked();
return;
}
//DrawDebugLine(GetWorld(), LT_Start, OutHit.ImpactPoint, FColor::Green, false, 0.2, 0, 1);
PotentialHackTarget = OutHit.GetActor();
DisplayFoundPotentialTarget();
}
void ARingModule::Activate()
{
if (GadgetCantBeUsed() || !IsValid(PotentialHackTarget)) return;
Super::Activate();
HackedEnemies.Add(PotentialHackTarget->GetUniqueID());
PlayHackingAnim(GadgetMaxUptime);
}
void ARingModule::FinishedUsing()
{
SpawnRingingPhoneForAllNearbyEnemies() ? DisplayHackingSuccess() : DisplayHackingFailure();
Super::FinishedUsing();
PlayRechargingAnim(CooldownTime);
}
bool ARingModule::SpawnRingingPhoneForAllNearbyEnemies()
{
FTransform EmptyTransform;
USphereComponent* SphereCollision = Cast<USphereComponent>(AddComponentByClass(USphereComponent::StaticClass(), false, EmptyTransform, false));
SphereCollision->SetSphereRadius(AreaOfEffectInMeters * 100, true);
TArray<AActor*> OverlappingActors;
TArray<AActor*> EnemiesInRadius;
SphereCollision->GetOverlappingActors(OverlappingActors, ACharacter::StaticClass());
for (AActor* OverlappingActor : OverlappingActors)
{
if (OverlappingActor->ActorHasTag(FName("Enemy")) && !OverlappingActor->ActorHasTag(FName("Dead"))) EnemiesInRadius.Add(OverlappingActor);
}
if (EnemiesInRadius.IsEmpty())
{
SphereCollision->DestroyComponent();
return false;
}
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
for (AActor* Enemy : EnemiesInRadius)
{
AActor* SpawnedPhone = GetWorld()->SpawnActor<AActor>(PhoneRingingClass, Enemy->GetActorLocation(), Enemy->GetActorRotation(), SpawnParams);
SpawnedPhone->AttachToComponent(Enemy->GetRootComponent(), AttachmentRules);
}
return true;
}

View File

@ -0,0 +1,72 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "PhoneRinging.h"
#include "EndlessVendetta/GadgetSystem/ReconGadget.h"
#include "Camera/CameraComponent.h"
#include "RingModule.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API ARingModule : public AReconGadget
{
GENERATED_BODY()
ACharacter* PlayerChar;
UCameraComponent* PlayerCam;
AActor* PotentialHackTarget;
// An Array of previously hacked enemies, stops player from hacking the same Dead Enemy
TArray<uint32> HackedEnemies;
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void Activate() override;
virtual void FinishedUsing() override;
void CheckForPotentialHackTarget();
// Returns false if there are no nearby enemies
bool SpawnRingingPhoneForAllNearbyEnemies();
protected:
UPROPERTY(EditDefaultsOnly, Category = "Ring Module")
float AreaOfEffectInMeters = 20;
UPROPERTY(EditDefaultsOnly, Category = "Ring Module")
float DeadBodyCheckDistance = 250;
UPROPERTY(EditDefaultsOnly, Category = "Ring Module")
TSubclassOf<APhoneRinging> PhoneRingingClass;
// --------------- Display Functions ---------------
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void DisplayAlreadyHacked();
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void DisplayNeedADeadEnemy();
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void DisplayFoundPotentialTarget();
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void PlayHackingAnim(float Loadingtime);
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void DisplayHackingFailure();
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void DisplayHackingSuccess();
UFUNCTION(BlueprintImplementableEvent, Category = "Ring Module")
void PlayRechargingAnim(float RechargingTime);
};

View File

@ -60,12 +60,11 @@ void AVisionLinkEnemyLOSTest::TestLOS(TArray<uint32> EnemiesInLink, AActor* LOSA
return;
}
for (AActor* Enemy : OverlappingEnemies)
/*for (AActor* Enemy : OverlappingEnemies)
{
FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(LOSActor->GetActorLocation(), Enemy->GetActorLocation());
UE_LOG(LogTemp, Warning, TEXT("Look at Rotation: %f"), LookAtRotation.Yaw);
UE_LOG(LogTemp, Warning, TEXT("enemy name: %s"), *Enemy->GetName());
}
}*/
Destroy();

View File

@ -2,7 +2,10 @@
#include "BaseWeaponClass.h"
#include "AIHelpers.h"
#include "EndlessVendetta/EndlessVendettaCharacter.h"
#include "Kismet/KismetMathLibrary.h"
#include "Components/CapsuleComponent.h"
#include "Kismet/GameplayStatics.h"
@ -21,46 +24,180 @@ void ABaseWeaponClass::BeginPlay()
// Attempt to find the player character
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
player = Cast<AEndlessVendettaCharacter>(PlayerController->GetCharacter());
if (PlayerController)
playerInWorld = Cast<AEndlessVendettaCharacter>(PlayerController->GetCharacter());
endlessVendettaChar = Cast<AEndlessVendettaCharacter>(playerInWorld);
for (UActorComponent* actorComp : playerInWorld->GetComponentsByTag(UArrowComponent::StaticClass(), FName("GunStart")))
{
if (player)
{
UE_LOG(LogTemp, Display, TEXT("BeginPlay: Player found."));
}
else
{
UE_LOG(LogTemp, Error, TEXT("BeginPlay: Player not found."));
}
GunStartArrow = Cast<UArrowComponent>(actorComp);
break;
}
else
if (!playerControllerRef)
{
UE_LOG(LogTemp, Error, TEXT("BeginPlay: Player controller not found."));
playerControllerRef = UGameplayStatics::GetPlayerController(GetWorld(), 0);
}
originalMagnitude = recoilMagnitude;
originalMaxAngleLeft = recoilMaxAngleLeft;
originalMaxAngleRight = recoilMaxAngleRight;
originalMinMultiplier = recoilMinMultiplier;
currentAmmoCount = MagazineSize;
UE_LOG(LogTemp, Display, TEXT("crnnt ammo: %d"), MagazineSize);
}
// Called every frame
void ABaseWeaponClass::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ABaseWeaponClass::TapFire()
{
FHitResult outHit;
FVector traceStart;
FVector traceEnd;
traceStart = player->GetActorLocation();
traceEnd = traceStart + (player->GetActorForwardVector() * 50);
UE_LOG(LogTemp, Display, TEXT("World: %s"), *GetWorld()->GetName());
FCollisionQueryParams collisionParams;
GetWorld()->LineTraceSingleByChannel(outHit, traceStart, traceEnd, ECC_Visibility, collisionParams);
//Debug line to see where the trace hit
DrawDebugLine(this->GetWorld(), traceStart, traceEnd, FColor::Red, true);
if (outHit.bBlockingHit)
if (playerInWorld)
{
UE_LOG(LogTemp, Display, TEXT("Hit something"));
ApplyRecoil(DeltaTime);
}
UE_LOG(LogTemp, Display, TEXT("BOOMBOOMBIMBAMBIM"));
}
// Recoil Handling ////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ABaseWeaponClass::GenerateRecoilVector()
{
float angle = FMath::RandRange(recoilMaxAngleLeft, -recoilMaxAngleRight); //randomg recoil vector angle between left and right
float recMag = recoilMagnitude * 252.f; //converting degrees to controller units
float tempMag = -FMath::RandRange(recMag * recoilMinMultiplier, recMag); // recoil magnitude
recoilResultYaw = FMath::Sin(FMath::DegreesToRadians(angle));
recoilResultPitch = FMath::Cos(FMath::DegreesToRadians(angle));
//scaling direction to magnitude
recoilResultPitch *= -tempMag;
recoilResultYaw *= tempMag;
//reset recoil to 0 of curve
recoilTime = 0;
}
void ABaseWeaponClass::ApplyRecoil(float DeltaTime)
{
if (recoilTime < 0.3)
{
float amplitude = RecoilCurve->GetFloatValue(recoilTime); //get current value of curve in time
recoilTime += DeltaTime;
playerInWorld->AddControllerPitchInput(GetRecoilPitch(amplitude, recoilTime));
playerInWorld->AddControllerYawInput(GetRecoilYaw(amplitude, recoilTime));
UpdateSamples(amplitude, recoilTime);
}
}
void ABaseWeaponClass::nullSamples()
{
recoilCurvet = 0;
recoilCurvez1 = 0;
}
float ABaseWeaponClass::GetRecoilPitch(float Amp, float Time)
{
//Using the trapez method and we are getting the surface under the curve, each trapezoid consist of square and right triangle
float lower = recoilCurvez1 < Amp ? recoilCurvez1 : Amp; //get which point is common for both triangle and square of trapezoid
//lower point
float mult = (Time - recoilCurvet) * lower; //getting surface of square
mult += (Time - recoilCurvet) * (Amp - recoilCurvez1) / 2.0f; //getting and adding surface of triangle
return (recoilResultPitch * mult) / playerControllerRef->InputPitchScale_DEPRECATED; //calculating and return recoil force for current frame
}
//Same as getrecoilpitch
float ABaseWeaponClass::GetRecoilYaw(float Amp, float Time)
{
float lower = recoilCurvez1 < Amp ? recoilCurvez1 : Amp;
float mult = (Time - recoilCurvet) * lower;
mult += (Time - recoilCurvet) * (Amp - recoilCurvez1) / 2.0f;
return (recoilResultYaw * mult) / playerControllerRef->InputYawScale_DEPRECATED;
}
void ABaseWeaponClass::UpdateSamples(float Amp, float Time)
{
recoilCurvez1 = Amp;
recoilCurvet = Time;
}
// Fire handling //////////////////////////////////////////////////////////////////////////////////////////////////////////
void ABaseWeaponClass::ClickDetectionTimer()
{
GetWorldTimerManager().SetTimer(timerHandle, this, &ABaseWeaponClass::Fire, 1 / FireRate, false);
}
void ABaseWeaponClass::CancelFire()
{
GetWorldTimerManager().ClearTimer(timerHandle);
}
void ABaseWeaponClass::Fire()
{
if(currentAmmoCount > 0)
{
//do damage fallof based off distance
FHitResult outHit;
FVector traceStart;
FVector traceEnd;
traceStart = GunStartArrow->GetComponentLocation();
traceEnd = traceStart + (GunStartArrow->GetForwardVector() * BulletDistance);
FCollisionQueryParams collisionParams;
collisionParams.AddIgnoredActor(playerInWorld);
collisionParams.AddIgnoredActor(this);
if (GetWorldTimerManager().IsTimerActive(timerHandle))
{
return;
}
GetWorld()->LineTraceSingleByChannel(outHit, traceStart, traceEnd, ECC_Visibility, collisionParams);
//Debug line to see where the trace hit
DrawDebugLine(this->GetWorld(), traceStart, traceEnd, FColor::Red, false, 5.0f, 0U, 2.5f);
playerControllerRef->PlayerCameraManager->StartCameraShake(CameraShakeClass, 1);
currentAmmoCount -= 1;
UE_LOG(LogTemp, Display, TEXT("Ammo Count: %d"), currentAmmoCount);
GenerateRecoilVector();
ClickDetectionTimer();
if (outHit.bBlockingHit)
{
UE_LOG(LogTemp, Display, TEXT("hit item: %s"), *outHit.GetActor()->GetName());
}
}
else if(currentAmmoCount <= 0)
{
UE_LOG(LogTemp, Display, TEXT("No ammo, Ammo count: %d"), currentAmmoCount);
}
}
void ABaseWeaponClass::WeaponScopedFire()
{
if (endlessVendettaChar->bIsScoped)
{
recoilMagnitude -= 0.2f;
recoilMaxAngleLeft /= 2.f;
recoilMaxAngleRight /= 2.f;
recoilMinMultiplier -= 0.2f;
}
else
{
recoilMagnitude = originalMagnitude;
recoilMaxAngleLeft = originalMaxAngleLeft;
recoilMaxAngleRight = originalMaxAngleRight;
recoilMinMultiplier = originalMinMultiplier;
}
}
void ABaseWeaponClass::WeaponReload()
{
if(MagazineSize > currentAmmoCount)
{
UE_LOG(LogTemp, Display, TEXT("Weapon Reloading: mag size: %d"), MagazineSize);
currentAmmoCount = MagazineSize;
}
}

View File

@ -4,6 +4,8 @@
#include "CoreMinimal.h"
#include "WeaponItemClass.h"
#include "Components/ArrowComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "BaseWeaponClass.generated.h"
class AEndlessVendettaCharacter;
@ -22,6 +24,23 @@ protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void GenerateRecoilVector();
void ApplyRecoil(float DeltaTime);
void nullSamples();
//recoil previous curve
float recoilCurvez1 = 0;
//recoil previous curve time
float recoilCurvet = 0;
float recoilTime = 0;
float recoilResultPitch = 0;
float recoilResultYaw = 0;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
@ -42,17 +61,70 @@ public:
UTexture2D* WeaponImage;
UFUNCTION(BlueprintCallable, Category = "Weapons")
void TapFire();
virtual void Fire();
UFUNCTION(BlueprintCallable, Category = "Weapons")
void ClickDetectionTimer();
void CancelFire();
UPROPERTY(VisibleAnywhere)
ACharacter* player;
ACharacter* playerInWorld;
AEndlessVendettaCharacter* endlessVendettaChar;
APlayerController* playerControllerRef;
FTimerHandle timerHandle;
//Add HoldFire functionality after pistol is complete for holding fire for pistol and make it start spraying innacuratly.
// UFUNCTION(BlueprintCallable, Category = "Weapons")
// void HoldFire();
bool bFirstBulletShot = false;
UPROPERTY(EditAnywhere)
TSubclassOf<UCameraShakeBase> CameraShakeClass;
/* How far the gun goes up*/
UPROPERTY(EditAnywhere, Category = "Recoil")
float recoilMagnitude;
UPROPERTY(EditAnywhere, Category = "Recoil")
float recoilMaxAngleLeft;
UPROPERTY(EditAnywhere, Category = "Recoil")
float recoilMaxAngleRight;
UPROPERTY(EditAnywhere, Category = "Recoil")
float recoilMinMultiplier;
UPROPERTY(EditAnywhere, Category = "Recoil")
class UCurveFloat* RecoilCurve;
UFUNCTION(BlueprintCallable, Category = "Recoil")
float GetRecoilPitch(float Amp, float Time);
UFUNCTION(BlueprintCallable, Category = "Recoil")
float GetRecoilYaw(float Amp, float Time);
UFUNCTION(BlueprintCallable, Category = "Recoil")
void UpdateSamples(float Amp, float Time);
UFUNCTION(BlueprintCallable, Category = "Weapons")
void WeaponScopedFire();
UFUNCTION(BlueprintCallable, Category = "Weapons")
void WeaponReload();
private:
UArrowComponent* GunStartArrow;
UPROPERTY(EditAnywhere)
float BulletDistance;
float originalMagnitude;
float originalMaxAngleLeft;
float originalMaxAngleRight;
float originalMinMultiplier;
int currentAmmoCount;
};

View File

@ -24,3 +24,9 @@ void APistolClass::Tick(float DeltaTime)
Super::Tick(DeltaTime);
}
void APistolClass::Fire()
{
Super::Fire();
UE_LOG(LogTemp, Display, TEXT("Testing overrides: Pistol has been fired"));
}

View File

@ -22,4 +22,6 @@ protected:
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void Fire() override;
};

View File

@ -0,0 +1,4 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "WeaponCameraShake.h"

View File

@ -0,0 +1,16 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "WeaponCameraShake.generated.h"
/**
*
*/
UCLASS()
class ENDLESSVENDETTA_API UWeaponCameraShake : public UCameraShakeBase
{
GENERATED_BODY()
};