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

158 lines
3.3 KiB
C++

// © 2025 Naked People Team. All Rights Reserved.
#include "Commission.h"
#include "CommissionObjective.h"
void UCommission::Accept(ANakedDesireCharacter* InPlayer)
{
if (State != ECommissionState::Offered)
return;
Player = InPlayer;
SetState(ECommissionState::Accepted);
ArmObjectives();
// Arming evaluates immediately, so a commission already satisfied on accept completes now.
if (AreAllObjectivesSatisfied())
Complete();
}
void UCommission::Abandon()
{
if (State != ECommissionState::Accepted)
return;
DisarmObjectives();
SetState(ECommissionState::Offered);
}
void UCommission::Expire()
{
if (State != ECommissionState::Accepted)
return;
DisarmObjectives();
SetState(ECommissionState::Expired);
}
void UCommission::RestoreState(ECommissionState SavedState, ANakedDesireCharacter* InPlayer)
{
Player = InPlayer;
if (SavedState == ECommissionState::Accepted)
{
SetState(ECommissionState::Accepted);
ArmObjectives();
if (AreAllObjectivesSatisfied())
Complete();
}
else
{
SetState(SavedState);
}
}
void UCommission::Complete()
{
if (State != ECommissionState::Accepted)
return; // already resolved — guards against double completion / double payout
DisarmObjectives();
SetState(ECommissionState::Completed);
OnCompleted.Broadcast(this);
}
bool UCommission::AreAllObjectivesSatisfied() const
{
if (Objectives.Num() == 0)
return false; // a commission with no objectives never auto-completes
for (const UCommissionObjective* Objective : Objectives)
{
if (!Objective || !Objective->IsSatisfied())
return false;
}
return true;
}
void UCommission::ArmObjectives()
{
// Subscribe to all objectives up front; activation differs by mode.
for (UCommissionObjective* Objective : Objectives)
{
if (Objective)
Objective->OnStateChanged.AddUObject(this, &UCommission::HandleObjectiveStateChanged);
}
if (bSequentialObjectives)
{
ActiveObjectiveIndex = INDEX_NONE;
AdvanceSequential();
}
else
{
for (UCommissionObjective* Objective : Objectives)
{
if (Objective)
Objective->Activate(Player);
}
}
}
void UCommission::DisarmObjectives()
{
for (UCommissionObjective* Objective : Objectives)
{
if (!Objective)
continue;
Objective->OnStateChanged.RemoveAll(this);
Objective->Deactivate();
}
ActiveObjectiveIndex = INDEX_NONE;
}
void UCommission::AdvanceSequential()
{
for (int32 Index = 0; Index < Objectives.Num(); ++Index)
{
UCommissionObjective* Objective = Objectives[Index];
if (!Objective)
continue;
if (!Objective->IsSatisfied())
{
// Activate the first unsatisfied step (only if it isn't already the armed one — Activate
// resets progress, so re-activating the live objective would wipe its hold timer).
if (ActiveObjectiveIndex != Index)
{
ActiveObjectiveIndex = Index;
Objective->Activate(Player);
}
return;
}
}
ActiveObjectiveIndex = INDEX_NONE;
Complete();
}
void UCommission::SetState(ECommissionState NewState)
{
State = NewState;
OnStateChanged.Broadcast(this);
}
void UCommission::HandleObjectiveStateChanged(UCommissionObjective* Objective)
{
if (State != ECommissionState::Accepted)
return;
if (bSequentialObjectives)
AdvanceSequential(); // the armed step finished -> activate the next, or complete
else if (AreAllObjectivesSatisfied())
Complete();
}