using UnityEngine; using UnityEngine.UI; public class uLevel_skills : MonoBehaviour { public userLevel_skills_SO ulsSO; public Player_SO pso; [Header("objs")] public GameObject uSkillBarPrefab; public Transform uSkillBarParent; [Header("current selected skill details")] public Image btm_skillImage; public Image skillIcon_Profile; public Text skill_thisSkillName; public Text skill_thisSkillSummary; [Header("change")] public Slider need_progress; public Text need_text; public Text need_howmuchCoins; public Button yesChangeButton; public Button noCancelButton; private readonly System.Collections.Generic.List spawnedBars = new System.Collections.Generic.List(); private bool hasStarted = false; private int pendingSkillIndex = -1; private Color defaultNeedCoinsColor = Color.white; private const int SkillSwitchCooldownMatches = 3; private const int SkillSwitchMinimumCost = 200; private void Start() { hasStarted = true; CacheUiDefaults(); RegisterButtons(); PlayerSkillService.RegisterSkillAsset(ulsSO); RefreshSkillBars(); } private void OnEnable() { CacheUiDefaults(); RegisterButtons(); PlayerSkillService.RegisterSkillAsset(ulsSO); if (hasStarted) { RefreshSkillBars(); } } private void OnDestroy() { UnregisterButtons(); } public void SetPlayerSo(Player_SO playerSo) { pso = playerSo; } public void RefreshSkillBars() { EnsurePlayerSo(); if (uSkillBarParent == null || uSkillBarPrefab == null || ulsSO == null) return; NormalizeSelectionState(); ClearExistingBars(); spawnedBars.Clear(); for (int i = 0; i < ulsSO.skills.Count; i++) { var entry = ulsSO.skills[i]; if (entry == null) continue; GameObject instance = Instantiate(uSkillBarPrefab, uSkillBarParent); instance.SetActive(true); lrPrefab bar = instance.GetComponent(); if (bar == null) continue; bar.Bind(this, ulsSO, i, entry, IsSkillUnlocked(entry)); spawnedBars.Add(bar); } RefreshDetailPanel(); RefreshChangeUi(); } public void ToggleSkill(int index) { if (ulsSO == null || index < 0 || index >= ulsSO.skills.Count) return; var entry = ulsSO.skills[index]; if (entry == null || !IsSkillUnlocked(entry)) return; int currentEnabledIndex = GetEnabledSkillIndex(); if (index == currentEnabledIndex) { pendingSkillIndex = -1; RefreshDetailPanel(); RefreshChangeUi(); RefreshStatusesOnly(); return; } pendingSkillIndex = pendingSkillIndex == index ? -1 : index; RefreshDetailPanel(); RefreshChangeUi(); RefreshStatusesOnly(); } public bool IsSkillPreselected(int index) { return pendingSkillIndex >= 0 && pendingSkillIndex == index; } public bool IsSkillUnlocked(userLevel_skills_SO.UserLevelSkillEntry entry) { EnsurePlayerSo(); if (entry == null) return false; int currentExp = pso != null ? Mathf.Max(0, pso.player_currentEXP) : 0; return currentExp >= Mathf.Max(0, entry.thisLevelNeedExps); } private void RefreshStatusesOnly() { for (int i = 0; i < spawnedBars.Count; i++) { if (spawnedBars[i] == null) continue; spawnedBars[i].RefreshVisualState(); } } private void RefreshDetailPanel() { if (ulsSO == null || ulsSO.skills == null || ulsSO.skills.Count == 0) { SetDetailPanel(null); return; } int detailIndex = pendingSkillIndex >= 0 ? pendingSkillIndex : GetEnabledSkillIndex(); if (detailIndex < 0 || detailIndex >= ulsSO.skills.Count) { SetDetailPanel(null); return; } SetDetailPanel(ulsSO.skills[detailIndex]); } private void SetDetailPanel(userLevel_skills_SO.UserLevelSkillEntry entry) { if (skillIcon_Profile != null) { skillIcon_Profile.sprite = entry != null ? entry.skillIcon : null; } if (skill_thisSkillName != null) { skill_thisSkillName.text = entry != null ? (entry.skillName ?? string.Empty) : string.Empty; } if (skill_thisSkillSummary != null) { skill_thisSkillSummary.text = entry != null ? (entry.skillDescription ?? string.Empty) : string.Empty; } } private void RefreshChangeUi() { int cooldownRemaining = PlayerSkillService.GetSkillSwitchCooldownRemainingMatches(); int currentEnabledIndex = GetEnabledSkillIndex(); bool hasPendingSelection = pendingSkillIndex >= 0 && pendingSkillIndex != currentEnabledIndex; if (need_text != null) { need_text.text = cooldownRemaining > 0 ? $"还需要{cooldownRemaining}场比赛" : "可以切换技能"; } if (need_progress != null) { need_progress.minValue = 0f; need_progress.maxValue = 1f; need_progress.value = cooldownRemaining > 0 ? Mathf.Clamp01((float)(SkillSwitchCooldownMatches - cooldownRemaining) / SkillSwitchCooldownMatches) : 1f; } int switchCost = GetSkillSwitchCost(); bool hasEnoughCoins = HasEnoughCoinsForSwitch(switchCost); if (need_howmuchCoins != null) { need_howmuchCoins.text = switchCost.ToString(); need_howmuchCoins.color = hasEnoughCoins ? defaultNeedCoinsColor : Color.red; } if (yesChangeButton != null) { yesChangeButton.interactable = hasPendingSelection && cooldownRemaining <= 0 && hasEnoughCoins; } if (noCancelButton != null) { noCancelButton.interactable = pendingSkillIndex >= 0; } } private int GetSkillSwitchCost() { int currentCoins = Application.isPlaying ? PlayerEconomyLedger.EnsureInstance().GetCoins() : (pso != null ? Mathf.Max(0, pso.Coins) : 0); int percentCost = Mathf.CeilToInt(currentCoins * 0.01f); return Mathf.Max(SkillSwitchMinimumCost, percentCost); } private bool HasEnoughCoinsForSwitch(int amount) { if (amount <= 0) return true; return Application.isPlaying ? PlayerEconomyLedger.EnsureInstance().HasEnoughCoins(amount) : (pso != null && pso.Coins >= amount); } private void HandleConfirmSwitchClicked() { int currentEnabledIndex = GetEnabledSkillIndex(); if (pendingSkillIndex < 0 || pendingSkillIndex == currentEnabledIndex || ulsSO == null) { return; } if (PlayerSkillService.GetSkillSwitchCooldownRemainingMatches() > 0) { RefreshChangeUi(); return; } int switchCost = GetSkillSwitchCost(); bool spent = Application.isPlaying ? PlayerEconomyLedger.EnsureInstance().TrySpendCoins(switchCost) : (pso != null && pso.TrySpendCoins(switchCost)); if (!spent) { RefreshChangeUi(); return; } PlayerSkillService.ConfirmSkillSelection(ulsSO, pendingSkillIndex); pendingSkillIndex = -1; MarkSkillsDirty(); RefreshStatusesOnly(); RefreshDetailPanel(); RefreshChangeUi(); } private void HandleCancelPreselectClicked() { pendingSkillIndex = -1; RefreshStatusesOnly(); RefreshDetailPanel(); RefreshChangeUi(); } private void ClearExistingBars() { for (int i = uSkillBarParent.childCount - 1; i >= 0; i--) { Transform child = uSkillBarParent.GetChild(i); if (Application.isPlaying) Destroy(child.gameObject); else DestroyImmediate(child.gameObject); } } private void MarkSkillsDirty() { #if UNITY_EDITOR if (!Application.isPlaying && ulsSO != null) UnityEditor.EditorUtility.SetDirty(ulsSO); #endif } private void EnsurePlayerSo() { if (pso == null) pso = Resources.Load("playerdata/playerData_uniqueData"); } private void CacheUiDefaults() { if (need_howmuchCoins != null) { defaultNeedCoinsColor = need_howmuchCoins.color; } } private void RegisterButtons() { if (yesChangeButton != null) { yesChangeButton.onClick.RemoveListener(HandleConfirmSwitchClicked); yesChangeButton.onClick.AddListener(HandleConfirmSwitchClicked); } if (noCancelButton != null) { noCancelButton.onClick.RemoveListener(HandleCancelPreselectClicked); noCancelButton.onClick.AddListener(HandleCancelPreselectClicked); } } private void UnregisterButtons() { if (yesChangeButton != null) { yesChangeButton.onClick.RemoveListener(HandleConfirmSwitchClicked); } if (noCancelButton != null) { noCancelButton.onClick.RemoveListener(HandleCancelPreselectClicked); } } private int GetEnabledSkillIndex() { if (ulsSO == null || ulsSO.skills == null) return -1; for (int i = 0; i < ulsSO.skills.Count; i++) { var entry = ulsSO.skills[i]; if (entry != null && entry.isEnabled) return i; } return -1; } private void NormalizeSelectionState() { if (ulsSO == null || ulsSO.skills == null || ulsSO.skills.Count == 0) return; int selectedIndex = -1; for (int i = 0; i < ulsSO.skills.Count; i++) { var entry = ulsSO.skills[i]; if (entry == null || !entry.isEnabled) continue; if (selectedIndex < 0) { selectedIndex = i; } else { entry.isEnabled = false; } } if (selectedIndex < 0) { for (int i = 0; i < ulsSO.skills.Count; i++) { var entry = ulsSO.skills[i]; if (entry == null) continue; selectedIndex = i; entry.isEnabled = true; break; } } for (int i = 0; i < ulsSO.skills.Count; i++) { var entry = ulsSO.skills[i]; if (entry == null) continue; entry.isEnabled = (i == selectedIndex); } MarkSkillsDirty(); PlayerSkillService.RegisterSkillAsset(ulsSO); pendingSkillIndex = -1; } }