411 lines
11 KiB
C#
411 lines
11 KiB
C#
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<lrPrefab> spawnedBars = new System.Collections.Generic.List<lrPrefab>();
|
|
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<lrPrefab>();
|
|
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<Player_SO>("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;
|
|
}
|
|
}
|