559 lines
20 KiB
C#
559 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using BrewMonster;
|
||
using BrewMonster.Scripts.Skills;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace BrewMonster.UI
|
||
{
|
||
[DisallowMultipleComponent]
|
||
public class CDlgSkillSubList : AUIDialog
|
||
{
|
||
[Header("Templates")]
|
||
[SerializeField] private AUISubDialog m_pSubRank;
|
||
[SerializeField] private CDlgSkillSubListItem m_pSubSkill;
|
||
|
||
[Header("Layout")]
|
||
[SerializeField] private RectTransform m_contentRoot;
|
||
[SerializeField] private RectTransform m_contentRootSkill;
|
||
[SerializeField] private ScrollRect m_scrollRect;
|
||
[SerializeField] private float m_windowScale = 1f;
|
||
[SerializeField] private TMP_Text totalSPText;
|
||
|
||
[Header("State")]
|
||
[SerializeField] private bool m_isEvil;
|
||
|
||
private readonly Dictionary<int, AUISubDialog> m_rankSubDialogs = new();
|
||
private readonly List<CDlgSkillSubListItem> m_skillSubDialogs = new();
|
||
private readonly Dictionary<int, CDlgSkillSubListItem> m_skillSubDialogsMap = new();
|
||
|
||
private int m_skillSubCount; // 当前显示的技能数量 / Current shown skill count
|
||
private float m_curBottom; // 当前底部位置 / Current bottom position
|
||
private float m_skillHeight; // 技能子对话高度 / Skill sub dialog height
|
||
private float m_rankHeight; // 阶位对话高度 / Rank dialog height
|
||
private float m_originWidth; // 初始宽度 / Initial width
|
||
private float m_originHeight; // 初始高度 / Initial height
|
||
private float m_originBottom; // 初始底部位置 / Initial bottom position
|
||
private bool m_bAllocRankDlgs; // 是否已创建阶位子对话 / Whether rank sub dialogs are allocated
|
||
|
||
private int m_selectedSkillId;
|
||
|
||
private void Awake()
|
||
{
|
||
if (m_contentRoot == null)
|
||
{
|
||
m_contentRoot = transform as RectTransform;
|
||
}
|
||
EventBus.Subscribe<CECSkillPanelChange>(OnModelChange);
|
||
CacheTemplateInfo();
|
||
HideTemplates();
|
||
}
|
||
|
||
public override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
OnShowDialog();
|
||
}
|
||
|
||
private void OnShowDialog()
|
||
{
|
||
BMLogger.LogError("HoangDev: OnShowDialog ");
|
||
InitRankDlgs();
|
||
ResetDialog();
|
||
|
||
// 保留原始隐藏新图标逻辑 / Keep original "hide new" logic (pending port)
|
||
// GetGameUIMan()->m_pDlgSystem->ShowNewImg(false);
|
||
// GetGameUIMan()->m_pDlgSystemb->ShowNewImg(false);
|
||
// GetGameUIMan()->m_pDlgSystem5->ShowNewImg(false);
|
||
// GetGameUIMan()->m_pDlgSystem5b->ShowNewImg(false);
|
||
}
|
||
|
||
// 初始化模板尺寸 / Cache template sizing info
|
||
private void CacheTemplateInfo()
|
||
{
|
||
if (m_pSubRank != null)
|
||
{
|
||
m_rankHeight = m_pSubRank.GetSize().y;
|
||
m_originBottom = m_pSubRank.GetPos().y;
|
||
}
|
||
|
||
|
||
if (m_contentRoot != null)
|
||
{
|
||
m_originWidth = m_contentRoot.rect.width;
|
||
m_originHeight = m_contentRoot.rect.height;
|
||
}
|
||
}
|
||
|
||
private void HideTemplates()
|
||
{
|
||
if (m_pSubRank != null)
|
||
{
|
||
m_pSubRank.Show(false);
|
||
}
|
||
|
||
if (m_pSubSkill != null)
|
||
{
|
||
m_pSubSkill.Show(false);
|
||
}
|
||
}
|
||
|
||
// 初始化所有阶位子对话框 / Initialize all rank sub dialogs///
|
||
private void InitRankDlgs()
|
||
{
|
||
if (m_bAllocRankDlgs || m_pSubRank == null || m_contentRoot == null)
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-E] InitRankDlgs skipped reason={(m_bAllocRankDlgs ? "already_alloc" : (m_pSubRank == null ? "no_sub_rank" : "no_content_root"))} allocRank={m_bAllocRankDlgs} subSkill={m_pSubSkill != null} contentRoot={m_contentRoot != null}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
m_bAllocRankDlgs = true;
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetBaseRankBegin();
|
||
taoistRank != CECTaoistRank.GetBaseRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
CreateOneRankDlg(taoistRank);
|
||
}
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetGodRankBegin();
|
||
taoistRank != CECTaoistRank.GetGodRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
CreateOneRankDlg(taoistRank);
|
||
}
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetEvilRankBegin();
|
||
taoistRank != CECTaoistRank.GetEvilRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
CreateOneRankDlg(taoistRank);
|
||
}
|
||
|
||
}
|
||
|
||
// ��ʼ�����������ڶԻ���һ���Է�����ڴ� / Initialize rank sub-dialogs once to avoid realloc
|
||
private void CreateOneRankDlg(CECTaoistRank taoistRank)
|
||
{
|
||
BMLogger.LogError("HoangDev: CreateOneRankDlg");
|
||
AUISubDialog pSubRank = Instantiate(m_pSubRank, m_contentRoot, transform);
|
||
pSubRank.SetName($"{m_pSubRank.GetName()}{taoistRank.GetID()}");
|
||
pSubRank.Show(false);
|
||
|
||
m_rankSubDialogs[taoistRank.GetID()] = pSubRank;
|
||
}
|
||
|
||
// ���¶������Ի�����в��� / Reset dialog with all rank/skill sub dialogs
|
||
public void ResetDialog()
|
||
{
|
||
m_skillSubDialogsMap.Clear();
|
||
m_skillSubCount = 0;
|
||
m_curBottom = m_originBottom;
|
||
|
||
foreach (var rank in m_rankSubDialogs.Values)
|
||
{
|
||
rank.Show(false);
|
||
}
|
||
|
||
foreach (var skill in m_skillSubDialogs)
|
||
{
|
||
skill.Show(false);
|
||
}
|
||
|
||
var skillModel = CECHostSkillModel.Instance;
|
||
IReadOnlyDictionary<int, List<int>> allRankProfSkills = skillModel?.GetAllRankProfSkills();
|
||
|
||
// #region agent log
|
||
int totalCatalogSkills = allRankProfSkills != null ? allRankProfSkills.Values.Sum(l => l?.Count ?? 0) : -1;
|
||
BMLogger.LogError($"[SkillSubList][H-A] ResetDialog start modelNull={skillModel == null} rankBuckets={allRankProfSkills?.Count ?? -1} catalogSkills={totalCatalogSkills} isEvil={IsEvil()} allocRank={m_bAllocRankDlgs} subSkillTpl={m_pSubSkill != null} contentRoot={m_contentRoot != null} hostNull={GetHostPlayer() == null}");
|
||
// #endregion
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetBaseRankBegin();
|
||
taoistRank != CECTaoistRank.GetBaseRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
//BMLogger.LogError ("ResetDialog base rank " + taoistRank.GetName());
|
||
AddDlgsOfOneRank(taoistRank);
|
||
}
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetGodRankBegin();
|
||
taoistRank != CECTaoistRank.GetGodRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
//BMLogger.LogError("ResetDialog base rank " + taoistRank.GetName());
|
||
AddDlgsOfOneRank(taoistRank);
|
||
}
|
||
|
||
for (CECTaoistRank taoistRank = CECTaoistRank.GetEvilRankBegin();
|
||
taoistRank != CECTaoistRank.GetEvilRankEnd();
|
||
taoistRank = taoistRank.GetNext())
|
||
{
|
||
//BMLogger.LogError("ResetDialog Evil rank " + taoistRank.GetName());
|
||
AddDlgsOfOneRank(taoistRank);
|
||
}
|
||
|
||
if (m_contentRoot != null)
|
||
{
|
||
FitSize();
|
||
ShowLastSelectedSkill();
|
||
}
|
||
UpdateTotalSPText();
|
||
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-E] ResetDialog end shownSkills={m_skillSubCount} rankBuckets={allRankProfSkills?.Count ?? -1} isEvil={IsEvil()} allocRank={m_bAllocRankDlgs}");
|
||
// #endregion
|
||
}
|
||
|
||
public void UpdateTotalSPText()
|
||
{
|
||
if (totalSPText != null && GetHostPlayer() != null)
|
||
{
|
||
totalSPText.text = " <color=yellow>Nguyên Thần:</color> " + GetHostPlayer().GetBasicProps().iSP.ToString() + "</color>";
|
||
}
|
||
}
|
||
|
||
// ��鵯��ħ״̬ / Reset when switching between god/evil
|
||
public void ResetGodEvil()
|
||
{
|
||
if (isActiveAndEnabled)
|
||
{
|
||
ResetDialog();
|
||
}
|
||
}
|
||
|
||
// ��ijһ����������״̬ / Refresh a single skill sub dialog
|
||
private void UpdateOneSubDlg(int skillID)
|
||
{
|
||
BMLogger.LogError("UpdateOneSubDlg");
|
||
if (!m_skillSubDialogsMap.TryGetValue(skillID, out var pSub))
|
||
{
|
||
return;
|
||
}
|
||
|
||
CDlgSkillSubListItem subListItem = pSub;
|
||
if(subListItem == null )
|
||
{
|
||
return;
|
||
}
|
||
subListItem.UpdateSkill(skillID);
|
||
subListItem.Show(true);
|
||
BMLogger.LogError("HoangDEv subListItem true");
|
||
if (GetSelectedSkillID() == skillID)
|
||
{
|
||
//GetGameUIMan()->m_pDlgSkillAction->ShowSkillTree(skillID);
|
||
}
|
||
}
|
||
|
||
// ����һ�����漶��Ի��� / Show a rank sub dialog
|
||
private void AddRankSubDig(int rankID)
|
||
{
|
||
if (!m_rankSubDialogs.TryGetValue(rankID, out var pSub))
|
||
{
|
||
return;
|
||
}
|
||
|
||
pSub.Show(true);
|
||
pSub.SetLabel(CECTaoistRank.GetTaoistRank(rankID).GetName());
|
||
//pSub.SetPos(0f, m_curBottom);
|
||
//m_curBottom += m_rankHeight * m_windowScale;
|
||
|
||
pSub.SetLabel(CECTaoistRank.GetTaoistRank(rankID).GetName());
|
||
}
|
||
|
||
// ����һ�����ܶԻ����øú����������UpdateOneSubDlg / Add a skill sub dialog then update it
|
||
private void AddSkillSubDlg(int skillID, int rankID)
|
||
{
|
||
BMLogger.LogError("HoangDev: AddSkillSubDlg(int skillID, int rankID)");
|
||
if (m_pSubSkill == null || m_contentRoot == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (m_skillSubCount >= m_skillSubDialogs.Count)
|
||
{
|
||
CDlgSkillSubListItem pSubSkill = Instantiate(m_pSubSkill, m_rankSubDialogs[rankID].transform);
|
||
m_skillSubDialogs.Add(pSubSkill);
|
||
}
|
||
|
||
CDlgSkillSubListItem curSubSkill = m_skillSubDialogs[m_skillSubCount];
|
||
curSubSkill?.SetHighlight(false);
|
||
|
||
m_skillSubDialogsMap[skillID] = curSubSkill;
|
||
m_skillSubCount++;
|
||
UpdateOneSubDlg(skillID);
|
||
}
|
||
|
||
// ��ijһ�����漶���Ӧ�����м���������Ի��� / Add dialogs for one rank
|
||
private void AddDlgsOfOneRank(CECTaoistRank taoistRank)
|
||
{
|
||
BMLogger.LogError("HoangDev: AddDlgsOfOneRank(CECTaoistRank taoistRank)");
|
||
CECHostSkillModel model = CECHostSkillModel.Instance;
|
||
IReadOnlyDictionary<int, List<int>> allRankProfSkills = model.GetAllRankProfSkills();
|
||
|
||
int rankID = taoistRank.GetID();
|
||
|
||
if (allRankProfSkills == null)
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-A] AddDlgsOfOneRank skip reason=allRankProfSkills_null rankId={rankID}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
if (IsEvil() && taoistRank.IsGodRank())
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-C] AddDlgsOfOneRank skip reason=evil_hides_god rankId={rankID}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
else if (!IsEvil() && taoistRank.IsEvilRank())
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-C] AddDlgsOfOneRank skip reason=non_evil_hides_evil rankId={rankID}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
|
||
|
||
if (!allRankProfSkills.TryGetValue(rankID, out var rankItr) || rankItr == null || rankItr.Count == 0)
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-A] AddDlgsOfOneRank skip reason=rank_empty rankId={rankID}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
|
||
List<int> rankSkills = new List<int>();
|
||
int overriddenSkipped = 0;
|
||
foreach (var skillID in rankItr)
|
||
{
|
||
if (ElementSkill.IsOverridden((uint)skillID))
|
||
{
|
||
overriddenSkipped++;
|
||
BMLogger.LogError($"[SkillSubList][H-D] skill overridden skillId={skillID} rankId={rankID}");
|
||
continue;
|
||
}
|
||
/* bool bOnlyShowSkillCanLearn = GetGameUIMan()->m_pDlgSkillAction->IsOnlyShowSkillCanLearn();
|
||
if (bOnlyShowSkillCanLearn)
|
||
{
|
||
if (model.GetSkillFitLevel(skillID) == CECHostSkillModel::SKILL_NOT_FIT_LEVEL)
|
||
{
|
||
continue;
|
||
}
|
||
int curLevel = model.GetSkillCurrentLevel(skillID);
|
||
int requiredItem = model.GetRequiredBook(skillID, curLevel + 1);
|
||
if (requiredItem && !model.CheckPreItem(requiredItem))
|
||
{
|
||
continue;
|
||
}
|
||
}*/
|
||
rankSkills.Add(skillID);
|
||
}
|
||
if (rankSkills.Count == 0)
|
||
{
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-D] AddDlgsOfOneRank skip reason=all_overridden rankId={rankID} raw={rankItr.Count} overriddenSkipped={overriddenSkipped}");
|
||
// #endregion
|
||
return;
|
||
}
|
||
|
||
// #region agent log
|
||
BMLogger.LogError($"[SkillSubList][H-E] AddDlgsOfOneRank adding rankId={rankID} raw={rankItr.Count} shown={rankSkills.Count} overriddenSkipped={overriddenSkipped} isEvil={IsEvil()}");
|
||
// #endregion
|
||
|
||
AddRankSubDig(rankID);
|
||
rankSkills.Sort();
|
||
foreach (int skillID in rankSkills)
|
||
{
|
||
AddSkillSubDlg(skillID , rankID);
|
||
}
|
||
}
|
||
|
||
private string GetRankName(int rankID)
|
||
{
|
||
// 尝试使用阶位名字,否则使用 ID / Use rank name if available, otherwise ID
|
||
// TODO: wire into localization table once available
|
||
return $"Rank {rankID}";
|
||
}
|
||
|
||
// ����������洢��λ�õ���ȡֵ / Scroll helpers use the stored positions
|
||
public void ScrollToShowSelectedSkill()
|
||
{
|
||
if (m_scrollRect == null || GetSelectedSkillID() == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!m_skillSubDialogsMap.TryGetValue(GetSelectedSkillID(), out var sub))
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
// �����Ľ��� / Prepare for layout change
|
||
public bool OnChangeLayoutBegin()
|
||
{
|
||
foreach (var kv in m_rankSubDialogs)
|
||
{
|
||
Destroy(kv.Value.gameObject);
|
||
}
|
||
m_rankSubDialogs.Clear();
|
||
|
||
foreach (var dlg in m_skillSubDialogs)
|
||
{
|
||
Destroy(dlg.gameObject);
|
||
}
|
||
m_skillSubDialogs.Clear();
|
||
|
||
m_skillSubDialogsMap.Clear();
|
||
m_skillSubCount = 0;
|
||
m_curBottom = 0f;
|
||
|
||
return true;
|
||
}
|
||
|
||
// 布局变更结束时 / After layout change
|
||
public void OnChangeLayoutEnd(bool bAllDone)
|
||
{
|
||
if (isActiveAndEnabled)
|
||
{
|
||
InitRankDlgs();
|
||
FitSize();
|
||
ShowLastSelectedSkill();
|
||
}
|
||
}
|
||
|
||
private void FitSize()
|
||
{
|
||
if (m_contentRoot == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
float height = Mathf.Max(m_curBottom, m_originHeight);
|
||
m_contentRoot.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
|
||
}
|
||
|
||
private void ShowLastSelectedSkill()
|
||
{
|
||
int originSelected = GetSelectedSkillID();
|
||
SetSelectedSkillID(0);
|
||
SelectSkill(originSelected);
|
||
ScrollToShowSelectedSkill();
|
||
}
|
||
|
||
public void SelectSkill(int skillID)
|
||
{
|
||
if (skillID != 0 && !m_skillSubDialogsMap.ContainsKey(skillID))
|
||
{
|
||
skillID = ConvertSkillID(skillID);
|
||
}
|
||
|
||
if (skillID != 0 && !m_skillSubDialogsMap.ContainsKey(skillID))
|
||
{
|
||
SetSelectedSkillID(0);
|
||
return;
|
||
}
|
||
|
||
int originSelectedSkillID = GetSelectedSkillID();
|
||
if (originSelectedSkillID != 0 && m_skillSubDialogsMap.TryGetValue(originSelectedSkillID, out var originSub))
|
||
{
|
||
originSub.GetComponent<CDlgSkillSubListItem>()?.SetHighlight(false);
|
||
}
|
||
|
||
if (skillID != 0 && m_skillSubDialogsMap.TryGetValue(skillID, out var newSub))
|
||
{
|
||
newSub.GetComponent<CDlgSkillSubListItem>()?.SetHighlight(true);
|
||
}
|
||
|
||
SetSelectedSkillID(skillID);
|
||
}
|
||
|
||
public void EnableUpgrade(bool bEnable)
|
||
{
|
||
foreach (var kv in m_skillSubDialogsMap)
|
||
{
|
||
kv.Value.GetComponent<CDlgSkillSubListItem>()?.EnableUpgrade(bEnable);
|
||
}
|
||
}
|
||
|
||
public int GetSelectedSkillID()
|
||
{
|
||
return m_selectedSkillId;
|
||
}
|
||
|
||
public void SetSelectedSkillID(int skillID)
|
||
{
|
||
m_selectedSkillId = skillID;
|
||
}
|
||
|
||
public bool IsEvil()
|
||
{
|
||
return m_isEvil;
|
||
}
|
||
|
||
public void SetEvil(bool value)
|
||
{
|
||
if (m_isEvil != value)
|
||
{
|
||
m_isEvil = value;
|
||
ResetGodEvil();
|
||
}
|
||
}
|
||
|
||
// ���ܱ������Ӧ�����Ƿ�����б��� / Check whether skill or its converted counterpart exists
|
||
public bool IsSkillOrConvertSkillExist(int skillID)
|
||
{
|
||
if (m_skillSubDialogsMap.ContainsKey(skillID))
|
||
{
|
||
return true;
|
||
}
|
||
|
||
int convertSkillID = ConvertSkillID(skillID);
|
||
return convertSkillID != 0 && m_skillSubDialogsMap.ContainsKey(convertSkillID);
|
||
}
|
||
|
||
private int ConvertSkillID(int skillID)
|
||
{
|
||
// 预留转换逻辑 / Placeholder for conversion logic
|
||
return skillID;
|
||
}
|
||
|
||
// �м��ܱ������ˣ���Ҫ������������ / Handle model change notifications
|
||
public void OnModelChange(CECSkillPanelChange q)
|
||
{
|
||
/* if (!GetGameUIMan().m_pDlgSkillAction.IsShow())
|
||
{
|
||
return;
|
||
}*/
|
||
if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN)
|
||
{
|
||
ResetDialog();
|
||
}
|
||
else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP)
|
||
{
|
||
UpdateTotalSPText();
|
||
if (q.m_skillLevel == 1)
|
||
{
|
||
foreach (var kv in m_skillSubDialogsMap)
|
||
{
|
||
UpdateOneSubDlg(kv.Key);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
UpdateOneSubDlg(q.m_skillID);
|
||
}
|
||
}
|
||
else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC)
|
||
{
|
||
//GetGameUIMan()->m_pDlgSkillAction->Show(false);
|
||
}
|
||
}
|
||
}
|
||
}
|