I managed to add a “Shield” attribute. I added it to healthset. I also have the variables in Health component for Shield change and other functions that the health has. I managed to link a “Shield” bar onto the UI. It has the same functions as the health bar. As I have the C++ set atm. Instead of the character losing health on damage from guns or damage pad. They lose Shield. Everything to that point works. I have very limited knowledge of c++
So, my question. What do I add to the c++?
I want the bOutOfShield to be called when shield is equal to 0. and Damage to be subtracted from Health instead.
HealthSet.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
include “AbilitySystemComponent.h”
include “LyraAttributeSet.h”
include “NativeGameplayTags.h”
include “LyraHealthSet.generated.h”
class UObject;
struct FFrame;
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_Damage);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_DamageImmunity);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_DamageSelfDestruct);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_FellOutOfWorld);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Lyra_Damage_Message);
struct FGameplayEffectModCallbackData;
/**
- ULyraHealthSet
- Class that defines attributes that are necessary for taking damage.
- Attribute examples include: health, shields, and resistances.
*/
UCLASS(BlueprintType)
class ULyraHealthSet : public ULyraAttributeSet
{
GENERATED_BODY()
public:
ULyraHealthSet();
ATTRIBUTE_ACCESSORS(ULyraHealthSet, Health);
ATTRIBUTE_ACCESSORS(ULyraHealthSet, MaxHealth);
ATTRIBUTE_ACCESSORS(ULyraHealthSet, Shield);
ATTRIBUTE_ACCESSORS(ULyraHealthSet, MaxShield);
ATTRIBUTE_ACCESSORS(ULyraHealthSet, Healing);
ATTRIBUTE_ACCESSORS(ULyraHealthSet, Damage);
// Delegate to broadcast when the health attribute reaches zero.
mutable FLyraAttributeEvent OnOutOfHealth;
mutable FLyraAttributeEvent OnOutOfShield;
protected:
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_Shield(const FGameplayAttributeData& OldValue);
UFUNCTION()
void OnRep_MaxShield(const FGameplayAttributeData& OldValue);
virtual bool PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data) override;
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
virtual void PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
void ClampAttribute(const FGameplayAttribute& Attribute, float& NewValue) const;
private:
// The current health attribute. The health will be capped by the max health attribute. Health is hidden from modifiers so only executions can modify it.
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Lyra|Health", Meta = (HideFromModifiers, AllowPrivateAccess = true))
FGameplayAttributeData Health;
// The current max health attribute. Max health is an attribute since gameplay effects can modify it.
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Lyra|Health", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData MaxHealth;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Lyra|Health", Meta = (HideFromModifiers, AllowPrivateAccess = true))
FGameplayAttributeData Shield;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Lyra|Health", Meta = (HideFromModifiers, AllowPrivateAccess = true))
FGameplayAttributeData MaxShield;
// Used to track when the health reaches 0.
bool bOutOfHealth;
bool bOutOfShield;
// -------------------------------------------------------------------
// Meta Attribute (please keep attributes that aren't 'stateful' below
// -------------------------------------------------------------------
private:
// Incoming healing. This is mapped directly to +Health
UPROPERTY(BlueprintReadOnly, Category=“Lyra|Health”, Meta=(AllowPrivateAccess=true))
FGameplayAttributeData Healing;
// Incoming damage. This is mapped directly to -Health
UPROPERTY(BlueprintReadOnly, Category="Lyra|Health", Meta=(HideFromModifiers, AllowPrivateAccess=true))
FGameplayAttributeData Damage;
};
HealthSet.cpp
// Copyright Epic Games, Inc. All Rights Reserved.
include “LyraHealthSet.h”
include “AbilitySystem/Attributes/LyraAttributeSet.h”
include “LyraGameplayTags.h”
include “Net/UnrealNetwork.h”
include “AbilitySystem/LyraAbilitySystemComponent.h”
include “Engine/World.h”
include “GameplayEffectExtension.h”
include “Messages/LyraVerbMessage.h”
include “GameFramework/GameplayMessageSubsystem.h”
include UE_INLINE_GENERATED_CPP_BY_NAME(LyraHealthSet)
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_Damage, “Gameplay.Damage”);
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_DamageImmunity, “Gameplay.DamageImmunity”);
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_DamageSelfDestruct, “Gameplay.Damage.SelfDestruct”);
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_FellOutOfWorld, “Gameplay.Damage.FellOutOfWorld”);
UE_DEFINE_GAMEPLAY_TAG(TAG_Lyra_Damage_Message, “Lyra.Damage.Message”);
ULyraHealthSet::ULyraHealthSet()
: Health(100.0f)
, MaxHealth(100.0f)
, Shield(100.0f)
, MaxShield(100.0f)
{
bOutOfHealth = false;
bOutOfShield = false;
}
void ULyraHealthSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ULyraHealthSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ULyraHealthSet, MaxHealth, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ULyraHealthSet, Shield, COND_OwnerOnly, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ULyraHealthSet, MaxShield, COND_OwnerOnly, REPNOTIFY_Always);
}
void ULyraHealthSet::OnRep_Health(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ULyraHealthSet, Health, OldValue);
}
void ULyraHealthSet::OnRep_MaxHealth(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ULyraHealthSet, MaxHealth, OldValue);
}
void ULyraHealthSet::OnRep_Shield(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ULyraHealthSet, Shield, OldValue);
}
void ULyraHealthSet::OnRep_MaxShield(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ULyraHealthSet, MaxShield, OldValue);
}
bool ULyraHealthSet::PreGameplayEffectExecute(FGameplayEffectModCallbackData &Data)
{
if (!Super::PreGameplayEffectExecute(Data))
{
return false;
}
// Handle modifying incoming normal damage
if (Data.EvaluatedData.Attribute == GetDamageAttribute())
{
if (Data.EvaluatedData.Magnitude > 0.0f)
{
const bool bIsDamageFromSelfDestruct = Data.EffectSpec.GetDynamicAssetTags().HasTagExact(TAG_Gameplay_DamageSelfDestruct);
if (Data.Target.HasMatchingGameplayTag(TAG_Gameplay_DamageImmunity) && !bIsDamageFromSelfDestruct)
{
// Do not take away any health.
Data.EvaluatedData.Magnitude = 0.0f;
return false;
}
#if !UE_BUILD_SHIPPING
// Check GodMode cheat, unlimited health is checked below
if (Data.Target.HasMatchingGameplayTag(LyraGameplayTags::Cheat_GodMode) && !bIsDamageFromSelfDestruct)
{
// Do not take away any health.
Data.EvaluatedData.Magnitude = 0.0f;
return false;
}
#endif // #if !UE_BUILD_SHIPPING
}
}
return true;
}
void ULyraHealthSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
const bool bIsDamageFromSelfDestruct = Data.EffectSpec.GetDynamicAssetTags().HasTagExact(TAG_Gameplay_DamageSelfDestruct);
float MinimumShield = 0.0f;
float MinimumHealth = 0.0f;
#if !UE_BUILD_SHIPPING
// Godmode and unlimited health stop death unless it’s a self destruct
if (!bIsDamageFromSelfDestruct &&
(Data.Target.HasMatchingGameplayTag(LyraGameplayTags::Cheat_GodMode) || Data.Target.HasMatchingGameplayTag(LyraGameplayTags::Cheat_UnlimitedHealth) ))
{
MinimumHealth = 1.0f;
}
#endif // #if !UE_BUILD_SHIPPING
if (Data.EvaluatedData.Attribute == GetDamageAttribute())
{
// Send a standardized verb message that other systems can observe
if (Data.EvaluatedData.Magnitude > 0.0f)
{
FLyraVerbMessage Message;
Message.Verb = TAG_Lyra_Damage_Message;
Message.Instigator = Data.EffectSpec.GetEffectContext().GetEffectCauser();
Message.InstigatorTags = *Data.EffectSpec.CapturedSourceTags.GetAggregatedTags();
Message.Target = GetOwningActor();
Message.TargetTags = *Data.EffectSpec.CapturedTargetTags.GetAggregatedTags();
//@TODO: Fill out context tags, and any non-ability-system source/instigator tags
//@TODO: Determine if it's an opposing team kill, self-own, team kill, etc...
Message.Magnitude = Data.EvaluatedData.Magnitude;
UGameplayMessageSubsystem& MessageSystem = UGameplayMessageSubsystem::Get(GetWorld());
MessageSystem.BroadcastMessage(Message.Verb, Message);
}
// Convert into -Health and then clamp
SetShield(FMath::Clamp(GetShield() - GetDamage(), MinimumShield, GetMaxShield()));
SetDamage(0.0f);
}
else if (Data.EvaluatedData.Attribute == GetHealingAttribute())
{
// Convert into +Health and then clamo
SetShield(FMath::Clamp(GetShield() + GetHealing(), MinimumShield, GetMaxShield()));
SetHealing(0.0f);
}
else if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
// Clamp and fall into out of health handling below
SetHealth(FMath::Clamp(GetHealth(), MinimumHealth, GetMaxHealth()));
}
if ((GetShield() <= 0.0f) && !bOutOfShield)
{
if (OnOutOfShield.IsBound())
{
const FGameplayEffectContextHandle& EffectContext = Data.EffectSpec.GetEffectContext();
AActor* Instigator = EffectContext.GetOriginalInstigator();
AActor* Causer = EffectContext.GetEffectCauser();
OnOutOfShield.Broadcast(Instigator, Causer, Data.EffectSpec, Data.EvaluatedData.Magnitude);
}
}
if ((GetHealth() <= 0.0f) && !bOutOfHealth)
{
if (OnOutOfHealth.IsBound())
{
const FGameplayEffectContextHandle& EffectContext = Data.EffectSpec.GetEffectContext();
AActor* Instigator = EffectContext.GetOriginalInstigator();
AActor* Causer = EffectContext.GetEffectCauser();
OnOutOfHealth.Broadcast(Instigator, Causer, Data.EffectSpec, Data.EvaluatedData.Magnitude);
}
}
// Check health again in case an event above changed it.
bOutOfHealth = (GetHealth() <= 0.0f);
bOutOfShield = (GetShield() <= 0.0f);
}
void ULyraHealthSet::PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const
{
Super::PreAttributeBaseChange(Attribute, NewValue);
ClampAttribute(Attribute, NewValue);
}
void ULyraHealthSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
ClampAttribute(Attribute, NewValue);
}
void ULyraHealthSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
Super::PostAttributeChange(Attribute, OldValue, NewValue);
if (Attribute == GetMaxHealthAttribute())
{
// Make sure current health is not greater than the new max health.
if (GetHealth() > NewValue)
{
ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent();
check(LyraASC);
LyraASC->ApplyModToAttribute(GetHealthAttribute(), EGameplayModOp::Override, NewValue);
}
}
if (Attribute == GetMaxShieldAttribute())
{
// Make sure current Shield is not greater than the new max Shield.
if (GetShield() > NewValue)
{
ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent();
check(LyraASC);
LyraASC->ApplyModToAttribute(GetShieldAttribute(), EGameplayModOp::Override, NewValue);
}
}
if (bOutOfHealth && (GetHealth() > 0.0f))
{
bOutOfHealth = false;
}
if (bOutOfShield && (GetShield() > 0.0f))
{
bOutOfShield = false;
}
}
void ULyraHealthSet::ClampAttribute(const FGameplayAttribute& Attribute, float& NewValue) const
{
if (Attribute == GetHealthAttribute())
{
// Do not allow health to go negative or above max health.
NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxHealth());
}
else if (Attribute == GetMaxHealthAttribute())
{
// Do not allow max health to drop below 1.
NewValue = FMath::Max(NewValue, 1.0f);
}
if (Attribute == GetShieldAttribute())
{
// Do not allow Shield to go negative or above max health.
NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxShield());
}
else if (Attribute == GetMaxShieldAttribute())
{
// Do not allow max Shield to drop below 1.
NewValue = FMath::Max(NewValue, 1.0f);
}
}