77 lines
2.4 KiB
C++
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;
|
|
}; |