fr.jeanf.questsystem 0.0.61 → 0.0.63
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/Quests/Quest_VisitAllPlaces.prefab +4 -3
- package/Runtime/Scripts/Core/Quest.cs +0 -31
- package/Runtime/Scripts/Core/QuestItem.cs +49 -56
- package/Runtime/Scripts/Core/QuestManager.cs +82 -84
- package/Runtime/Scripts/Core/QuestStep.cs +38 -18
- package/Runtime/Scripts/GraphEditor/QuestGraphWindow.cs +30 -0
- package/Runtime/Scripts/GraphEditor/QuestGraphWindow.cs.meta +11 -0
- package/Runtime/Scripts/GraphEditor/QuestStepNode.cs +11 -0
- package/Runtime/Scripts/GraphEditor/QuestStepNode.cs.meta +11 -0
- package/Runtime/Scripts/GraphEditor.meta +8 -0
- package/Runtime/Scripts/jeanf.QuestSystem.asmdef +3 -1
- package/package.json +9 -11
|
@@ -28,13 +28,13 @@ Transform:
|
|
|
28
28
|
m_PrefabInstance: {fileID: 0}
|
|
29
29
|
m_PrefabAsset: {fileID: 0}
|
|
30
30
|
m_GameObject: {fileID: 5258580714634048286}
|
|
31
|
-
serializedVersion: 2
|
|
32
31
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
|
33
32
|
m_LocalPosition: {x: 7.37, y: 1, z: 6.08}
|
|
34
33
|
m_LocalScale: {x: 3, y: 3, z: 3}
|
|
35
34
|
m_ConstrainProportionsScale: 0
|
|
36
35
|
m_Children: []
|
|
37
36
|
m_Father: {fileID: 0}
|
|
37
|
+
m_RootOrder: -2
|
|
38
38
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
39
39
|
--- !u!33 &7682207879693783699
|
|
40
40
|
MeshFilter:
|
|
@@ -171,7 +171,8 @@ MonoBehaviour:
|
|
|
171
171
|
progress: 0
|
|
172
172
|
clearToStart: 0
|
|
173
173
|
QuestProgress: {fileID: 11400000, guid: d6b05e1957994c8449fb72e849a2a3d6, type: 2}
|
|
174
|
-
StartQuestEventChannel: {fileID: 11400000, guid: c510c1e4d26428740b3e329cca98e5d1,
|
|
175
|
-
type: 2}
|
|
176
174
|
QuestInitialCheck: {fileID: 11400000, guid: 4f5235d1ff779064cabee9ca65296d7f, type: 2}
|
|
175
|
+
resetChannel: {fileID: 11400000, guid: f5878d9ead688634e8a37cb28026e722, type: 2}
|
|
177
176
|
requirementCheck: {fileID: 11400000, guid: a4dae407f780f974abbf43c280515876, type: 2}
|
|
177
|
+
loadRequiredScenesEventChannel: {fileID: 0}
|
|
178
|
+
unlockDoorsEventChannel: {fileID: 0}
|
|
@@ -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
|
}
|
|
@@ -11,6 +11,8 @@ namespace jeanf.questsystem
|
|
|
11
11
|
{
|
|
12
12
|
public class QuestItem : MonoBehaviour, IDebugBehaviour, IValidatable
|
|
13
13
|
{
|
|
14
|
+
|
|
15
|
+
#region interface variables
|
|
14
16
|
public bool isDebug
|
|
15
17
|
{
|
|
16
18
|
get => _isDebug;
|
|
@@ -20,28 +22,30 @@ namespace jeanf.questsystem
|
|
|
20
22
|
|
|
21
23
|
[SerializeField] private bool _isDebug = false;
|
|
22
24
|
[SerializeField] private bool _startQuestOnEnable = false;
|
|
25
|
+
#endregion
|
|
23
26
|
|
|
27
|
+
#region Step Dictionaries
|
|
24
28
|
[Tooltip("Visual feedback for the quest state")] [Header("Quest")]
|
|
25
29
|
[SerializeField] [Validation("A reference to a questSO is required")] private QuestSO questSO;
|
|
26
30
|
private Dictionary<string, QuestStep> stepMap = new Dictionary<string, QuestStep>();
|
|
27
31
|
private Dictionary<string, QuestStep> activeSteps = new Dictionary<string, QuestStep>();
|
|
28
32
|
private Dictionary<string, QuestStep> completedSteps = new Dictionary<string, QuestStep>();
|
|
29
33
|
private List<QuestStep> rootSteps = new List<QuestStep>();
|
|
34
|
+
#endregion
|
|
30
35
|
|
|
31
|
-
public delegate void ValidateStep(string stepId);
|
|
32
|
-
|
|
33
|
-
public static ValidateStep ValidateStepEvent;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[ReadOnly] [Range(0, 1)] [SerializeField]
|
|
37
|
-
private float progress = 0.0f;
|
|
38
36
|
|
|
37
|
+
#region main data
|
|
39
38
|
[SerializeField] [ReadOnly]
|
|
40
39
|
private bool clearToStart = false;
|
|
41
|
-
|
|
42
40
|
private string questId;
|
|
43
41
|
private QuestState currentQuestState;
|
|
42
|
+
[ReadOnly][Range(0, 1)][SerializeField]
|
|
43
|
+
private float progress = 0.0f;
|
|
44
|
+
#endregion
|
|
44
45
|
|
|
46
|
+
#region events
|
|
47
|
+
public delegate void ValidateStep(string stepId);
|
|
48
|
+
public static ValidateStep ValidateStepEvent;
|
|
45
49
|
// these events are Located in Assets/Resources/Quests/Channels - it is searched for at Awake time.
|
|
46
50
|
// if they do not exist simply right click in the hierarchy and find >InitializeQuestSystem<
|
|
47
51
|
[Header("Listening on:")]
|
|
@@ -53,10 +57,10 @@ namespace jeanf.questsystem
|
|
|
53
57
|
private StringEventChannelSO requirementCheck;
|
|
54
58
|
[SerializeField][Validation("A reference to the LoadRequiredScenesEventChannel SO is required")] StringListEventChannelSO loadRequiredScenesEventChannel;
|
|
55
59
|
[SerializeField] IntEventChannelSO unlockDoorsEventChannel;
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
#endregion
|
|
61
|
+
|
|
58
62
|
|
|
59
|
-
#region
|
|
63
|
+
#region Standard Unity Methods
|
|
60
64
|
private void Awake()
|
|
61
65
|
{
|
|
62
66
|
questId = questSO.id;
|
|
@@ -67,7 +71,10 @@ namespace jeanf.questsystem
|
|
|
67
71
|
rootSteps.Add(questSO.rootSteps[i]);
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
|
-
|
|
74
|
+
private void Reset()
|
|
75
|
+
{
|
|
76
|
+
Init(questId);
|
|
77
|
+
}
|
|
71
78
|
private void OnEnable()
|
|
72
79
|
{
|
|
73
80
|
Subscribe();
|
|
@@ -76,7 +83,6 @@ namespace jeanf.questsystem
|
|
|
76
83
|
}
|
|
77
84
|
private void OnDisable() => Unsubscribe();
|
|
78
85
|
private void OnDestroy() => Unsubscribe();
|
|
79
|
-
|
|
80
86
|
private void Subscribe()
|
|
81
87
|
{
|
|
82
88
|
resetChannel.OnEventRaised += Reset;
|
|
@@ -88,7 +94,6 @@ namespace jeanf.questsystem
|
|
|
88
94
|
QuestStep.stepActive += UpdateStepStatus;
|
|
89
95
|
QuestStep.childStep += AddStepToStepMap;
|
|
90
96
|
}
|
|
91
|
-
|
|
92
97
|
private void Unsubscribe()
|
|
93
98
|
{
|
|
94
99
|
resetChannel.OnEventRaised -= Reset;
|
|
@@ -104,11 +109,6 @@ namespace jeanf.questsystem
|
|
|
104
109
|
}
|
|
105
110
|
#endregion
|
|
106
111
|
|
|
107
|
-
private void Reset()
|
|
108
|
-
{
|
|
109
|
-
Init(questId);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
112
|
#region Instantiations & Loading
|
|
113
113
|
public void InstantiateQuestStep(string id)
|
|
114
114
|
{
|
|
@@ -116,10 +116,10 @@ namespace jeanf.questsystem
|
|
|
116
116
|
if (stepMap[id].stepStatus != QuestStepStatus.Inactive) return;
|
|
117
117
|
if (activeSteps.ContainsKey(id)) return;
|
|
118
118
|
|
|
119
|
+
|
|
119
120
|
Instantiate(stepMap[id], this.transform, true);
|
|
120
|
-
//if(!activeSteps.ContainsKey(id)) activeSteps.Add(id,Instantiate(stepMap[id], this.transform, true));
|
|
121
|
-
}
|
|
122
121
|
|
|
122
|
+
}
|
|
123
123
|
private void LoadDependencies()
|
|
124
124
|
{
|
|
125
125
|
loadRequiredScenesEventChannel.RaiseEvent(questSO.ScenesToLoad);
|
|
@@ -129,43 +129,22 @@ namespace jeanf.questsystem
|
|
|
129
129
|
unlockDoorsEventChannel.RaiseEvent(roomToUnlock);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
#endregion
|
|
133
|
-
|
|
134
|
-
public void UpdateStepStatus(string id, QuestStepStatus status)
|
|
135
|
-
{
|
|
136
|
-
switch (status)
|
|
137
|
-
{
|
|
138
|
-
case QuestStepStatus.Completed when activeSteps.ContainsKey(id):
|
|
139
|
-
// put step in completed list
|
|
140
|
-
activeSteps.Remove(id);
|
|
141
|
-
completedSteps.Add(id, stepMap[id]);
|
|
142
|
-
break;
|
|
143
|
-
case QuestStepStatus.Active when !activeSteps.ContainsKey(id):
|
|
144
|
-
// put step in active list
|
|
145
|
-
activeSteps.Add(id, stepMap[id]);
|
|
146
|
-
break;
|
|
147
|
-
case QuestStepStatus.Inactive:
|
|
148
|
-
// do nothing
|
|
149
|
-
default:
|
|
150
|
-
// do nothing
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
132
|
private void AddStepToStepMap(QuestStep step)
|
|
156
133
|
{
|
|
157
|
-
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.");
|
|
158
135
|
if (!stepMap.ContainsKey(step.StepId))
|
|
159
136
|
{
|
|
160
|
-
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.");
|
|
161
138
|
stepMap.Add(step.StepId, step);
|
|
162
139
|
}
|
|
163
140
|
if (completedSteps.ContainsKey(step.StepId))
|
|
164
141
|
{
|
|
165
|
-
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.");
|
|
166
143
|
completedSteps.Remove(step.StepId);
|
|
167
144
|
}
|
|
168
145
|
}
|
|
146
|
+
#endregion
|
|
147
|
+
|
|
169
148
|
#region quest process
|
|
170
149
|
private void Init(string id)
|
|
171
150
|
{
|
|
@@ -196,7 +175,26 @@ namespace jeanf.questsystem
|
|
|
196
175
|
|
|
197
176
|
LoadDependencies();
|
|
198
177
|
}
|
|
199
|
-
|
|
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
|
+
}
|
|
200
198
|
private void UpdateState()
|
|
201
199
|
{
|
|
202
200
|
if (isDebug) Debug.Log($"Updating State...");
|
|
@@ -232,14 +230,12 @@ namespace jeanf.questsystem
|
|
|
232
230
|
throw new ArgumentOutOfRangeException();
|
|
233
231
|
}
|
|
234
232
|
}
|
|
235
|
-
|
|
236
233
|
private void UpdateProgress(string id, float progress)
|
|
237
234
|
{
|
|
238
235
|
if (id != questId) return;
|
|
239
236
|
this.progress = progress;
|
|
240
237
|
if (isDebug) Debug.Log($"questid [{id}] progress = {progress * 100}%");
|
|
241
238
|
}
|
|
242
|
-
|
|
243
239
|
private void QuestStateChange(Quest quest)
|
|
244
240
|
{
|
|
245
241
|
// only update the quest state if this point has the corresponding quest
|
|
@@ -251,6 +247,7 @@ namespace jeanf.questsystem
|
|
|
251
247
|
}
|
|
252
248
|
#endregion
|
|
253
249
|
|
|
250
|
+
#region Complete all Steps
|
|
254
251
|
public void ValidateCurrentlyActiveSteps()
|
|
255
252
|
{
|
|
256
253
|
var currentlyActiveSteps = activeSteps.Keys;
|
|
@@ -262,18 +259,15 @@ namespace jeanf.questsystem
|
|
|
262
259
|
if(activeSteps.ContainsKey(stepKey)) ValidateStepEvent.Invoke(stepKey);
|
|
263
260
|
}
|
|
264
261
|
}
|
|
262
|
+
#endregion
|
|
265
263
|
|
|
266
264
|
#region validation tools
|
|
267
265
|
|
|
268
|
-
|
|
266
|
+
#if UNITY_EDITOR
|
|
269
267
|
public void OnValidate()
|
|
270
268
|
{
|
|
271
269
|
ValidityCheck();
|
|
272
270
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
271
|
public void LogActiveSteps()
|
|
278
272
|
{
|
|
279
273
|
Debug.Log($"There is {activeSteps.Count} active steps at the moment.");
|
|
@@ -283,7 +277,6 @@ namespace jeanf.questsystem
|
|
|
283
277
|
}
|
|
284
278
|
}
|
|
285
279
|
#endif
|
|
286
|
-
|
|
287
280
|
private void ValidityCheck()
|
|
288
281
|
{
|
|
289
282
|
const string searching = "attempting to find";
|
|
@@ -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
|
}
|
|
@@ -13,15 +13,17 @@ namespace jeanf.questsystem
|
|
|
13
13
|
[System.Serializable, NodeMenuItem("questSystem/QuestStep"), DefaultExecutionOrder(1)]
|
|
14
14
|
public class QuestStep : MonoBehaviour, IDebugBehaviour
|
|
15
15
|
{
|
|
16
|
+
#region Ids and status
|
|
16
17
|
[field: Space(10)][field: ReadOnly][SerializeField] string stepId;
|
|
17
18
|
public string StepId { get { return stepId; } }
|
|
18
19
|
|
|
19
20
|
string questId;
|
|
20
21
|
public string QuestId { get { return questId; } }
|
|
22
|
+
[field: ReadOnly][SerializeField] public QuestStepStatus stepStatus;
|
|
23
|
+
#endregion
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
[field: ReadOnly] [SerializeField] public QuestStepStatus stepStatus;
|
|
24
25
|
|
|
26
|
+
#region timeline
|
|
25
27
|
[Tooltip("This boolean has to be enabled if the quest step has an intro timeline.")]
|
|
26
28
|
public bool isUsingIntroTimeline = false;
|
|
27
29
|
|
|
@@ -29,7 +31,9 @@ namespace jeanf.questsystem
|
|
|
29
31
|
[SerializeField] private TimelineTriggerEventChannelSO _timelineTriggerEventChannelSo;
|
|
30
32
|
[DrawIf("isUsingIntroTimeline", true, ComparisonType.Equals, DisablingType.DontDraw)]
|
|
31
33
|
public PlayableAsset timeline;
|
|
34
|
+
#endregion
|
|
32
35
|
|
|
36
|
+
#region step trigger and completion
|
|
33
37
|
[Header("Quest Step Progression events & Variables")]
|
|
34
38
|
public List<QuestStep> questStepsToTrigger = new List<QuestStep>();
|
|
35
39
|
public delegate void SendNextStepId(string id);
|
|
@@ -41,14 +45,18 @@ namespace jeanf.questsystem
|
|
|
41
45
|
public static StepActive stepActive;
|
|
42
46
|
public delegate void ChildStep(QuestStep step);
|
|
43
47
|
public static ChildStep childStep;
|
|
44
|
-
|
|
48
|
+
#endregion
|
|
49
|
+
|
|
50
|
+
#region events
|
|
45
51
|
[Header("Quest Tooltip")]
|
|
46
52
|
[SerializeField] private QuestTooltipSO questTooltipSO;
|
|
47
53
|
|
|
48
54
|
[Header("Event Channels")]
|
|
49
55
|
[SerializeField] private StringEventChannelSO sendQuestStepTooltip;
|
|
50
56
|
[SerializeField] private StringEventChannelSO stepValidationOverride;
|
|
51
|
-
|
|
57
|
+
#endregion
|
|
58
|
+
|
|
59
|
+
#region standard unity methods
|
|
52
60
|
public void OnEnable()
|
|
53
61
|
{
|
|
54
62
|
Subscribe();
|
|
@@ -65,13 +73,14 @@ namespace jeanf.questsystem
|
|
|
65
73
|
if(stepValidationOverride) stepValidationOverride.OnEventRaised += ValidateCurrentStep;
|
|
66
74
|
}
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
protected virtual void Unsubscribe()
|
|
69
77
|
{
|
|
70
78
|
QuestItem.ValidateStepEvent -= ValidateCurrentStep;
|
|
71
79
|
if(stepValidationOverride) stepValidationOverride.OnEventRaised -= ValidateCurrentStep;
|
|
72
80
|
}
|
|
81
|
+
#endregion
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
#region step progress
|
|
75
84
|
public void InitializeQuestStep()
|
|
76
85
|
{
|
|
77
86
|
// failsafe to avoid lauching the same step more than once at a time.
|
|
@@ -91,6 +100,7 @@ namespace jeanf.questsystem
|
|
|
91
100
|
{
|
|
92
101
|
if(isDebug) Debug.Log($"sending trigger to timeline: {timeline.name}, triggerValue: true");
|
|
93
102
|
_timelineTriggerEventChannelSo.RaiseEvent(timeline, true);
|
|
103
|
+
|
|
94
104
|
}
|
|
95
105
|
|
|
96
106
|
if(isDebug) Debug.Log($"Step with id [{stepId}] has {questStepsToTrigger.Count} childSteps");
|
|
@@ -107,7 +117,6 @@ namespace jeanf.questsystem
|
|
|
107
117
|
FinishQuestStep();
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
|
|
111
120
|
public void FinishQuestStep()
|
|
112
121
|
{
|
|
113
122
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Changing status to completed", this);
|
|
@@ -118,23 +127,28 @@ namespace jeanf.questsystem
|
|
|
118
127
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending tooltip", this);
|
|
119
128
|
sendQuestStepTooltip.RaiseEvent(string.Empty);
|
|
120
129
|
}
|
|
121
|
-
;
|
|
122
130
|
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Requesting to start next step: {questStep.stepId}", this);
|
|
126
|
-
sendNextStepId?.Invoke(questStep.stepId);
|
|
127
|
-
}
|
|
131
|
+
|
|
128
132
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Sending stepCompleted Event (delegate) with argument: {stepId}", this);
|
|
129
133
|
stepCompleted?.Invoke(stepId);
|
|
130
|
-
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);
|
|
131
135
|
stepActive?.Invoke(stepId, stepStatus);
|
|
132
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
|
+
|
|
133
146
|
if(isDebug) Debug.Log($" ---- Step with id: {stepId} finished. Destroying the gameobject with name {this.name}", this);
|
|
134
147
|
Destroy(this.gameObject);
|
|
135
148
|
}
|
|
149
|
+
#endregion
|
|
136
150
|
|
|
137
|
-
|
|
151
|
+
#region tooltip
|
|
138
152
|
protected void DisplayActiveQuestStep()
|
|
139
153
|
{
|
|
140
154
|
if (questTooltipSO != null)
|
|
@@ -142,8 +156,10 @@ namespace jeanf.questsystem
|
|
|
142
156
|
sendQuestStepTooltip.RaiseEvent(questTooltipSO.Tooltip);
|
|
143
157
|
}
|
|
144
158
|
}
|
|
159
|
+
#endregion
|
|
145
160
|
|
|
146
|
-
#
|
|
161
|
+
#region validation
|
|
162
|
+
#if UNITY_EDITOR
|
|
147
163
|
private void OnValidate()
|
|
148
164
|
{
|
|
149
165
|
if (stepId == string.Empty || stepId == null) GenerateId();
|
|
@@ -155,16 +171,20 @@ namespace jeanf.questsystem
|
|
|
155
171
|
UnityEditor.EditorUtility.SetDirty(this);
|
|
156
172
|
}
|
|
157
173
|
|
|
158
|
-
|
|
159
|
-
|
|
174
|
+
#endif
|
|
175
|
+
#endregion
|
|
160
176
|
|
|
177
|
+
#region debug
|
|
161
178
|
public bool isDebug { get => _isDebug; set => _isDebug = value; }
|
|
162
179
|
private bool _isDebug = true;
|
|
180
|
+
#endregion
|
|
163
181
|
|
|
182
|
+
#region Status
|
|
164
183
|
public QuestStepStatus GetStatus()
|
|
165
184
|
{
|
|
166
185
|
return stepStatus;
|
|
167
186
|
}
|
|
187
|
+
#endregion
|
|
168
188
|
}
|
|
169
189
|
|
|
170
190
|
public enum QuestStepStatus
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#if UNITY_EDITOR
|
|
2
|
+
using UnityEngine;
|
|
3
|
+
using UnityEditor;
|
|
4
|
+
using GraphProcessor;
|
|
5
|
+
|
|
6
|
+
public class QuestGraphWindow : BaseGraphWindow
|
|
7
|
+
{
|
|
8
|
+
[MenuItem("QuestGraph/01_DefaultGraph")]
|
|
9
|
+
public static BaseGraphWindow Open()
|
|
10
|
+
{
|
|
11
|
+
var graphWindow = GetWindow<QuestGraphWindow>();
|
|
12
|
+
|
|
13
|
+
graphWindow.Show();
|
|
14
|
+
|
|
15
|
+
return graphWindow;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
protected override void InitializeWindow(BaseGraph graph)
|
|
19
|
+
{
|
|
20
|
+
// Set the window title
|
|
21
|
+
titleContent = new GUIContent("Default Graph");
|
|
22
|
+
|
|
23
|
+
// Here you can use the default BaseGraphView or a custom one (see section below)
|
|
24
|
+
var graphView = new BaseGraphView(this);
|
|
25
|
+
|
|
26
|
+
rootView.Add(graphView);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
#endif
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
using UnityEngine;
|
|
2
|
+
using GraphProcessor;
|
|
3
|
+
using jeanf.questsystem;
|
|
4
|
+
|
|
5
|
+
public class QuestStepNode : BaseNode
|
|
6
|
+
{
|
|
7
|
+
[Input(name = "A")]
|
|
8
|
+
private QuestStep StepsRequiredForCompletion;
|
|
9
|
+
[Output(name = "Out")]
|
|
10
|
+
private QuestStep StepsTriggeredOnCompletion;
|
|
11
|
+
}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
"GUID:e8958e6939af7314a97769de4be4ce25",
|
|
8
8
|
"GUID:db1b0a3157155ad47996061dbcc07bbb",
|
|
9
9
|
"GUID:ca937d03ee5dd4d699091438dc0f3ae6",
|
|
10
|
-
"GUID:a432eb0a70c5c4a37ab50d59671586f8"
|
|
10
|
+
"GUID:a432eb0a70c5c4a37ab50d59671586f8",
|
|
11
|
+
"GUID:b8e24fd1eb19b4226afebb2810e3c19b",
|
|
12
|
+
"GUID:002c1bbed08fa44d282ef34fd5edb138"
|
|
11
13
|
],
|
|
12
14
|
"includePlatforms": [],
|
|
13
15
|
"excludePlatforms": [],
|
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.63",
|
|
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
|
-
]
|
|
19
|
+
"samples": []
|
|
22
20
|
}
|