diff --git a/Content/CombatSystem/Blueprints/Actor/BP_ToughSword.uasset b/Content/CombatSystem/Blueprints/Actor/BP_ToughSword.uasset index 244a5f64..d8ac7fb7 100644 Binary files a/Content/CombatSystem/Blueprints/Actor/BP_ToughSword.uasset and b/Content/CombatSystem/Blueprints/Actor/BP_ToughSword.uasset differ diff --git a/Content/CombatSystem/Blueprints/Animnotifies/CollisionTrace_ANS.uasset b/Content/CombatSystem/Blueprints/Animnotifies/CollisionTrace_ANS.uasset new file mode 100644 index 00000000..4589e463 Binary files /dev/null and b/Content/CombatSystem/Blueprints/Animnotifies/CollisionTrace_ANS.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front.uasset b/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front.uasset index 4622687f..f5908367 100644 Binary files a/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front.uasset and b/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front_Montage.uasset b/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front_Montage.uasset new file mode 100644 index 00000000..ba349fdd Binary files /dev/null and b/Content/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front_Montage.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack01_Montage.uasset b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack01_Montage.uasset index d6feab3a..5427cf0d 100644 Binary files a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack01_Montage.uasset and b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack01_Montage.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack02_Montage.uasset b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack02_Montage.uasset index f247c687..9d5fcfe5 100644 Binary files a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack02_Montage.uasset and b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack02_Montage.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack03_Montage.uasset b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack03_Montage.uasset index 49b2753f..210aa133 100644 Binary files a/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack03_Montage.uasset and b/Content/CombatSystem/CourseFiles/Animations/LightSword/LightAttack/LightAttack03_Montage.uasset differ diff --git a/Content/CombatSystem/CourseFiles/Meshes/Weapons/SM_ToughSword.uasset b/Content/CombatSystem/CourseFiles/Meshes/Weapons/SM_ToughSword.uasset index 8bd6b994..76e9baab 100644 Binary files a/Content/CombatSystem/CourseFiles/Meshes/Weapons/SM_ToughSword.uasset and b/Content/CombatSystem/CourseFiles/Meshes/Weapons/SM_ToughSword.uasset differ diff --git a/Content/__ExternalActors__/Maps/ThirdPersonMap/7/YS/ZFVZV5RGVXFDJDFNO8TVNW.uasset b/Content/__ExternalActors__/Maps/ThirdPersonMap/7/YS/ZFVZV5RGVXFDJDFNO8TVNW.uasset new file mode 100644 index 00000000..bb1604a7 Binary files /dev/null and b/Content/__ExternalActors__/Maps/ThirdPersonMap/7/YS/ZFVZV5RGVXFDJDFNO8TVNW.uasset differ diff --git a/Source/D1/Actor/BaseEquippable.cpp b/Source/D1/Actor/BaseEquippable.cpp index d1819e7a..2a7c5cc8 100644 --- a/Source/D1/Actor/BaseEquippable.cpp +++ b/Source/D1/Actor/BaseEquippable.cpp @@ -31,6 +31,14 @@ void ABaseEquippable::AttachActor(const FName SocketName) } } +UPrimitiveComponent* ABaseEquippable::GetItemMesh() +{ + if (IsValid(ItemStaticMesh->GetStaticMesh())) + return ItemStaticMesh; + else + return ItemSkeletalMesh; +} + void ABaseEquippable::OnEquipped() { SetIsEquipped(true); diff --git a/Source/D1/Actor/BaseEquippable.h b/Source/D1/Actor/BaseEquippable.h index a24c3337..1af1bcc8 100644 --- a/Source/D1/Actor/BaseEquippable.h +++ b/Source/D1/Actor/BaseEquippable.h @@ -18,6 +18,7 @@ public: public: UFUNCTION(BlueprintCallable) virtual void AttachActor(const FName SocketName); + UPrimitiveComponent* GetItemMesh(); virtual void OnEquipped(); virtual void OnUnequipped(); virtual void SetIsEquipped(bool IsEquipped); diff --git a/Source/D1/Actor/BaseWeapon.cpp b/Source/D1/Actor/BaseWeapon.cpp index c6bb6e2c..40b1844d 100644 --- a/Source/D1/Actor/BaseWeapon.cpp +++ b/Source/D1/Actor/BaseWeapon.cpp @@ -4,11 +4,22 @@ #include "Actor/BaseWeapon.h" #include "Components/CombatComponent.h" #include "GameFramework/Character.h" +#include "Components/CollisionComponent.h" +#include "Interface/CombatInterface.h" #include "Kismet/GameplayStatics.h" ABaseWeapon::ABaseWeapon() { + CollisionComponent = CreateDefaultSubobject(TEXT("CollisionComponent")); + CollisionComponent->OnHitDelegate.BindUObject(this, &ABaseWeapon::OnHit); + CollisionComponent->SetTraceRaius(20.f); + CollisionComponent->SetStartSocketName(TEXT("WeaponStart")); + CollisionComponent->SetEndSocketName(TEXT("WeaponEnd")); + TArray> InputCollisionObjectTypes; + InputCollisionObjectTypes.Add(UEngineTypes::ConvertToObjectType(ECollisionChannel::ECC_Pawn)); + CollisionComponent->SetCollisionObjectTypes(InputCollisionObjectTypes); + CollisionComponent->SetDrawDebugType(EDrawDebugTrace::None); } void ABaseWeapon::OnEquipped() @@ -30,17 +41,23 @@ void ABaseWeapon::OnEquipped() UCombatAnimInstance* animInstance = Cast(character->GetMesh()->GetAnimInstance()); animInstance->UpdateCombatType(CombatType); } + + CollisionComponent->SetCollisionMeshComponent(GetItemMesh()); + CollisionComponent->AddActorToIgnore(GetOwner()); } void ABaseWeapon::OnHit(FHitResult hitResult) { - //float UGameplayStatics::ApplyPointDamage( - // AActor * DamagedActor, float BaseDamage, FVector const& HitFromDirection, - // FHitResult const& HitInfo, AController * EventInstigator, AActor * DamageCauser, - // TSubclassOf DamageTypeClass) - - if (true) // TODO : Interface CanReceiveDamage + ICombatInterface* pActor = Cast(hitResult.GetActor()); + if (pActor) { - UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), Damage, GetOwner()->GetActorForwardVector(), hitResult, GetInstigatorController(), this, TSubclassOf(UDamageType::StaticClass())); + if (pActor->Execute_CanReceiveDamage(hitResult.GetActor())) + UGameplayStatics::ApplyPointDamage(hitResult.GetActor(), Damage, GetOwner()->GetActorForwardVector(), hitResult, GetInstigatorController(), this, TSubclassOf(UDamageType::StaticClass())); } } + +void ABaseWeapon::SimulateWeaponPhysics() +{ + GetItemMesh()->SetCollisionProfileName(TEXT("PhysicsActor"), true); + GetItemMesh()->SetSimulatePhysics(true); +} diff --git a/Source/D1/Actor/BaseWeapon.h b/Source/D1/Actor/BaseWeapon.h index e68ac2be..19728a60 100644 --- a/Source/D1/Actor/BaseWeapon.h +++ b/Source/D1/Actor/BaseWeapon.h @@ -22,11 +22,15 @@ public: ABaseWeapon(); public: + //override void OnEquipped() override; public: //Delegate void OnHit(FHitResult hitResult); +public: + //Normal + void SimulateWeaponPhysics(); public: FORCEINLINE UAnimMontage* GetEnterCombat() const { return EnterCombat; } FORCEINLINE UAnimMontage* GetExitCombat() const { return ExitCombat; } @@ -42,6 +46,9 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components") TObjectPtr CombatComponent; + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components") + TObjectPtr CollisionComponent; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages") TObjectPtr EnterCombat; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Montages") diff --git a/Source/D1/CombatCharacter.cpp b/Source/D1/CombatCharacter.cpp index 18e85513..8821c2b2 100644 --- a/Source/D1/CombatCharacter.cpp +++ b/Source/D1/CombatCharacter.cpp @@ -9,11 +9,13 @@ #include "GameFramework/SpringArmComponent.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" -#include "Kismet/KismetSystemLibrary.h" -#include "Kismet/KismetMathLibrary.h" #include "Interface/Interact.h" #include "Actor/BaseWeapon.h" #include "Components/CombatComponent.h" +#include "Engine/DamageEvents.h" +#include "Kismet/KismetSystemLibrary.h" +#include "Kismet/KismetMathLibrary.h" +#include "Kismet/GameplayStatics.h" ////////////////////////////////////////////////////////////////////////// // ACombatCharacter @@ -60,6 +62,16 @@ ACombatCharacter::ACombatCharacter() CombatEnabled = false; IsTogglingCombat = false; IsDodge = false; + IsDisabled = false; + IsDead = false; + Health = 100.f; + + PelvisBoneName = TEXT("pelvis"); + + //³ªÁß¿¡ ¼öÁ¤ÇÒ ¼ö ÀÖÀ½ + static ConstructorHelpers::FObjectFinder findHitMontage(TEXT("/Script/Engine.AnimMontage'/Game/CombatSystem/CourseFiles/Animations/HitReactions/Standing_React_Large_Front_Montage.Standing_React_Large_Front_Montage'")); + if (findHitMontage.Succeeded()) + HitMontage = findHitMontage.Object; } void ACombatCharacter::BeginPlay() @@ -85,6 +97,29 @@ void ACombatCharacter::BeginPlay() SpawnItem->OnEquipped(); } +float ACombatCharacter::TakeDamage(float Damage, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) +{ + float fDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser); + + if (DamageEvent.IsOfType(FPointDamageEvent::ClassID)) + { + const FPointDamageEvent* PointDamageEvent = static_cast(&DamageEvent); + + CharacterTakeDamage(fDamage); + + //TODO : Sound, Effect Emitter, Play anim montage + //static void PlaySoundAtLocation( + // const UObject * WorldContextObject, USoundBase * Sound, FVector Location, + // float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, float StartTime = 0.f, + // class USoundAttenuation* AttenuationSettings = nullptr, USoundConcurrency * ConcurrencySettings = nullptr, + // const UInitialActiveSoundParams * InitialParams = nullptr) + //UGameplayStatics::PlaySoundAtLocation(this, HitSound, PointDamageEvent->HitInfo.Location); + PlayAnimMontage(HitMontage); + IsDisabled = true; + } + return fDamage; +} + void ACombatCharacter::ContinueAttack_Implementation() { CombatComponent->SetIsAttacking(false); @@ -116,6 +151,11 @@ FRotator ACombatCharacter::GetDesiredRotation_Implementation() return UKismetMathLibrary::MakeRotFromX(GetLastMovementInputVector()); } +bool ACombatCharacter::CanReceiveDamage_Implementation() +{ + return !IsDead; +} + ////////////////////////////////////////////////////////////////////////// // Input @@ -249,6 +289,36 @@ void ACombatCharacter::AttackEvent() ToggleCombatEvent(); } +void ACombatCharacter::CharacterTakeDamage(float InDamage) +{ + float tmp = Health - InDamage; + Health = UKismetMathLibrary::Clamp(tmp, 0, Health); + + if (Health <= 0) + PerformDeath(); +} + +void ACombatCharacter::ApplyHitReactionPhysicsVelocity(float InitialSpeed) +{ + if (!GetMesh()) + return; + + GetMesh()->SetPhysicsLinearVelocity(GetActorForwardVector() * -InitialSpeed, false, PelvisBoneName); +} + +void ACombatCharacter::EnableRagdoll() +{ + GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None, 0); + GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore); + GetCapsuleComponent()->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore); + FAttachmentTransformRules rules(EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, true); + GetCameraBoom()->AttachToComponent(GetMesh(), rules, PelvisBoneName); + GetCameraBoom()->bDoCollisionTest = false; + GetMesh()->SetCollisionProfileName(TEXT("ragdoll"), true); + GetMesh()->SetAllBodiesBelowSimulatePhysics(PelvisBoneName, true, true); + GetMesh()->SetAllBodiesBelowPhysicsBlendWeight(PelvisBoneName, 1.f); +} + void ACombatCharacter::PerformAttack(int32 attackIndex) { ABaseWeapon* CurrentWeapon = CombatComponent->GetMainWeapon(); @@ -296,19 +366,70 @@ void ACombatCharacter::PerformDodge() } } +void ACombatCharacter::PerformDeath() +{ + IsDead = true; + EnableRagdoll(); + ApplyHitReactionPhysicsVelocity(2000.f); + + if (IsValid(CombatComponent->GetMainWeapon())) + CombatComponent->GetMainWeapon()->SimulateWeaponPhysics(); + + FTimerHandle deathTimer; + GetWorld()->GetTimerManager().SetTimer(deathTimer, FTimerDelegate::CreateLambda([&]() + { + if (IsValid(CombatComponent->GetMainWeapon())) + CombatComponent->GetMainWeapon()->Destroy(); + this->Destroy(); + }), 4.f, false); +} + bool ACombatCharacter::CanPerformToggleCombat() { - return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat); + bool ReturnValue = true; + ReturnValue &= !CombatComponent->GetIsAttacking(); + ReturnValue &= !IsTogglingCombat; + ReturnValue &= !IsDodge; + ReturnValue &= !IsDisabled; + ReturnValue &= !IsDead; + ReturnValue &= !GetCharacterMovement()->IsFalling(); + return ReturnValue; } bool ACombatCharacter::CanPerformAttack() { - return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat); + bool ReturnValue = true; + ReturnValue &= !CombatComponent->GetIsAttacking(); + ReturnValue &= !IsTogglingCombat; + ReturnValue &= !IsDodge; + ReturnValue &= !IsDisabled; + ReturnValue &= !IsDead; + ReturnValue &= !GetCharacterMovement()->IsFalling(); + return ReturnValue; } bool ACombatCharacter::CanPerformDodge() { - return (!CombatComponent->GetIsAttacking() && !IsTogglingCombat && !IsDodge); + bool ReturnValue = true; + ReturnValue &= !CombatComponent->GetIsAttacking(); + ReturnValue &= !IsTogglingCombat; + ReturnValue &= !IsDodge; + ReturnValue &= !IsDisabled; + ReturnValue &= !IsDead; + ReturnValue &= !GetCharacterMovement()->IsFalling(); + return ReturnValue; +} + +bool ACombatCharacter::CanJumping() +{ + bool ReturnValue = true; + ReturnValue &= !CombatComponent->GetIsAttacking(); + ReturnValue &= !IsTogglingCombat; + ReturnValue &= !IsDodge; + ReturnValue &= !IsDisabled; + ReturnValue &= !IsDead; + ReturnValue &= !GetCharacterMovement()->IsFalling(); + return ReturnValue; } diff --git a/Source/D1/CombatCharacter.h b/Source/D1/CombatCharacter.h index c9a7d67b..b198af4b 100644 --- a/Source/D1/CombatCharacter.h +++ b/Source/D1/CombatCharacter.h @@ -63,8 +63,9 @@ public: protected: // APawn interface virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; - virtual void BeginPlay(); - + virtual void BeginPlay() override; + virtual float TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override; + public: // Inherited via ICombatInterface UFUNCTION(BlueprintCallable, BlueprintNativeEvent) @@ -79,27 +80,34 @@ public: UFUNCTION(BlueprintCallable, BlueprintNativeEvent) FRotator GetDesiredRotation(); virtual FRotator GetDesiredRotation_Implementation() override; + UFUNCTION(BlueprintCallable, BlueprintNativeEvent) + bool CanReceiveDamage(); + virtual bool CanReceiveDamage_Implementation() override; + protected: - /** Called for movement input */ + //Input Funcs void Move(const FInputActionValue& Value); - - /** Called for looking input */ void Look(const FInputActionValue& Value); - void Interact(const FInputActionValue& Value); void ToggleCombat(const FInputActionValue& Value); void LightAttack(const FInputActionValue& Value); void Dodge(const FInputActionValue& Value); - + private: void ToggleCombatEvent(); void AttackEvent(); + void CharacterTakeDamage(float InDamage); + void ApplyHitReactionPhysicsVelocity(float InitialSpeed); + void EnableRagdoll(); + void PerformAttack(int32 attackIndex); void PerformDodge(); + void PerformDeath(); bool CanPerformToggleCombat(); bool CanPerformAttack(); bool CanPerformDodge(); + bool CanJumping(); public: UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta=(AllowPrivateAccess="true")) TObjectPtr CombatComponent; @@ -107,9 +115,19 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta = (AllowPrivateAccess = "true")) TSubclassOf Weapon; + UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true")) + FName PelvisBoneName; + +private: + //TODO : particle, sound Ãß°¡ + //class USoundWave* HitSound; + TObjectPtr HitMontage; private: bool CombatEnabled; bool IsTogglingCombat; bool IsDodge; + bool IsDisabled; + bool IsDead; + float Health; }; diff --git a/Source/D1/Components/CollisionComponent.cpp b/Source/D1/Components/CollisionComponent.cpp index e1a6a79e..7b844130 100644 --- a/Source/D1/Components/CollisionComponent.cpp +++ b/Source/D1/Components/CollisionComponent.cpp @@ -30,7 +30,7 @@ void UCollisionComponent::TickComponent(float DeltaTime, ELevelTick TickType, FA { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - if (IsCollisionEnabled) + if (bCollisionEnabled) CollisionTrace(); } @@ -56,12 +56,14 @@ void UCollisionComponent::CollisionTrace() { HitActor = LastHit.GetActor(); AlreadyHitActors.Add(HitActor); - OnHit.ExecuteIfBound(LastHit); + OnHitDelegate.ExecuteIfBound(LastHit); //Multi¸é º¯°æÇØ¾ßµÊ } } } void UCollisionComponent::EnableCollision() { + ClearHitActors(); + bCollisionEnabled = true; } diff --git a/Source/D1/Components/CollisionComponent.h b/Source/D1/Components/CollisionComponent.h index 177014dd..72fe8ab1 100644 --- a/Source/D1/Components/CollisionComponent.h +++ b/Source/D1/Components/CollisionComponent.h @@ -7,7 +7,8 @@ #include "Kismet/KismetSystemLibrary.h" #include "CollisionComponent.generated.h" -DECLARE_DELEGATE_OneParam(FOnHit, FHitResult hitResult); +//DECLARE_MULTICAST_DELEGATE_OneParam ·Î º¯°æ ÇÊ¿ä +DECLARE_DELEGATE_OneParam(FOnHit, FHitResult); UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class D1_API UCollisionComponent : public UActorComponent @@ -29,11 +30,30 @@ public: public: void CollisionTrace(); public: - FORCEINLINE void SetCollisionMesh(UPrimitiveComponent* InputComponent) { CollisionMeshComponent = InputComponent; } - FORCEINLINE void EnableCollision(); - FORCEINLINE void DisableCollision() { IsCollisionEnabled = false; } + TArray GetAlreadyHitActors() { return AlreadyHitActors; } FORCEINLINE void ClearHitActors() { AlreadyHitActors.Empty(); } + FHitResult GetLastHit() { return LastHit; } + + UPrimitiveComponent* GetCollisionMeshComponent() { return CollisionMeshComponent; } + FORCEINLINE void SetCollisionMeshComponent(UPrimitiveComponent* InputComponent) { CollisionMeshComponent = InputComponent; } + + FORCEINLINE void AddActorToIgnore(AActor* inputActor) { ActorsToIgnore.Add(inputActor); } + void RemoveActorToIgnore(AActor* inputActor) { ActorsToIgnore.Remove(inputActor); } + TArray GetActorToIgnore() { return ActorsToIgnore; } + + //Initialize + FORCEINLINE void SetTraceRaius(float inputTrace) { TraceRadius = inputTrace; } + FORCEINLINE void SetStartSocketName(FName InputStartSocketName) { StartSocketName = InputStartSocketName; } + FORCEINLINE void SetEndSocketName(FName InpuEndSocketName) { EndSocketName = InpuEndSocketName; } + FORCEINLINE void SetCollisionObjectTypes(TArray> InputCollisionObjectTypes) { CollisionObjectTypes = InputCollisionObjectTypes; } + FORCEINLINE void SetDrawDebugType(TEnumAsByte InputDrawDebugType) { DrawDebugType = InputDrawDebugType; } +public: + UFUNCTION(BlueprintCallable) + FORCEINLINE void EnableCollision(); + UFUNCTION(BlueprintCallable) + FORCEINLINE void DisableCollision() { bCollisionEnabled = false; } + bool IsCollisionEnabled() { return bCollisionEnabled; } private: UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Initialization", meta=(AllowPrivateAccess="true")) float TraceRadius; @@ -53,11 +73,12 @@ private: UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="Components", meta = (AllowPrivateAccess = "true")) TObjectPtr CollisionMeshComponent; - bool IsCollisionEnabled; + bool bCollisionEnabled; TArray> AlreadyHitActors; TArray> ActorsToIgnore; FHitResult LastHit; TObjectPtr HitActor; - FOnHit OnHit; +public: + FOnHit OnHitDelegate; }; diff --git a/Source/D1/Interface/CombatInterface.h b/Source/D1/Interface/CombatInterface.h index ca62828a..32e39c46 100644 --- a/Source/D1/Interface/CombatInterface.h +++ b/Source/D1/Interface/CombatInterface.h @@ -30,4 +30,6 @@ public: void ResetCombat(); UFUNCTION(BlueprintCallable, BlueprintNativeEvent) FRotator GetDesiredRotation(); + UFUNCTION(BlueprintCallable, BlueprintNativeEvent) + bool CanReceiveDamage(); };