diff --git a/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset b/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset index f187494..3b0f648 100644 Binary files a/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset and b/Content/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.uasset differ diff --git a/Content/UI/WBP_StaminaBar.uasset b/Content/UI/WBP_StaminaBar.uasset index 1442030..c4847e8 100644 Binary files a/Content/UI/WBP_StaminaBar.uasset and b/Content/UI/WBP_StaminaBar.uasset differ diff --git a/Source/KingshearthLegacy/HealthComponent.cpp b/Source/KingshearthLegacy/HealthComponent.cpp index dfbedda..3081ceb 100644 --- a/Source/KingshearthLegacy/HealthComponent.cpp +++ b/Source/KingshearthLegacy/HealthComponent.cpp @@ -9,7 +9,7 @@ void UHealthComponent::BeginPlay() { Super::BeginPlay(); - CurrentHealth = MaxHealth; + CurrentHealth = GetEffectiveMaxHealth(); } float UHealthComponent::GetHealth() const @@ -22,18 +22,28 @@ float UHealthComponent::GetMaxHealth() const return MaxHealth; } +float UHealthComponent::GetHealthDebuff() const +{ + return HealthDebuff; +} + +float UHealthComponent::GetEffectiveMaxHealth() const +{ + return MaxHealth * (1.0f - HealthDebuff); +} + void UHealthComponent::SetMaxHealth(float NewMaxHealth) { MaxHealth = FMath::Max(NewMaxHealth, 0.0f); - CurrentHealth = FMath::Clamp(CurrentHealth, 0.0f, MaxHealth); + CurrentHealth = FMath::Clamp(CurrentHealth, 0.0f, GetEffectiveMaxHealth()); } void UHealthComponent::SetHealth(float NewHealth) { const float PreviousHealth = CurrentHealth; - CurrentHealth = FMath::Clamp(NewHealth, 0.0f, MaxHealth); + CurrentHealth = FMath::Clamp(NewHealth, 0.0f, GetEffectiveMaxHealth()); OnHealthChanged.Broadcast(CurrentHealth); @@ -62,4 +72,18 @@ void UHealthComponent::RemoveHealth(float Amount) } SetHealth(CurrentHealth - Amount); -} \ No newline at end of file +} + +void UHealthComponent::SetHealthDebuff(float NewHealthDebuff) +{ + HealthDebuff = FMath::Clamp(NewHealthDebuff, 0.0f, 1.0f); + + const float ClampedHealth = FMath::Clamp(CurrentHealth, 0.0f, GetEffectiveMaxHealth()); + if (!FMath::IsNearlyEqual(ClampedHealth, CurrentHealth)) + { + CurrentHealth = ClampedHealth; + OnHealthChanged.Broadcast(CurrentHealth); + } + + OnHealthDebuffChanged.Broadcast(HealthDebuff); +} diff --git a/Source/KingshearthLegacy/HealthComponent.h b/Source/KingshearthLegacy/HealthComponent.h index c904a30..f69b6df 100644 --- a/Source/KingshearthLegacy/HealthComponent.h +++ b/Source/KingshearthLegacy/HealthComponent.h @@ -5,6 +5,7 @@ #include "HealthComponent.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthDebuffChanged, float, NewHealthDebuff); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDeath); UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) @@ -23,9 +24,14 @@ public: UFUNCTION(BlueprintPure, Category = "Health") float GetHealth() const; + /** Nominal cap, unaffected by HealthDebuff. Feeds the health bar's total width. */ UFUNCTION(BlueprintPure, Category = "Health") float GetMaxHealth() const; + /** 0-1 fraction of MaxHealth currently locked/unusable (curses, status effects, ...). */ + UFUNCTION(BlueprintPure, Category = "Health") + float GetHealthDebuff() const; + UFUNCTION(BlueprintCallable, Category = "Health") void SetMaxHealth(float NewMaxHealth); @@ -38,17 +44,30 @@ public: UFUNCTION(BlueprintCallable, Category = "Health") void RemoveHealth(float Amount); + /** Sets how much of MaxHealth is currently locked away (0-1). Not driven by anything yet - a future debuff/curse/status-effect system calls this. */ + UFUNCTION(BlueprintCallable, Category = "Health") + void SetHealthDebuff(float NewHealthDebuff); + protected: + /** MaxHealth minus whatever HealthDebuff currently locks away - what Health is actually clamped against. */ + float GetEffectiveMaxHealth() const; + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Health") float MaxHealth = 100.0f; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health") float CurrentHealth = 100.0f; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health") + float HealthDebuff = 0.0f; + public: UPROPERTY(BlueprintAssignable, Category = "Health") FOnHealthChanged OnHealthChanged; + UPROPERTY(BlueprintAssignable, Category = "Health") + FOnHealthDebuffChanged OnHealthDebuffChanged; + UPROPERTY(BlueprintAssignable, Category = "Health") FOnDeath OnDeath; }; \ No newline at end of file diff --git a/Source/KingshearthLegacy/KingshearthLegacyCharacter.cpp b/Source/KingshearthLegacy/KingshearthLegacyCharacter.cpp index 4f80a44..06d412e 100644 --- a/Source/KingshearthLegacy/KingshearthLegacyCharacter.cpp +++ b/Source/KingshearthLegacy/KingshearthLegacyCharacter.cpp @@ -69,8 +69,9 @@ void AKingshearthLegacyCharacter::Tick(float DeltaSeconds) } const bool bIsMoving = GetVelocity().SizeSquared() > FMath::Square(SprintMovementThreshold); + const bool bIsGrounded = GetCharacterMovement()->IsMovingOnGround(); - if (bWantsToSprint && bIsMoving && StaminaComponent->GetStamina() > 0.0f) + if (bWantsToSprint && bIsMoving && bIsGrounded && StaminaComponent->GetStamina() > 0.0f) { GetCharacterMovement()->MaxWalkSpeed = BaseWalkSpeed * SprintSpeedMultiplier; StaminaComponent->RemoveStamina(SprintStaminaDrainRate * DeltaSeconds); diff --git a/Source/KingshearthLegacy/UI/HealthBarWidget.cpp b/Source/KingshearthLegacy/UI/HealthBarWidget.cpp index dee33a6..57340c7 100644 --- a/Source/KingshearthLegacy/UI/HealthBarWidget.cpp +++ b/Source/KingshearthLegacy/UI/HealthBarWidget.cpp @@ -11,16 +11,18 @@ void UHealthBarWidget::InitializeHealthBar(UHealthComponent* InHealthComponent) if (HealthComponent) { HealthComponent->OnHealthChanged.RemoveDynamic(this, &UHealthBarWidget::HandleHealthChanged); + HealthComponent->OnHealthDebuffChanged.RemoveDynamic(this, &UHealthBarWidget::HandleHealthDebuffChanged); HealthComponent->OnDeath.RemoveDynamic(this, &UHealthBarWidget::HandleDeath); } HealthComponent = InHealthComponent; HealthComponent->OnHealthChanged.AddDynamic(this, &UHealthBarWidget::HandleHealthChanged); + HealthComponent->OnHealthDebuffChanged.AddDynamic(this, &UHealthBarWidget::HandleHealthDebuffChanged); HealthComponent->OnDeath.AddDynamic(this, &UHealthBarWidget::HandleDeath); SetStatValue(HealthComponent->GetHealth(), HealthComponent->GetMaxHealth()); - SetMaxHealthDebuff(DefaultMaxHealthDebuffPercent); + SetMaxHealthDebuff(HealthComponent->GetHealthDebuff()); } void UHealthBarWidget::SetMaxHealthDebuff(float InDebuffPercent) @@ -36,6 +38,11 @@ void UHealthBarWidget::HandleHealthChanged(float NewHealth) } } +void UHealthBarWidget::HandleHealthDebuffChanged(float NewHealthDebuff) +{ + SetMaxHealthDebuff(NewHealthDebuff); +} + void UHealthBarWidget::HandleDeath() { OnHealthDepleted(); diff --git a/Source/KingshearthLegacy/UI/HealthBarWidget.h b/Source/KingshearthLegacy/UI/HealthBarWidget.h index 2631c3c..b2152ad 100644 --- a/Source/KingshearthLegacy/UI/HealthBarWidget.h +++ b/Source/KingshearthLegacy/UI/HealthBarWidget.h @@ -27,6 +27,9 @@ protected: UFUNCTION() void HandleHealthChanged(float NewHealth); + UFUNCTION() + void HandleHealthDebuffChanged(float NewHealthDebuff); + UFUNCTION() void HandleDeath(); @@ -36,8 +39,4 @@ protected: UPROPERTY(BlueprintReadOnly, Category = "Health") TObjectPtr HealthComponent; - - /** 0-1 starting max-health debuff applied in InitializeHealthBar, e.g. 0.1 = 10% of max health locked/unusable. Defaults to 0 since this bar reflects a live component. */ - UPROPERTY(EditDefaultsOnly, Category = "Health") - float DefaultMaxHealthDebuffPercent = 0.0f; };