init
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "GoalRestriction.h"
|
||||
|
||||
void UGoalRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
IsSuccess = false;
|
||||
Player = PlayerCharacter;
|
||||
OnUpdate.Broadcast(this);
|
||||
}
|
||||
|
||||
void UGoalRestriction::Complete()
|
||||
{
|
||||
Complete(true);
|
||||
}
|
||||
|
||||
void UGoalRestriction::Complete(const bool Value)
|
||||
{
|
||||
IsSuccess = Value;
|
||||
OnUpdate.Broadcast(this);
|
||||
}
|
||||
|
||||
FText UGoalRestriction::GetDescription() const
|
||||
{
|
||||
return FText::GetEmpty();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "GoalRestriction.generated.h"
|
||||
|
||||
class ANakedDesireCharacter;
|
||||
class UGoalRestriction;
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FMissionRestrictionUpdateSignature, UGoalRestriction*);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew, BlueprintType)
|
||||
class NAKEDDESIRE_API UGoalRestriction : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
FMissionRestrictionUpdateSignature OnUpdate;
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
bool GetIsSuccess() const
|
||||
{
|
||||
return IsSuccess;
|
||||
}
|
||||
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter);
|
||||
virtual void Complete();
|
||||
virtual void Complete(bool Value);
|
||||
virtual void Stop() {};
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
virtual FText GetDescription() const;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
ANakedDesireCharacter* Player = nullptr;
|
||||
|
||||
bool IsSuccess = false;
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "FlashGoal.h"
|
||||
|
||||
#include "NakedDesire/NPC/NPCAIController.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Missions.Goals.Flash"
|
||||
const FText GoalsFlashSingle = LOCTEXT("Description.Single", "Flash someone {BodyPart} once");
|
||||
const FText GoalsFlashMultiple = LOCTEXT("Description.Multiple", "Flash {BodyPart} to {PeopleCount} people");
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
void UFlashGoal::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Super::Init(PlayerCharacter);
|
||||
|
||||
PlayerNoticedHandle = PlayerCharacter->OnNoticed.AddUObject(this, &UFlashGoal::OnPlayerNoticed);
|
||||
}
|
||||
|
||||
void UFlashGoal::Complete()
|
||||
{
|
||||
Super::Complete();
|
||||
|
||||
Player->OnNoticed.Remove(PlayerNoticedHandle);
|
||||
}
|
||||
|
||||
FText UFlashGoal::GetDescription() const
|
||||
{
|
||||
const FText BodyTypeString = UPrivateBodyPartType::GetString(BodyType);
|
||||
|
||||
if (RequiredFlashCount == 1)
|
||||
{
|
||||
return FText::Format(GoalsFlashSingle,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("BodyPart"), BodyTypeString}
|
||||
});
|
||||
}
|
||||
|
||||
return FText::Format(GoalsFlashMultiple,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("BodyPart"), BodyTypeString},
|
||||
{TEXT("PeopleCount"), RequiredFlashCount}
|
||||
});
|
||||
}
|
||||
|
||||
void UFlashGoal::OnPlayerNoticed(ANPCAIController* NPC)
|
||||
{
|
||||
if (IsCompleted || !CheckRestrictions())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NoticedActors.Contains(NPC))
|
||||
{
|
||||
NoticedActors.Add(NPC);
|
||||
}
|
||||
|
||||
if (NoticedActors.Num() >= RequiredFlashCount)
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NakedDesire/MissionBuilder/MissionGoal.h"
|
||||
#include "NakedDesire/Player/PrivateBodyPartType.h"
|
||||
#include "FlashGoal.generated.h"
|
||||
|
||||
class ANPCAIController;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew)
|
||||
class NAKEDDESIRE_API UFlashGoal : public UMissionGoal
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, meta = (ClampMin = 1))
|
||||
int RequiredFlashCount = 1;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
EPrivateBodyPartType BodyType;
|
||||
|
||||
FDelegateHandle PlayerNoticedHandle;
|
||||
|
||||
UPROPERTY()
|
||||
TSet<AActor*> NoticedActors;
|
||||
|
||||
public:
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
||||
virtual void Complete() override;
|
||||
virtual FText GetDescription() const override;
|
||||
|
||||
private:
|
||||
void OnPlayerNoticed(ANPCAIController* NPC);
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#include "MinTimeGoal.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Missions.Goals.MinTime"
|
||||
const FText GoalsMinTimeDescription = LOCTEXT("Description", "Do following at least {MinTime} seconds");
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
|
||||
FText UMinTimeGoal::GetDescription() const
|
||||
{
|
||||
return FText::Format(GoalsMinTimeDescription,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("MinTime"), MinTime}
|
||||
});
|
||||
}
|
||||
|
||||
void UMinTimeGoal::OnRestrictionUpdated(UGoalRestriction* Restriction)
|
||||
{
|
||||
Super::OnRestrictionUpdated(Restriction);
|
||||
|
||||
if (CheckRestrictions())
|
||||
{
|
||||
if (!TimerHandle.IsValid())
|
||||
{
|
||||
GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &UMinTimeGoal::TimeIsUp, MinTime, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TimerHandle.IsValid())
|
||||
{
|
||||
GetWorld()->GetTimerManager().ClearTimer(TimerHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UMinTimeGoal::TimeIsUp()
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "../MissionGoal.h"
|
||||
#include "MinTimeGoal.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew)
|
||||
class NAKEDDESIRE_API UMinTimeGoal : public UMissionGoal
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual FText GetDescription() const override;
|
||||
|
||||
protected:
|
||||
virtual void OnRestrictionUpdated(UGoalRestriction* Restriction) override;
|
||||
|
||||
private:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float MinTime = 3.f;
|
||||
|
||||
FTimerHandle TimerHandle;
|
||||
|
||||
void TimeIsUp();
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "Mission.h"
|
||||
|
||||
#include "MissionGoal.h"
|
||||
|
||||
void UMission::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Player = PlayerCharacter;
|
||||
|
||||
for (const auto& Goal : Goals)
|
||||
{
|
||||
Goal->Init(Player);
|
||||
auto Handle = Goal->OnUpdate.AddUObject(this, &UMission::OnGoalUpdated);
|
||||
GoalUpdateHandles.Add(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
void UMission::OnGoalUpdated(UMissionGoal* MissionGoal)
|
||||
{
|
||||
if (IsCompleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckGoals())
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
|
||||
void UMission::Complete()
|
||||
{
|
||||
IsCompleted = true;
|
||||
|
||||
for (const auto& Goal : Goals)
|
||||
{
|
||||
for (const auto& Handle : GoalUpdateHandles)
|
||||
{
|
||||
Goal->OnUpdate.Remove(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
OnComplete.Broadcast(this);
|
||||
}
|
||||
|
||||
bool UMission::CheckGoals()
|
||||
{
|
||||
if (IsCompleted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& Goal : Goals)
|
||||
{
|
||||
if (!Goal->GetIsCompleted() || !Goal->CheckRestrictions())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "Mission.generated.h"
|
||||
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FMissionCompleteSignature, class UMission*);
|
||||
|
||||
class UMissionGoal;
|
||||
class ANakedDesireCharacter;
|
||||
class UGoalRestriction;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew, BlueprintType)
|
||||
class NAKEDDESIRE_API UMission : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Instanced)
|
||||
TArray<UMissionGoal*> Goals;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
int MoneyReward = 0;
|
||||
|
||||
bool IsCompleted = false;
|
||||
|
||||
TArray<FDelegateHandle> GoalUpdateHandles;
|
||||
|
||||
public:
|
||||
FMissionCompleteSignature OnComplete;
|
||||
|
||||
void Init(ANakedDesireCharacter* PlayerCharacter);
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
int GetMoneyReward() const
|
||||
{
|
||||
return MoneyReward;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
TArray<UMissionGoal*> GetGoals() const
|
||||
{
|
||||
return Goals;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
bool GetIsCompleted() const
|
||||
{
|
||||
return IsCompleted;
|
||||
}
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
ANakedDesireCharacter* Player = nullptr;
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void OnGoalUpdated(UMissionGoal* MissionGoal);
|
||||
|
||||
void Complete();
|
||||
|
||||
bool CheckGoals();
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "MissionGoal.h"
|
||||
|
||||
#include "GoalRestriction.h"
|
||||
|
||||
void UMissionGoal::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Player = PlayerCharacter;
|
||||
|
||||
for (const auto& Elem : Restrictions)
|
||||
{
|
||||
Elem->Init(Player);
|
||||
auto Handle = Elem->OnUpdate.AddUObject(this, &UMissionGoal::OnRestrictionUpdated);
|
||||
RestrictionUpdateHandles.Add(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
void UMissionGoal::Complete()
|
||||
{
|
||||
if (!CheckRestrictions())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsCompleted = true;
|
||||
for (const auto& Restriction : Restrictions)
|
||||
{
|
||||
Restriction->Stop();
|
||||
for (const auto& Handle : RestrictionUpdateHandles)
|
||||
{
|
||||
Restriction->OnUpdate.Remove(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
OnUpdate.Broadcast(this);
|
||||
}
|
||||
|
||||
bool UMissionGoal::CheckRestrictions()
|
||||
{
|
||||
if (IsCompleted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& Restriction : Restrictions)
|
||||
{
|
||||
if (!Restriction->GetIsSuccess())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FText UMissionGoal::GetDescription() const
|
||||
{
|
||||
return FText::GetEmpty();
|
||||
}
|
||||
|
||||
void UMissionGoal::OnRestrictionUpdated(UGoalRestriction* Restriction)
|
||||
{
|
||||
if (IsCompleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnUpdate.Broadcast(this);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "MissionGoal.generated.h"
|
||||
|
||||
class ANakedDesireCharacter;
|
||||
class UMissionGoal;
|
||||
class UGoalRestriction;
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FGoalUpdateSignature, UMissionGoal*);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew, BlueprintType)
|
||||
class NAKEDDESIRE_API UMissionGoal : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Instanced)
|
||||
TArray<UGoalRestriction*> Restrictions;
|
||||
|
||||
TArray<FDelegateHandle> RestrictionUpdateHandles;
|
||||
|
||||
public:
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter);
|
||||
virtual void Complete();
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
bool GetIsCompleted() const
|
||||
{
|
||||
return IsCompleted;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
TArray<UGoalRestriction*> GetRestrictions() const
|
||||
{
|
||||
return Restrictions;
|
||||
}
|
||||
|
||||
FGoalUpdateSignature OnUpdate;
|
||||
|
||||
bool CheckRestrictions();
|
||||
|
||||
UFUNCTION(BlueprintPure)
|
||||
virtual FText GetDescription() const;
|
||||
|
||||
protected:
|
||||
UPROPERTY()
|
||||
ANakedDesireCharacter* Player = nullptr;
|
||||
|
||||
virtual void OnRestrictionUpdated(UGoalRestriction* Restriction);
|
||||
|
||||
bool IsCompleted = false;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "MissionsConfig.h"
|
||||
@@ -0,0 +1,34 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "MissionsConfig.generated.h"
|
||||
|
||||
class UMission;
|
||||
|
||||
USTRUCT()
|
||||
struct NAKEDDESIRE_API FMissionsConfigItem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Instanced)
|
||||
TArray<UMission*> Missions;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API UMissionsConfig : public UPrimaryDataAsset
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FMissionsConfigItem> DailyMissions;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
TArray<FMissionsConfigItem> WeeklyMissions;
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "MissionsManager.h"
|
||||
#include "Mission.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
|
||||
|
||||
UMissionsManager::UMissionsManager()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
}
|
||||
|
||||
void UMissionsManager::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
Player = Cast<ANakedDesireCharacter>(GetOwner());
|
||||
UE_LOG(LogTemp, Warning, TEXT("Player is NULL %s"), Player == nullptr ? TEXT("True") : TEXT("False"));
|
||||
|
||||
for (const auto& Mission : AvailableMissions)
|
||||
{
|
||||
Mission->Init(Player);
|
||||
Mission->OnComplete.AddUObject(this, &UMissionsManager::CompleteMission);
|
||||
}
|
||||
}
|
||||
|
||||
void UMissionsManager::CompleteMission(UMission* Mission)
|
||||
{
|
||||
CompletedMissions.Add(Mission);
|
||||
AvailableMissions.Remove(Mission);
|
||||
OnMissionCompleted.Broadcast(Mission);
|
||||
}
|
||||
|
||||
void UMissionsManager::CollectRewards()
|
||||
{
|
||||
if (CompletedMissions.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int TotalReward = 0;
|
||||
for (const UMission* Mission : CompletedMissions)
|
||||
{
|
||||
TotalReward += Mission->GetMoneyReward();
|
||||
}
|
||||
|
||||
Player->Money += TotalReward;
|
||||
CompletedMissions.Empty();
|
||||
OnRewardsCollected.Broadcast(TotalReward);
|
||||
}
|
||||
|
||||
void UMissionsManager::RefreshDailyMissions(const TArray<UMission*>& NewMissions)
|
||||
{
|
||||
for (auto Mission : AvailableMissions)
|
||||
{
|
||||
Mission->OnComplete.RemoveAll(this);
|
||||
AvailableMissions.Remove(Mission);
|
||||
}
|
||||
|
||||
AvailableMissions.Append(NewMissions);
|
||||
|
||||
for (auto Mission : AvailableMissions)
|
||||
{
|
||||
Mission->Init(Player);
|
||||
Mission->OnComplete.AddUObject(this, &UMissionsManager::CompleteMission);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "MissionsManager.generated.h"
|
||||
|
||||
|
||||
class UMission;
|
||||
class ANakedDesireCharacter;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMissionCompletedSignature, UMission*, Mission);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRewardsCollected, int, Reward);
|
||||
|
||||
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
|
||||
class NAKEDDESIRE_API UMissionsManager : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY()
|
||||
ANakedDesireCharacter* Player = nullptr;
|
||||
|
||||
public:
|
||||
UMissionsManager();
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, Instanced, BlueprintReadOnly)
|
||||
TArray<UMission*> AvailableMissions;
|
||||
|
||||
UPROPERTY(BlueprintReadWrite)
|
||||
TArray<UMission*> CompletedMissions;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnMissionCompletedSignature OnMissionCompleted;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnRewardsCollected OnRewardsCollected;
|
||||
|
||||
void CompleteMission(UMission* Mission);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void CollectRewards();
|
||||
|
||||
UFUNCTION()
|
||||
void RefreshDailyMissions(const TArray<UMission*>& NewMissions);
|
||||
|
||||
protected:
|
||||
virtual void BeginPlay() override;
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "EquipClothingRestriction.h"
|
||||
|
||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
||||
#include "NakedDesire/Clothing/ClothingItemData.h"
|
||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Missions.Restriction.EquipClothing"
|
||||
const FText RestrictionEquipClothingDescriptionSingle = LOCTEXT("Description.Single", "Equip {ItemName}");
|
||||
const FText RestrictionEquipClothingDescriptionMultiple = LOCTEXT("Description.Multiple", "Equip one of: {ItemNames}");
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
void UEquipClothingRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Super::Init(PlayerCharacter);
|
||||
|
||||
if (!ClothingEquippedDelegateHandle.IsValid())
|
||||
{
|
||||
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UEquipClothingRestriction::OnClothingEquipped);
|
||||
}
|
||||
|
||||
if (!ClothingUnequippedDelegateHandle.IsValid())
|
||||
{
|
||||
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UEquipClothingRestriction::OnClothingUnequipped);
|
||||
}
|
||||
|
||||
CheckClothing();
|
||||
}
|
||||
|
||||
void UEquipClothingRestriction::Stop()
|
||||
{
|
||||
Super::Stop();
|
||||
|
||||
Player->ClothingManager->OnClothingEquip.Remove(this, TEXT("OnClothingEquipped"));
|
||||
Player->ClothingManager->OnClothingUnequip.Remove(this, TEXT("OnClothingUnequipped"));
|
||||
}
|
||||
|
||||
FText UEquipClothingRestriction::GetDescription() const
|
||||
{
|
||||
if (ClothingItems.Num() == 1 && ClothingItems[0])
|
||||
{
|
||||
return FText::Format(RestrictionEquipClothingDescriptionSingle,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("ItemName"), ClothingItems[0]->Name}
|
||||
});
|
||||
}
|
||||
|
||||
FString Items = TEXT("");
|
||||
for (const auto& Item : ClothingItems)
|
||||
{
|
||||
if (Item)
|
||||
{
|
||||
Items += Item->Name.ToString() + ", ";
|
||||
}
|
||||
}
|
||||
return FText::Format(RestrictionEquipClothingDescriptionMultiple,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("ItemNames"), FText::FromString(Items)}
|
||||
});
|
||||
}
|
||||
|
||||
void UEquipClothingRestriction::OnClothingEquipped(const UClothingItemData* ClothingData)
|
||||
{
|
||||
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingData](const UClothingItem* Item)
|
||||
{
|
||||
return Item && Item->Name.EqualTo(ClothingData->Info->Name);
|
||||
}) != nullptr;
|
||||
if (IsTargetClothing)
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
|
||||
void UEquipClothingRestriction::OnClothingUnequipped(const UClothingItemData* ClothingData)
|
||||
{
|
||||
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingData](const UClothingItem* Item)
|
||||
{
|
||||
return Item && Item->Name.EqualTo(ClothingData->Info->Name);
|
||||
}) != nullptr;
|
||||
if (IsTargetClothing)
|
||||
{
|
||||
Init(Player);
|
||||
}
|
||||
}
|
||||
|
||||
void UEquipClothingRestriction::CheckClothing()
|
||||
{
|
||||
for (const FClothingSlotData& ClothingSlot : Player->ClothingManager->ClothingSlots)
|
||||
{
|
||||
if (!ClothingSlot.ClothingData)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingSlot](const UClothingItem* Item)
|
||||
{
|
||||
return Item && Item->Name.EqualTo(ClothingSlot.ClothingData->Info->Name);
|
||||
}) != nullptr;
|
||||
if (IsTargetClothing)
|
||||
{
|
||||
Complete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
|
||||
#include "EquipClothingRestriction.generated.h"
|
||||
|
||||
class UClothingItem;
|
||||
class UClothingItemData;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew)
|
||||
class NAKEDDESIRE_API UEquipClothingRestriction : public UGoalRestriction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, meta = (ToolTip =
|
||||
"One of provided clothing items should be equipped by player. If multiple clothing items required provide multiple restrictions"))
|
||||
TArray<UClothingItem*> ClothingItems;
|
||||
|
||||
public:
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
||||
virtual void Stop() override;
|
||||
virtual FText GetDescription() const override;
|
||||
|
||||
private:
|
||||
FDelegateHandle ClothingEquippedDelegateHandle;
|
||||
FDelegateHandle ClothingUnequippedDelegateHandle;
|
||||
|
||||
UFUNCTION()
|
||||
void OnClothingEquipped(const UClothingItemData* ClothingData);
|
||||
|
||||
UFUNCTION()
|
||||
void OnClothingUnequipped(const UClothingItemData* ClothingData);
|
||||
|
||||
void CheckClothing();
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "ExposeBodyPartRestriction.h"
|
||||
|
||||
#include "NakedDesire/Clothing/ClothingItemData.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Missions.Restrictions.ExposeBodyPart"
|
||||
const FText RestrictionsExposeBodyPartDescription = LOCTEXT("Description", "Expose {BodyPart}");
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
void UExposeBodyPartRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Super::Init(PlayerCharacter);
|
||||
|
||||
PlayerCharacter->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UExposeBodyPartRestriction::EquipClothing);
|
||||
PlayerCharacter->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UExposeBodyPartRestriction::UnequipClothing);
|
||||
|
||||
CheckClothing();
|
||||
}
|
||||
|
||||
void UExposeBodyPartRestriction::Stop()
|
||||
{
|
||||
Super::Stop();
|
||||
|
||||
Player->ClothingManager->OnClothingEquip.Remove(this, TEXT("ClothingEquip"));
|
||||
Player->ClothingManager->OnClothingUnequip.Remove(this, TEXT("ClothingUnequip"));
|
||||
}
|
||||
|
||||
FText UExposeBodyPartRestriction::GetDescription() const
|
||||
{
|
||||
FText Part = UPrivateBodyPartType::GetString(BodyPart);
|
||||
|
||||
return FText::Format(RestrictionsExposeBodyPartDescription,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("BodyPart"), Part}
|
||||
});
|
||||
}
|
||||
|
||||
void UExposeBodyPartRestriction::EquipClothing(const UClothingItemData* ClothingData)
|
||||
{
|
||||
if (IsSuccess && ClothingData->Info->CoveredBodyParts.Contains(BodyPart))
|
||||
{
|
||||
Init(Player);
|
||||
}
|
||||
}
|
||||
|
||||
void UExposeBodyPartRestriction::UnequipClothing(const UClothingItemData* ClothingData)
|
||||
{
|
||||
if (IsSuccess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CheckClothing();
|
||||
}
|
||||
|
||||
void UExposeBodyPartRestriction::CheckClothing()
|
||||
{
|
||||
if (!Player || !Player->ClothingManager || Player->ClothingManager->ClothingSlots.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const FClothingSlotData* TargetClothingItem = Player->ClothingManager->ClothingSlots.FindByPredicate([this](const FClothingSlotData& ClothingSlot)
|
||||
{
|
||||
if (ClothingSlot.ClothingData)
|
||||
{
|
||||
return ClothingSlot.ClothingData->Info->CoveredBodyParts.Contains(BodyPart);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
if (!TargetClothingItem)
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NakedDesire/Player/PrivateBodyPartType.h"
|
||||
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
|
||||
#include "ExposeBodyPartRestriction.generated.h"
|
||||
|
||||
class UClothingItemData;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(EditInlineNew)
|
||||
class NAKEDDESIRE_API UExposeBodyPartRestriction : public UGoalRestriction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FDelegateHandle EquipClothingHandle;
|
||||
FDelegateHandle UnequipClothingHandle;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
EPrivateBodyPartType BodyPart;
|
||||
|
||||
protected:
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
||||
virtual void Stop() override;
|
||||
virtual FText GetDescription() const override;
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void EquipClothing(const UClothingItemData* ClothingData);
|
||||
|
||||
UFUNCTION()
|
||||
void UnequipClothing(const UClothingItemData* ClothingData);
|
||||
|
||||
void CheckClothing();
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
|
||||
#include "LocationRestriction.h"
|
||||
#include "NakedDesire/Locations/LocationData.h"
|
||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "Missions.Restrictions.Location"
|
||||
const FText RestrictionsLocationDescription = LOCTEXT("Description", "Visit {LocationName}");
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
void ULocationRestriction::Init(ANakedDesireCharacter* PlayerCharacter)
|
||||
{
|
||||
Super::Init(PlayerCharacter);
|
||||
|
||||
AreaEnterHandle = PlayerCharacter->OnAreaEnter.AddUObject(this, &ULocationRestriction::OnAreaEnter);
|
||||
AreaExitHandle = PlayerCharacter->OnAreaExit.AddUObject(this, &ULocationRestriction::OnAreaExit);
|
||||
}
|
||||
|
||||
void ULocationRestriction::Stop()
|
||||
{
|
||||
Super::Stop();
|
||||
|
||||
Player->OnAreaEnter.Remove(AreaEnterHandle);
|
||||
Player->OnAreaExit.Remove(AreaExitHandle);
|
||||
}
|
||||
|
||||
FText ULocationRestriction::GetDescription() const
|
||||
{
|
||||
return FText::Format(RestrictionsLocationDescription,
|
||||
FFormatNamedArguments
|
||||
{
|
||||
{TEXT("LocationName"), TargetLocation->Name}
|
||||
});
|
||||
}
|
||||
|
||||
void ULocationRestriction::OnAreaEnter(ULocationData* LocationData)
|
||||
{
|
||||
if (!IsSuccess && LocationData->Tag.MatchesTag(TargetLocation->Tag))
|
||||
{
|
||||
Complete();
|
||||
}
|
||||
}
|
||||
|
||||
void ULocationRestriction::OnAreaExit(ULocationData* LocationData)
|
||||
{
|
||||
if (IsSuccess && LocationData->Tag.MatchesTag(TargetLocation->Tag))
|
||||
{
|
||||
Init(Player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// © 2025 Naked People Team. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "NakedDesire/MissionBuilder/GoalRestriction.h"
|
||||
#include "LocationRestriction.generated.h"
|
||||
|
||||
class ULocationData;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API ULocationRestriction : public UGoalRestriction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FDelegateHandle AreaEnterHandle;
|
||||
FDelegateHandle AreaExitHandle;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
ULocationData* TargetLocation;
|
||||
|
||||
protected:
|
||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
||||
virtual void Stop() override;
|
||||
virtual FText GetDescription() const override;
|
||||
|
||||
private:
|
||||
void OnAreaEnter(ULocationData* LocationData);
|
||||
void OnAreaExit(ULocationData* LocationData);
|
||||
};
|
||||
Reference in New Issue
Block a user