#pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "Core/DescentHandle.h" #include "Core/Tuning/DescentTune_Player.h" #include "DescentVitals.generated.h" /** What the vitals rules need to know about this step. */ namespace Descent::Vitals { /** U2: 100 points in 2,400 s (40 minutes). */ constexpr double NutritionDrainPerSec = 100.0 / 2400.0; constexpr double StarveHPPerSec = 1.0; } struct FDescentVitalsInput { bool bSwimming = false; bool bSprint = false; // sprinting or gliding: O2 x 1.4 bool bHeadAtPoolSurface = false; // in the shaft, head within 0.6 m of the pool surface: O2 refills bool bHonestVoid = false; // swimming inside an honest void }; /** * The player's vitals as plain data and arithmetic (DESIGN_UE.md sections 5.3 and 5.8), so the rules are tested without a world. * M3 owns O2, health, death and respawn; nutrition is a number that does not move until M8; the debt is kept here until M5 owns money. */ struct THEDESCENT_API FDescentVitalsState { double Nutrition = Descent::Tune::Player::NutritionStartPct; double O2 = Descent::Tune::Player::O2BaseSec; double O2Max = Descent::Tune::Player::O2BaseSec; double Health = 100.0; double Debt = 0.0; bool bDrowning = false; bool bDead = false; FString DeadReason; int32 Deaths = 0; void Advance(const FDescentVitalsInput& In, double Dt); /** "drown" (also an honest void while swimming) adds 900 cr of debt, "implode" 4,800 cr. */ void Die(const TCHAR* Reason); /** Health 60, O2 full, alive (section 5.8). */ void Respawn(); }; /** The vitals of the character, stepped in sim step 6 (Vitals). */ UCLASS(ClassGroup = (Descent)) class THEDESCENT_API UDescentVitalsComponent : public UActorComponent { GENERATED_BODY() public: UDescentVitalsComponent(); virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type Reason) override; FDescentVitalsState State; private: void Step(double Dt); FDescentHandle StepHandle; };