// © 2025 Naked People Team. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Subsystems/WorldSubsystem.h" #include "MissionSubsystem.generated.h" class UCommission; class UCommissionBoardConfig; class ANakedDesireCharacter; class UGlobalSaveGameData; struct FCommissionReward; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnCommissionBoardChangedSignature); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCommissionCompletedSignature, UCommission*, Commission); /** * Runtime owner of the commission board (GDD §13). Offers the hand-authored pool, drives the * accept / complete / expire lifecycle, pays rewards instantly on completion (§23 #23), and persists * commission state to the save. A WorldSubsystem (like UTimeOfDaySubsystem / SessionManager): it needs * world access + OnDayChanged, and rehydrates durable state from the GameInstance save each level. */ UCLASS() class NAKEDDESIRE_API UMissionSubsystem : public UWorldSubsystem { GENERATED_BODY() public: virtual void OnWorldBeginPlay(UWorld& InWorld) override; virtual void Deinitialize() override; UFUNCTION(BlueprintPure) const TArray& GetOfferedCommissions() const { return OfferedCommissions; } UFUNCTION(BlueprintPure) const TArray& GetAcceptedCommissions() const { return AcceptedCommissions; } // Commissions completed within the current period. Cleared at the day-roll alongside the accepted // list (see ExpireAccepted), so today this is "completed today" for both tiers — true week-long // retention for weeklies needs the deferred §13.1 weekly-lifecycle work. UFUNCTION(BlueprintPure) const TArray& GetCompletedCommissions() const { return CompletedCommissions; } UFUNCTION(BlueprintCallable) void AcceptCommission(UCommission* Commission); UFUNCTION(BlueprintCallable) void AbandonCommission(UCommission* Commission); UPROPERTY(BlueprintAssignable) FOnCommissionBoardChangedSignature OnBoardChanged; UPROPERTY(BlueprintAssignable) FOnCommissionCompletedSignature OnCommissionCompleted; private: UFUNCTION() void HandleDayChanged(int32 NewDay); void BuildBoard(); // instantiate offered commissions from the config void RestoreFromSave(); // re-apply persisted accepted / completed states void ExpireAccepted(); // deadline: accepted & unfinished -> expired void HandleCommissionCompleted(UCommission* Commission); void ApplyReward(const FCommissionReward& Reward); void PersistState() const; ANakedDesireCharacter* GetPlayer() const; UGlobalSaveGameData* GetSave() const; UCommissionBoardConfig* GetBoardConfig() const; UPROPERTY() TArray OfferedCommissions; UPROPERTY() TArray AcceptedCommissions; UPROPERTY() TArray CompletedCommissions; };