#pragma once #include "CoreMinimal.h" /** * Everything the HUD shows, as plain data (DESIGN_UE.md section 8.5 "HUD layout", section 9.4 `ui.hud`). * * The seam: gameplay systems WRITE their fields into the model (UDescentHudSubsystem::Model(), normally from a * callback registered on EDescentLateStep::HudModel), and the UI track READS it to draw. Neither includes the other. * So the model is declared complete up front; a field a system needs and cannot find goes into `Extras` until the * Administrator's merge promotes it to a real field. * * Positions on screen are never stored here: the HUD lays itself out. Strings are the finished text the HUD prints * (a system formats its own readout, with the helpers at the bottom of this file for the common ones). */ enum class EDescentHudToastKind : uint8 { Info, Good, Warn, Bad }; struct FDescentHudToast { FString Text; EDescentHudToastKind Kind = EDescentHudToastKind::Info; /** Counts down in real time (late steps); the toast is removed at 0. */ float SecondsLeft = 4.f; }; /** Bottom left: health, O2 (seconds), nutrition gauges; small BIO reserve readout (section 8.5). */ struct FDescentHudVitals { float Health = 100.f; // 0..100 float Nutrition = 42.f; // 0..100 percent float O2Seconds = 45.f; float O2MaxSeconds = 45.f; bool bShowO2 = false; // only while swimming float BioReserveFu = 0.f; // the carrier's biomass reserve (U3), food units float BioCapFu = 0.f; bool bShowBio = true; }; struct FDescentHudHotbarSlot { FName ItemId; // NAME_None = empty slot FString Label; // two-letter glyph or short name int32 Count = 0; }; /** Bottom right: hull, power, hold, speed of the controlled vehicle. Only shown when no dashboard is on screen. */ struct FDescentHudVehiclePanel { bool bVisible = false; FString Title; // "CANTICLE", "KAZAH-1" float HullPct = 100.f; float PowerPct = 100.f; float HoldUsed = 0.f; float HoldCap = 0.f; float SpeedMps = 0.f; float ThrottlePct = 0.f; // helm }; /** Right centre, helm views 1 to 4. */ struct FDescentHudProximityRow { FString Label; // "BOW", "KEEL", ... float DistanceM = 0.f; bool bWarning = false; }; /** Distance-labelled marker in the world: beacon, carrier, Tender. */ struct FDescentHudMarker { FName Id; FString Label; FVector WorldUU = FVector::ZeroVector; bool bShowDistance = true; FLinearColor Color = FLinearColor::White; }; /** A sonar hit (M9): drawn over the scene at its screen position, never hidden by the fog or the rock in front of it. */ struct FDescentHudSonarPoint { FVector WorldUU = FVector::ZeroVector; FLinearColor Color = FLinearColor::White; float SizePx = 2.f; }; /** Which warnings are lit. The HUD decides how they look. */ struct FDescentHudWarnings { bool bShear = false; // above the rim, in the Shear current (section 2.11) bool bCrush = false; // near the Tender's rating depth bool bHull = false; bool bPower = false; bool bLowO2 = false; bool bHunger = false; // nutrition below 20 percent bool bNearSoftLimit = false; // U7: diegetic warning before the playable space ends FString Text; // the line shown for the most important active warning, "" when none }; struct THEDESCENT_API FDescentHudModel { /** Maximum toasts on screen (section 8.5: toast stack of 3). The oldest is dropped for a new one. */ static constexpr int32 MaxToasts = 3; // ---- who is controlling what (the HUD hides and shows regions by this) ---- FName Mode; // EDescentMode name: Title, Foot, Helm, Sub, Swim, ... (NAME_None before the player exists) bool bUiWindowOpen = false; // a PDA / station window is open on top of the mode // ---- top centre: depth panel and compass ---- double DepthM = 0.0; // Descent::DepthOfZ of the reference point (section 5.9) FString DepthText; // "1,810 m" FString Band; // "THE THROAT" double RatingM = 0.0; // depth rating of the controlled vehicle, 0 = none shown FString RatingText; // "RATING 3,250 m" float CompassHeadingDeg = 0.f; // 0..360, 0 = +X // ---- top left ---- FString Objective; bool bObjectiveFolded = false; // ---- top right ---- TArray Toasts; // ---- bottom left ---- FDescentHudVitals Vitals; double TemperatureC = 26.0; // at the reference point, from Descent::AmbientTemperatureAt FString TemperatureLabel; // "CABIN" inside the hull, "WATER" outside, "" = hide FString TemperatureText; // "CABIN 26.0 deg C" // ---- bottom right ---- FDescentHudVehiclePanel Vehicle; // ---- bottom centre ---- TArray Hotbar; int32 HotbarSelected = 0; bool bShowHotbar = false; FString Radio; // the radio line, "" = hidden float RadioSecondsLeft = 0.f; // counts down; the line is cleared at 0 (set <= 0 with a text to keep it until cleared) // ---- centre ---- bool bCrosshair = true; FString Prompt; // "E Take the helm", "" = hidden bool bHelmReticle = false; // helm aim reticle and hull-nose marker FVector2D HelmAimNormalized = FVector2D::ZeroVector; // -1..1 from the screen centre FString BuildReason; // why the build ghost is red, "" = none // ---- right centre ---- bool bShowProximity = false; TArray Proximity; // ---- world markers and warnings ---- TArray Markers; TArray Sonar; FDescentHudWarnings Warnings; /** Stopgap for a field nobody anticipated. Promote to a real field at merge time. */ TMap Extras; void Reset() { *this = FDescentHudModel(); } /** Pushes a toast; the oldest goes when the stack is full. */ void PushToast(const FString& Text, EDescentHudToastKind Kind = EDescentHudToastKind::Info, float Seconds = 4.f); /** Sets the radio line; Seconds <= 0 keeps it until it is set to "" again. */ void SetRadio(const FString& Text, float Seconds = 6.f); /** Counts down toasts and the radio line. Called by UDescentHudSubsystem once per late step. */ void Advance(float DeltaSeconds); // ---- formatting helpers, so every writer prints numbers the same way ---- /** 1810.4 -> "1,810" (rounded, thousands separators). */ static FString FormatThousands(double Value); /** 1810.4 -> "1,810 m" */ static FString FormatDepth(double DepthMetres); /** (26.0, "CABIN") -> "CABIN 26.0 deg C" */ static FString FormatTemperature(double Celsius, const FString& Label); };