first commit
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OTGIntegrated.Items;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Quests
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class QuestRewardItem
|
||||
{
|
||||
public ItemData item;
|
||||
[Min(1)] public int amount = 1;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "QuestData", menuName = "OTG Integrated/Quest Data")]
|
||||
public sealed class QuestData : ScriptableObject
|
||||
{
|
||||
public string questId;
|
||||
public string displayName;
|
||||
[TextArea(3, 7)] public string description;
|
||||
public string giverNpcId;
|
||||
public string turnInNpcId;
|
||||
public List<QuestGoal> goals = new List<QuestGoal>();
|
||||
[Min(0)] public int rewardExperience;
|
||||
[Min(0)] public int rewardTalentPoints;
|
||||
public List<QuestRewardItem> rewardItems = new List<QuestRewardItem>();
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(questId))
|
||||
{
|
||||
questId = name;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(displayName))
|
||||
{
|
||||
displayName = questId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12fa02eac54ea59fca4b6c5a2c604992
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using OTGIntegrated.Items;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Quests
|
||||
{
|
||||
public enum QuestGoalType
|
||||
{
|
||||
CollectItem,
|
||||
KillEnemy,
|
||||
TalkToNPC,
|
||||
CraftItem
|
||||
}
|
||||
|
||||
public enum QuestStatus
|
||||
{
|
||||
Active,
|
||||
ReadyToComplete,
|
||||
Completed
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class QuestGoal
|
||||
{
|
||||
public QuestGoalType goalType;
|
||||
public ItemData targetItem;
|
||||
public string enemyId;
|
||||
public string npcId;
|
||||
[Min(1)] public int requiredAmount = 1;
|
||||
|
||||
public string GetTargetKey()
|
||||
{
|
||||
switch (goalType)
|
||||
{
|
||||
case QuestGoalType.CollectItem:
|
||||
case QuestGoalType.CraftItem:
|
||||
return targetItem != null ? targetItem.itemId : string.Empty;
|
||||
case QuestGoalType.KillEnemy:
|
||||
return enemyId;
|
||||
case QuestGoalType.TalkToNPC:
|
||||
return npcId;
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetDisplayName()
|
||||
{
|
||||
switch (goalType)
|
||||
{
|
||||
case QuestGoalType.CollectItem:
|
||||
return targetItem != null ? targetItem.displayName : "Предмет";
|
||||
case QuestGoalType.CraftItem:
|
||||
return targetItem != null ? $"Создать {targetItem.displayName}" : "Создать предмет";
|
||||
case QuestGoalType.KillEnemy:
|
||||
return string.IsNullOrWhiteSpace(enemyId) ? "Враг" : enemyId;
|
||||
case QuestGoalType.TalkToNPC:
|
||||
return string.IsNullOrWhiteSpace(npcId) ? "NPC" : npcId;
|
||||
default:
|
||||
return "Цель";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67df6628261903cac9131cc30928ae5b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,172 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace OTGIntegrated.Quests
|
||||
{
|
||||
public sealed class QuestLogUI : MonoBehaviour
|
||||
{
|
||||
public GameObject panelRoot;
|
||||
public Transform activeListRoot;
|
||||
public Transform completedListRoot;
|
||||
public Text titleText;
|
||||
public Text detailText;
|
||||
public Button closeButton;
|
||||
public Font uiFont;
|
||||
|
||||
private QuestManager questManager;
|
||||
private QuestState selectedState;
|
||||
private readonly List<GameObject> spawnedButtons = new List<GameObject>();
|
||||
|
||||
public void Initialize(QuestManager manager)
|
||||
{
|
||||
questManager = manager;
|
||||
if (questManager != null)
|
||||
{
|
||||
questManager.OnQuestsChanged -= Refresh;
|
||||
questManager.OnQuestsChanged += Refresh;
|
||||
}
|
||||
|
||||
if (closeButton != null)
|
||||
{
|
||||
closeButton.onClick.RemoveAllListeners();
|
||||
closeButton.onClick.AddListener(() => FindObjectOfType<OTGIntegrated.UI.UIManager>()?.CloseCurrentWindow());
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (questManager != null)
|
||||
{
|
||||
questManager.OnQuestsChanged -= Refresh;
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
ClearButtons();
|
||||
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = "Журнал квестов";
|
||||
}
|
||||
|
||||
if (questManager == null)
|
||||
{
|
||||
SetDetails(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedState == null && questManager.ActiveQuests.Count > 0)
|
||||
{
|
||||
selectedState = questManager.ActiveQuests[0];
|
||||
}
|
||||
|
||||
CreateButtons(activeListRoot, questManager.ActiveQuests);
|
||||
CreateButtons(completedListRoot, questManager.CompletedQuests);
|
||||
SetDetails(selectedState);
|
||||
}
|
||||
|
||||
private void CreateButtons(Transform parent, IReadOnlyList<QuestState> states)
|
||||
{
|
||||
if (parent == null || states == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < states.Count; i++)
|
||||
{
|
||||
QuestState state = states[i];
|
||||
if (state == null || state.questData == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject root = new GameObject(state.questData.displayName, typeof(RectTransform), typeof(Image), typeof(Button));
|
||||
root.transform.SetParent(parent, false);
|
||||
spawnedButtons.Add(root);
|
||||
root.GetComponent<RectTransform>().sizeDelta = new Vector2(320f, 44f);
|
||||
|
||||
Image image = root.GetComponent<Image>();
|
||||
image.color = GetStatusColor(state.status);
|
||||
|
||||
Text label = CreateText(root.transform, "Text", state.questData.displayName, 16, TextAnchor.MiddleLeft);
|
||||
label.rectTransform.anchorMin = Vector2.zero;
|
||||
label.rectTransform.anchorMax = Vector2.one;
|
||||
label.rectTransform.offsetMin = new Vector2(12f, 0f);
|
||||
label.rectTransform.offsetMax = new Vector2(-8f, 0f);
|
||||
|
||||
Button button = root.GetComponent<Button>();
|
||||
button.onClick.AddListener(() =>
|
||||
{
|
||||
selectedState = state;
|
||||
SetDetails(selectedState);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDetails(QuestState state)
|
||||
{
|
||||
if (detailText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == null || state.questData == null)
|
||||
{
|
||||
detailText.text = "Нет выбранного квеста.";
|
||||
return;
|
||||
}
|
||||
|
||||
QuestData quest = state.questData;
|
||||
detailText.text =
|
||||
$"{quest.displayName}\n\n{quest.description}\n\nСтатус: {state.status}\n\n{questManager.GetStateProgressText(state)}\n\nНаграды:\nОпыт: {quest.rewardExperience}\nОчки талантов: {quest.rewardTalentPoints}";
|
||||
}
|
||||
|
||||
private Color GetStatusColor(QuestStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case QuestStatus.ReadyToComplete:
|
||||
return new Color(0.16f, 0.42f, 0.22f, 0.95f);
|
||||
case QuestStatus.Completed:
|
||||
return new Color(0.16f, 0.2f, 0.34f, 0.82f);
|
||||
default:
|
||||
return new Color(0.46f, 0.34f, 0.12f, 0.92f);
|
||||
}
|
||||
}
|
||||
|
||||
private Text CreateText(Transform parent, string name, string value, int fontSize, TextAnchor anchor)
|
||||
{
|
||||
GameObject textObject = new GameObject(name, typeof(RectTransform), typeof(Text));
|
||||
textObject.transform.SetParent(parent, false);
|
||||
Text text = textObject.GetComponent<Text>();
|
||||
text.font = uiFont != null ? uiFont : Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
text.fontSize = fontSize;
|
||||
text.alignment = anchor;
|
||||
text.color = new Color(0.94f, 0.93f, 0.88f, 1f);
|
||||
text.text = value;
|
||||
return text;
|
||||
}
|
||||
|
||||
private void ClearButtons()
|
||||
{
|
||||
for (int i = 0; i < spawnedButtons.Count; i++)
|
||||
{
|
||||
if (spawnedButtons[i] != null)
|
||||
{
|
||||
Destroy(spawnedButtons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
spawnedButtons.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61452d00fee61482aa5fb3d1fda042cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,498 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OTGIntegrated.Core;
|
||||
using OTGIntegrated.Items;
|
||||
using OTGIntegrated.Stats;
|
||||
using OTGIntegrated.Talents;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTGIntegrated.Quests
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class QuestState
|
||||
{
|
||||
public QuestData questData;
|
||||
public QuestStatus status;
|
||||
public List<int> progress = new List<int>();
|
||||
|
||||
public QuestState(QuestData quest)
|
||||
{
|
||||
questData = quest;
|
||||
status = QuestStatus.Active;
|
||||
int count = quest != null && quest.goals != null ? quest.goals.Count : 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
progress.Add(0);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetProgress(int goalIndex)
|
||||
{
|
||||
return goalIndex >= 0 && goalIndex < progress.Count ? progress[goalIndex] : 0;
|
||||
}
|
||||
|
||||
public void SetProgress(int goalIndex, int amount)
|
||||
{
|
||||
if (questData == null || questData.goals == null || goalIndex < 0 || goalIndex >= questData.goals.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (progress.Count < questData.goals.Count)
|
||||
{
|
||||
progress.Add(0);
|
||||
}
|
||||
|
||||
int required = Mathf.Max(1, questData.goals[goalIndex].requiredAmount);
|
||||
progress[goalIndex] = Mathf.Clamp(amount, 0, required);
|
||||
}
|
||||
|
||||
public void AddProgress(int goalIndex, int amount)
|
||||
{
|
||||
SetProgress(goalIndex, GetProgress(goalIndex) + Mathf.Max(0, amount));
|
||||
}
|
||||
|
||||
public bool IsGoalComplete(int goalIndex)
|
||||
{
|
||||
if (questData == null || questData.goals == null || goalIndex < 0 || goalIndex >= questData.goals.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetProgress(goalIndex) >= Mathf.Max(1, questData.goals[goalIndex].requiredAmount);
|
||||
}
|
||||
|
||||
public bool AreAllGoalsComplete()
|
||||
{
|
||||
if (questData == null || questData.goals == null || questData.goals.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < questData.goals.Count; i++)
|
||||
{
|
||||
if (!IsGoalComplete(i))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class QuestSaveEntry
|
||||
{
|
||||
public string questId;
|
||||
public QuestStatus status;
|
||||
public List<int> progress = new List<int>();
|
||||
}
|
||||
|
||||
public sealed class QuestManager : MonoBehaviour
|
||||
{
|
||||
public List<QuestData> allQuests = new List<QuestData>();
|
||||
|
||||
[SerializeField] private List<QuestState> activeQuests = new List<QuestState>();
|
||||
[SerializeField] private List<QuestState> completedQuests = new List<QuestState>();
|
||||
|
||||
private OTGIntegrated.Inventory.Inventory inventory;
|
||||
private LevelSystem levelSystem;
|
||||
private TalentManager talentManager;
|
||||
private readonly Dictionary<string, QuestData> questLookup = new Dictionary<string, QuestData>(StringComparer.Ordinal);
|
||||
|
||||
public event Action OnQuestsChanged;
|
||||
public IReadOnlyList<QuestState> ActiveQuests => activeQuests;
|
||||
public IReadOnlyList<QuestState> CompletedQuests => completedQuests;
|
||||
|
||||
public void Initialize(OTGIntegrated.Inventory.Inventory inventory, LevelSystem levelSystem, TalentManager talentManager)
|
||||
{
|
||||
this.inventory = inventory;
|
||||
this.levelSystem = levelSystem;
|
||||
this.talentManager = talentManager;
|
||||
BuildLookup();
|
||||
OnQuestsChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
GameEvents.OnItemAdded += HandleItemAdded;
|
||||
GameEvents.OnEnemyKilled += HandleEnemyKilled;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
GameEvents.OnItemAdded -= HandleItemAdded;
|
||||
GameEvents.OnEnemyKilled -= HandleEnemyKilled;
|
||||
}
|
||||
|
||||
public bool StartQuest(QuestData quest)
|
||||
{
|
||||
if (quest == null || IsQuestActive(quest) || IsQuestCompleted(quest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QuestState state = new QuestState(quest);
|
||||
activeQuests.Add(state);
|
||||
SynchronizeInventoryGoals(state);
|
||||
UpdateReadyState(state);
|
||||
|
||||
GameEvents.RaiseQuestStarted(quest);
|
||||
GameEvents.RaiseNotification($"Квест получен: {quest.displayName}");
|
||||
OnQuestsChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryCompleteQuest(QuestData quest, string npcId)
|
||||
{
|
||||
QuestState state = GetActiveState(quest);
|
||||
if (state == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(quest.turnInNpcId) && quest.turnInNpcId != npcId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.status != QuestStatus.ReadyToComplete && !state.AreAllGoalsComplete())
|
||||
{
|
||||
GameEvents.RaiseNotification("Цели квеста ещё не выполнены");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ConsumeCollectGoals(quest))
|
||||
{
|
||||
GameEvents.RaiseNotification("Не хватает предметов для сдачи квеста");
|
||||
return false;
|
||||
}
|
||||
|
||||
state.status = QuestStatus.Completed;
|
||||
activeQuests.Remove(state);
|
||||
completedQuests.Add(state);
|
||||
|
||||
if (quest.rewardExperience > 0 && levelSystem != null)
|
||||
{
|
||||
levelSystem.AddExperience(quest.rewardExperience);
|
||||
}
|
||||
|
||||
if (quest.rewardTalentPoints > 0 && talentManager != null)
|
||||
{
|
||||
talentManager.AddTalentPoints(quest.rewardTalentPoints);
|
||||
}
|
||||
|
||||
if (quest.rewardItems != null && inventory != null)
|
||||
{
|
||||
for (int i = 0; i < quest.rewardItems.Count; i++)
|
||||
{
|
||||
QuestRewardItem reward = quest.rewardItems[i];
|
||||
if (reward != null && reward.item != null && reward.amount > 0)
|
||||
{
|
||||
inventory.AddItem(reward.item, reward.amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameEvents.RaiseQuestCompleted(quest);
|
||||
GameEvents.RaiseNotification($"Квест выполнен: {quest.displayName}");
|
||||
OnQuestsChanged?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void NotifyNpcTalked(string npcId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(npcId))
|
||||
{
|
||||
UpdateProgress(QuestGoalType.TalkToNPC, npcId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsQuestActive(QuestData quest)
|
||||
{
|
||||
return GetActiveState(quest) != null;
|
||||
}
|
||||
|
||||
public bool IsQuestCompleted(QuestData quest)
|
||||
{
|
||||
return quest != null && completedQuests.Exists(state => state.questData == quest);
|
||||
}
|
||||
|
||||
public bool IsQuestReady(QuestData quest)
|
||||
{
|
||||
QuestState state = GetActiveState(quest);
|
||||
return state != null && state.status == QuestStatus.ReadyToComplete;
|
||||
}
|
||||
|
||||
public QuestState GetActiveState(QuestData quest)
|
||||
{
|
||||
return quest == null ? null : activeQuests.Find(state => state.questData == quest);
|
||||
}
|
||||
|
||||
public QuestData GetQuestById(string questId)
|
||||
{
|
||||
BuildLookup();
|
||||
if (string.IsNullOrWhiteSpace(questId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
questLookup.TryGetValue(questId, out QuestData quest);
|
||||
return quest;
|
||||
}
|
||||
|
||||
public string GetPrimaryTrackerText()
|
||||
{
|
||||
QuestState state = activeQuests.Count > 0 ? activeQuests[0] : null;
|
||||
if (state == null || state.questData == null)
|
||||
{
|
||||
return "Нет активных квестов";
|
||||
}
|
||||
|
||||
return $"{state.questData.displayName}\n{GetStateProgressText(state)}";
|
||||
}
|
||||
|
||||
public string GetStateProgressText(QuestState state)
|
||||
{
|
||||
if (state == null || state.questData == null || state.questData.goals == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
System.Text.StringBuilder builder = new System.Text.StringBuilder();
|
||||
for (int i = 0; i < state.questData.goals.Count; i++)
|
||||
{
|
||||
QuestGoal goal = state.questData.goals[i];
|
||||
if (goal == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Append(goal.GetDisplayName());
|
||||
builder.Append(": ");
|
||||
builder.Append(state.GetProgress(i));
|
||||
builder.Append(" / ");
|
||||
builder.Append(goal.requiredAmount);
|
||||
if (i < state.questData.goals.Count - 1)
|
||||
{
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
if (state.status == QuestStatus.ReadyToComplete)
|
||||
{
|
||||
builder.AppendLine();
|
||||
builder.Append("Вернитесь к NPC");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public List<QuestSaveEntry> SaveData()
|
||||
{
|
||||
List<QuestSaveEntry> entries = new List<QuestSaveEntry>();
|
||||
AppendSaveEntries(activeQuests, entries);
|
||||
AppendSaveEntries(completedQuests, entries);
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void LoadData(List<QuestSaveEntry> entries)
|
||||
{
|
||||
BuildLookup();
|
||||
activeQuests.Clear();
|
||||
completedQuests.Clear();
|
||||
|
||||
if (entries != null)
|
||||
{
|
||||
for (int i = 0; i < entries.Count; i++)
|
||||
{
|
||||
QuestSaveEntry entry = entries[i];
|
||||
if (entry == null || string.IsNullOrWhiteSpace(entry.questId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QuestData quest = GetQuestById(entry.questId);
|
||||
if (quest == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QuestState state = new QuestState(quest);
|
||||
state.status = entry.status;
|
||||
for (int p = 0; entry.progress != null && p < entry.progress.Count && p < state.progress.Count; p++)
|
||||
{
|
||||
state.SetProgress(p, entry.progress[p]);
|
||||
}
|
||||
|
||||
if (state.status == QuestStatus.Completed)
|
||||
{
|
||||
completedQuests.Add(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
activeQuests.Add(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnQuestsChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void HandleItemAdded(ItemData item, int amount)
|
||||
{
|
||||
if (item == null || amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateProgress(QuestGoalType.CollectItem, item.itemId, amount);
|
||||
UpdateProgress(QuestGoalType.CraftItem, item.itemId, amount);
|
||||
}
|
||||
|
||||
private void HandleEnemyKilled(string enemyId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(enemyId))
|
||||
{
|
||||
UpdateProgress(QuestGoalType.KillEnemy, enemyId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateProgress(QuestGoalType goalType, string targetKey, int amount)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(targetKey) || amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
for (int i = 0; i < activeQuests.Count; i++)
|
||||
{
|
||||
QuestState state = activeQuests[i];
|
||||
QuestData quest = state.questData;
|
||||
if (state.status == QuestStatus.ReadyToComplete || quest == null || quest.goals == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int goalIndex = 0; goalIndex < quest.goals.Count; goalIndex++)
|
||||
{
|
||||
QuestGoal goal = quest.goals[goalIndex];
|
||||
if (goal == null || goal.goalType != goalType || goal.GetTargetKey() != targetKey || state.IsGoalComplete(goalIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
state.AddProgress(goalIndex, amount);
|
||||
changed = true;
|
||||
GameEvents.RaiseQuestProgressChanged(quest);
|
||||
GameEvents.RaiseNotification($"{quest.displayName}: {goal.GetDisplayName()} {state.GetProgress(goalIndex)}/{goal.requiredAmount}");
|
||||
}
|
||||
|
||||
if (UpdateReadyState(state))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
OnQuestsChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateReadyState(QuestState state)
|
||||
{
|
||||
if (state == null || state.status != QuestStatus.Active || !state.AreAllGoalsComplete())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
state.status = QuestStatus.ReadyToComplete;
|
||||
GameEvents.RaiseQuestReadyToComplete(state.questData);
|
||||
GameEvents.RaiseNotification($"Квест готов к сдаче: {state.questData.displayName}");
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SynchronizeInventoryGoals(QuestState state)
|
||||
{
|
||||
if (state == null || state.questData == null || state.questData.goals == null || inventory == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < state.questData.goals.Count; i++)
|
||||
{
|
||||
QuestGoal goal = state.questData.goals[i];
|
||||
if (goal != null && goal.goalType == QuestGoalType.CollectItem && goal.targetItem != null)
|
||||
{
|
||||
state.SetProgress(i, inventory.GetAmount(goal.targetItem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ConsumeCollectGoals(QuestData quest)
|
||||
{
|
||||
if (quest == null || quest.goals == null || inventory == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < quest.goals.Count; i++)
|
||||
{
|
||||
QuestGoal goal = quest.goals[i];
|
||||
if (goal != null && goal.goalType == QuestGoalType.CollectItem && goal.targetItem != null)
|
||||
{
|
||||
if (!inventory.HasItem(goal.targetItem, goal.requiredAmount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < quest.goals.Count; i++)
|
||||
{
|
||||
QuestGoal goal = quest.goals[i];
|
||||
if (goal != null && goal.goalType == QuestGoalType.CollectItem && goal.targetItem != null)
|
||||
{
|
||||
inventory.RemoveItem(goal.targetItem, goal.requiredAmount);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BuildLookup()
|
||||
{
|
||||
questLookup.Clear();
|
||||
for (int i = 0; i < allQuests.Count; i++)
|
||||
{
|
||||
QuestData quest = allQuests[i];
|
||||
if (quest != null && !string.IsNullOrWhiteSpace(quest.questId))
|
||||
{
|
||||
questLookup[quest.questId] = quest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AppendSaveEntries(List<QuestState> states, List<QuestSaveEntry> entries)
|
||||
{
|
||||
for (int i = 0; i < states.Count; i++)
|
||||
{
|
||||
QuestState state = states[i];
|
||||
if (state == null || state.questData == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.Add(new QuestSaveEntry
|
||||
{
|
||||
questId = state.questData.questId,
|
||||
status = state.status,
|
||||
progress = new List<int>(state.progress)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a384ce688ea1dd4db6978f80a709235
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user