Files
Naked-Desire/Source/NakedDesire/Commissions/CommissionObjective.h
T
2026-06-03 15:17:02 +03:00

77 lines
2.4 KiB
C++

// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "CommissionObjective.generated.h"
class ANakedDesireCharacter;
class UCommissionObjective;
class UCommissionConstraint;
DECLARE_MULTICAST_DELEGATE_OneParam(FOnObjectiveStateChangedSignature, UCommissionObjective*);
/**
* One typed objective step (GDD §13.4). Replaces the old Goal/Restriction split: a step owns its own
* condition and, optionally, a sustained-hold requirement (RequiredHoldSeconds). Subclasses override
* IsConditionMet() and call NotifyConditionChanged() when their inputs change; count-style objectives
* can instead call MarkSatisfied() directly. The hold timer lives here, so "expose for N seconds" and
* "expose once" differ only by a data value, not a class.
*/
UCLASS(Abstract, EditInlineNew, BlueprintType)
class NAKEDDESIRE_API UCommissionObjective : public UObject
{
GENERATED_BODY()
public:
FOnObjectiveStateChangedSignature OnStateChanged;
void Activate(ANakedDesireCharacter* InPlayer);
void Deactivate();
bool IsSatisfied() const { return bSatisfied; }
UFUNCTION(BlueprintPure)
virtual FText GetDescription() const;
// 0..1 for UI. Default: 1 when satisfied, partial while a hold timer runs, else 0.
UFUNCTION(BlueprintPure)
virtual float GetProgress() const;
protected:
UPROPERTY()
ANakedDesireCharacter* Player = nullptr;
// Continuous seconds the condition must hold to satisfy. 0 = satisfied the instant it is first met.
UPROPERTY(EditDefaultsOnly, meta = (ClampMin = 0))
float RequiredHoldSeconds = 0.0f;
// "While Y" gates: the objective only counts progress while every constraint reports IsMet().
UPROPERTY(EditDefaultsOnly, Instanced)
TArray<TObjectPtr<UCommissionConstraint>> Constraints;
virtual void OnActivate() {}
virtual void OnDeactivate() {}
// Sustained objectives override this; the base ANDs it with the constraints to drive the hold timer.
virtual bool IsConditionMet() const { return false; }
// True when every attached constraint is currently satisfied (count-style subclasses gate on this too).
bool AreConstraintsMet() const;
// Re-check the condition and (re)arm or cancel the hold timer accordingly.
void NotifyConditionChanged();
void MarkSatisfied();
bool bSatisfied = false;
private:
void HandleConstraintChanged();
void OnHoldElapsed();
void ClearHoldTimer();
FTimerHandle HoldTimerHandle;
float HoldStartTime = 0.0f;
};