Space Plunder
Loading...
Searching...
No Matches
QuestData.h
Go to the documentation of this file.
1// Fill out your copyright notice in the Description page of Project Settings.
2
3#pragma once
4
5#include "CoreMinimal.h"
6#include "GameplayTagContainer.h"
7#include "Data/BaseData.h"
8#include "Engine/DataTable.h"
9#include "UObject/UnrealType.h"
10#include "QuestData.generated.h"
11
12
13struct FGameplayTag;
14DECLARE_LOG_CATEGORY_CLASS(LogQuestSystem, Display, All);
15
16DECLARE_STATS_GROUP(TEXT("Quest System Stat Group"), STATGROUP_Quests, STATCAT_Advanced)
17DECLARE_CYCLE_STAT(TEXT("Player Component"), STATGROUP_Quests_PlayerComponent, STATGROUP_Quests);
18DECLARE_CYCLE_STAT(TEXT("BPLib"), STATGROUP_Quests_BPLib, STATGROUP_Quests);
19DECLARE_CYCLE_STAT(TEXT("Game Component"), STATGROUP_Quests_GameComponent, STATGROUP_Quests);
20DECLARE_CYCLE_STAT(TEXT("All Widgets"), STATGROUP_Quests_Widgets, STATGROUP_Quests);
21DECLARE_CYCLE_STAT(TEXT("Goal Component"), STATGROUP_Quests_GoalComponents, STATGROUP_Quests);
22
23
24
25
26UENUM(Blueprintable, BlueprintType, meta = (ScriptName = "EFilterQuestTypePython"))
27enum class EFilterQuestType : uint8
28{
29 All UMETA(DisplayName = "All"),
30 Main UMETA(DisplayName = "Main"),
31 Side UMETA(DisplayName = "Side"),
32 HumanQuest UMETA(DisplayName = "Human"),
33 AlienQuest UMETA(DisplayName = "Alien"),
34 RaiderQuest UMETA(DisplayName = "Raider"),
35 RobotQuest UMETA(DisplayName = "Robot"),
36 ZombieQuest UMETA(DisplayName = "Zombie"),
37 Completed UMETA(DisplayName = "Completed"),
38 Failed UMETA(DisplayName = "Failed"),
39 Abandoned UMETA(DisplayName = "Abandoned"),
40 Single UMETA(DisplayName = "Single"),
41 Multiple UMETA(DisplayName = "Multiple")
42};
43
44// Quest Faction: Robots
45// Quest Category: Main
46// Quest Status: Current
47
48
49UENUM(Blueprintable, BlueprintType, meta = (ScriptName = "EQuestLocationPython"))
50enum class EQuestLocation : uint8
51{
53};
54
55UENUM(Blueprintable, BlueprintType, meta = (ScriptName = "EQuestOutcomePython"))
56enum class EQuestStatus : uint8
57{
58 NotStarted UMETA(DisplayName = "Not Started"),
59 Active UMETA(DisplayName = "Active"),
60 Completed UMETA(DisplayName = "Completed"),
61 Failed UMETA(DisplayName = "Failed"),
62 Abandoned UMETA(DisplayName = "Abandoned"),
63 NotAvailable UMETA(DisplayName = "Not Available") // When quest goes down an alternative path
64};
65
66
67// USTRUCT(BlueprintType)
68// struct FQuestID
69// {
70// GENERATED_BODY()
71//
72// UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
73// FString ID = "ID";
74//
75// void SetUniqueNumber(const int32 NewID)
76// {
77// UniqueID = NewID;
78// }
79// int32 GetUniqueNumber() const
80// {
81// return UniqueID;
82// }
83//
84//
85// FQuestID()
86// {
87//
88// }
89// explicit FQuestID(const FString& NewID)
90// {
91// ID = NewID;
92// };
93// explicit FQuestID(const FString& NewID, const int32 NewUniqueID)
94// {
95// ID = NewID;
96// UniqueID = NewUniqueID;
97// };
98//
99// bool IsValid() const
100// {
101// bool bValid = false;
102// if(ID != "ID"){bValid = true;};
103// return bValid;
104// }
105// bool operator==(const FQuestID& Other) const
106// {
107// return (ID == Other.ID) && (UniqueID == Other.UniqueID);
108// }
109// bool operator!=(const FQuestID& Other) const
110// {
111// return (ID != Other.ID) || (ID == Other.ID && UniqueID != Other.UniqueID);
112// }
113// protected:
114// UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="General")
115// int32 UniqueID = 0;
116//
117// };
118
119USTRUCT(BlueprintType)
121{
122 GENERATED_BODY()
123
124 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
125 FString ObjectiveID = "Default";
126 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
127 int32 ObjectiveAmount = 0;
128
129 //- Maybe? //
130 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System")
131 bool bHasWorldMarker = false;
132
133};
134
135
136
138USTRUCT(BlueprintType)
140{
141 GENERATED_BODY()
142
143 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
144 FString QuestItemID = "Default";
145 // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
146 // FString QuestItemID = "Default";
147
148 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
149 FString ObjectiveID = {""};
150 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
151 int32 ObjectiveAmount = 0;
152
153 //@TODO For multiple Objectives
154 // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System|Goal")
155 // TArray<FString> ObjectiveIDs = {""};
156
157 //? Maybe Have TMAP for ObjectiveID and Objective Amount
158
159 //- Maybe? //
160 // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Quest System")
161 // bool bHasWorldMarker = false;
162
163};
164
165USTRUCT(BlueprintType)
167{
168 GENERATED_BODY()
169
170 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Reward")
171 int32 Experience = 0;
172 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Reward")
173 int32 Credits = 0;
174 //@ TODO reward Items
175 // UPROPERTY(BlueprintReadWrite, Category="Quest System")
176 // TMap<FString, int32> Items;
177
179 {
180
181 }
182};
183
184USTRUCT(BlueprintType)
186{
187 GENERATED_BODY()
188
189 // Returns the elapsed time after updating it
190 float GetElapsedTime() const
191 {
192 return ElapsedTime;
193 }
195 float GetStartTime() const
196 {
197 return StartTimeInSeconds;
198 }
199
200 void StartObjective(const UObject* Owner)
201 {
202 if(GetIsStarted() == false)
203 {
204 Status = EQuestStatus::Active;
205 // bInProgress = true;
206 if(const UWorld* World = GEngine->GetWorldFromContextObject(Owner, EGetWorldErrorMode::LogAndReturnNull))
207 {
208 StartTimeInSeconds = World->GetTimeSeconds();
209 }
210 }
211 //
212 else
213 {
214
215 }
216 }
218 {
219 Status = EQuestStatus::NotStarted;
220 }
221 float SaveObjectiveTime(const UObject* Owner)
222 {
223 if(Status != EQuestStatus::Active){return ElapsedTime;}
224 if(const UWorld* World = GEngine->GetWorldFromContextObject(Owner, EGetWorldErrorMode::LogAndReturnNull))
225 {
226 const float CurrentTimeInSeconds = World->GetTimeSeconds();
227 ElapsedTime = CurrentTimeInSeconds - StartTimeInSeconds;
228 }
229 return ElapsedTime;
230 }
232 {
233 if(Status != EQuestStatus::Active){return;}
234 StartTimeInSeconds = -ElapsedTime;
235 }
236 bool GetIsFailed(const int32 RequiredFailProgress) const
237 {
238 if(FailProgress >= RequiredFailProgress)
239 {
240 return true;
241 }
242 return Status == EQuestStatus::Failed;
243 }
245 bool GetDidCompleteInTime(const bool bObjectiveTimed = false, const float TimeToComplete = 0.0f) const
246 {
247 //- Sets ElapsedTime //
248 if(bObjectiveTimed && StartTimeInSeconds >= 0.0f)
249 {
250 return ElapsedTime <= TimeToComplete;
251 }
252 return true;
253 }
255 bool IsFinished(const int32 RequiredFailProgress, const int32 RequiredProgress) const
256 {
257 return (FailProgress >= RequiredFailProgress) || (CurrentProgress >= RequiredProgress);
258 }
259 bool IsSuccessful(const int32 RequiredFailProgress, const int32 RequiredProgress) const
260 {
261 return (CurrentProgress >= RequiredProgress) && (FailProgress < RequiredFailProgress);
262 }
263 //- Will Return if Progress is At Required, Finished or Failed
264 bool Complete(const int32 RequiredFailProgress, const int32 RequiredProgress) const
265 {
266 if(FailProgress >= RequiredFailProgress)
267 {
268 return true;
269 }
270 return CurrentProgress >= RequiredProgress;
271 }
272
274 {
275 return Status;
276 }
277 bool IsActive() const
278 {
279 return (Status == EQuestStatus::Active);
280 }
281 bool GetIsStarted() const
282 {
283 return (Status != EQuestStatus::NotAvailable && Status != EQuestStatus::NotStarted);
284 }
286 {
287 return Status == EQuestStatus::NotStarted;
288 }
289
291 bool AddProgress(const int32 Amount, const int32 RequiredProgress)
292 {
293 CurrentProgress += Amount;
294 if(CurrentProgress >= RequiredProgress)
295 {
296 CurrentProgress = RequiredProgress;
297 if(Status == EQuestStatus::Active)
298 {
299 Status = EQuestStatus::Completed;
300 return true;
301 }
302 }
303 return false;
304 }
306 bool AddFailProgress(const int32 Amount, const int32 RequiredFailProgress)
307 {
308 FailProgress += Amount;
309 if(FailProgress >= RequiredFailProgress)
310 {
311 FailProgress = RequiredFailProgress;
312 if(Status == EQuestStatus::Active)
313 {
314 Status = EQuestStatus::Failed;
315 return true;
316 }
317 }
318 return false;
319 }
320 int32 GetCurrentProgress() const
321 {
322 return CurrentProgress;
323 }
324 int32 GetFailProgress() const
325 {
326 return FailProgress;
327 }
328 void SetUniqueID(const int32 NewUID)
329 {
330 UniqueID = NewUID;
331 }
332 int32 GetUniqueID() const
333 {
334 return UniqueID;
335 }
336
337
338protected:
339 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
340 EQuestStatus Status = EQuestStatus::NotStarted;
341
342 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="ID")
343 int32 UniqueID = -1;
344
345
346 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Timed")
347 float StartTimeInSeconds = -1.0f;
348 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Timed")
349 float ElapsedTime = -1.0f;
350 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Progress")
351 int32 FailProgress = 0;
352 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Progress")
353 int32 CurrentProgress = 0;
354};
355
356
357
358
359USTRUCT(BlueprintType)
360struct FQuestObjectives : public FTableRowBase
361{
362 GENERATED_BODY()
363
364 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
365 FString ObjectiveID = "Default Quest Objective";
366 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
367 FString ObjectiveDescription = "Default Description";
368 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
369 TArray<FString> ObjectiveHints = {"Objective","Hint"};
370
371 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
372 bool bHasWorldMarker = false;
373 //@TODO World Markers per Objecive, or have on like Quest Goal
374 // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
375 // TArray<AActor*> WorldMarkers;
376 //@TODO World marker after certain progress
377
378 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Status")
379 bool bIsOptional = false;
380
381 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
382 int32 RequiredFailProgress = 100;
383 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
384 int32 RequiredProgress = 100;
385 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
386 bool bShowProgress = true;
387 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
388 bool bShowFailProgress = true;
389
391 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
392 bool bDynamicProgress = false;
393
394
396 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress")
397 bool bIsUnlockedAtCertainProgress = false;
398 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Progress", meta=(EditCondition=bIsUnlockedAtCertainProgress))
399 int32 UnlockProgressNeeded = 15;
400
401 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Timed")
402 bool bObjectiveTimed = false;
403 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Timed", meta=(EditCondition=bObjectiveTimed))
404 float TimeToComplete = 10.0f;
405
406 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Reward")
407 FQuestReward RewardBonus;
408
409 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
410 FQuestObjectivesStatus ObjectiveStatus;
411
412 //@ TODO Add Branch to complete, finished etc.
413 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
414 bool bBranchObjective = false;
415
417 {
418
419 }
421 bool AddProgress(const int32 Amount)
422 {
423 return ObjectiveStatus.AddProgress(Amount, RequiredProgress);
424 }
426 bool AddFailProgress(const int32 Amount)
427 {
428 return ObjectiveStatus.AddFailProgress(Amount, RequiredFailProgress);
429 }
430 void StartObjective(const UObject* Owner)
431 {
432 if(bIsUnlockedAtCertainProgress && CanStart(GetCurrentProgress()) == false)
433 {
434 ObjectiveStatus.SetObjectiveNotYetStarted();
435 return;
436 }
437 ObjectiveStatus.StartObjective(Owner);
438 }
439 void StartObjective(const UObject* Owner, const int32 QuestProgress)
440 {
441 if(bIsUnlockedAtCertainProgress && CanStart(QuestProgress) == false)
442 {
443 ObjectiveStatus.SetObjectiveNotYetStarted();
444 return;
445 }
446 ObjectiveStatus.StartObjective(Owner);
447 }
449 {
450 ObjectiveStatus.ResumeFromElapsedTime();
451 }
452 float SaveObjectiveTime(const UObject* Owner)
453 {
454 return ObjectiveStatus.SaveObjectiveTime(Owner);
455 }
456
457 void SetUniqueID(const int32 ID)
458 {
459 ObjectiveStatus.SetUniqueID(ID);
460 }
461
462
463
464 //~ Getters ~//
465
467 {
468 FUniqueID ID = FUniqueID(ObjectiveID);
469 ID.SetUniqueNumber(ObjectiveStatus.GetUniqueID());
470 return ID;
471 }
472
473
474 // Returns the elapsed time after updating it
475 float GetElapsedTime() const
476 {
477 return ObjectiveStatus.GetElapsedTime();
478 }
479 float GetStartTime() const
480 {
481 return ObjectiveStatus.GetStartTime();
482 }
484 {
485 return ObjectiveStatus.GetDidCompleteInTime(bObjectiveTimed, TimeToComplete);
486 }
487 int32 GetCurrentProgress() const
488 {
489 return ObjectiveStatus.GetCurrentProgress();
490 }
491 int32 GetFailProgress() const
492 {
493 return ObjectiveStatus.GetFailProgress();
494 }
497 {
498 return static_cast<float>(GetCurrentProgress()) / static_cast<float>(RequiredProgress);
499 }
501 {
502 return static_cast<float>(GetFailProgress()) / static_cast<float>(RequiredFailProgress);
503 }
504
505 bool CanStart(const int32 TotalProgress) const
506 {
507 if(bIsUnlockedAtCertainProgress)
508 {
509 return TotalProgress >= UnlockProgressNeeded;
510 }
511 return true;
512 }
513 bool GetIsFailed() const
514 {
515 return ObjectiveStatus.GetIsFailed(RequiredFailProgress);
516 }
517 bool GetIsActive() const
518 {
519 return ObjectiveStatus.IsActive();
520 }
521 bool GetIsStarted() const
522 {
523 return ObjectiveStatus.GetIsStarted();
524 }
526 {
527 return ObjectiveStatus.GetIsNotYetStarted();
528 }
529
530 bool GetIsFinished() const
531 {
532 return ObjectiveStatus.IsFinished(RequiredFailProgress, RequiredProgress);
533 }
534 bool GetIsSuccessful() const
535 {
536 return ObjectiveStatus.IsSuccessful(RequiredFailProgress, RequiredProgress);
537 }
538 //- Will Return if Progress is At Required, Finished or Failed
539 bool GetIsComplete() const
540 {
541 return ObjectiveStatus.Complete(RequiredFailProgress, RequiredProgress);
542 }
544 {
545 return ObjectiveStatus.GetStatus();
546 }
547
549 {
550 return (ObjectiveID == Other.ObjectiveID) && (GetUniqueID() == Other.GetUniqueID());
551 }
553 {
554 return (ObjectiveID != Other.ObjectiveID) || ((ObjectiveID == Other.ObjectiveID) && (GetUniqueID() != Other.GetUniqueID()));
555 }
556 //@ TODO Does the objective need to be marked unique?
557 bool operator==(const FUniqueID& OtherID) const
558 {
559 return (GetUniqueID() == OtherID);
560 // if(bUnique){return (GetUniqueID() == OtherID);}
561 // return (ObjectiveID == OtherID.ID);
562 }
563 bool operator!=(const FUniqueID& OtherID) const
564 {
565 return (GetUniqueID() != OtherID);
566 // if(bUnique){return (GetUniqueID() != OtherID);}
567 // return (ObjectiveID != OtherID.ID);
568 }
569
570 // bool operator==(const FString& OtherID, const int32 OtherUniqueID) const
571 // {
572 // return ObjectiveID == OtherID && (UniqueID == OtherUniqueID);
573 // }
574 // bool operator!=(const FString& OtherID, const int32 OtherUniqueID) const
575 // {
576 // return ObjectiveID != OtherID && (UniqueID == OtherUniqueID);
577 // }
578};
579
580
581
582USTRUCT(BlueprintType)
584{
585 GENERATED_BODY()
586
587 void StartQuest(const UObject* Owner)
588 {
589 if(GetQuestStatus() == EQuestStatus::Active){return;}
590 SetStatus(EQuestStatus::Active);
591 if(const UWorld* World = GEngine->GetWorldFromContextObject(Owner, EGetWorldErrorMode::LogAndReturnNull))
592 {
593 StartTimeInSeconds = World->GetTimeSeconds();
594 }
595 }
596 void SetStatus(const EQuestStatus NewQuestStatus)
597 {
598 QuestStatus = NewQuestStatus;
599 }
600 bool GetIsActive() const
601 {
602 return QuestStatus == EQuestStatus::Active;
603 }
605 {
606 return QuestStatus;
607 }
608 TArray<FString> GetAllObjectiveIDs() const
609 {
610 TArray<FString> AllObjectiveIDs;
611 for(const auto& Objective: ObjectiveReferences)
612 {
613 if(Objective == nullptr){continue;}
614 AllObjectiveIDs.AddUnique(Objective->ObjectiveID);
615 }
616 return AllObjectiveIDs;
617 }
618 int32 GetObjectivesNum() const
619 {
620 return ObjectiveReferences.Num();
621 }
622 int32 GetTotalProgress() const
623 {
624 int32 TotalProgress = 0;
625 for(const auto& Objective : ObjectiveReferences)
626 {
627 if(Objective == nullptr){continue;}
628 if(!Objective->bIsOptional)
629 {
630 TotalProgress += Objective->GetCurrentProgress();
631 }
632 }
633 return TotalProgress;
634 }
635
637 {
638 int32 TotalRequired = 0;
639 for(const auto& Objective : ObjectiveReferences)
640 {
641 if(Objective == nullptr){continue;}
642 if(!Objective->bIsOptional)
643 {
644 TotalRequired += Objective->RequiredProgress;
645 }
646 }
647 return TotalRequired;
648 }
649 float SaveQuestTime(const UObject* Owner)
650 {
651 if(GetIsActive())
652 {
653 if(const UWorld* World = GEngine->GetWorldFromContextObject(Owner, EGetWorldErrorMode::LogAndReturnNull))
654 {
655 const float CurrentTimeInSeconds = World->GetTimeSeconds();
656 ElapsedTime = CurrentTimeInSeconds - StartTimeInSeconds;
657 }
658 }
659 return ElapsedTime;
660 }
662 {
663 if(QuestStatus != EQuestStatus::Active){return;}
664 StartTimeInSeconds = -ElapsedTime;
665 }
666 bool GetDidCompleteInTime(const float TimeToComplete) const
667 {
668 //- Sets ElapsedTime //
669 if(StartTimeInSeconds >= 0.0f)
670 {
671 return ElapsedTime <= TimeToComplete;
672 }
673 return false;
674 }
675 //@ TODO Check over this logic
676 bool GetCanBeCompleted(const UObject* Owner, EQuestStatus& QuestOutcome)
677 {
678 //- Sets Elapsed Time //
679 SaveQuestTime(Owner);
680 QuestOutcome = QuestStatus;
681 if(QuestOutcome != EQuestStatus::Active){return false;}
682 //@ TODO add this function to Player Quest Status, which can check Objectives too
683 for(const FQuestObjectives* QuestObjective : ObjectiveReferences)
684 {
685 //- Don't Check Optional Objectives //
686 if(QuestObjective->bIsOptional){continue;}
687 if(QuestObjective->GetIsFailed())
688 {
689 QuestOutcome = EQuestStatus::Failed;
690 return true;
691 }
692 if(QuestObjective->bObjectiveTimed && !QuestObjective->GetDidCompleteInTime())
693 {
694 QuestOutcome = EQuestStatus::Failed;
695 return true;
696 }
697 //- If any of the non optional Objectives aren't complete //
698 if(QuestObjective->GetIsFinished() == false)
699 {
700 QuestOutcome = EQuestStatus::Active;
701 return false;
702 }
703 }
704 //- All Objectives Complete //
705 QuestOutcome = EQuestStatus::Completed;
706 return true;
707 }
708 float GetElapsedTime() const
709 {
710 return ElapsedTime;
711 }
712 float GetStartTime() const
713 {
714 return StartTimeInSeconds;
715 }
716 int32 GetUniqueID() const
717 {
718 return UniqueID;
719 }
720 void SetUniqueID(const int32 ID)
721 {
722 UniqueID = ID;
723 }
724
725
726 TArray<FString> GetActiveObjectiveIDs() const
727 {
728 TArray<FString> ActiveObjectiveIDs;
729 for(const auto& Objective : ObjectiveReferences)
730 {
731 if(Objective != nullptr)
732 {
733 if(Objective->GetIsActive())
734 {
735 ActiveObjectiveIDs.Add(Objective->ObjectiveID);
736 }
737 }
738 }
739 return ActiveObjectiveIDs;
740 }
741 TArray<FString> GetNotStartedObjectiveIDs() const
742 {
743 TArray<FString> NotStartedObjectiveIDs;
744 for(const auto& Objective : ObjectiveReferences)
745 {
746 if(Objective != nullptr)
747 {
748 if(Objective->GetIsNotYetStarted())
749 {
750 NotStartedObjectiveIDs.Add(Objective->ObjectiveID);
751 }
752 }
753 }
754 return NotStartedObjectiveIDs;
755 }
756
757 TArray<FString> GetActiveObjectiveIDsWithMarkers() const
758 {
759 TArray<FString> ActiveObjectiveIDs;
760 for(const auto& Objective : ObjectiveReferences)
761 {
762 if(Objective != nullptr)
763 {
764 if(Objective->GetIsActive())
765 {
766 if(Objective->bHasWorldMarker)
767 {
768 ActiveObjectiveIDs.Add(Objective->ObjectiveID);
769 }
770 }
771 }
772 }
773 return ActiveObjectiveIDs;
774 }
775
776 TArray<const FQuestObjectives*> ObjectiveReferences;
777
778protected:
779 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
780 EQuestStatus QuestStatus = EQuestStatus::NotStarted;
781 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
782 int32 UniqueID = 0;
783
784
785
786 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Timed")
787 float StartTimeInSeconds = -1.0f;
788 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Timed")
789 float ElapsedTime = -1.0f;
790
791 // bool b
792
793};
794
795
796USTRUCT(BlueprintType)
797struct FQuestInfo : public FTableRowBase
798{
799 GENERATED_BODY()
800
801 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
802 FString QuestID = "QID_01";
803
804 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
805 FString QuestName = "Quest Name";
806 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
807 FString Description = "Quest Description";
808
809 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
810 TArray<FString> ObjectiveIDs = {"QOID_01", "QOID_02"};
811
812 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Status")
813 bool bUniqueObjectives = true;
814
815 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
816 bool bShowOverallProgress = false;
817
818 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
820 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Requirements")
821 TArray<FString> RequiredQuests;
822 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="General")
823 TArray<FString> QuestsToBeAddedAfterCompletion;
824 //- Abandoned == Can be retried //
825 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="State")
826 bool bCanQuestBeAbandoned = false;
827 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="State")
828 bool bCanQuestFail = false;
829 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="State")
830 bool bCanRetry = false;
832 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="State")
833 bool bRepeatable = false;
834
835 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Status")
837
838
839 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Timed")
840 bool bQuestTimed = false;
841 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Timed", meta=(EditCondition=bQuestTimed))
842 float TimeToComplete = 10.0f;
843
844 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Category")
845 FGameplayTag CategoryTag;
846 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Category")
848 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Category")
850 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Category")
851 FGameplayTag LocationTag;
852
853 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Requirements")
854 int32 RecommendedLevel = 0;
855
856
858 {
859
860 }
861
862 explicit FQuestInfo(const FQuestInfoStatus& QuestStatus)
863 {
864 Status = QuestStatus;
865 }
866
867 // Implementing the '==' operator for the struct
868 bool operator==(const FQuestInfo& Other) const
869 {
870 // Define what makes two FQuestInfo structs equal.
871 // In this example, we assume two FQuestInfo are equal if their QuestIDs are equal.
872 // You may need to adjust this based on what makes sense for your use case.
873 return (QuestID == Other.QuestID) && (GetUniqueID() == Other.GetUniqueID());
874 }
875 bool operator!=(const FQuestInfo& Other) const
876 {
877 // Define what makes two FQuestInfo structs equal.
878 // In this example, we assume two FQuestInfo are equal if their QuestIDs are equal.
879 // You may need to adjust this based on what makes sense for your use case.
880 return (QuestID != Other.QuestID) || (GetUniqueID() != Other.GetUniqueID());
881 }
882 bool operator==(const FUniqueID& OtherID) const
883 {
884 if(bUniqueObjectives){return (GetUniqueID() == OtherID);}
885 return (QuestID == OtherID.ID);
886 }
887 bool operator!=(const FUniqueID& OtherID) const
888 {
889 if(bUniqueObjectives){return (GetUniqueID() != OtherID);}
890 return (QuestID != OtherID.ID);
891 }
892
893 bool IsValid() const
894 {
895 if(QuestID == "Default Quest"){return false;}
896 if(QuestName == "Default Name"){return false;}
897 if(Status.GetObjectivesNum() == 0){return false;}
898 return true;
899 }
901 {
902 FQuestInfo EmptyQuestInfo;
903 return EmptyQuestInfo;
904 }
905
906 bool GetIsActive() const
907 {
908 return Status.GetIsActive();
909 }
911 {
912 return Status.GetQuestStatus();
913 }
914 void SetUniqueID(const int32 ID)
915 {
916 Status.SetUniqueID(ID);
917 }
919 {
920 FUniqueID ID = FUniqueID(QuestID);
921 ID.SetUniqueNumber(Status.GetUniqueID());
922 return ID;
923 }
924 void SetStatus(const EQuestStatus NewQuestStatus)
925 {
926 Status.SetStatus(NewQuestStatus);
927 }
928 int32 GetObjectivesNum() const
929 {
930 return Status.ObjectiveReferences.Num();
931 }
932 int32 GetTotalProgress() const
933 {
934 return Status.GetTotalProgress();
935 }
936
938 {
939 return Status.GetTotalRequiredProgress();
940 }
941
942 float GetElapsedTime() const
943 {
944 return Status.GetElapsedTime();
945 }
946 float GetStartTime() const
947 {
948 return Status.GetStartTime();
949 }
950
951 //- Timer //
952 void StartQuest(const UObject* Owner)
953 {
954 Status.StartQuest(Owner);
955 }
956 float SaveQuestTime(const UObject* Owner)
957 {
958 const float ElapsedTime = Status.SaveQuestTime(Owner);
959 return ElapsedTime;
960 }
962 {
963 Status.ResumeFromElapsedTime();
964 }
966 bool GetIsQuestInTime() const
967 {
968 if(bQuestTimed)
969 {
970 return Status.GetDidCompleteInTime(TimeToComplete);
971 }
972 return true;
973 }
974 //- //
975
976 //@ TODO Change to getting from the pointers, then maybe just remove and put in PlayerQuestStatus
977 TArray<FQuestObjectives> GetCompletedObjectives() const
978 {
979 TArray<FQuestObjectives> CompletedObjectives;
980 for(const auto& Objective : Status.ObjectiveReferences)
981 {
982 if(Objective == nullptr){continue;}
983 if(Objective->GetIsComplete())
984 {
985 CompletedObjectives.AddUnique(*Objective);
986 }
987 }
988 return CompletedObjectives;
989 }
990 TArray<FString> GetActiveObjectiveIDs() const
991 {
992 return Status.GetActiveObjectiveIDs();
993 }
994 TArray<FString> GetNotStartedObjectiveIDs() const
995 {
996 return Status.GetNotStartedObjectiveIDs();
997 }
998 TArray<FString> GetActiveObjectiveIDsWithMarkers() const
999 {
1000 return Status.GetActiveObjectiveIDsWithMarkers();
1001 }
1003 {
1004 FQuestReward FullReward = Reward;
1005 for(const auto& Objective : GetCompletedObjectives())
1006 {
1007 FullReward.Credits += Objective.RewardBonus.Credits;
1008 FullReward.Experience += Objective.RewardBonus.Experience;
1009 }
1010 return FullReward;
1011 }
1012 TArray<FQuestObjectives> GetObjectives() const
1013 {
1014 TArray<FQuestObjectives> Objectives;
1015 for(const auto Objective : Status.ObjectiveReferences)
1016 {
1017 if(Objective == nullptr || Objective->ObjectiveID.IsEmpty())
1018 {
1019 UE_LOG(LogTemp, Warning, TEXT("Null objective pointer"));
1020 continue;
1021 }
1022 const FQuestObjectives ObjectiveCopy = *Objective;
1023 Objectives.Add(ObjectiveCopy);
1024 }
1025 return Objectives;
1026 }
1027
1028
1029 bool GetCanBeCompleted(const UObject* Owner, EQuestStatus& QuestOutcome)
1030 {
1031 //- Sets Elapsed Time //
1032 SaveQuestTime(Owner);
1033 if(GetIsQuestInTime())
1034 {
1035 return Status.GetCanBeCompleted(Owner, QuestOutcome);
1036 }
1037 QuestOutcome = EQuestStatus::Failed;
1038 return true;
1039 }
1040 // QuestOutcome = EQuestStatus::Active;
1041 // for(FQuestObjectives& QuestObjective : Objectives)
1042 // {
1043 // //- Don't Check Optional Objectives //
1044 // if(QuestObjective.bIsOptional){continue;}
1045 // if(QuestObjective.GetIsFailed())
1046 // {
1047 // QuestOutcome = EQuestStatus::Failed;
1048 // return true;
1049 // }
1050 // if(QuestObjective.bObjectiveTimed && !QuestObjective.GetDidCompleteInTime(Owner))
1051 // {
1052 // QuestOutcome = EQuestStatus::Failed;
1053 // return true;
1054 // }
1055 // //- If any of the non optional Objectives aren't complete //
1056 // if(QuestObjective.IsFinished() == false)
1057 // {
1058 // QuestOutcome = EQuestStatus::Active;
1059 // return false;
1060 // }
1061 // }
1062 // //- All Objectives Complete //
1063 // if(bQuestTimed)
1064 // {
1065 // if(!GetDidCompleteInTime(Owner))
1066 // {
1067 // QuestOutcome = EQuestStatus::Failed;
1068 // return true;
1069 // }
1070 // }
1071 // QuestOutcome = EQuestStatus::Completed;
1072 // return true;
1073 // }
1074};
1075
1076FORCEINLINE uint32 GetTypeHash(const FQuestInfo& QuestInfo)
1077{
1078 // Hash based on a unique property of FQuestInfo, or combine multiple properties
1079 return FCrc::MemCrc32(&QuestInfo.QuestID, sizeof(QuestInfo.QuestID));
1080}
1081
1082USTRUCT(BlueprintType)
1084{
1085 GENERATED_BODY()
1086
1087 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Quest System")
1088 FUniqueID QuestID;
1089 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Quest System")
1090 FString QuestName = "Name";
1091 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Quest System")
1092 TArray<FQuestObjectives> CompletedObjectives;
1093 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Quest System")
1094 EQuestStatus Outcome = EQuestStatus::Completed;
1095 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Quest System")
1097
1099 {
1100
1101 }
1102
1103 explicit FQuestOutcome(const TArray<FQuestObjectives>& NewCompletedObjectives)
1104 {
1105 CompletedObjectives = NewCompletedObjectives;
1106 }
1107 explicit FQuestOutcome(const TArray<FQuestObjectives>& NewCompletedObjectives, const EQuestStatus FinishedOutcome)
1108 {
1109 CompletedObjectives = NewCompletedObjectives;
1110 Outcome = FinishedOutcome;
1111 }
1112};
1113
1114
1115USTRUCT(BlueprintType)
1116struct FPlayerQuestStatus : public FTableRowBase
1117{
1118 GENERATED_BODY()
1119
1121 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="General")
1122 TArray<FQuestInfo> ActiveQuests;
1123 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
1124 int32 Credits = 0;
1125 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
1126 int32 Experience = 0;
1127 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Other")
1128 int32 MaximumActiveQuests = 999;
1129
1130
1131 TArray<FQuestOutcome> CanQuestsBeCompleted(const UObject* Owner)
1132 {
1133 SaveTimes(Owner);
1134 TArray<FQuestOutcome> AllOutcomes;
1135 for(auto& Quest : ActiveQuests)
1136 {
1137 FQuestOutcome Outcome;
1138 EQuestStatus QuestOutcome;
1139 if(Quest.GetCanBeCompleted(Owner, QuestOutcome))
1140 {
1141 Outcome.Outcome = QuestOutcome;
1142 Outcome.CompletedObjectives = Quest.GetCompletedObjectives();
1143 Outcome.QuestID = Quest.GetUniqueID();
1144 Outcome.QuestName = Quest.QuestName;
1145 AllOutcomes.Add(Outcome);
1146 }
1147 }
1148 return AllOutcomes;
1149 }
1150
1151
1153 bool AddObjective(const FQuestObjectives& ObjectiveInfo)
1154 {
1155 const FQuestObjectives* ExistingPtr = Objectives.FindByPredicate(
1156 [&](const FQuestObjectives& Obj)
1157 {
1158 return (Obj.ObjectiveID == ObjectiveInfo.ObjectiveID && Obj.GetUniqueID() == ObjectiveInfo.GetUniqueID());
1159 });
1160
1161 if(ExistingPtr)
1162 {
1163 AddObjectiveToQuests(ExistingPtr);
1164 return true;
1165 }
1166 const int32 Index = Objectives.AddUnique(ObjectiveInfo);
1167 const FQuestObjectives* NewPtr = &Objectives[Index];
1168 AddObjectiveToQuests(NewPtr);
1169 return true;
1170
1171 //@TODO if Objective is not Unique
1172 // const int32 Index = Objectives.AddUnique(ObjectiveInfo);
1173 // TSharedPtr<FQuestObjectives> ObjectivePtr = MakeShared<FQuestObjectives>(Objectives[Index]);
1174 // if(ObjectivePtr == nullptr){return false;}
1175 // AddObjectiveToQuests(ObjectivePtr);
1176 // return true;
1177 }
1178 // @TODO move to Protected
1180 {
1181 if(Objective == nullptr){return false;}
1182 for(auto& Quest : ActiveQuests)
1183 {
1184 //@ TODO Check
1185 if(Quest.bUniqueObjectives && Quest.GetUniqueID().GetUniqueNumber() != Objective->GetUniqueID().GetUniqueNumber())
1186 {
1187 continue;
1188 }
1189 //- @TODO And need to check if Unique
1190 if(Quest.ObjectiveIDs.Contains(Objective->ObjectiveID))
1191 {
1192 const bool bAlreadyAdded = Quest.Status.ObjectiveReferences.ContainsByPredicate(
1193 [&](const FQuestObjectives* Existing)
1194 {
1195 return Existing == Objective;
1196 });
1197
1198 if(!bAlreadyAdded)
1199 {
1200 Quest.Status.ObjectiveReferences.Add(Objective);
1201 }
1202 }
1203 }
1204 return true;
1205 }
1206 int32 GetNewUniqueID(const FString& QuestID) const
1207 {
1208 int32 UniqueID = 1;
1209 for(const auto& Quest :ActiveQuests)
1210 {
1211 if(Quest.QuestID == QuestID)
1212 {
1213 if(UniqueID <= Quest.GetUniqueID().GetUniqueNumber())
1214 {
1215 UniqueID = Quest.GetUniqueID().GetUniqueNumber() + 1;
1216 }
1217 }
1218 }
1219 return UniqueID;
1220 }
1222 int32 StartQuest(const UObject* Owner, FQuestInfo& QuestInfo)
1223 {
1224 QuestInfo.StartQuest(Owner);
1225 if(QuestInfo.bUniqueObjectives)
1226 {
1227 const int32 UniqueID = GetNewUniqueID(QuestInfo.QuestID);
1228 QuestInfo.SetUniqueID(UniqueID);
1229 return ActiveQuests.Add(QuestInfo);
1230 }
1231 // QuestInfo.GetTotalProgress()
1232
1233 //@ TODO add seperate Objectives function? or should GScomp just start the objectives when they're found from DT ?
1234 // StartObjectives();
1235 for(auto& Objective : Objectives)
1236 {
1237 //@ TODO is there better way to check? is this just 2 for loops?
1238 // if(Objective.ObjectiveID == )
1239 if(QuestInfo.ObjectiveIDs.Contains(Objective.ObjectiveID))
1240 {
1241 Objective.StartObjective(Owner);
1242 }
1243 }
1244 return ActiveQuests.AddUnique(QuestInfo);
1245 }
1246 void StartObjectives(const UObject* Owner)
1247 {
1248 for(auto& ActiveQuest : ActiveQuests)
1249 {
1250 //- If We have unique Objectives, Update them with the Unique progress
1251 if(ActiveQuest.bUniqueObjectives)
1252 {
1253 for(auto& Objective : Objectives)
1254 {
1255 if(ActiveQuest.ObjectiveIDs.Contains(Objective.ObjectiveID))
1256 {
1257 if(ActiveQuest.GetUniqueID().GetUniqueNumber() == Objective.GetUniqueID().GetUniqueNumber())
1258 {
1259 Objective.StartObjective(Owner, ActiveQuest.GetTotalProgress());
1260 }
1261 }
1262 }
1263 }
1264 else
1265 {
1266 for(auto& Objective : Objectives)
1267 {
1268 if(Objective.GetUniqueID().IsUnique()){continue;}
1269 if(ActiveQuest.GetUniqueID().GetUniqueNumber() == Objective.GetUniqueID().GetUniqueNumber())
1270 {
1271 Objective.StartObjective(Owner);
1272 }
1273 }
1274
1275 }
1276 }
1277 }
1278
1279 bool AddObjectiveAmount(const FString& ObjectiveID, const int32 Amount)
1280 {
1281 bool bCompleted = false;
1282 // Go through each Objective
1283 for(FQuestObjectives& Objective : Objectives)
1284 {
1285 // Ignore complete ones, or Unactive ones //! Potentially redundant before ID check as only the matching ID will work be edited
1286 if(Objective.GetIsComplete() || Objective.GetIsActive() == false){continue;}
1287 //- if It's the Correct ID
1288 if(ObjectiveID == Objective.ObjectiveID)
1289 {
1290 const bool bFinishedObjective = Objective.AddProgress(Amount);
1291 if(bCompleted == false)
1292 {
1293 bCompleted = bFinishedObjective;
1294 }
1295 }
1296 }
1297 return bCompleted;
1298 }
1299
1300 bool AddObjectiveAmount(const FUniqueID& ObjectiveID, const int32 Amount)
1301 {
1302 bool bCompleted = false;
1303 // Go through each Objective
1304 for(FQuestObjectives& Objective : Objectives)
1305 {
1306 // Ignore complete ones, or Unactive ones //! Potentially redundant before ID check as only the matching ID will work be edited
1307 if(Objective.GetIsComplete() || Objective.GetIsActive() == false){continue;}
1308 //- if It's the Correct ID
1309 if(ObjectiveID == Objective.GetUniqueID())
1310 {
1311 bCompleted = Objective.AddProgress(Amount);
1312 }
1313 }
1314 return bCompleted;
1315 }
1316
1317 bool AddObjectiveFailAmount(const FString& ObjectiveID, const int32 Amount)
1318 {
1319 bool bCompleted = false;
1320 // Go through each Objective
1321 for(FQuestObjectives& Objective : Objectives)
1322 {
1323 // Ignore complete ones, or Unactive ones //! Potentially redundant before ID check as only the matching ID will work be edited
1324 if(Objective.GetIsComplete() || Objective.GetIsActive() == false){continue;}
1325 //- if It's the Correct ID
1326 if(ObjectiveID == Objective.ObjectiveID)
1327 {
1328 bCompleted = Objective.AddFailProgress(Amount);
1329 }
1330 }
1331 return bCompleted;
1332 }
1333 bool AddObjectiveFailAmount(const FUniqueID& ObjectiveID, const int32 Amount)
1334 {
1335 bool bCompleted = false;
1336 // Go through each Objective
1337 for(FQuestObjectives& Objective : Objectives)
1338 {
1339 // Ignore complete ones, or Unactive ones //! Potentially redundant before ID check as only the matching ID will work be edited
1340 if(Objective.GetIsComplete() || Objective.GetIsActive() == false){continue;}
1341 //- if It's the Correct ID
1342 if(ObjectiveID == Objective.GetUniqueID())
1343 {
1344 bCompleted = Objective.AddFailProgress(Amount);
1345 }
1346 }
1347 return bCompleted;
1348 }
1349
1351 bool GetQuestObjectivesIDs(const FString& QuestID, TArray<FString>& ObjectiveIDs) const
1352 {
1353 for(const auto& Quest : ActiveQuests)
1354 {
1355 if(Quest.QuestID == QuestID)
1356 {
1357 ObjectiveIDs = Quest.ObjectiveIDs;
1358 return true;
1359 }
1360 }
1361 return false;
1362 }
1363 bool GetQuestActiveObjectivesIDs(const FString& QuestID, TArray<FString>& ObjectiveIDs) const
1364 {
1365 for(const auto& Quest : ActiveQuests)
1366 {
1367 if(Quest.QuestID == QuestID)
1368 {
1369 ObjectiveIDs = Quest.GetActiveObjectiveIDs();
1370 return true;
1371 }
1372 }
1373 return false;
1374 }
1375
1376 bool GetQuestActiveObjectivesIDsWithMarkers(const FUniqueID& QuestID, TArray<FString>& ObjectiveIDs) const
1377 {
1378 for(const auto& Quest : ActiveQuests)
1379 {
1380 if(Quest.GetUniqueID() == QuestID)
1381 {
1382 ObjectiveIDs = Quest.GetActiveObjectiveIDsWithMarkers();
1383 return true;
1384 }
1385 }
1386 return false;
1387 }
1388 bool GetDoesObjectiveHaveWorldMarker(const FString& ObjectiveID) const
1389 {
1390 for(const auto& Objective : Objectives)
1391 {
1392 if(Objective.ObjectiveID == ObjectiveID)
1393 {
1394 return Objective.bHasWorldMarker;
1395 }
1396 }
1397 return false;
1398 }
1399 bool GetQuestIndex(const FQuestInfo& QuestInfo, int32& Index) const
1400 {
1401 for(int32 i = 0; i < ActiveQuests.Num(); i++)
1402 {
1403 if(ActiveQuests[i].GetUniqueID() == QuestInfo.GetUniqueID())
1404 {
1405 Index = i;
1406 return true;
1407 }
1408 }
1409 return false;
1410 }
1411 bool GetQuestIndex(const FUniqueID& QuestID, int32& Index) const
1412 {
1413 for(int32 i = 0; i < ActiveQuests.Num(); i++)
1414 {
1415 if(ActiveQuests[i].GetUniqueID() == QuestID)
1416 {
1417 Index = i;
1418 return true;
1419 }
1420 }
1421 // if(ActiveQuests.Contains(QuestID))
1422 // {
1423 // const int32 QuestIndex = ActiveQuests.IndexOfByKey(QuestID);
1424 // Index = QuestIndex;
1425 // return true;
1426 // }
1427 return false;
1428 }
1429
1430 bool RemoveQuest(const FQuestInfo& QuestInfo)
1431 {
1432 int32 Index = 0;
1433 TArray<FString> ObjectiveIDs;
1434 bool bFound = false;
1435 for(int32 i = 0; i < ActiveQuests.Num(); i++)
1436 {
1437 if(ActiveQuests[i].GetUniqueID() == QuestInfo.GetUniqueID())
1438 {
1439 Index = i;
1440 ObjectiveIDs = ActiveQuests[Index].ObjectiveIDs;
1441 bFound = true;
1442 break;
1443 }
1444 }
1445 if(bFound)
1446 {
1447 ActiveQuests.RemoveAt(Index);
1448 CheckObjectives(ObjectiveIDs);
1449 }
1450 return bFound;
1451 }
1452 // bool RemoveQuest(const FString& QuestID)
1453 // {
1454 // for(const FQuestInfo Quest : ActiveQuests)
1455 // {
1456 // if(Quest.QuestID == QuestID)
1457 // {
1458 // ActiveQuests.Remove(Quest);
1459 // // ResetCurrentQuest();
1460 // CheckObjectives(Quest.ObjectiveIDs);
1461 // return true;
1462 // }
1463 // }
1464 // return false;
1465 // }
1467 void CheckObjectives(TArray<FString> ObjectiveIDs)
1468 {
1469 for(const auto& ObjectiveID : ObjectiveIDs) // {QO_01 QO_02}
1470 {
1471 // Check if any other quest uses this objective
1472 bool bUsedInOtherQuest = false;
1473 for(const FQuestInfo& Quest: ActiveQuests)
1474 {
1476 if(Quest.ObjectiveIDs.Contains(ObjectiveID))
1477 {
1478 bUsedInOtherQuest = true;
1479 }
1480 }
1481 if(bUsedInOtherQuest)
1482 {
1483
1484 }
1485 else
1486 {
1487 Objectives.RemoveAll([&](const FQuestObjectives& Old)
1488 {
1489 return Old.ObjectiveID == ObjectiveID; // uses operator== under the hood
1490 });
1491 }
1492 }
1493 }
1496 {
1497 TArray<FString> ObjectiveIDs;
1498 for(const FQuestInfo& Quest: ActiveQuests)
1499 {
1500 ObjectiveIDs.Append(Quest.ObjectiveIDs);
1501 }
1502
1503 Objectives.RemoveAll([&](const FQuestObjectives& Old)
1504 {
1505 return !ObjectiveIDs.Contains(Old.ObjectiveID);
1506 });
1507 }
1508 TArray<FString> GetQuestsToBeAddedAfterCompletion(const FString& QuestID)
1509 {
1510 TArray<FString> QuestsToBeAdded;
1511 for (const FQuestInfo& Quest: ActiveQuests)
1512 {
1513 if(QuestID == Quest.QuestID)
1514 {
1515 QuestsToBeAdded.Append(Quest.QuestsToBeAddedAfterCompletion);
1516 }
1517 }
1518 return QuestsToBeAdded;
1519 }
1520 FString GetQuestName(const FString& QuestID)
1521 {
1522 for (const FQuestInfo& Quest: ActiveQuests)
1523 {
1524 if(QuestID == Quest.QuestID)
1525 {
1526 return Quest.QuestName;
1527 }
1528 }
1529 return "";
1530 }
1531
1532 TArray<FString> GetQuestIDs()
1533 {
1534 TArray<FString> ActiveQuestIDs;
1535 for (const FQuestInfo& Quest: ActiveQuests)
1536 {
1537 ActiveQuestIDs.Add(Quest.QuestID);
1538 }
1539 return ActiveQuestIDs;
1540 }
1541 TArray<FString> GetObjectiveIDs()
1542 {
1543 TArray<FString> ActiveObjectiveIDs;
1544 for (const auto& Objective: Objectives)
1545 {
1546 ActiveObjectiveIDs.Add(Objective.ObjectiveID);
1547 }
1548 return ActiveObjectiveIDs;
1549 }
1550 const FQuestObjectives* GetQuestObjectivePtr(const FUniqueID& ObjectiveID) const
1551 {
1552 return Objectives.FindByPredicate([&](const FQuestObjectives& Elem){ return Elem.GetUniqueID() == ObjectiveID;});
1553 }
1554
1555 bool GetActiveQuest(const FUniqueID& QuestID, FQuestInfo& QuestInfo)
1556 {
1557 for(const auto& Quest : ActiveQuests)
1558 {
1559 if(Quest.GetUniqueID() == QuestID)
1560 {
1561 QuestInfo = Quest;
1562 return true;
1563 }
1564 }
1565 return false;
1566 }
1567 bool GetIsQuestActive(const FString& QuestID) const
1568 {
1569 for(const auto& Quest : ActiveQuests)
1570 {
1571 if(Quest.QuestID == QuestID)
1572 {
1573 return Quest.GetIsActive();
1574 }
1575 }
1576 return false;
1577 }
1578 bool GetIsQuestActive(const FUniqueID& QuestID) const
1579 {
1580 for(const auto& Quest : ActiveQuests)
1581 {
1582 if(Quest.GetUniqueID() == QuestID)
1583 {
1584 return Quest.GetIsActive();
1585 }
1586 }
1587 return false;
1588 }
1589 bool GetIsQuestActive(const int32 QuestIndex) const
1590 {
1591 if(ActiveQuests.IsValidIndex(QuestIndex))
1592 {
1593 return ActiveQuests[QuestIndex].GetIsActive();
1594 }
1595 return false;
1596 }
1598 bool GetQuest(const int32 QuestIndex, FQuestInfo& QuestInfo) const
1599 {
1600 if(ActiveQuests.IsValidIndex(QuestIndex))
1601 {
1602 QuestInfo = ActiveQuests[QuestIndex];
1603 return true;
1604 }
1605 return false;
1606 }
1607 bool GetQuestID(const int32 QuestIndex, FUniqueID& QuestID) const
1608 {
1609 if(ActiveQuests.IsValidIndex(QuestIndex))
1610 {
1611 QuestID = ActiveQuests[QuestIndex].GetUniqueID();
1612 return true;
1613 }
1614 return false;
1615 }
1616
1617 EQuestStatus GetQuestStatus(const FString& QuestID) const
1618 {
1619 for(const auto& Quest : ActiveQuests)
1620 {
1621 if(Quest.QuestID == QuestID)
1622 {
1623 return Quest.GetQuestStatus();
1624 }
1625 }
1626 return EQuestStatus::NotStarted;
1627 }
1628 int32 GetLevel() const
1629 {
1630 return FMath::Min(static_cast<int32>(Experience / XP_PER_LEVEL), MAX_SKILL_LEVEL); // Ensure Level does not exceed MaxLevel
1631 }
1632
1633 void SaveTimes(const UObject* Owner)
1634 {
1635 SaveQuestTimes(Owner);
1636 SaveObjectiveTimes(Owner);
1637 }
1639 {
1640 for(auto& Quest : ActiveQuests)
1641 {
1642 if(Quest.GetIsActive())
1643 {
1644 Quest.ResumeFromElapsedTime();
1645 }
1646 }
1647 for(auto& Objective : Objectives)
1648 {
1649 if(Objective.GetIsActive())
1650 {
1651 Objective.ResumeFromElapsedTime();
1652 }
1653 }
1654 }
1655 //@ TODO
1657 void UpdateQuestDetails(const FQuestInfo& UpdatedQuestInfo)
1658 {
1659 for(auto& OldQuest : ActiveQuests)
1660 {
1661 if(OldQuest.QuestID == UpdatedQuestInfo.QuestID)
1662 {
1663 FQuestInfo NewQuestDetails = UpdatedQuestInfo;
1664 NewQuestDetails.Status = OldQuest.Status;
1665 OldQuest = NewQuestDetails;
1666 }
1667 }
1668 }
1669 bool UpdateObjectiveDetails(const FQuestObjectives& UpdatedObjectiveInfo)
1670 {
1671 //- @TODO We need a case for when the objective is new and not in the array of objectives, or when it's not in the array
1672 for(auto& OldObjective : Objectives)
1673 {
1674 if(OldObjective.ObjectiveID == UpdatedObjectiveInfo.ObjectiveID)
1675 {
1676 FQuestObjectives NewObjectiveDetails = UpdatedObjectiveInfo;
1677 NewObjectiveDetails.ObjectiveStatus = OldObjective.ObjectiveStatus;
1678 OldObjective = NewObjectiveDetails;
1679 return true;
1680 }
1681 }
1682 //- Updated Objective Doesn't Exist? Add it to Array
1683 Objectives.Add(UpdatedObjectiveInfo);
1684 return false;
1685
1686 //- @TODO Missing if an Objective gets Deleted
1687
1688
1689 // const int32 ObjectiveIndex = Objectives.Find(UpdatedObjectiveInfo);
1690 // //@TODO if it's not in the Objectives array, add it.
1691 // if(Objectives.IsValidIndex(ObjectiveIndex))
1692 // {
1693 // // BUG NOT FINISHED
1694 //
1695 // Objectives[ObjectiveIndex];
1696 // return true;
1697 // }
1698 // Objectives.Add(UpdatedObjectiveInfo);
1699 // for(auto& Objective : Objectives)
1700 // {
1701 // if(Objective.ObjectiveID == UpdatedObjectiveInfo.ObjectiveID)
1702 // {
1703 // FQuestObjectives NewObjectiveInfo = UpdatedObjectiveInfo;
1704 // NewObjectiveInfo.ObjectiveStatus = Objective.ObjectiveStatus;
1705 // Objective = NewObjectiveInfo;
1706 // }
1707 // }
1708 }
1710 {
1711 for(auto& Quest : ActiveQuests)
1712 {
1713 if(Quest.GetUniqueID() == Outcome.QuestID)
1714 {
1715 switch(Outcome.Outcome)
1716 {
1717 case EQuestStatus::NotStarted:
1718 Quest.SetStatus(Outcome.Outcome);
1719 break;
1720 case EQuestStatus::Active:
1721 Quest.SetStatus(Outcome.Outcome);
1722 break;
1723 case EQuestStatus::Completed:
1724 Quest.SetStatus(Outcome.Outcome);
1725 Outcome.Reward = Quest.GetFullQuestReward();
1726 break;
1727 case EQuestStatus::Failed:
1728 if(Quest.bCanQuestFail)
1729 {
1730 Outcome.Reward = Quest.GetFullQuestReward();
1731 Quest.SetStatus(Outcome.Outcome);
1732 }
1733 else
1734 {
1735 return false;
1736 }
1737 break;
1738 case EQuestStatus::Abandoned:
1739 if(Quest.bCanQuestBeAbandoned)
1740 {
1741 Quest.SetStatus(Outcome.Outcome);
1742 }
1743 else
1744 {
1745 return false;
1746 }
1747 break;
1748 case EQuestStatus::NotAvailable:
1749 Quest.SetStatus(Outcome.Outcome);
1750 break;
1751 }
1752 return true;
1753 }
1754 }
1755 return false;
1756 }
1757
1758 TArray<FQuestInfo> FilterQuests(const EQuestStatus QuestFilter)
1759 {
1760 TArray<FQuestInfo> FilteredQuests;
1761 for(auto& Quest : ActiveQuests)
1762 {
1763 if(Quest.GetQuestStatus() == QuestFilter)
1764 {
1765 FilteredQuests.Add(Quest);
1766 }
1767 }
1768 return FilteredQuests;
1769 }
1770
1771 //- Checks if was made valid in constructor //
1772 bool IsValid() const
1773 {
1774 return bValid;
1775 }
1776protected:
1777 void SaveQuestTimes(const UObject* Owner)
1778 {
1779 for(auto& ActiveQuest : ActiveQuests)
1780 {
1781 ActiveQuest.SaveQuestTime(Owner);
1782 }
1783 }
1784 void SaveObjectiveTimes(const UObject* Owner)
1785 {
1786 for(auto& Objective : Objectives)
1787 {
1788 Objective.SaveObjectiveTime(Owner);
1789 }
1790 }
1791
1792 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="General")
1793 TArray<FQuestObjectives> Objectives;
1794
1795private:
1796
1797 bool bValid = true;
1798};
static int32 XP_PER_LEVEL
Definition BaseData.h:707
static int32 MAX_SKILL_LEVEL
Definition BaseData.h:706
@ Failed
Definition InteractionData.h:29
DECLARE_STATS_GROUP(TEXT("LineOfSight Stat Group"), STATGROUP_LineOfSight, STATCAT_Advanced)
DECLARE_CYCLE_STAT(TEXT("Player Component"), STATGROUP_Quests_PlayerComponent, STATGROUP_Quests)
EFilterQuestType
Definition QuestData.h:28
FORCEINLINE uint32 GetTypeHash(const FQuestInfo &QuestInfo)
Definition QuestData.h:1076
EQuestStatus
Definition QuestData.h:57
DECLARE_LOG_CATEGORY_CLASS(LogQuestSystem, Display, All)
EQuestLocation
Definition QuestData.h:51
Definition QuestData.h:1117
bool AddObjectiveToQuests(const FQuestObjectives *Objective)
Definition QuestData.h:1179
bool GetQuestIndex(const FQuestInfo &QuestInfo, int32 &Index) const
Definition QuestData.h:1399
bool GetQuestActiveObjectivesIDs(const FString &QuestID, TArray< FString > &ObjectiveIDs) const
Definition QuestData.h:1363
bool AddObjectiveAmount(const FUniqueID &ObjectiveID, const int32 Amount)
Definition QuestData.h:1300
TArray< FString > GetQuestsToBeAddedAfterCompletion(const FString &QuestID)
Definition QuestData.h:1508
void ResumeQuestsAndObjectives()
Definition QuestData.h:1638
TArray< FQuestInfo > FilterQuests(const EQuestStatus QuestFilter)
Definition QuestData.h:1758
int32 StartQuest(const UObject *Owner, FQuestInfo &QuestInfo)
Definition QuestData.h:1222
bool GetIsQuestActive(const FUniqueID &QuestID) const
Definition QuestData.h:1578
bool UpdateObjectiveDetails(const FQuestObjectives &UpdatedObjectiveInfo)
Definition QuestData.h:1669
void CheckObjectives(TArray< FString > ObjectiveIDs)
Definition QuestData.h:1467
bool RemoveQuest(const FQuestInfo &QuestInfo)
Definition QuestData.h:1430
void CheckAllObjectives()
Definition QuestData.h:1495
bool AddObjective(const FQuestObjectives &ObjectiveInfo)
Definition QuestData.h:1153
TArray< FString > GetQuestIDs()
Definition QuestData.h:1532
bool GetActiveQuest(const FUniqueID &QuestID, FQuestInfo &QuestInfo)
Definition QuestData.h:1555
void SaveQuestTimes(const UObject *Owner)
Definition QuestData.h:1777
void SaveObjectiveTimes(const UObject *Owner)
Definition QuestData.h:1784
bool GetDoesObjectiveHaveWorldMarker(const FString &ObjectiveID) const
Definition QuestData.h:1388
bool GetIsQuestActive(const FString &QuestID) const
Definition QuestData.h:1567
TArray< FString > GetObjectiveIDs()
Definition QuestData.h:1541
bool UpdateQuestStatus(FQuestOutcome &Outcome)
Definition QuestData.h:1709
bool GetQuestIndex(const FUniqueID &QuestID, int32 &Index) const
Definition QuestData.h:1411
EQuestStatus GetQuestStatus(const FString &QuestID) const
Definition QuestData.h:1617
void UpdateQuestDetails(const FQuestInfo &UpdatedQuestInfo)
Check if this is worth doing with this or just putting in GameState component.
Definition QuestData.h:1657
const FQuestObjectives * GetQuestObjectivePtr(const FUniqueID &ObjectiveID) const
Definition QuestData.h:1550
bool GetQuestID(const int32 QuestIndex, FUniqueID &QuestID) const
Definition QuestData.h:1607
bool GetQuest(const int32 QuestIndex, FQuestInfo &QuestInfo) const
Definition QuestData.h:1598
void SaveTimes(const UObject *Owner)
Definition QuestData.h:1633
bool IsValid() const
Definition QuestData.h:1772
bool AddObjectiveFailAmount(const FUniqueID &ObjectiveID, const int32 Amount)
Definition QuestData.h:1333
FString GetQuestName(const FString &QuestID)
Definition QuestData.h:1520
bool GetIsQuestActive(const int32 QuestIndex) const
Definition QuestData.h:1589
bool GetQuestActiveObjectivesIDsWithMarkers(const FUniqueID &QuestID, TArray< FString > &ObjectiveIDs) const
Definition QuestData.h:1376
bool AddObjectiveAmount(const FString &ObjectiveID, const int32 Amount)
Definition QuestData.h:1279
int32 GetLevel() const
Definition QuestData.h:1628
int32 GetNewUniqueID(const FString &QuestID) const
Definition QuestData.h:1206
void StartObjectives(const UObject *Owner)
Definition QuestData.h:1246
bool AddObjectiveFailAmount(const FString &ObjectiveID, const int32 Amount)
Definition QuestData.h:1317
bool GetQuestObjectivesIDs(const FString &QuestID, TArray< FString > &ObjectiveIDs) const
Definition QuestData.h:1351
Definition QuestData.h:121
Definition QuestData.h:798
TArray< FString > GetActiveObjectiveIDs() const
Definition QuestData.h:990
TArray< FQuestObjectives > GetCompletedObjectives() const
Definition QuestData.h:977
void ResumeFromElapsedTime()
Definition QuestData.h:961
bool bUniqueObjectives
Definition QuestData.h:813
bool GetIsQuestInTime() const
Definition QuestData.h:966
float GetElapsedTime() const
Definition QuestData.h:942
bool GetCanBeCompleted(const UObject *Owner, EQuestStatus &QuestOutcome)
Definition QuestData.h:1029
int32 GetTotalRequiredProgress() const
Definition QuestData.h:937
bool operator!=(const FUniqueID &OtherID) const
Definition QuestData.h:887
bool GetIsActive() const
Definition QuestData.h:906
FUniqueID GetUniqueID() const
Definition QuestData.h:918
TArray< FString > GetNotStartedObjectiveIDs() const
Definition QuestData.h:994
int32 GetObjectivesNum() const
Definition QuestData.h:928
TArray< FString > ObjectiveIDs
Definition QuestData.h:810
bool operator==(const FQuestInfo &Other) const
Definition QuestData.h:868
bool operator==(const FUniqueID &OtherID) const
Definition QuestData.h:882
FQuestInfoStatus Status
Definition QuestData.h:836
TArray< FQuestObjectives > GetObjectives() const
Definition QuestData.h:1012
bool IsValid() const
Definition QuestData.h:893
static FQuestInfo Empty()
Definition QuestData.h:900
void SetStatus(const EQuestStatus NewQuestStatus)
Definition QuestData.h:924
void SetUniqueID(const int32 ID)
Definition QuestData.h:914
FString QuestID
Definition QuestData.h:802
bool operator!=(const FQuestInfo &Other) const
Definition QuestData.h:875
FQuestReward GetFullQuestReward() const
Definition QuestData.h:1002
void StartQuest(const UObject *Owner)
Definition QuestData.h:952
int32 GetTotalProgress() const
Definition QuestData.h:932
EQuestStatus GetQuestStatus() const
Definition QuestData.h:910
float SaveQuestTime(const UObject *Owner)
Definition QuestData.h:956
float GetStartTime() const
Definition QuestData.h:946
FQuestInfo(const FQuestInfoStatus &QuestStatus)
Definition QuestData.h:862
TArray< FString > GetActiveObjectiveIDsWithMarkers() const
Definition QuestData.h:998
Definition QuestData.h:584
void ResumeFromElapsedTime()
Definition QuestData.h:661
bool GetCanBeCompleted(const UObject *Owner, EQuestStatus &QuestOutcome)
Definition QuestData.h:676
TArray< FString > GetActiveObjectiveIDs() const
Definition QuestData.h:726
void SetUniqueID(const int32 ID)
Definition QuestData.h:720
bool GetIsActive() const
Definition QuestData.h:600
TArray< FString > GetActiveObjectiveIDsWithMarkers() const
Definition QuestData.h:757
int32 GetTotalRequiredProgress() const
Definition QuestData.h:636
int32 GetTotalProgress() const
Definition QuestData.h:622
TArray< FString > GetAllObjectiveIDs() const
Definition QuestData.h:608
float SaveQuestTime(const UObject *Owner)
Definition QuestData.h:649
float GetElapsedTime() const
Definition QuestData.h:708
TArray< FString > GetNotStartedObjectiveIDs() const
Definition QuestData.h:741
void SetStatus(const EQuestStatus NewQuestStatus)
Definition QuestData.h:596
float GetStartTime() const
Definition QuestData.h:712
TArray< const FQuestObjectives * > ObjectiveReferences
Definition QuestData.h:776
int32 GetObjectivesNum() const
Definition QuestData.h:618
bool GetDidCompleteInTime(const float TimeToComplete) const
Definition QuestData.h:666
int32 GetUniqueID() const
Definition QuestData.h:716
EQuestStatus GetQuestStatus() const
Definition QuestData.h:604
Definition QuestData.h:140
Definition QuestData.h:361
void SetUniqueID(const int32 ID)
Definition QuestData.h:457
FUniqueID GetUniqueID() const
Definition QuestData.h:466
FString ObjectiveID
Definition QuestData.h:365
float GetCurrentProgressPercent() const
Definition QuestData.h:496
bool operator!=(const FUniqueID &OtherID) const
Definition QuestData.h:563
EQuestStatus GetStatus() const
Definition QuestData.h:543
void StartObjective(const UObject *Owner)
Definition QuestData.h:430
bool GetIsActive() const
Definition QuestData.h:517
bool operator==(const FUniqueID &OtherID) const
Definition QuestData.h:557
int32 GetFailProgress() const
Definition QuestData.h:491
bool GetIsStarted() const
Definition QuestData.h:521
float GetStartTime() const
Definition QuestData.h:479
bool GetIsFinished() const
Definition QuestData.h:530
float GetElapsedTime() const
Definition QuestData.h:475
bool GetIsNotYetStarted() const
Definition QuestData.h:525
void StartObjective(const UObject *Owner, const int32 QuestProgress)
Definition QuestData.h:439
FQuestObjectivesStatus ObjectiveStatus
Definition QuestData.h:410
int32 GetCurrentProgress() const
Definition QuestData.h:487
bool operator!=(const FQuestObjectives &Other) const
Definition QuestData.h:552
bool AddProgress(const int32 Amount)
Definition QuestData.h:421
float SaveObjectiveTime(const UObject *Owner)
Definition QuestData.h:452
bool GetIsFailed() const
Definition QuestData.h:513
bool GetDidCompleteInTime() const
Definition QuestData.h:483
bool GetIsSuccessful() const
Definition QuestData.h:534
bool AddFailProgress(const int32 Amount)
Definition QuestData.h:426
float GetFailProgressPercent() const
Definition QuestData.h:500
bool operator==(const FQuestObjectives &Other) const
Definition QuestData.h:548
void ResumeFromElapsedTime()
Definition QuestData.h:448
bool GetIsComplete() const
Definition QuestData.h:539
bool CanStart(const int32 TotalProgress) const
Definition QuestData.h:505
Definition QuestData.h:186
bool GetIsFailed(const int32 RequiredFailProgress) const
Definition QuestData.h:236
bool AddProgress(const int32 Amount, const int32 RequiredProgress)
Definition QuestData.h:291
int32 GetFailProgress() const
Definition QuestData.h:324
float SaveObjectiveTime(const UObject *Owner)
Definition QuestData.h:221
bool GetIsStarted() const
Definition QuestData.h:281
bool IsFinished(const int32 RequiredFailProgress, const int32 RequiredProgress) const
Definition QuestData.h:255
bool AddFailProgress(const int32 Amount, const int32 RequiredFailProgress)
Definition QuestData.h:306
EQuestStatus GetStatus() const
Definition QuestData.h:273
float GetStartTime() const
Definition QuestData.h:195
int32 GetUniqueID() const
Definition QuestData.h:332
bool GetIsNotYetStarted() const
Definition QuestData.h:285
bool GetDidCompleteInTime(const bool bObjectiveTimed=false, const float TimeToComplete=0.0f) const
Not sure if works becuase it needs to stop counting once objective is complete //.
Definition QuestData.h:245
bool IsActive() const
Definition QuestData.h:277
int32 GetCurrentProgress() const
Definition QuestData.h:320
void ResumeFromElapsedTime()
Definition QuestData.h:231
void StartObjective(const UObject *Owner)
Definition QuestData.h:200
bool IsSuccessful(const int32 RequiredFailProgress, const int32 RequiredProgress) const
Definition QuestData.h:259
bool Complete(const int32 RequiredFailProgress, const int32 RequiredProgress) const
Definition QuestData.h:264
void SetObjectiveNotYetStarted()
Definition QuestData.h:217
void SetUniqueID(const int32 NewUID)
Definition QuestData.h:328
Definition QuestData.h:1084
FQuestReward Reward
Definition QuestData.h:1096
EQuestStatus Outcome
Definition QuestData.h:1094
FQuestOutcome(const TArray< FQuestObjectives > &NewCompletedObjectives, const EQuestStatus FinishedOutcome)
Definition QuestData.h:1107
TArray< FQuestObjectives > CompletedObjectives
Definition QuestData.h:1092
FString QuestName
Definition QuestData.h:1090
FQuestOutcome(const TArray< FQuestObjectives > &NewCompletedObjectives)
Definition QuestData.h:1103
FUniqueID QuestID
Definition QuestData.h:1088
Definition QuestData.h:167
int32 Experience
Definition QuestData.h:171
int32 Credits
Definition QuestData.h:173
Definition BaseData.h:253
FString ID
Definition BaseData.h:257
void SetUniqueNumber(const int32 NewID)
Definition BaseData.h:259
int32 GetUniqueNumber() const
Definition BaseData.h:263