158 lines
3.3 KiB
C++
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();
|
|
} |