using UnityEngine; namespace BulletHellTemplate { /// /// Manages game data and settings. /// public class GameInstance : MonoBehaviour { [Header("GameData (Scriptables)")] [Tooltip("Array of character data scriptable objects.")] public CharacterData[] characterData; [Tooltip("Array of icon items.")] public IconItem[] iconItems; [Tooltip("Array of frame items.")] public FrameItem[] frameItems; [Tooltip("Array of inventory items.")] public InventoryItem[] inventoryItems; [Tooltip("List of all character types.")] public CharacterTypeData[] characterTypes; [Tooltip("Array of all map info data in the game.")] public MapInfoData[] mapInfoData; [Tooltip("Array of quest items.")] public QuestItem[] questData; [Tooltip("Array of coupon items.")] public CouponItem[] couponData; [Header("Controller Reference")] [Tooltip("Reference to the main character entity.")] public CharacterEntity characterEntity; [Header("Account Levels")] [Tooltip("Information about account levels.")] public AccountLevel accountLevels; [Header("Character Mastery")] [Tooltip("Settings for character mastery.")] public CharacterMastery characterMastery; [Header("Mastery Levels")] [Tooltip("Array of mastery level details.")] public CharacterMasteryLevel[] masteryLevels; [Header("Elements Settings")] [Tooltip("Percentage increase in damage when advantage element.")] public float advantageDamageIncrease = 0.2f; // 20% increase [Tooltip("Percentage reduction in damage when weakness element.")] public float weaknessDamageReduction = 0.2f; // 20% reduction [Header("Platform Selection")] [Tooltip("Specifies the platform type to determine the correct UIGameplay.")] public PlatformType platformType; [Header("Prefab References")] [Tooltip("Reference to the UIGameplay for mobile platform.")] public UIGameplay mobileGameplay; [Tooltip("Reference to the UIGameplay for desktop platform.")] public UIGameplay desktopGameplay; public static GameInstance Singleton; private bool isInitialized; /// /// Initializes the GameInstance as a singleton. /// private void Awake() { if (Singleton == null) { Singleton = this; DontDestroyOnLoad(gameObject); isInitialized = true; } else { Destroy(gameObject); } } /// /// Checks if the GameInstance has been initialized. /// /// True if initialized; otherwise, false. public bool IsInitialized() { return isInitialized; } /// /// Gets the CharacterData for the selected character. /// /// The matching CharacterData, or null if not found. public CharacterData GetCharacterData() { foreach (var character in characterData) { if (character.characterId == PlayerSave.GetSelectedCharacter()) { return character; } } Debug.LogWarning($"CharacterData with ID '{PlayerSave.GetSelectedCharacter()}' not found."); return null; } /// /// Gets the icon for a given character type. /// /// The character type data. /// The corresponding icon sprite. public Sprite GetIconForCharacterType(CharacterTypeData characterType) { return characterType.icon; } /// /// Calculates the total damage with elemental advantages and disadvantages. /// /// The element of the attacker. /// The element of the target. /// The base damage before elemental adjustments. /// The final damage after applying elemental adjustments. public float TotalDamageWithElements(CharacterTypeData attackerElement, CharacterTypeData targetElement, float totalDamageWithoutElements) { if (attackerElement == null || targetElement == null) { Debug.LogWarning("Attacker or target element is null."); return totalDamageWithoutElements; } if (System.Array.Exists(targetElement.weaknesses, element => element == attackerElement)) { return totalDamageWithoutElements * (1 + advantageDamageIncrease); } if (System.Array.Exists(attackerElement.strengths, element => element == targetElement)) { return totalDamageWithoutElements * (1 - weaknessDamageReduction); } return totalDamageWithoutElements; } /// /// Gets the UIGameplay instance based on the current platform. /// /// The corresponding UIGameplay instance for PC or Mobile. public UIGameplay GetUIGameplayForPlatform() { switch (platformType) { case PlatformType.PC: return desktopGameplay; case PlatformType.Mobile: return mobileGameplay; default: Debug.LogWarning("Unsupported platform type specified."); return null; } } /// /// Gets the current platform type. /// /// The platform type. public PlatformType GetCurrentPlatform() { return platformType; } public int GetAccountExpForLevel(int level) { if (accountLevels.accountExpPerLevel != null && level >= 1 && level < accountLevels.accountExpPerLevel.Length) { return accountLevels.accountExpPerLevel[level - 1]; } Debug.LogWarning("Invalid account level requested."); return -1; } /// /// Gets the required mastery experience for a specific mastery level. /// /// The mastery level (1-based index). /// The required experience for the given mastery level, or -1 if level is invalid. public int GetMasteryExpForLevel(int level) { if (characterMastery.masteryExpPerLevel != null && level >= 0 && level < characterMastery.masteryExpPerLevel.Length) { return characterMastery.masteryExpPerLevel[level]; } Debug.LogWarning("Invalid mastery level requested."); return 0; } /// /// Gets the mastery level details for a specific level. /// /// The mastery level (1-based index). /// The mastery level details, or a default value if level is invalid. public CharacterMasteryLevel GetMasteryLevel(int level) { if (masteryLevels != null && level < masteryLevels.Length) { return masteryLevels[level]; } Debug.LogWarning("Invalid mastery level requested."); return masteryLevels[masteryLevels.Length -1]; } /// /// Automatically fills the mastery experience array based on the calculation method set in 'characterMastery.characterExpCalculationMethod'. /// public void AutoFillMasteryExp() { if (characterMastery.Equals(null)) { Debug.LogWarning("CharacterMastery is not assigned."); return; } ExpCalculationMethod method = characterMastery.characterExpCalculationMethod; int maxLevel = characterMastery.maxMasteryLevel; characterMastery.masteryExpPerLevel = new int[maxLevel]; for (int i = 0; i < maxLevel; i++) { int value = 0; float t = (maxLevel > 1) ? (float)i / (maxLevel - 1) : 0f; switch (method) { case ExpCalculationMethod.Linear: value = Mathf.RoundToInt(Mathf.Lerp(characterMastery.initialExp, characterMastery.finalExp, t)); break; case ExpCalculationMethod.Exponential: if (characterMastery.initialExp <= 0) characterMastery.initialExp = 1; value = Mathf.RoundToInt(characterMastery.initialExp * Mathf.Pow((float)characterMastery.finalExp / characterMastery.initialExp, t)); break; case ExpCalculationMethod.Custom: default: value = Mathf.RoundToInt(Mathf.Lerp(characterMastery.initialExp, characterMastery.finalExp, t)); break; } characterMastery.masteryExpPerLevel[i] = value; } } /// /// Automatically fills the account experience array based on the calculation method set in 'accountLevels.accountExpCalculationMethod'. /// public void AutoFillAccountExp() { if (accountLevels.Equals(null)) { Debug.LogWarning("AccountLevel is not assigned."); return; } ExpCalculationMethod method = accountLevels.accountExpCalculationMethod; int maxLevel = accountLevels.accountMaxLevel; accountLevels.accountExpPerLevel = new int[maxLevel]; for (int i = 0; i < maxLevel; i++) { int value = 0; float t = (maxLevel > 1) ? (float)i / (maxLevel - 1) : 0f; switch (method) { case ExpCalculationMethod.Linear: value = Mathf.RoundToInt(Mathf.Lerp(accountLevels.initialExp, accountLevels.finalExp, t)); break; case ExpCalculationMethod.Exponential: if (accountLevels.initialExp <= 0) accountLevels.initialExp = 1; value = Mathf.RoundToInt(accountLevels.initialExp * Mathf.Pow((float)accountLevels.finalExp / accountLevels.initialExp, t)); break; case ExpCalculationMethod.Custom: default: value = Mathf.RoundToInt(Mathf.Lerp(accountLevels.initialExp, accountLevels.finalExp, t)); break; } accountLevels.accountExpPerLevel[i] = value; } } } /// /// Represents the available platform types. /// public enum PlatformType { Mobile, PC } [System.Serializable] public struct AccountLevel { [Tooltip("Maximum account level.")] public int accountMaxLevel; [Tooltip("Initial EXP for account leveling.")] public int initialExp; [Tooltip("Final EXP for the highest account level.")] public int finalExp; [Tooltip("Selected calculation method for account EXP progression.")] public ExpCalculationMethod accountExpCalculationMethod; [Tooltip("EXP required per account level.")] public int[] accountExpPerLevel; } /// /// Represents the character mastery settings. /// [System.Serializable] public struct CharacterMastery { [Tooltip("Maximum mastery level.")] public int maxMasteryLevel; [Tooltip("Initial EXP for mastery leveling.")] public int initialExp; [Tooltip("Final EXP for the highest mastery level.")] public int finalExp; [Tooltip("Selected calculation method for mastery EXP progression.")] public ExpCalculationMethod characterExpCalculationMethod; [Tooltip("Experience points required per mastery level.")] public int[] masteryExpPerLevel; } /// /// Represents the details for a specific mastery level. /// [System.Serializable] public struct CharacterMasteryLevel { [Tooltip("Name of the mastery level.")] public string masteryName; [Tooltip("Translated name of the mastery level.")] public NameTranslatedByLanguage[] masteryNameTranslated; [Tooltip("Icon representing the mastery level.")] public Sprite masteryIcon; } /// /// Contains translation data for a name by language. /// [System.Serializable] public struct NameTranslatedByLanguage { public string LanguageId; public string Translate; } /// /// Contains translation data for a description by language. /// [System.Serializable] public struct DescriptionTranslatedByLanguage { public string LanguageId; [TextArea] public string Translate; } /// /// Methods for calculating experience progression. /// public enum ExpCalculationMethod { Linear, Exponential, Custom } }