ProjectM/Source/ProjectT/System/SinglePlay/Characters/NPC/SPNpcFixed.cpp

304 lines
9.9 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "SPNpcFixed.h"
#include "Components/BoxComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/SphereComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Kismet/KismetMathLibrary.h"
#include "ProjectT/System/Core/Characters/NPC/Animations/NpcFixedAnimInstance.h"
#include "ProjectT/System/Core/Characters/Player/CorePlayerCharacter.h"
#include "ProjectT/System/Core/Common/GlobalUtilsLibrary.h"
#include "ProjectT/System/SinglePlay/Components/SPNpcStatusComponent.h"
ASPNpcFixed::ASPNpcFixed() :
HeadPitchAngle(-37.f),
DetectParameterName(TEXT("Detect"))
{
PrimaryActorTick.bCanEverTick = true;
GetCapsuleComponent()->SetCollisionProfileName(TEXT("Fixed"));
GetMesh()->SetAnimationMode(EAnimationMode::AnimationBlueprint);
GetMesh()->SetAnimInstanceClass(UNpcFixedAnimInstance::StaticClass());
DetectCollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("DetectCollisionComponent"));
DetectSpotMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DetectSpotMeshComponent"));
DetectConeMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DetectConeMeshComponent"));
BoundingBoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("BoundingBoxComponent"));
NMT_CHECKF(DetectCollisionComponent && DetectSpotMeshComponent && DetectConeMeshComponent && BoundingBoxComponent)
DetectCollisionComponent->SetupAttachment(RootComponent);
DetectCollisionComponent->SetCollisionProfileName(TEXT("InteractionRange"));
DetectCollisionComponent->SetSphereRadius(76.f);
DetectCollisionComponent->OnComponentBeginOverlap.AddDynamic(this, &ASPNpcFixed::DetectBeginOverlap);
DetectCollisionComponent->OnComponentEndOverlap.AddDynamic(this, &ASPNpcFixed::DetectEndOverlap);
DetectSpotMeshComponent->SetupAttachment(DetectCollisionComponent);
DetectSpotMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
DetectConeMeshComponent->SetupAttachment(SpringArmComponent);
DetectConeMeshComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
DetectConeMeshComponent->SetRelativeLocation(FVector(140.0, 0, 8.0));
DetectConeMeshComponent->SetRelativeRotation(FRotator(90.0, 0, 0));
DetectConeMeshComponent->SetRelativeScale3D(FVector(1.25, 2.0, 2.5));
BoundingBoxComponent->SetupAttachment(RootComponent);
BoundingBoxComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
BoundingBoxComponent->SetBoxExtent(FVector(200.f, 150.f, 120.f));
GetMesh()->SetupAttachment(BoundingBoxComponent);
GetMesh()->bUseAttachParentBound = true;
GetCharacterMovement()->GravityScale = 0.f;
GetCharacterMovement()->SetComponentTickEnabled(false);
WeaponDynamicComponent->SetComponentTickEnabled(false);
WeaponStaticComponent->SetComponentTickEnabled(false);
AccessoryMeshComponent->SetComponentTickEnabled(false);
}
void ASPNpcFixed::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
}
void ASPNpcFixed::SetSpringArmRotation()
{
FRotator ArmRotator = SpringArmComponent->GetComponentRotation();
SpringArmComponent->SetWorldRotation(UKismetMathLibrary::MakeRotator(ArmRotator.Roll, ArmRotator.Pitch, GetMesh()->GetSocketRotation(EyeSocketName).Yaw));
}
void ASPNpcFixed::BeginPlay()
{
Super::BeginPlay();
}
void ASPNpcFixed::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ASPNpcFixed::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
}
UBlackboardData* ASPNpcFixed::GetBlackboardData_Implementation()
{
return Blackboard;
}
UBehaviorTree* ASPNpcFixed::GetBehaviorTree_Implementation()
{
return BehaviorTree;
}
void ASPNpcFixed::StartDisableNpc()
{
Super::StartDisableNpc();
SetVisionMode(EVisionMode::None);
SetActorTickEnabled(false);
SetActorEnableCollision(false);
if(bEnableRespawn)
GetWorldTimerManager().SetTimer(RespawnTimerHandle, this, &ASPNpcFixed::Respawn, RespawnTime, false);
}
void ASPNpcFixed::CompleteDisableNpc()
{
Super::CompleteDisableNpc();
}
void ASPNpcFixed::ApplyDamageEvent_Implementation(AActor* InOccurActor, const FVector& InOriginLocation, const float InDamage, const TArray<FEffect>& InSkillEffects)
{
if(NpcStatusComponent->ApplyDamage(InDamage))
{
ChangeNpcState(ENpcState::Dead);
}
else
{
for(FEffect EffectType : InSkillEffects)
{
EEffectSubTypes EffectSubType = UGlobalUtilsLibrary::GetStringToEnum<EEffectSubTypes>(EffectType.sEffect);
switch(EffectSubType)
{
case EEffectSubTypes::None:
{
ChangeNpcState(ENpcState::Chase);
break;
}
case EEffectSubTypes::Hitback:
{
ChangeNpcState(ENpcState::Hit);
break;
}
case EEffectSubTypes::Jumpback:
{
ChangeNpcState(ENpcState::Hit);
break;
}
case EEffectSubTypes::Unrecog:
{
SetUnDetectTarget(true);
break;
}
case EEffectSubTypes::Slow: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Slow")
break;
case EEffectSubTypes::Bind: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Bind")
break;
case EEffectSubTypes::Fast: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Fast")
break;
case EEffectSubTypes::CogImmune: NOT_IMPLEMENTED_MSG("EEffectSubTypes::CogImmune")
break;
case EEffectSubTypes::Stun: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Stun")
break;
case EEffectSubTypes::Surge: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Surge")
break;
case EEffectSubTypes::HitbackImmune: NOT_IMPLEMENTED_MSG("EEffectSubTypes::HitbackImmune")
break;
case EEffectSubTypes::Heal: NOT_IMPLEMENTED_MSG("EEffectSubTypes::Heal")
break;
default: NMT_LOG("Not Valid")
}
}
}
}
void ASPNpcFixed::ApplyRecoveryEvent_Implementation(const TArray<FEffect>& InReleaseEffects)
{
for(FEffect LocCurEffect : InReleaseEffects)
{
EEffectSubTypes LoCurReleaseEffect = UGlobalUtilsLibrary::GetStringToEnum<EEffectSubTypes>(LocCurEffect.sEffect);
switch(LoCurReleaseEffect)
{
case EEffectSubTypes::Unrecog:
{
SetUnDetectTarget(false);
TArray<AActor*> OverlappedActors;
DetectCollisionComponent->GetOverlappingActors(OverlappedActors);
if(!OverlappedActors.IsEmpty())
{
for(AActor* OverlappedActor : OverlappedActors)
{
if(ACorePlayerCharacter* Player = Cast<ACorePlayerCharacter>(OverlappedActor))
{
UpdateDetectState(true, Player);
break;
}
}
}
break;
}
case EEffectSubTypes::CogImmune: break;
case EEffectSubTypes::Surge: break;
case EEffectSubTypes::Bind: break;
case EEffectSubTypes::Fast: break;
case EEffectSubTypes::Slow: break;
case EEffectSubTypes::Hitback: break;
case EEffectSubTypes::Jumpback: break;
case EEffectSubTypes::None: break;
case EEffectSubTypes::Stun: break;
case EEffectSubTypes::HitbackImmune: break;
case EEffectSubTypes::Heal: break;
default: NMT_LOG("No Release Effect Type");
}
}
}
void ASPNpcFixed::InitializeProperty()
{
Super::InitializeProperty();
FixedAnimInstance = Cast<UNpcFixedAnimInstance>(GetMesh()->GetAnimInstance());
NMT_CHECKF(FixedAnimInstance);
NpcAnimInstance->ForwardHeadRotation.Pitch = NpcAnimInstance->HeadRotation.Pitch = HeadPitchAngle;
SetDetectSpotLocation();
DetectConeMeshComponent->AttachToComponent(GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, true), EyeSocketName);
DetectSpotDynamicMaterial = DetectSpotMeshComponent->CreateAndSetMaterialInstanceDynamic(0);
DetectConeDynamicMaterial = DetectConeMeshComponent->CreateAndSetMaterialInstanceDynamic(0);
}
void ASPNpcFixed::ActivateCharacter(const bool InbEnable)
{
Super::ActivateCharacter(InbEnable);
}
#if WITH_EDITOR
void ASPNpcFixed::ApplyCharacterData(const FTableRowBase* RowData)
{
Super::ApplyCharacterData(RowData);
}
#endif
void ASPNpcFixed::DetectBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if(ACorePlayerCharacter* Player = Cast<ACorePlayerCharacter>(OtherActor))
{
if(OtherComp->ComponentHasTag("PlayerCapsule"))
UpdateDetectState(true, Player);
}
}
void ASPNpcFixed::DetectEndOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if(Cast<ACorePlayerCharacter>(OtherActor) && OtherComp->ComponentHasTag("PlayerCapsule"))
{
UpdateDetectState(false, nullptr);
}
}
void ASPNpcFixed::SetDetectSpotLocation()
{
UWorld* World = UGlobalUtilsLibrary::GetValidWorld(this);
NMT_CHECKF(World)
FHitResult HitResult;
FVector EyeLocation = GetMesh()->GetSocketLocation(EyeSocketName);
FRotator EyeRotation = GetActorRotation() + FRotator(HeadPitchAngle, 0.0, 0.0);
FVector Dir = EyeRotation.Vector().GetSafeNormal();
FVector EndLocation = EyeLocation + Dir * 1500.f;
bool bHitGround = World->LineTraceSingleByObjectType(HitResult, EyeLocation, EndLocation, ECC_GameTraceChannel5, FCollisionQueryParams());
if(bHitGround)
{
DetectCollisionComponent->SetWorldLocation(FVector(HitResult.Location.X, HitResult.Location.Y, HitResult.Location.Z + 1.f));
}
DetectCollisionComponent->AttachToComponent(SpringArmComponent, FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, true));
}
void ASPNpcFixed::SetDetectMaterial(const bool InbDetect) const
{
DetectSpotDynamicMaterial->SetScalarParameterValue(DetectParameterName, InbDetect);
DetectConeDynamicMaterial->SetScalarParameterValue(DetectParameterName, InbDetect);
}
void ASPNpcFixed::UpdateDetectState(const bool InbDetect, const class ACorePlayerCharacter* InTarget)
{
if(InbDetect)
{
if(!InTarget)
return;
bool PlayerUnDetect;
InTarget->GetUnDetectState(PlayerUnDetect);
if(PlayerUnDetect || bUnDetect)
return;
SetDetectMaterial(true);
Alert(InTarget->GetActorLocation());
}
else
{
SetDetectMaterial(false);
bCanTriggerAlert = true;
}
}