From 7c98bb7d41e7cda5a0f484339f3fa066667c871d Mon Sep 17 00:00:00 2001 From: nathan Date: Mon, 18 May 2026 21:13:31 -0700 Subject: [PATCH] Add MVP death respawn UI --- AGRARIAN_DEVELOPMENT_ROADMAP.md | 2 +- Scripts/verify_mvp_death_respawn_ui.py | 57 +++++++++++++++++++ Source/AgrarianGame/AgrarianDebugHUD.cpp | 36 ++++++++++++ Source/AgrarianGame/AgrarianDebugHUD.h | 4 ++ .../AgrarianGamePlayerController.cpp | 13 +++++ .../AgrarianGamePlayerController.h | 3 + 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 Scripts/verify_mvp_death_respawn_ui.py diff --git a/AGRARIAN_DEVELOPMENT_ROADMAP.md b/AGRARIAN_DEVELOPMENT_ROADMAP.md index 130057a..48235cf 100644 --- a/AGRARIAN_DEVELOPMENT_ROADMAP.md +++ b/AGRARIAN_DEVELOPMENT_ROADMAP.md @@ -802,7 +802,7 @@ Target deliverable: A small group can join a server, spawn into one biome, gathe - [x] Add inventory UI. Promoted the existing compact replicated-inventory HUD panel into the 0.1.N UI pass with `AgrarianToggleInventoryUI`, keeping the MVP inventory surface lightweight while full drag/drop inventory remains later work. - [x] Add crafting UI. Promoted the existing compact crafting HUD panel into the 0.1.N UI pass with `AgrarianToggleCraftingUI`, showing known recipes and ingredient readiness while keeping full crafting menus for later UX expansion. - [x] Add interaction prompts. Promoted the existing centered interactable prompt renderer into the 0.1.N UI pass with `AgrarianToggleInteractionPrompts`, keeping prompt text driven by focused interactables. -- [ ] Add death/respawn UI. +- [x] Add death/respawn UI. Added a dedicated dead-state MVP panel with last death reason, Ground Zero respawn context, and `AgrarianToggleDeathRespawnUI` while preserving the existing server-authoritative respawn command. - [ ] Add debug/dev menu. - [ ] Add accessibility basics. - [ ] Ensure UI scales on common resolutions. diff --git a/Scripts/verify_mvp_death_respawn_ui.py b/Scripts/verify_mvp_death_respawn_ui.py new file mode 100644 index 0000000..20ce475 --- /dev/null +++ b/Scripts/verify_mvp_death_respawn_ui.py @@ -0,0 +1,57 @@ +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +FILES = { + "AgrarianDebugHUD.h": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.h", + "AgrarianDebugHUD.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianDebugHUD.cpp", + "AgrarianGamePlayerController.h": ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.h", + "AgrarianGamePlayerController.cpp": ROOT / "Source" / "AgrarianGame" / "AgrarianGamePlayerController.cpp", + "AGRARIAN_DEVELOPMENT_ROADMAP.md": ROOT / "AGRARIAN_DEVELOPMENT_ROADMAP.md", +} + +EXPECTED = { + "AgrarianDebugHUD.h": [ + "bShowDeathRespawnUI", + "DrawDeathRespawnPanel", + ], + "AgrarianDebugHUD.cpp": [ + "DrawDeathRespawnPanel(AgrarianCharacter)", + "Survival.bIsDead", + "YOU DID NOT SURVIVE", + "LastDeathReason", + "Respawn will return you to Ground Zero", + ], + "AgrarianGamePlayerController.h": [ + "AgrarianToggleDeathRespawnUI", + "AgrarianRespawn", + ], + "AgrarianGamePlayerController.cpp": [ + "AgrarianToggleDeathRespawnUI", + "bShowDeathRespawnUI = !AgrarianHUD->bShowDeathRespawnUI", + "MVP death/respawn UI shown.", + "ServerAgrarianRespawn_Implementation", + ], + "AGRARIAN_DEVELOPMENT_ROADMAP.md": [ + "[x] Add death/respawn UI.", + "`AgrarianToggleDeathRespawnUI`", + ], +} + + +def main(): + missing = [] + for label, path in FILES.items(): + text = path.read_text(encoding="utf-8") + for snippet in EXPECTED[label]: + if snippet not in text: + missing.append(f"{label}: {snippet}") + + if missing: + raise RuntimeError("MVP death/respawn UI verification failed: " + "; ".join(missing)) + + print("Agrarian MVP death/respawn UI verification complete.") + + +if __name__ == "__main__": + main() diff --git a/Source/AgrarianGame/AgrarianDebugHUD.cpp b/Source/AgrarianGame/AgrarianDebugHUD.cpp index 0833c5d..df43a02 100644 --- a/Source/AgrarianGame/AgrarianDebugHUD.cpp +++ b/Source/AgrarianGame/AgrarianDebugHUD.cpp @@ -24,6 +24,7 @@ void AAgrarianDebugHUD::DrawHUD() } DrawMvpHudFrame(AgrarianCharacter); + DrawDeathRespawnPanel(AgrarianCharacter); DrawInteractionPrompt(AgrarianCharacter); DrawCriticalStats(AgrarianCharacter->GetSurvivalComponent()); const float InventoryBottomY = DrawInventoryPanel(AgrarianCharacter); @@ -68,6 +69,41 @@ void AAgrarianDebugHUD::DrawMvpHudFrame(const AAgrarianGameCharacter* AgrarianCh DrawText(HudText, FColor(225, 235, 220), X + (18.0f * Scale), Y + (16.0f * Scale), nullptr, 0.86f * Scale, false); } +void AAgrarianDebugHUD::DrawDeathRespawnPanel(const AAgrarianGameCharacter* AgrarianCharacter) +{ + if (!bShowDeathRespawnUI || !AgrarianCharacter || !Canvas) + { + return; + } + + const UAgrarianSurvivalComponent* SurvivalComponent = AgrarianCharacter->GetSurvivalComponent(); + if (!SurvivalComponent || !SurvivalComponent->Survival.bIsDead) + { + return; + } + + const float Scale = FMath::Max(0.25f, TextScale); + const float PanelWidth = FMath::Min(Canvas->ClipX - 80.0f, 560.0f * Scale); + const float PanelHeight = 178.0f * Scale; + const float X = (Canvas->ClipX - PanelWidth) * 0.5f; + const float Y = (Canvas->ClipY - PanelHeight) * 0.5f; + + DrawRect(FLinearColor(0.035f, 0.018f, 0.016f, 0.86f), X, Y, PanelWidth, PanelHeight); + DrawRect(FLinearColor(0.78f, 0.20f, 0.16f, 0.95f), X, Y, PanelWidth, 4.0f * Scale); + + float TextY = Y + (28.0f * Scale); + DrawScaledLine(TEXT("YOU DID NOT SURVIVE"), X + (28.0f * Scale), TextY, 1.28f * Scale, FColor(245, 150, 130)); + DrawScaledLine( + FString::Printf(TEXT("Cause: %s"), *SurvivalComponent->Survival.LastDeathReason.ToString()), + X + (30.0f * Scale), + TextY, + 0.92f * Scale, + FColor(225, 210, 195)); + TextY += 10.0f * Scale; + DrawScaledLine(TEXT("Respawn will return you to Ground Zero with acute conditions stabilized."), X + (30.0f * Scale), TextY, 0.86f * Scale, FColor(190, 205, 180)); + DrawScaledLine(TEXT("Use the MVP respawn action when ready."), X + (30.0f * Scale), TextY, 0.86f * Scale, FColor(190, 205, 180)); +} + void AAgrarianDebugHUD::DrawInteractionPrompt(const AAgrarianGameCharacter* AgrarianCharacter) { if (!bShowInteractionPrompt || !AgrarianCharacter || !AgrarianCharacter->HasInteractionPrompt() || !Canvas) diff --git a/Source/AgrarianGame/AgrarianDebugHUD.h b/Source/AgrarianGame/AgrarianDebugHUD.h index d5091ed..f8488a7 100644 --- a/Source/AgrarianGame/AgrarianDebugHUD.h +++ b/Source/AgrarianGame/AgrarianDebugHUD.h @@ -51,11 +51,15 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD") bool bShowInteractionPrompt = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD") + bool bShowDeathRespawnUI = true; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|HUD", meta = (ClampMin = "0.25")) float PromptTextScale = 1.15f; protected: void DrawMvpHudFrame(const class AAgrarianGameCharacter* AgrarianCharacter); + void DrawDeathRespawnPanel(const class AAgrarianGameCharacter* AgrarianCharacter); void DrawInteractionPrompt(const class AAgrarianGameCharacter* AgrarianCharacter); void DrawCriticalStats(const UAgrarianSurvivalComponent* SurvivalComponent); float DrawInventoryPanel(const class AAgrarianGameCharacter* AgrarianCharacter); diff --git a/Source/AgrarianGame/AgrarianGamePlayerController.cpp b/Source/AgrarianGame/AgrarianGamePlayerController.cpp index 220848a..93f858d 100644 --- a/Source/AgrarianGame/AgrarianGamePlayerController.cpp +++ b/Source/AgrarianGame/AgrarianGamePlayerController.cpp @@ -320,6 +320,19 @@ void AAgrarianGamePlayerController::AgrarianToggleInteractionPrompts() ClientMessage(AgrarianHUD->bShowInteractionPrompt ? TEXT("MVP interaction prompts shown.") : TEXT("MVP interaction prompts hidden.")); } +void AAgrarianGamePlayerController::AgrarianToggleDeathRespawnUI() +{ + AAgrarianDebugHUD* AgrarianHUD = GetHUD(); + if (!AgrarianHUD) + { + ClientMessage(TEXT("No Agrarian HUD is active.")); + return; + } + + AgrarianHUD->bShowDeathRespawnUI = !AgrarianHUD->bShowDeathRespawnUI; + ClientMessage(AgrarianHUD->bShowDeathRespawnUI ? TEXT("MVP death/respawn UI shown.") : TEXT("MVP death/respawn UI hidden.")); +} + void AAgrarianGamePlayerController::AgrarianSelectCharacter(FName Archetype) { if (!MvpFrontendWidget) diff --git a/Source/AgrarianGame/AgrarianGamePlayerController.h b/Source/AgrarianGame/AgrarianGamePlayerController.h index f694c34..bfc7795 100644 --- a/Source/AgrarianGame/AgrarianGamePlayerController.h +++ b/Source/AgrarianGame/AgrarianGamePlayerController.h @@ -100,6 +100,9 @@ public: UFUNCTION(Exec) void AgrarianToggleInteractionPrompts(); + UFUNCTION(Exec) + void AgrarianToggleDeathRespawnUI(); + UFUNCTION(Exec) void AgrarianSelectCharacter(FName Archetype);