188 lines
6.9 KiB
C#

using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace BulletHellTemplate
{
/// <summary>
/// Manages the display of quests in the UI.
/// Displays available quests, handles quest completion logic,
/// and can optionally hide completed quests.
/// </summary>
public class UIQuestMenu : MonoBehaviour
{
#region Singleton and Public Fields
[Tooltip("Prefab for individual quest entries")]
public QuestEntry questEntryPrefab;
[Tooltip("Container where quest entries will be instantiated")]
public Transform container;
/// <summary>
/// Singleton reference for global access to UIQuestMenu.
/// </summary>
public static UIQuestMenu Singleton;
[Tooltip("Whether or not to hide completed quests from the UI")]
public bool hideCompletedQuests;
/// <summary>
/// Current language code or identifier used by the UI.
/// </summary>
[HideInInspector]
public string currentLang;
#endregion
#region Unity Callbacks
/// <summary>
/// Initializes the singleton reference on startup.
/// </summary>
private void Start()
{
Singleton = this;
}
/// <summary>
/// Called when the object becomes enabled and active.
/// Sets the current language and loads quests into the UI.
/// </summary>
private void OnEnable()
{
currentLang = LanguageManager.LanguageManager.Instance.GetCurrentLanguage();
LoadQuestsAsync().Forget();
}
#endregion
#region Public Methods
private async UniTaskVoid LoadQuestsAsync()
{
await BackendManager.Service.RefreshQuestLevelProgressAsync();
LoadQuests();
}
/// <summary>
/// Loads and displays the available quests in the UI.
/// If 'hideCompletedQuests' is true, completed quests (except repeat) will be skipped.
/// Otherwise, all quests are shown, with an indicator for those that are completed.
/// Additionally, it checks if the player's level or characters' levels
/// exceed any quest requirements to set progress to 100%.
/// </summary>
public void LoadQuests()
{
// Clear containerPassItems
foreach (Transform child in container)
Destroy(child.gameObject);
List<QuestItem> allQuests = GameInstance.Singleton.questData.ToList();
foreach (QuestItem quest in allQuests)
{
bool isCompleted = PlayerSave.IsQuestCompleted(quest.questId);
if (hideCompletedQuests && quest.questType != QuestType.Repeat && isCompleted)
continue;
var entry = Instantiate(questEntryPrefab, container);
string title = GetTranslatedString(quest.titleTranslated, quest.title, currentLang);
string desc = GetTranslatedString(quest.descriptionTranslated, quest.description, currentLang);
entry.Setup(title, desc, quest, isCompleted);
int progress = PlayerSave.LoadQuestProgress(quest.questId);
int target = quest.requirement.targetAmount;
entry.UpdateProgress(progress, target);
}
}
/// <summary>
/// Called by the QuestEntry when the player tries to complete the quest.
/// Checks if the quest is indeed completable, then applies rewards.
/// Marks the quest as completed or resets its progress if it's a repeat quest.
/// Finally, reloads the quest UI for updated feedback.
/// </summary>
/// <param name="quest">The quest item the player is attempting to complete.</param>
public async void OnUserAttemptCompleteQuest(QuestItem quest)
{
if (quest == null) return;
RequestResult res = await BackendManager.Service.CompleteQuestAsync(quest.questId);
if (!res.Success)
{
string msg = res.Reason switch
{
"0" => "Already completed!",
"1" => "Not enough progress!",
"2" => "Quest not found!",
_ => "Unknown error"
};
Debug.LogWarning(msg);
return;
}
// Reload UI to reflect new state
LoadQuests();
}
/// <summary>
/// Returns a translated string according to the current language
/// or a fallback string if no translation is found.
/// </summary>
/// <param name="translations">An array of translations for different languages.</param>
/// <param name="fallback">The default (fallback) string if no matching translation is found.</param>
/// <param name="currentLang">The language code or identifier currently in use.</param>
/// <returns>A string in the user's selected language, or the fallback if none is found.</returns>
public string GetTranslatedString(NameTranslatedByLanguage[] translations, string fallback, string currentLang)
{
if (translations != null)
{
foreach (var trans in translations)
{
if (!string.IsNullOrEmpty(trans.LanguageId)
&& trans.LanguageId.Equals(currentLang)
&& !string.IsNullOrEmpty(trans.Translate))
{
return trans.Translate;
}
}
}
return fallback;
}
/// <summary>
/// Returns a translated description string according to the current language
/// or a fallback string if no translation is found.
/// </summary>
/// <param name="translations">An array of description translations for different languages.</param>
/// <param name="fallback">The default (fallback) string if no matching translation is found.</param>
/// <param name="currentLang">The language code or identifier currently in use.</param>
/// <returns>A string in the user's selected language, or the fallback if none is found.</returns>
public string GetTranslatedString(DescriptionTranslatedByLanguage[] translations, string fallback, string currentLang)
{
if (translations != null)
{
foreach (var trans in translations)
{
if (!string.IsNullOrEmpty(trans.LanguageId)
&& trans.LanguageId.Equals(currentLang)
&& !string.IsNullOrEmpty(trans.Translate))
{
return trans.Translate;
}
}
}
return fallback;
}
#endregion
}
}