// Copyright IHY. Universal Bars plugin. // One animated UMG bar driven by M_UI_UniversalBar. Handles a single logical // value (HP, stamina, durability, ...) plus optional data-driven penalty zones // for combined PEAK-style capacity bars (hunger / weight / cold eating into max). #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "UniversalBarWidget.generated.h" class UImage; class UMaterialInstanceDynamic; // A penalty / reserve zone consuming capacity from the right end of the bar. USTRUCT(BlueprintType) struct FBarZone { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone") FName Id = NAME_None; // Target width as a fraction of the full track (0..1). UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone", meta=(ClampMin="0", ClampMax="1")) float Width = 0.f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone") FLinearColor Color = FLinearColor(0.9f, 0.6f, 0.2f, 1.f); // Animated width that eases toward Width at runtime (not authored). float DisplayWidth = 0.f; }; UCLASS() class UNIVERSALBARS_API UUniversalBarWidget : public UUserWidget { GENERATED_BODY() public: UUniversalBarWidget(const FObjectInitializer& ObjectInitializer); // Name this "BarImage" in the WBP; assign an MI_UI_Bar_* (or the master) to its Brush. UPROPERTY(meta=(BindWidget)) TObjectPtr BarImage = nullptr; // ---- animation tuning ---- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float FillRiseSpeed = 7.f; // how fast the bright fill grows on increase/heal UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float DelayedFallSpeed = 4.f; // how fast the damage-lag tail drains on decrease UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float DelayedDelay = 0.25f; // pause before the tail starts draining (sec) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float FlashSpeed = 6.f; // flash decay rate UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float ZoneInterpSpeed = 8.f; // penalty-zone width easing UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") float LowThreshold = 0.25f; // below this, low-value pulse turns on UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim") bool bAutoFlashOnChange = true; // SetFillPercent auto-plays damage/heal flash UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Colors") FLinearColor DamageFlashColor = FLinearColor(1.f, 0.12f, 0.12f, 1.f); UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Colors") FLinearColor HealFlashColor = FLinearColor(0.6f, 1.f, 0.6f, 1.f); // ---- data-driven penalty zones (combined / PEAK mode) ---- UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zones") TArray PenaltyZones; // ===== public API ===== // Animated set of the bar's main value (0..1). Decrease => instant drop + lag // tail (+ damage flash). Increase => smooth rise (+ heal flash). UFUNCTION(BlueprintCallable, Category="Bar") void SetFillPercent(float NewValue, bool bAnimate = true); UFUNCTION(BlueprintCallable, Category="Bar") void SetShieldPercent(float NewValue); UFUNCTION(BlueprintCallable, Category="Bar") void PlayDamageFlash(); UFUNCTION(BlueprintCallable, Category="Bar") void PlayHealFlash(); UFUNCTION(BlueprintCallable, Category="Bar") void PlayFlash(FLinearColor Color); UFUNCTION(BlueprintCallable, Category="Bar") void SetBarColors(FLinearColor Fill, FLinearColor Empty, FLinearColor Border, FLinearColor Delayed); UFUNCTION(BlueprintCallable, Category="Bar") void SetSegmentCount(int32 Count); // ---- penalty zone management (animated) ---- UFUNCTION(BlueprintCallable, Category="Bar|Zones") void SetPenaltyZone(FName Id, float Width, FLinearColor Color); UFUNCTION(BlueprintCallable, Category="Bar|Zones") void SetPenaltyZoneWidth(FName Id, float Width); UFUNCTION(BlueprintCallable, Category="Bar|Zones") void RemovePenaltyZone(FName Id); UFUNCTION(BlueprintCallable, Category="Bar|Zones") void ClearPenaltyZones(); // Generic escape hatches. UFUNCTION(BlueprintCallable, Category="Bar") void SetScalar(FName Param, float Value); UFUNCTION(BlueprintCallable, Category="Bar") void SetVector(FName Param, FLinearColor Value); UFUNCTION(BlueprintPure, Category="Bar") float GetFillPercent() const { return TargetFill; } // ---- zone layout in bar-U space (0..1), using current animated widths ---- // Right edge of the usable region (1 - sum of penalty display widths). UFUNCTION(BlueprintPure, Category="Bar|Zones") float GetUsableEnd() const; // U-coordinate of a penalty zone's centre; -1 if the zone is absent. UFUNCTION(BlueprintPure, Category="Bar|Zones") float GetZoneCenter(FName Id) const; protected: virtual void NativeConstruct() override; virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override; UMaterialInstanceDynamic* EnsureMID(); void PushZones(bool bImmediate); private: UPROPERTY(Transient) TObjectPtr BarMID = nullptr; float TargetFill = 1.f; float DisplayFill = 1.f; float DelayedFill = 1.f; float DelayTimer = 0.f; float FlashAmount = 0.f; bool bFlashing = false; FLinearColor PendingFlashColor = FLinearColor::Red; float PulseAmount = 0.f; static constexpr int32 MaxMaterialZones = 4; };