added commission tracker to HUD
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
[/Script/EngineSettings.GameMapsSettings]
|
||||
EditorStartupMap=/Game/Test/Maps/L_Test.L_Test
|
||||
EditorStartupMap=/Game/Test/Maps/L_TestCity.L_TestCity
|
||||
LocalMapOptions=
|
||||
TransitionMap=None
|
||||
bUseSplitscreen=True
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -121,6 +121,10 @@
|
||||
{
|
||||
"Name": "VisualStudioCodeSourceCodeAccess",
|
||||
"Enabled": false
|
||||
},
|
||||
{
|
||||
"Name": "PCG",
|
||||
"Enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -18,7 +18,7 @@ A pass over the actual tree on 2026-05-30 shows the code is **well ahead** of §
|
||||
- **Save — rearchitected, the "empty save" bug is gone.** `UGlobalSaveGameData` is now the durable state container with granular `Add/Update/Remove` for `WardrobeItems`/`EquippedItems`/`WorldItems` (all `FItemSaveRecord`). `USaveSubsystem::GetCurrentSave` creates + seeds a new save from `StartingSaveData`. `GameMode::BeginPlay` rehydrates world `AItemPickup`s from records with transforms. Round-trip architecture is in place.
|
||||
- **Phase 2 — done.** `Interactables/ItemPickup` is the world item actor; drop/pickup + interaction (`Interaction/InteractionComponent`) exist.
|
||||
- **Phase 3 — done.** `SessionManagerSubsystem` + `SessionLossResolver` as previously noted.
|
||||
- **New since snapshot:** `Censorship/CensorshipComponent`, `Clothing/ClothingVisualsComponent` (runtime per-slot mesh spawning) + `ClothingSlotsData`, GASP-style movement enums (`Global/Gait|Stance|AirMode|MovementState`), and a full **UI layer** (`UI/HUDWidget`, `GameLayoutWidget`, `Inventory/*` panels, **`RadialMenu/*` = the §14.1 quick-action menu**).
|
||||
- **New since snapshot:** `Censorship/CensorshipComponent`, `Clothing/ClothingVisualsComponent` (runtime per-slot mesh spawning) + `ClothingSlotsData`, GASP-style movement enums (`Global/Gait|Stance|AirMode|MovementState`), and a full **UI layer** (`UI/HUDWidget`, `UI/HUDCommissionTrackerWidget` = on-screen active-commission tracker, `GameLayoutWidget`, `Inventory/*` panels, **`RadialMenu/*` = the §14.1 quick-action menu**).
|
||||
- **Minor spec drift to fix when convenient:** `ERestrictionType` spells `BlockPhoneUse` as `BlockPhoneUsage` and splits the GDD's single `BlockExposeAction` into `BlockBoobsExpose`/`BlockVaginaExpose`/`BlockAnalExpose`. `FClothingRestriction` fields lack `EditDefaultsOnly` so they aren't author-editable in the asset. Not blocking the slice.
|
||||
|
||||
§1 should be rewritten in a later pass; until then, trust §0.1 over §1 where they disagree.
|
||||
|
||||
@@ -198,7 +198,7 @@ ENPCType UNPCDirectorSubsystem::PickWeightedClass() const
|
||||
return ENPCType::None;
|
||||
}
|
||||
|
||||
bool UNPCDirectorSubsystem::FindSpawnPoint(const FVector& Around, FVector& OutLocation) const
|
||||
bool UNPCDirectorSubsystem::FindSpawnPoint(const FVector& Around, FVector& OutLocation)
|
||||
{
|
||||
UNavigationSystemV1* NavSys = UNavigationSystemV1::GetCurrent(GetWorld());
|
||||
const UNPCDirectorConfig* Config = GetConfig();
|
||||
@@ -214,7 +214,9 @@ bool UNPCDirectorSubsystem::FindSpawnPoint(const FVector& Around, FVector& OutLo
|
||||
if (NavSys->GetRandomReachablePointInRadius(Around, Config->SpawnRadiusMax, NavLocation) &&
|
||||
FVector::DistSquared(NavLocation.Location, Around) >= MinRadiusSq)
|
||||
{
|
||||
OutLocation = NavLocation.Location;
|
||||
FVector SpawnLocation = NavLocation.Location;
|
||||
CorrectSpawnLocation(SpawnLocation);
|
||||
OutLocation = SpawnLocation;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -227,6 +229,11 @@ TSubclassOf<ANPC> UNPCDirectorSubsystem::GetRandomNPCClass(TArray<TSubclassOf<AN
|
||||
return InNPCClasses[RandomIndex];
|
||||
}
|
||||
|
||||
void UNPCDirectorSubsystem::CorrectSpawnLocation(FVector& OutVector)
|
||||
{
|
||||
OutVector.Z += 50.0f;
|
||||
}
|
||||
|
||||
APawn* UNPCDirectorSubsystem::GetPlayerPawn() const
|
||||
{
|
||||
return UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
|
||||
|
||||
@@ -42,8 +42,9 @@ private:
|
||||
ANPC* TakeFromPool();
|
||||
void ReturnToPool(ANPC* NPC);
|
||||
ENPCType PickWeightedClass() const;
|
||||
bool FindSpawnPoint(const FVector& Around, FVector& OutLocation) const;
|
||||
bool FindSpawnPoint(const FVector& Around, FVector& OutLocation);
|
||||
TSubclassOf<ANPC> GetRandomNPCClass(TArray<TSubclassOf<ANPC>> InNPCClasses);
|
||||
void CorrectSpawnLocation(FVector& OutVector);
|
||||
|
||||
APawn* GetPlayerPawn() const;
|
||||
UNPCDirectorConfig* GetConfig() const;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "HUDCommissionTrackerWidget.h"
|
||||
|
||||
#include "Components/PanelWidget.h"
|
||||
#include "NakedDesire/Commissions/Commission.h"
|
||||
#include "NakedDesire/Commissions/MissionSubsystem.h"
|
||||
#include "NakedDesire/UI/Phone/Apps/ForumCommissionWidget.h"
|
||||
|
||||
void UHUDCommissionTrackerWidget::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
if (UMissionSubsystem* Missions = GetMissionSubsystem())
|
||||
Missions->OnBoardChanged.AddUniqueDynamic(this, &UHUDCommissionTrackerWidget::Rebuild);
|
||||
|
||||
Rebuild();
|
||||
}
|
||||
|
||||
void UHUDCommissionTrackerWidget::NativeDestruct()
|
||||
{
|
||||
if (UMissionSubsystem* Missions = GetMissionSubsystem())
|
||||
Missions->OnBoardChanged.RemoveDynamic(this, &UHUDCommissionTrackerWidget::Rebuild);
|
||||
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void UHUDCommissionTrackerWidget::Rebuild()
|
||||
{
|
||||
if (!CommissionContainer || !CommissionEntryClass)
|
||||
return;
|
||||
|
||||
CommissionContainer->ClearChildren();
|
||||
|
||||
UMissionSubsystem* Missions = GetMissionSubsystem();
|
||||
if (!Missions)
|
||||
return;
|
||||
|
||||
// Only accepted commissions are "active" — offered / completed / expired stay on the forum.
|
||||
for (UCommission* Commission : Missions->GetAcceptedCommissions())
|
||||
{
|
||||
if (!Commission)
|
||||
continue;
|
||||
|
||||
UForumCommissionWidget* Entry = CreateWidget<UForumCommissionWidget>(this, CommissionEntryClass);
|
||||
if (!Entry)
|
||||
continue;
|
||||
|
||||
// SetCommission collapses the accept control and keeps the row's objective progress polling live;
|
||||
// the HUD row BP simply omits the accept / abandon buttons (both optional binds).
|
||||
Entry->SetCommission(Commission);
|
||||
CommissionContainer->AddChild(Entry);
|
||||
}
|
||||
}
|
||||
|
||||
UMissionSubsystem* UHUDCommissionTrackerWidget::GetMissionSubsystem() const
|
||||
{
|
||||
const UWorld* World = GetWorld();
|
||||
return World ? World->GetSubsystem<UMissionSubsystem>() : nullptr;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonUserWidget.h"
|
||||
#include "HUDCommissionTrackerWidget.generated.h"
|
||||
|
||||
class UPanelWidget;
|
||||
class UForumCommissionWidget;
|
||||
class UMissionSubsystem;
|
||||
|
||||
// On-screen tracker for accepted commissions (GDD §13 / Phase 7 objective-tracker), so the player can
|
||||
// read their active objectives during play without opening the phone forum. Mirrors the forum's accepted
|
||||
// section: reads the live board from UMissionSubsystem, rebuilds on OnBoardChanged, and reuses the forum
|
||||
// row class for per-objective progress polling. Display-only — no accept / abandon controls.
|
||||
UCLASS(Abstract)
|
||||
class NAKEDDESIRE_API UHUDCommissionTrackerWidget : public UCommonUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
|
||||
private:
|
||||
// Holds one row per accepted commission.
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UPanelWidget> CommissionContainer;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Category = "HUD")
|
||||
TSubclassOf<UForumCommissionWidget> CommissionEntryClass;
|
||||
|
||||
// Bound to UMissionSubsystem::OnBoardChanged (a dynamic delegate, hence UFUNCTION).
|
||||
UFUNCTION()
|
||||
void Rebuild();
|
||||
|
||||
UMissionSubsystem* GetMissionSubsystem() const;
|
||||
};
|
||||
@@ -48,7 +48,8 @@ private:
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
TObjectPtr<UCommonTextBlock> DescriptionText;
|
||||
|
||||
UPROPERTY(meta = (BindWidget))
|
||||
// Optional so display-only hosts (e.g. the HUD commission tracker) can reuse this row without a button.
|
||||
UPROPERTY(meta = (BindWidgetOptional))
|
||||
TObjectPtr<UButton> AcceptButton;
|
||||
|
||||
UPROPERTY(meta = (BindWidgetOptional))
|
||||
|
||||
Reference in New Issue
Block a user