#include "StaminaAttributeSet.h" UStaminaAttributeSet::UStaminaAttributeSet() { InitStamina(100.0f); InitMaxStamina(100.0f); InitFatigue(0.0f); } void UStaminaAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) { Super::PreAttributeChange(Attribute, NewValue); if (Attribute == GetStaminaAttribute()) { NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxStamina()); } else if (Attribute == GetMaxStaminaAttribute()) { NewValue = FMath::Max(NewValue, 0.0f); } else if (Attribute == GetFatigueAttribute()) { NewValue = FMath::Clamp(NewValue, 0.0f, 1.0f); } } void UStaminaAttributeSet::PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const { Super::PreAttributeBaseChange(Attribute, NewValue); // ApplyModToAttribute (SpendStamina/RestoreStamina/regen) writes BaseValue through this hook, not // PreAttributeChange - without clamping here, a large delta (e.g. RestoreStamina's debug "fill to max") // pushes BaseValue past MaxStamina. PreAttributeChange still clamps the displayed CurrentValue, but the // bloated BaseValue then absorbs every subsequent spend/regen delta before CurrentValue moves again. if (Attribute == GetStaminaAttribute()) { NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxStamina()); } else if (Attribute == GetMaxStaminaAttribute()) { NewValue = FMath::Max(NewValue, 0.0f); } else if (Attribute == GetFatigueAttribute()) { NewValue = FMath::Clamp(NewValue, 0.0f, 1.0f); } } void UStaminaAttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) { Super::PostAttributeChange(Attribute, OldValue, NewValue); if (Attribute == GetStaminaAttribute()) { if (!FMath::IsNearlyEqual(OldValue, NewValue)) { OnStaminaChanged.Broadcast(NewValue); } if (OldValue > 0.0f && NewValue <= 0.0f) { OnExhausted.Broadcast(); } } else if (Attribute == GetMaxStaminaAttribute()) { if (!FMath::IsNearlyEqual(OldValue, NewValue)) { // MaxStamina shrank/grew (typically GE_StaminaFatiguePenalty re-evaluating) - pull Stamina back in range. ClampStamina(); } } else if (Attribute == GetFatigueAttribute()) { if (!FMath::IsNearlyEqual(OldValue, NewValue)) { OnFatigueChanged.Broadcast(NewValue); } } } void UStaminaAttributeSet::ClampStamina() { SetStamina(FMath::Clamp(GetStamina(), 0.0f, GetMaxStamina())); }