fr.jeanf.questsystem 0.0.60 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Runtime/Scripts/Core/Editor/QuestItem_Editor.cs +32 -0
- package/Runtime/Scripts/Core/Editor/QuestItem_Editor.cs.meta +11 -0
- package/Runtime/Scripts/Core/Editor/QuestStep_Editor.cs +8 -0
- package/Runtime/Scripts/Core/Quest.cs +0 -31
- package/Runtime/Scripts/Core/QuestItem.cs +62 -71
- package/Runtime/Scripts/Core/QuestManager.cs +82 -84
- package/Runtime/Scripts/Core/QuestStep.cs +60 -18
- package/package.json +10 -12
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#if UNITY_EDITOR
|
|
2
|
+
using UnityEditor;
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
|
|
5
|
+
namespace jeanf.questsystem
|
|
6
|
+
{
|
|
7
|
+
[CustomEditor(typeof(QuestItem), true)]
|
|
8
|
+
public class QuestItem_Editor : Editor
|
|
9
|
+
{
|
|
10
|
+
public override void OnInspectorGUI()
|
|
11
|
+
{
|
|
12
|
+
GUILayout.Space(10);
|
|
13
|
+
var eventToSend = (QuestItem)target;
|
|
14
|
+
GUILayout.BeginHorizontal();
|
|
15
|
+
if(GUILayout.Button("Log active steps", GUILayout.Height(20))) {
|
|
16
|
+
eventToSend.LogActiveSteps(); // how do i call this?
|
|
17
|
+
}
|
|
18
|
+
var originalColor = GUI.backgroundColor;
|
|
19
|
+
GUI.backgroundColor = Color.green;
|
|
20
|
+
if (GUILayout.Button("Validate Currently Active Steps", GUILayout.Height(20)))
|
|
21
|
+
{
|
|
22
|
+
eventToSend.ValidateCurrentlyActiveSteps(); // how do i call this?
|
|
23
|
+
}
|
|
24
|
+
GUI.backgroundColor = originalColor;
|
|
25
|
+
GUILayout.EndHorizontal();
|
|
26
|
+
GUILayout.Space(10);
|
|
27
|
+
|
|
28
|
+
DrawDefaultInspector();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
#endif
|
|
@@ -11,10 +11,18 @@ namespace jeanf.questsystem
|
|
|
11
11
|
{
|
|
12
12
|
GUILayout.Space(10);
|
|
13
13
|
var eventToSend = (QuestStep)target;
|
|
14
|
+
GUILayout.BeginHorizontal();
|
|
14
15
|
if (GUILayout.Button("Regenerate questStep id", GUILayout.Height(20)))
|
|
15
16
|
{
|
|
16
17
|
eventToSend.GenerateId(); // how do i call this?
|
|
17
18
|
}
|
|
19
|
+
var originalColor = GUI.backgroundColor;
|
|
20
|
+
GUI.backgroundColor = Color.green;
|
|
21
|
+
if(GUILayout.Button("Validate step", GUILayout.Height(20))) {
|
|
22
|
+
eventToSend.FinishQuestStep(); // how do i call this?
|
|
23
|
+
}
|
|
24
|
+
GUI.backgroundColor = originalColor;
|
|
25
|
+
GUILayout.EndHorizontal();
|
|
18
26
|
GUILayout.Space(10);
|
|
19
27
|
|
|
20
28
|
DrawDefaultInspector();
|
|
@@ -47,37 +47,6 @@ namespace jeanf.questsystem
|
|
|
47
47
|
this.questSO = questQuestSo;
|
|
48
48
|
this.state = questState;
|
|
49
49
|
this.questStepStates = questStepStates;
|
|
50
|
-
|
|
51
|
-
//if the quest step states and prefabs are different lengths,
|
|
52
|
-
//something has changed during development and the saved data is out of sync.
|
|
53
|
-
//if (this.questStepStates.Length != this.questSO.questSteps.Length)
|
|
54
|
-
//{
|
|
55
|
-
// Debug.LogWarning("Quest Step Prefabs and Quest Step States are "
|
|
56
|
-
// + "of different lengths. This indicates something changed "
|
|
57
|
-
// + "with the QuestInfo and the saved data is now out of sync. "
|
|
58
|
-
// + "Reset your data - as this might cause issues. QuestId: " + this.questSO.id);
|
|
59
|
-
//}
|
|
60
50
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
//public void StoreQuestStepState(QuestStepState questStepState, int stepIndex)
|
|
65
|
-
//{
|
|
66
|
-
// if (stepIndex < questStepStates.Count)
|
|
67
|
-
// {
|
|
68
|
-
// questStepStates[stepIndex].state = questStepState.state;
|
|
69
|
-
// }
|
|
70
|
-
// else
|
|
71
|
-
// {
|
|
72
|
-
// Debug.LogWarning("Tried to access quest step data, but stepIndex was out of range: "
|
|
73
|
-
// + "Quest Id = " + questSO.id + ", Step Index = " + stepIndex);
|
|
74
|
-
// }
|
|
75
|
-
//}
|
|
76
|
-
|
|
77
|
-
//public QuestData GetQuestData()
|
|
78
|
-
//{
|
|
79
|
-
// return new QuestData(state, currentQuestStepIndex, questStepStates);
|
|
80
|
-
//}
|
|
81
|
-
|
|
82
51
|
}
|
|
83
52
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections.Generic;
|
|
3
|
+
using System.Linq;
|
|
3
4
|
using jeanf.EventSystem;
|
|
4
5
|
using UnityEngine;
|
|
5
6
|
using jeanf.propertyDrawer;
|
|
6
7
|
using jeanf.validationTools;
|
|
7
8
|
using UnityEditor;
|
|
8
|
-
using System.Linq;
|
|
9
|
-
using Object = UnityEngine.Object;
|
|
10
|
-
|
|
11
9
|
|
|
12
10
|
namespace jeanf.questsystem
|
|
13
11
|
{
|
|
14
12
|
public class QuestItem : MonoBehaviour, IDebugBehaviour, IValidatable
|
|
15
13
|
{
|
|
14
|
+
|
|
15
|
+
#region interface variables
|
|
16
16
|
public bool isDebug
|
|
17
17
|
{
|
|
18
18
|
get => _isDebug;
|
|
@@ -22,24 +22,30 @@ namespace jeanf.questsystem
|
|
|
22
22
|
|
|
23
23
|
[SerializeField] private bool _isDebug = false;
|
|
24
24
|
[SerializeField] private bool _startQuestOnEnable = false;
|
|
25
|
+
#endregion
|
|
25
26
|
|
|
27
|
+
#region Step Dictionaries
|
|
26
28
|
[Tooltip("Visual feedback for the quest state")] [Header("Quest")]
|
|
27
29
|
[SerializeField] [Validation("A reference to a questSO is required")] private QuestSO questSO;
|
|
28
30
|
private Dictionary<string, QuestStep> stepMap = new Dictionary<string, QuestStep>();
|
|
29
31
|
private Dictionary<string, QuestStep> activeSteps = new Dictionary<string, QuestStep>();
|
|
30
32
|
private Dictionary<string, QuestStep> completedSteps = new Dictionary<string, QuestStep>();
|
|
31
33
|
private List<QuestStep> rootSteps = new List<QuestStep>();
|
|
34
|
+
#endregion
|
|
32
35
|
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
private float progress = 0.0f;
|
|
36
|
-
|
|
37
|
+
#region main data
|
|
37
38
|
[SerializeField] [ReadOnly]
|
|
38
39
|
private bool clearToStart = false;
|
|
39
|
-
|
|
40
40
|
private string questId;
|
|
41
41
|
private QuestState currentQuestState;
|
|
42
|
+
[ReadOnly][Range(0, 1)][SerializeField]
|
|
43
|
+
private float progress = 0.0f;
|
|
44
|
+
#endregion
|
|
42
45
|
|
|
46
|
+
#region events
|
|
47
|
+
public delegate void ValidateStep(string stepId);
|
|
48
|
+
public static ValidateStep ValidateStepEvent;
|
|
43
49
|
// these events are Located in Assets/Resources/Quests/Channels - it is searched for at Awake time.
|
|
44
50
|
// if they do not exist simply right click in the hierarchy and find >InitializeQuestSystem<
|
|
45
51
|
[Header("Listening on:")]
|
|
@@ -51,10 +57,10 @@ namespace jeanf.questsystem
|
|
|
51
57
|
private StringEventChannelSO requirementCheck;
|
|
52
58
|
[SerializeField][Validation("A reference to the LoadRequiredScenesEventChannel SO is required")] StringListEventChannelSO loadRequiredScenesEventChannel;
|
|
53
59
|
[SerializeField] IntEventChannelSO unlockDoorsEventChannel;
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
#endregion
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
|
|
63
|
+
#region Standard Unity Methods
|
|
58
64
|
private void Awake()
|
|
59
65
|
{
|
|
60
66
|
questId = questSO.id;
|
|
@@ -65,7 +71,10 @@ namespace jeanf.questsystem
|
|
|
65
71
|
rootSteps.Add(questSO.rootSteps[i]);
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
|
-
|
|
74
|
+
private void Reset()
|
|
75
|
+
{
|
|
76
|
+
Init(questId);
|
|
77
|
+
}
|
|
69
78
|
private void OnEnable()
|
|
70
79
|
{
|
|
71
80
|
Subscribe();
|
|
@@ -74,7 +83,6 @@ namespace jeanf.questsystem
|
|
|
74
83
|
}
|
|
75
84
|
private void OnDisable() => Unsubscribe();
|
|
76
85
|
private void OnDestroy() => Unsubscribe();
|
|
77
|
-
|
|
78
86
|
private void Subscribe()
|
|
79
87
|
{
|
|
80
88
|
resetChannel.OnEventRaised += Reset;
|
|
@@ -86,7 +94,6 @@ namespace jeanf.questsystem
|
|
|
86
94
|
QuestStep.stepActive += UpdateStepStatus;
|
|
87
95
|
QuestStep.childStep += AddStepToStepMap;
|
|
88
96
|
}
|
|
89
|
-
|
|
90
97
|
private void Unsubscribe()
|
|
91
98
|
{
|
|
92
99
|
resetChannel.OnEventRaised -= Reset;
|
|
@@ -102,11 +109,6 @@ namespace jeanf.questsystem
|
|
|
102
109
|
}
|
|
103
110
|
#endregion
|
|
104
111
|
|
|
105
|
-
private void Reset()
|
|
106
|
-
{
|
|
107
|
-
Init(questId);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
112
|
#region Instantiations & Loading
|
|
111
113
|
public void InstantiateQuestStep(string id)
|
|
112
114
|
{
|
|
@@ -114,10 +116,10 @@ namespace jeanf.questsystem
|
|
|
114
116
|
if (stepMap[id].stepStatus != QuestStepStatus.Inactive) return;
|
|
115
117
|
if (activeSteps.ContainsKey(id)) return;
|
|
116
118
|
|
|
119
|
+
|
|
117
120
|
Instantiate(stepMap[id], this.transform, true);
|
|
118
|
-
//if(!activeSteps.ContainsKey(id)) activeSteps.Add(id,Instantiate(stepMap[id], this.transform, true));
|
|
119
|
-
}
|
|
120
121
|
|
|
122
|
+
}
|
|
121
123
|
private void LoadDependencies()
|
|
122
124
|
{
|
|
123
125
|
loadRequiredScenesEventChannel.RaiseEvent(questSO.ScenesToLoad);
|
|
@@ -127,43 +129,22 @@ namespace jeanf.questsystem
|
|
|
127
129
|
unlockDoorsEventChannel.RaiseEvent(roomToUnlock);
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
|
-
#endregion
|
|
131
|
-
|
|
132
|
-
public void UpdateStepStatus(string id, QuestStepStatus status)
|
|
133
|
-
{
|
|
134
|
-
switch (status)
|
|
135
|
-
{
|
|
136
|
-
case QuestStepStatus.Completed when activeSteps.ContainsKey(id):
|
|
137
|
-
// put step in completed list
|
|
138
|
-
activeSteps.Remove(id);
|
|
139
|
-
completedSteps.Add(id, stepMap[id]);
|
|
140
|
-
break;
|
|
141
|
-
case QuestStepStatus.Active when !activeSteps.ContainsKey(id):
|
|
142
|
-
// put step in active list
|
|
143
|
-
activeSteps.Add(id, stepMap[id]);
|
|
144
|
-
break;
|
|
145
|
-
case QuestStepStatus.Inactive:
|
|
146
|
-
// do nothing
|
|
147
|
-
default:
|
|
148
|
-
// do nothing
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
132
|
private void AddStepToStepMap(QuestStep step)
|
|
154
133
|
{
|
|
155
|
-
if(isDebug) Debug.Log($"--- Received request to add step {step.name} with id: {step.StepId} to stepMap.");
|
|
134
|
+
if (isDebug) Debug.Log($"--- Received request to add step {step.name} with id: {step.StepId} to stepMap.");
|
|
156
135
|
if (!stepMap.ContainsKey(step.StepId))
|
|
157
136
|
{
|
|
158
|
-
if(isDebug) Debug.Log($"--- Step [{step.StepId}] not found in stepMap, adding it.");
|
|
137
|
+
if (isDebug) Debug.Log($"--- Step [{step.StepId}] not found in stepMap, adding it.");
|
|
159
138
|
stepMap.Add(step.StepId, step);
|
|
160
139
|
}
|
|
161
140
|
if (completedSteps.ContainsKey(step.StepId))
|
|
162
141
|
{
|
|
163
|
-
if(isDebug) Debug.Log($"--- Step [{step.StepId}] already completed removing it from completeSteps so that we can go through it again.");
|
|
142
|
+
if (isDebug) Debug.Log($"--- Step [{step.StepId}] already completed removing it from completeSteps so that we can go through it again.");
|
|
164
143
|
completedSteps.Remove(step.StepId);
|
|
165
144
|
}
|
|
166
145
|
}
|
|
146
|
+
#endregion
|
|
147
|
+
|
|
167
148
|
#region quest process
|
|
168
149
|
private void Init(string id)
|
|
169
150
|
{
|
|
@@ -194,7 +175,26 @@ namespace jeanf.questsystem
|
|
|
194
175
|
|
|
195
176
|
LoadDependencies();
|
|
196
177
|
}
|
|
197
|
-
|
|
178
|
+
public void UpdateStepStatus(string id, QuestStepStatus status)
|
|
179
|
+
{
|
|
180
|
+
switch (status)
|
|
181
|
+
{
|
|
182
|
+
case QuestStepStatus.Completed when activeSteps.ContainsKey(id):
|
|
183
|
+
// put step in completed list
|
|
184
|
+
activeSteps.Remove(id);
|
|
185
|
+
completedSteps.Add(id, stepMap[id]);
|
|
186
|
+
break;
|
|
187
|
+
case QuestStepStatus.Active when !activeSteps.ContainsKey(id):
|
|
188
|
+
// put step in active list
|
|
189
|
+
activeSteps.Add(id, stepMap[id]);
|
|
190
|
+
break;
|
|
191
|
+
case QuestStepStatus.Inactive:
|
|
192
|
+
// do nothing
|
|
193
|
+
default:
|
|
194
|
+
// do nothing
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
198
|
private void UpdateState()
|
|
199
199
|
{
|
|
200
200
|
if (isDebug) Debug.Log($"Updating State...");
|
|
@@ -230,14 +230,12 @@ namespace jeanf.questsystem
|
|
|
230
230
|
throw new ArgumentOutOfRangeException();
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
-
|
|
234
233
|
private void UpdateProgress(string id, float progress)
|
|
235
234
|
{
|
|
236
235
|
if (id != questId) return;
|
|
237
236
|
this.progress = progress;
|
|
238
237
|
if (isDebug) Debug.Log($"questid [{id}] progress = {progress * 100}%");
|
|
239
238
|
}
|
|
240
|
-
|
|
241
239
|
private void QuestStateChange(Quest quest)
|
|
242
240
|
{
|
|
243
241
|
// only update the quest state if this point has the corresponding quest
|
|
@@ -249,17 +247,27 @@ namespace jeanf.questsystem
|
|
|
249
247
|
}
|
|
250
248
|
#endregion
|
|
251
249
|
|
|
250
|
+
#region Complete all Steps
|
|
251
|
+
public void ValidateCurrentlyActiveSteps()
|
|
252
|
+
{
|
|
253
|
+
var currentlyActiveSteps = activeSteps.Keys;
|
|
254
|
+
|
|
255
|
+
for (var i = 0; i < currentlyActiveSteps.Count; i++)
|
|
256
|
+
{
|
|
257
|
+
var activeStep = activeSteps.ElementAt(i);
|
|
258
|
+
var stepKey = activeStep.Key;
|
|
259
|
+
if(activeSteps.ContainsKey(stepKey)) ValidateStepEvent.Invoke(stepKey);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
#endregion
|
|
263
|
+
|
|
252
264
|
#region validation tools
|
|
253
265
|
|
|
254
|
-
|
|
266
|
+
#if UNITY_EDITOR
|
|
255
267
|
public void OnValidate()
|
|
256
268
|
{
|
|
257
269
|
ValidityCheck();
|
|
258
270
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
271
|
public void LogActiveSteps()
|
|
264
272
|
{
|
|
265
273
|
Debug.Log($"There is {activeSteps.Count} active steps at the moment.");
|
|
@@ -269,7 +277,6 @@ namespace jeanf.questsystem
|
|
|
269
277
|
}
|
|
270
278
|
}
|
|
271
279
|
#endif
|
|
272
|
-
|
|
273
280
|
private void ValidityCheck()
|
|
274
281
|
{
|
|
275
282
|
const string searching = "attempting to find";
|
|
@@ -354,20 +361,4 @@ namespace jeanf.questsystem
|
|
|
354
361
|
}
|
|
355
362
|
#endregion
|
|
356
363
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
#if UNITY_EDITOR
|
|
360
|
-
[CustomEditor(typeof(QuestItem))]
|
|
361
|
-
public class BoolEventOnClickEditor : Editor {
|
|
362
|
-
override public void OnInspectorGUI () {
|
|
363
|
-
DrawDefaultInspector();
|
|
364
|
-
GUILayout.Space(10);
|
|
365
|
-
var eventToSend = (QuestItem) target;
|
|
366
|
-
if(GUILayout.Button("Log active steps", GUILayout.Height(30))) {
|
|
367
|
-
eventToSend.LogActiveSteps(); // how do i call this?
|
|
368
|
-
}
|
|
369
|
-
GUILayout.Space(10);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
#endif
|
|
373
364
|
}
|
|
@@ -11,6 +11,8 @@ namespace jeanf.questsystem
|
|
|
11
11
|
{
|
|
12
12
|
public class QuestManager : MonoBehaviour, IDebugBehaviour, IValidatable
|
|
13
13
|
{
|
|
14
|
+
#region variables
|
|
15
|
+
#region interface variables
|
|
14
16
|
public bool isDebug
|
|
15
17
|
{
|
|
16
18
|
get => _isDebug;
|
|
@@ -19,23 +21,26 @@ namespace jeanf.questsystem
|
|
|
19
21
|
public bool IsValid { get; private set; }
|
|
20
22
|
|
|
21
23
|
[SerializeField] private bool _isDebug = false;
|
|
24
|
+
#endregion
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
private bool loadSavedQuestState = true;
|
|
25
|
-
|
|
26
|
+
#region event channels
|
|
26
27
|
[Header("Broadcasting on:")]
|
|
27
28
|
[SerializeField] [Validation("A reference to the questStatusUpdateChannel is required.")] private StringEventChannelSO questStatusUpdateChannel;
|
|
28
29
|
[SerializeField] [Validation("A reference to the questProgress is required.")] private StringFloatEventChannelSO questProgress;
|
|
29
30
|
[SerializeField] [Validation("A reference to the questInitialCheck channel is required.")] private StringEventChannelSO QuestInitialCheck;
|
|
30
|
-
|
|
31
31
|
[Header("Listening on:")] [SerializeField] [Validation("A reference to the questStatusUpdateRequested is required.")] private StringEventChannelSO questStatusUpdateRequested;
|
|
32
|
+
#endregion
|
|
32
33
|
|
|
34
|
+
#region other variables
|
|
35
|
+
[FormerlySerializedAs("loadQuestState")] [Header("Config")] [SerializeField]
|
|
36
|
+
private bool loadSavedQuestState = true;
|
|
33
37
|
private Dictionary<string, Quest> questMap;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// quest start requirements
|
|
37
38
|
private int currentPlayerLevel;
|
|
39
|
+
#endregion
|
|
40
|
+
#endregion
|
|
38
41
|
|
|
42
|
+
#region Methods
|
|
43
|
+
#region Standard Unity Methods
|
|
39
44
|
private void Awake()
|
|
40
45
|
{
|
|
41
46
|
questMap = CreateQuestMap();
|
|
@@ -45,25 +50,16 @@ namespace jeanf.questsystem
|
|
|
45
50
|
CheckIfQuestIsAlreadyLoaded(quest.Key);
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
|
-
|
|
49
53
|
private void OnEnable()
|
|
50
54
|
{
|
|
51
55
|
GameEventsManager.instance.questEvents.onStartQuest += StartQuest;
|
|
52
|
-
GameEventsManager.instance.questEvents.onFinishQuest += FinishQuest;
|
|
53
|
-
|
|
56
|
+
GameEventsManager.instance.questEvents.onFinishQuest += FinishQuest;
|
|
54
57
|
//GameEventsManager.instance.questEvents.onQuestStepStateChange += QuestStepStateChange;
|
|
55
|
-
|
|
56
58
|
GameEventsManager.instance.playerEvents.onPlayerLevelChange += PlayerLevelChange;
|
|
57
|
-
|
|
58
59
|
questStatusUpdateRequested.OnEventRaised += ctx => CheckRequirementsMet(questMap[ctx]);
|
|
59
|
-
|
|
60
|
-
|
|
61
60
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
61
|
private void OnDisable() => Unsubscribe();
|
|
65
62
|
private void OnDestroy() => Unsubscribe();
|
|
66
|
-
|
|
67
63
|
private void Unsubscribe()
|
|
68
64
|
{
|
|
69
65
|
GameEventsManager.instance.questEvents.onStartQuest -= StartQuest;
|
|
@@ -74,7 +70,6 @@ namespace jeanf.questsystem
|
|
|
74
70
|
GameEventsManager.instance.playerEvents.onPlayerLevelChange -= PlayerLevelChange;
|
|
75
71
|
|
|
76
72
|
}
|
|
77
|
-
|
|
78
73
|
private void Start()
|
|
79
74
|
{
|
|
80
75
|
foreach (Quest quest in questMap.Values)
|
|
@@ -83,25 +78,63 @@ namespace jeanf.questsystem
|
|
|
83
78
|
GameEventsManager.instance.questEvents.QuestStateChange(quest);
|
|
84
79
|
}
|
|
85
80
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
private void CheckIfQuestIsAlreadyLoaded(string id)
|
|
81
|
+
private void Update()
|
|
89
82
|
{
|
|
90
|
-
|
|
83
|
+
// loop through ALL quests
|
|
84
|
+
foreach (Quest quest in questMap.Values)
|
|
85
|
+
{
|
|
86
|
+
// if we're now meeting the requirements, switch over to the CAN_START state
|
|
87
|
+
if (quest.state == QuestState.REQUIREMENTS_NOT_MET && CheckRequirementsMet(quest))
|
|
88
|
+
{
|
|
89
|
+
ChangeQuestState(quest.questSO.id, QuestState.CAN_START);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
-
private void ChangeQuestState(string id, QuestState state)
|
|
93
|
+
private void OnApplicationQuit()
|
|
94
94
|
{
|
|
95
|
-
Quest quest
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
foreach (Quest quest in questMap.Values)
|
|
96
|
+
{
|
|
97
|
+
SaveQuest(quest);
|
|
98
|
+
}
|
|
98
99
|
}
|
|
100
|
+
#endregion
|
|
99
101
|
|
|
100
|
-
|
|
102
|
+
#region Quest Checks and getters
|
|
103
|
+
private Dictionary<string, Quest> CreateQuestMap()
|
|
101
104
|
{
|
|
102
|
-
|
|
105
|
+
// loads all QuestInfoSO Scriptable Objects under the Assets/Resources/Quests folder
|
|
106
|
+
QuestSO[] allQuests = Resources.LoadAll<QuestSO>("Quests");
|
|
107
|
+
// Create the quest map
|
|
108
|
+
Dictionary<string, Quest> questMap = new Dictionary<string, Quest>();
|
|
109
|
+
foreach (QuestSO questSO in allQuests)
|
|
110
|
+
{
|
|
111
|
+
var id = questSO.id;
|
|
112
|
+
if (questMap.ContainsKey(id))
|
|
113
|
+
{
|
|
114
|
+
Debug.LogWarning("Duplicate ID found when creating quest map: " + questSO.id);
|
|
115
|
+
}
|
|
116
|
+
else
|
|
117
|
+
{
|
|
118
|
+
questMap.Add(id, LoadQuest(questSO));
|
|
119
|
+
}
|
|
120
|
+
if (isDebug) Debug.Log($"Adding {questSO.name} to the questmap, its id is: {questSO.id}");
|
|
121
|
+
}
|
|
122
|
+
return questMap;
|
|
123
|
+
}
|
|
124
|
+
private void CheckIfQuestIsAlreadyLoaded(string id)
|
|
125
|
+
{
|
|
126
|
+
QuestInitialCheck.RaiseEvent(id);
|
|
103
127
|
}
|
|
128
|
+
public Quest GetQuestById(string id)
|
|
129
|
+
{
|
|
130
|
+
Quest quest = questMap[id];
|
|
131
|
+
if (quest == null)
|
|
132
|
+
{
|
|
133
|
+
Debug.LogError("ID not found in the Quest Map: " + id);
|
|
134
|
+
}
|
|
104
135
|
|
|
136
|
+
return quest;
|
|
137
|
+
}
|
|
105
138
|
private bool CheckRequirementsMet(Quest quest)
|
|
106
139
|
{
|
|
107
140
|
// check player level requirements
|
|
@@ -115,25 +148,20 @@ namespace jeanf.questsystem
|
|
|
115
148
|
meetsRequirements = false;
|
|
116
149
|
}
|
|
117
150
|
}
|
|
118
|
-
|
|
119
|
-
if(isDebug) Debug.Log($"checking requirements for quest: {quest.questSO.name}, [{quest.questSO.id}], meetsRequirements: {meetsRequirements}");
|
|
151
|
+
|
|
152
|
+
if (isDebug) Debug.Log($"checking requirements for quest: {quest.questSO.name}, [{quest.questSO.id}], meetsRequirements: {meetsRequirements}");
|
|
120
153
|
|
|
121
154
|
return meetsRequirements;
|
|
122
155
|
}
|
|
123
|
-
|
|
124
|
-
private void Update()
|
|
156
|
+
private void ChangeQuestState(string id, QuestState state)
|
|
125
157
|
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// if we're now meeting the requirements, switch over to the CAN_START state
|
|
130
|
-
if (quest.state == QuestState.REQUIREMENTS_NOT_MET && CheckRequirementsMet(quest))
|
|
131
|
-
{
|
|
132
|
-
ChangeQuestState(quest.questSO.id, QuestState.CAN_START);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
158
|
+
Quest quest = GetQuestById(id);
|
|
159
|
+
quest.state = state;
|
|
160
|
+
GameEventsManager.instance.questEvents.QuestStateChange(quest);
|
|
135
161
|
}
|
|
162
|
+
#endregion
|
|
136
163
|
|
|
164
|
+
#region main process
|
|
137
165
|
private void StartQuest(string id)
|
|
138
166
|
{
|
|
139
167
|
Quest quest = GetQuestById(id);
|
|
@@ -143,7 +171,6 @@ namespace jeanf.questsystem
|
|
|
143
171
|
quest.messageChannel.RaiseEvent(quest.messageToSendOnInit);
|
|
144
172
|
if(isDebug) Debug.Log($"quest id:{id} started, a message was attatched to the initialization: {quest.messageToSendOnInit}");
|
|
145
173
|
}
|
|
146
|
-
|
|
147
174
|
private void UpdateProgress(Quest quest)
|
|
148
175
|
{
|
|
149
176
|
var progress = 0;
|
|
@@ -151,7 +178,6 @@ namespace jeanf.questsystem
|
|
|
151
178
|
if (isDebug) Debug.Log($"[{quest.questSO.id}] progress: {progress * 100}%", this);
|
|
152
179
|
questProgress.RaiseEvent(quest.questSO.id, progress);
|
|
153
180
|
}
|
|
154
|
-
|
|
155
181
|
private void FinishQuest(string id)
|
|
156
182
|
{
|
|
157
183
|
Quest quest = GetQuestById(id);
|
|
@@ -163,58 +189,26 @@ namespace jeanf.questsystem
|
|
|
163
189
|
SaveQuest(quest);
|
|
164
190
|
if (!quest.sendMessageOnFinish) return;
|
|
165
191
|
}
|
|
192
|
+
#endregion
|
|
166
193
|
|
|
194
|
+
#region rewards and progress
|
|
167
195
|
private void ClaimRewards(Quest quest)
|
|
168
196
|
{
|
|
169
197
|
GameEventsManager.instance.scenarioEvents.ScenarioUnlocked(quest.questSO.unlockedScenario);
|
|
170
198
|
}
|
|
171
199
|
|
|
172
|
-
private
|
|
173
|
-
{
|
|
174
|
-
// loads all QuestInfoSO Scriptable Objects under the Assets/Resources/Quests folder
|
|
175
|
-
QuestSO[] allQuests = Resources.LoadAll<QuestSO>("Quests");
|
|
176
|
-
// Create the quest map
|
|
177
|
-
Dictionary<string, Quest> questMap = new Dictionary<string, Quest>();
|
|
178
|
-
foreach (QuestSO questSO in allQuests)
|
|
179
|
-
{
|
|
180
|
-
var id = questSO.id;
|
|
181
|
-
if (questMap.ContainsKey(id))
|
|
182
|
-
{
|
|
183
|
-
Debug.LogWarning("Duplicate ID found when creating quest map: " + questSO.id);
|
|
184
|
-
}
|
|
185
|
-
else
|
|
186
|
-
{
|
|
187
|
-
questMap.Add(id, LoadQuest(questSO));
|
|
188
|
-
}
|
|
189
|
-
if(isDebug) Debug.Log($"Adding {questSO.name} to the questmap, its id is: {questSO.id}");
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return questMap;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
public Quest GetQuestById(string id)
|
|
196
|
-
{
|
|
197
|
-
Quest quest = questMap[id];
|
|
198
|
-
if (quest == null)
|
|
199
|
-
{
|
|
200
|
-
Debug.LogError("ID not found in the Quest Map: " + id);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return quest;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private void OnApplicationQuit()
|
|
200
|
+
private void PlayerLevelChange(int level)
|
|
207
201
|
{
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
SaveQuest(quest);
|
|
211
|
-
}
|
|
202
|
+
currentPlayerLevel = level;
|
|
212
203
|
}
|
|
204
|
+
#endregion
|
|
213
205
|
|
|
206
|
+
#region saving and loading
|
|
214
207
|
private void SaveQuest(Quest quest)
|
|
215
208
|
{
|
|
216
209
|
try
|
|
217
210
|
{
|
|
211
|
+
//Save; active steps + quest step status for each, completed steps, quest status, progress/playerLevel/?
|
|
218
212
|
QuestData questData = null;
|
|
219
213
|
//quest.GetQuestData();
|
|
220
214
|
// serialize using JsonUtility, but use whatever you want here (like JSON.NET)
|
|
@@ -230,7 +224,6 @@ namespace jeanf.questsystem
|
|
|
230
224
|
Debug.LogError("Failed to save quest with id " + quest.questSO.id + ": " + e);
|
|
231
225
|
}
|
|
232
226
|
}
|
|
233
|
-
|
|
234
227
|
private Quest LoadQuest(QuestSO questSO)
|
|
235
228
|
{
|
|
236
229
|
Debug.Log($"attempting to load quest with id: [{questSO.id}]");
|
|
@@ -259,6 +252,9 @@ namespace jeanf.questsystem
|
|
|
259
252
|
|
|
260
253
|
return quest;
|
|
261
254
|
}
|
|
255
|
+
#endregion
|
|
256
|
+
|
|
257
|
+
#region Validation Tools
|
|
262
258
|
private void ValidityCheck()
|
|
263
259
|
{
|
|
264
260
|
const string searching = "attempting to find";
|
|
@@ -334,5 +330,7 @@ namespace jeanf.questsystem
|
|
|
334
330
|
ValidityCheck();
|
|
335
331
|
#endif
|
|
336
332
|
}
|
|
333
|
+
#endregion
|
|
334
|
+
#endregion
|
|
337
335
|
}
|
|
338
336
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
using System;
|
|
1
2
|
using jeanf.EventSystem;
|
|
2
3
|
using jeanf.propertyDrawer;
|
|
3
4
|
using UnityEngine;
|
|
@@ -5,21 +6,24 @@ using UnityEngine.Playables;
|
|
|
5
6
|
using System.Collections.Generic;
|
|
6
7
|
using GraphProcessor;
|
|
7
8
|
using jeanf.validationTools;
|
|
9
|
+
using UnityEditor;
|
|
8
10
|
|
|
9
11
|
namespace jeanf.questsystem
|
|
10
12
|
{
|
|
11
13
|
[System.Serializable, NodeMenuItem("questSystem/QuestStep"), DefaultExecutionOrder(1)]
|
|
12
14
|
public class QuestStep : MonoBehaviour, IDebugBehaviour
|
|
13
15
|
{
|
|
16
|
+
#region Ids and status
|
|
14
17
|
[field: Space(10)][field: ReadOnly][SerializeField] string stepId;
|
|
15
18
|
public string StepId { get { return stepId; } }
|
|
16
19
|
|
|
17
20
|
string questId;
|
|
18
21
|
public string QuestId { get { return questId; } }
|
|
22
|
+
[field: ReadOnly][SerializeField] public QuestStepStatus stepStatus;
|
|
23
|
+
#endregion
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
[field: ReadOnly] [SerializeField] public QuestStepStatus stepStatus;
|
|
22
25
|
|
|
26
|
+
#region timeline
|
|
23
27
|
[Tooltip("This boolean has to be enabled if the quest step has an intro timeline.")]
|
|
24
28
|
public bool isUsingIntroTimeline = false;
|
|
25
29
|
|
|
@@ -27,7 +31,9 @@ namespace jeanf.questsystem
|
|
|
27
31
|
[SerializeField] private TimelineTriggerEventChannelSO _timelineTriggerEventChannelSo;
|
|
28
32
|
[DrawIf("isUsingIntroTimeline", true, ComparisonType.Equals, DisablingType.DontDraw)]
|
|
29
33
|
public PlayableAsset timeline;
|
|
34
|
+
#endregion
|
|
30
35
|
|
|
36
|
+
#region step trigger and completion
|
|
31
37
|
[Header("Quest Step Progression events & Variables")]
|
|
32
38
|
public List<QuestStep> questStepsToTrigger = new List<QuestStep>();
|
|
33
39
|
public delegate void SendNextStepId(string id);
|
|
@@ -39,22 +45,42 @@ namespace jeanf.questsystem
|
|
|
39
45
|
public static StepActive stepActive;
|
|
40
46
|
public delegate void ChildStep(QuestStep step);
|
|
41
47
|
public static ChildStep childStep;
|
|
42
|
-
|
|
48
|
+
#endregion
|
|
49
|
+
|
|
50
|
+
#region events
|
|
43
51
|
[Header("Quest Tooltip")]
|
|
44
52
|
[SerializeField] private QuestTooltipSO questTooltipSO;
|
|
45
53
|
|
|
46
54
|
[Header("Event Channels")]
|
|
47
55
|
[SerializeField] private StringEventChannelSO sendQuestStepTooltip;
|
|
56
|
+
[SerializeField] private StringEventChannelSO stepValidationOverride;
|
|
57
|
+
#endregion
|
|
48
58
|
|
|
59
|
+
#region standard unity methods
|
|
60
|
+
public void OnEnable()
|
|
61
|
+
{
|
|
62
|
+
Subscribe();
|
|
63
|
+
InitializeQuestStep();
|
|
64
|
+
}
|
|
49
65
|
|
|
66
|
+
public void OnDisable() => Unsubscribe();
|
|
50
67
|
|
|
68
|
+
public void OnDestroy() => Unsubscribe();
|
|
51
69
|
|
|
52
|
-
|
|
70
|
+
private void Subscribe()
|
|
53
71
|
{
|
|
54
|
-
|
|
72
|
+
QuestItem.ValidateStepEvent += ValidateCurrentStep;
|
|
73
|
+
if(stepValidationOverride) stepValidationOverride.OnEventRaised += ValidateCurrentStep;
|
|
55
74
|
}
|
|
56
75
|
|
|
76
|
+
protected virtual void Unsubscribe()
|
|
77
|
+
{
|
|
78
|
+
QuestItem.ValidateStepEvent -= ValidateCurrentStep;
|
|
79
|
+
if(stepValidationOverride) stepValidationOverride.OnEventRaised -= ValidateCurrentStep;
|
|
80
|
+
}
|
|
81
|
+
#endregion
|
|
57
82
|
|
|
83
|
+
#region step progress
|
|
58
84
|
public void InitializeQuestStep()
|
|
59
85
|
{
|
|
60
86
|
// failsafe to avoid lauching the same step more than once at a time.
|
|
@@ -74,6 +100,7 @@ namespace jeanf.questsystem
|
|
|
74
100
|
{
|
|
75
101
|
if(isDebug) Debug.Log($"sending trigger to timeline: {timeline.name}, triggerValue: true");
|
|
76
102
|
_timelineTriggerEventChannelSo.RaiseEvent(timeline, true);
|
|
103
|
+
|
|
77
104
|
}
|
|
78
105
|
|
|
79
106
|
if(isDebug) Debug.Log($"Step with id [{stepId}] has {questStepsToTrigger.Count} childSteps");
|
|
@@ -84,9 +111,13 @@ namespace jeanf.questsystem
|
|
|
84
111
|
}
|
|
85
112
|
}
|
|
86
113
|
|
|
114
|
+
public void ValidateCurrentStep(string stepId)
|
|
115
|
+
{
|
|
116
|
+
if(stepId != this.stepId)return;
|
|
117
|
+
FinishQuestStep();
|
|
118
|
+
}
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
protected void FinishQuestStep()
|
|
120
|
+
public void FinishQuestStep()
|
|
90
121
|
{
|
|
91
122
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Changing status to completed", this);
|
|
92
123
|
stepStatus = QuestStepStatus.Completed;
|
|
@@ -96,23 +127,28 @@ namespace jeanf.questsystem
|
|
|
96
127
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending tooltip", this);
|
|
97
128
|
sendQuestStepTooltip.RaiseEvent(string.Empty);
|
|
98
129
|
}
|
|
99
|
-
;
|
|
100
130
|
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Requesting to start next step: {questStep.stepId}", this);
|
|
104
|
-
sendNextStepId?.Invoke(questStep.stepId);
|
|
105
|
-
}
|
|
131
|
+
|
|
106
132
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending stepCompleted Event (delegate) with argument: {stepId}", this);
|
|
107
133
|
stepCompleted?.Invoke(stepId);
|
|
108
|
-
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending stepActive Event (delegate) with arguments: {stepId}, {stepStatus} ", this);
|
|
134
|
+
if (isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending stepActive Event (delegate) with arguments: {stepId}, {stepStatus} ", this);
|
|
109
135
|
stepActive?.Invoke(stepId, stepStatus);
|
|
110
136
|
|
|
137
|
+
foreach (QuestStep questStep in questStepsToTrigger)
|
|
138
|
+
{
|
|
139
|
+
if (isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Requesting to start next step: {questStep.stepId}", this);
|
|
140
|
+
|
|
141
|
+
//Si questStep.prerequisitesStep are in QuestItem.stepsCompleted
|
|
142
|
+
sendNextStepId?.Invoke(questStep.stepId);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
111
146
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Destroying the gameobject with name {this.name}", this);
|
|
112
147
|
Destroy(this.gameObject);
|
|
113
148
|
}
|
|
149
|
+
#endregion
|
|
114
150
|
|
|
115
|
-
|
|
151
|
+
#region tooltip
|
|
116
152
|
protected void DisplayActiveQuestStep()
|
|
117
153
|
{
|
|
118
154
|
if (questTooltipSO != null)
|
|
@@ -120,8 +156,10 @@ namespace jeanf.questsystem
|
|
|
120
156
|
sendQuestStepTooltip.RaiseEvent(questTooltipSO.Tooltip);
|
|
121
157
|
}
|
|
122
158
|
}
|
|
159
|
+
#endregion
|
|
123
160
|
|
|
124
|
-
#
|
|
161
|
+
#region validation
|
|
162
|
+
#if UNITY_EDITOR
|
|
125
163
|
private void OnValidate()
|
|
126
164
|
{
|
|
127
165
|
if (stepId == string.Empty || stepId == null) GenerateId();
|
|
@@ -133,16 +171,20 @@ namespace jeanf.questsystem
|
|
|
133
171
|
UnityEditor.EditorUtility.SetDirty(this);
|
|
134
172
|
}
|
|
135
173
|
|
|
136
|
-
|
|
137
|
-
|
|
174
|
+
#endif
|
|
175
|
+
#endregion
|
|
138
176
|
|
|
177
|
+
#region debug
|
|
139
178
|
public bool isDebug { get => _isDebug; set => _isDebug = value; }
|
|
140
179
|
private bool _isDebug = true;
|
|
180
|
+
#endregion
|
|
141
181
|
|
|
182
|
+
#region Status
|
|
142
183
|
public QuestStepStatus GetStatus()
|
|
143
184
|
{
|
|
144
185
|
return stepStatus;
|
|
145
186
|
}
|
|
187
|
+
#endregion
|
|
146
188
|
}
|
|
147
189
|
|
|
148
190
|
public enum QuestStepStatus
|
package/package.json
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name":"fr.jeanf.questsystem",
|
|
3
|
-
"version":"0.0.
|
|
4
|
-
"displayName":"Quest system",
|
|
5
|
-
"description":"This package uses Scriptable Objects to define quests.",
|
|
2
|
+
"name": "fr.jeanf.questsystem",
|
|
3
|
+
"version": "0.0.62",
|
|
4
|
+
"displayName": "Quest system",
|
|
5
|
+
"description": "This package uses Scriptable Objects to define quests.",
|
|
6
6
|
"unity": "2021.3",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"jeanf",
|
|
9
9
|
"quest system"
|
|
10
10
|
],
|
|
11
|
-
"author":{
|
|
12
|
-
"name":"Jean-François Robin",
|
|
13
|
-
"email":"robin.jeanfrancois@gmail.com",
|
|
14
|
-
"url":"https://jeanfrancoisrobin.art"
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Jean-François Robin",
|
|
13
|
+
"email": "robin.jeanfrancois@gmail.com",
|
|
14
|
+
"url": "https://jeanfrancoisrobin.art"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"fr.jeanf.propertydrawer": "1.1.6"
|
|
18
18
|
},
|
|
19
|
-
"samples": [
|
|
20
|
-
|
|
21
|
-
]
|
|
22
|
-
}
|
|
19
|
+
"samples": []
|
|
20
|
+
}
|