using UnityEngine; using System.Collections.Generic; [CreateAssetMenu(fileName = "NewAllyHero", menuName = "SO_Data/AllyHero")] public class AllyHero_SO : ScriptableObject { [Header("Inspector")] public string ally_heroName; public string ally_heroDesignation; public int ally_heroID; public bool isUnlocked; [Header("Inspector")] public Sprite ally_heroImage; [Header("Inspector")] public Sprite ally_heroProfile; [Header("Inspector")] public Sprite ally_heroSelectIcon; [Header("Inspector")] public Sprite ally_heroIcon; [Header("Inspector")] public Sprite ally_heroPoster; [Header("Inspector")] public Sprite ally_hero_HD_image; [Header("Inspector")] public Sprite ally_hero_squareProfile; [Header("Inspector")] public Color ally_heroThemeColor; [Header("Inspector")] [TextArea(3, 10)] [Tooltip("Documentation text normalized.")] public string ally_heroDescription; [Header("Inspector")] public List levelStats = new List(); [System.Serializable] public class AllyLevelInfo { [Tooltip("Documentation text normalized.")] public string levelName; public int levelID; [Tooltip("Documentation text normalized.")] public int attack = 0; [Tooltip("Documentation text normalized.")] public int maxHP = 100; [Tooltip("Documentation text normalized.")] public float damageResistance = 0f; [Tooltip("Documentation text normalized.")] public int maxMana = 100; [Tooltip("Documentation text normalized.")] public float scoreEfficiency = 1f; [Header("Inspector")] [Tooltip("Documentation text normalized.")] public int requiredEXP; [Header("Inspector")] [Tooltip("Documentation text normalized.")] public int skill_slot_limited; [Header("Note-hit shared parameters")] [Tooltip("Documentation text normalized.")] public int manaGainGood = 1; [Tooltip("Documentation text normalized.")] public int manaGainGreat = 2; [Tooltip("Documentation text normalized.")] public int manaGainPerfect = 3; [Tooltip("Documentation text normalized.")] public int manaGainOnMiss = 5; [Tooltip("Documentation text normalized.")] public float damageMultiplierGood = 0.5f; [Tooltip("Documentation text normalized.")] public float damageMultiplierGreat = 0.75f; [Tooltip("Documentation text normalized.")] public float damageMultiplierPerfect = 1f; [Tooltip("Documentation text normalized.")] public float missHpLossBase = 10f; } [Header("Inspector")] public int ally_currentEXP; public int ally_battleDeployCount; [Header("Skills")] public SkillDefinition[] availableSkills; [Tooltip("Indexes into availableSkills for preselected skills; empty means none selected")] public int[] selectedSkillIndices = new int[0]; [Tooltip("Primary selected skill index into availableSkills (-1 = none)")] public int primarySkillIndex = -1; // Documentation text normalized. [Tooltip("Skill groups defined on this hero. Each SkillGroup has a numeric skillGroupID which can be equipped into slots to allow activation of the entire group via that ID.")] public SkillGroup[] skillGroups = new SkillGroup[0]; [Tooltip("Equipped skill group IDs for this ally. Each int references a skillGroupID defined in skillGroups. Use 0 to indicate empty.")] public int[] equippedSkillGroupIDs = new int[0]; // Documentation text normalized. public SkillDefinition GetPrimarySkill() { if (availableSkills == null || primarySkillIndex < 0 || primarySkillIndex >= availableSkills.Length) return null; return availableSkills[primarySkillIndex]; } // Adjusted: primary group is no longer stored as an index; prefer the first equipped group ID, otherwise fall back to the first non-null defined group. public SkillGroup GetPrimarySkillGroup() { if (skillGroups == null || skillGroups.Length == 0) return null; // If equipped group IDs exist, prefer the first valid referenced group if (equippedSkillGroupIDs != null && equippedSkillGroupIDs.Length > 0) { foreach (var gid in equippedSkillGroupIDs) { if (gid == 0) continue; var g = GetSkillGroupByID(gid); if (g != null) return g; } } // Fallback: return first non-null skill group defined on the SO foreach (var g in skillGroups) { if (g != null) return g; } return null; } // New helper: find a SkillGroup by its numeric skillGroupID public SkillGroup GetSkillGroupByID(int groupID) { if (skillGroups == null || skillGroups.Length == 0) return null; foreach (var g in skillGroups) { if (g != null && g.skillGroupID == groupID) return g; } return null; } // Return the AllyLevelInfo that corresponds to the current ally_currentEXP. // Picks the highest level whose requiredEXP <= ally_currentEXP. If none match, returns levelStats[0] if present, otherwise null. public AllyLevelInfo GetEffectiveLevelForCurrentEXP() { if (levelStats == null || levelStats.Count == 0) return null; AllyLevelInfo best = null; int currentExp = ally_currentEXP; foreach (var lvl in levelStats) { if (lvl == null) continue; if (best == null) { if (currentExp >= lvl.requiredEXP) best = lvl; } else { if (currentExp >= lvl.requiredEXP && lvl.requiredEXP >= best.requiredEXP) best = lvl; } } if (best == null) return levelStats[0]; return best; } [System.Serializable] private class EquippedSkillGroupIDsPayload { public int[] equippedSkillGroupIDs; } private string GetEquippedSkillsPrefsKey() { return "ally_equippedSkillGroupIDs_" + ally_heroID; } public void SaveEquippedSkillsToLocal() { var payload = new EquippedSkillGroupIDsPayload { equippedSkillGroupIDs = equippedSkillGroupIDs ?? new int[0] }; string json = JsonUtility.ToJson(payload); PlayerPrefs.SetString(GetEquippedSkillsPrefsKey(), json); PlayerPrefs.Save(); } public void LoadEquippedSkillsFromLocal() { string key = GetEquippedSkillsPrefsKey(); if (!PlayerPrefs.HasKey(key)) return; string json = PlayerPrefs.GetString(key, ""); if (string.IsNullOrEmpty(json)) return; var payload = JsonUtility.FromJson(json); if (payload == null) return; equippedSkillGroupIDs = payload.equippedSkillGroupIDs ?? new int[0]; } public void SetUnlocked(bool value) { if (isUnlocked == value) return; isUnlocked = value; #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif } public void IncrementBattleDeployCount(int amount = 1) { if (amount <= 0) return; AllyHeroDeployLedger.EnsureInstance().IncrementDeployCount(this, amount); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif } public void LoadBattleDeployCountFromLocal() { ally_battleDeployCount = AllyHeroDeployLedger.EnsureInstance().GetDeployCount(ally_heroID); } public void SaveBattleDeployCountToLocal() { AllyHeroDeployLedger.EnsureInstance().SaveNow(); } }