Files
test/Assets/PerfectWorld/Scripts/Skills/EC_HostSkillModel.cs
T
vuong dinh hoang 263f7bfbc3 fix lable rank
2026-05-31 17:14:44 +07:00

804 lines
30 KiB
C#

using Animancer;
using BrewMonster;
using CSNetwork;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
namespace BrewMonster.Scripts.Skills
{
public class CECHostSkillModel
{
private static CECHostSkillModel instance;
public static CECHostSkillModel Instance
{
get
{
if (instance == null)
{
instance = new CECHostSkillModel();
}
return instance;
}
set => instance = value;
}
ElementSkill s = null;
Dictionary<int, ElementSkill> m_allProfSkills = new Dictionary<int, ElementSkill>();
Dictionary<int, List<int>> m_allRankProfSkills = new Dictionary<int, List<int>>();
private HashSet<int> m_allProfNPCs = new HashSet<int>();
private Dictionary<int, int> m_treeHeightMap = new Dictionary<int, int>();
private Dictionary<int, int> m_evilRootMap = new Dictionary<int, int>();
private Dictionary<int, int> m_godRootMap = new Dictionary<int, int>();
private Dictionary<int, int> m_baseRootMap = new Dictionary<int, int>();
private int m_skillLearnNPCNID;
private bool m_bReceivedNPCGreeting;
private bool m_bInitialized;
private Octets m_npcListData;
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void BeforeSceneLoad()
{
Instance = null;
}
#endif
public IReadOnlyDictionary<int, List<int>> GetAllRankProfSkills()
{
return m_allRankProfSkills;
}
/// <summary>
/// Same skill ID set as <see cref="BrewMonster.UI.CDlgSkillSubList"/> — walks base/god/evil ranks,
/// applies god/evil path filter and skips overridden skills.
/// 与 CDlgSkillSubList 相同的技能 ID 集合。
/// </summary>
public List<int> CollectSkillSubListSkillIds(bool isEvil)
{
var result = new List<int>();
var seen = new HashSet<int>();
void CollectRankRange(CECTaoistRank begin, CECTaoistRank end)
{
for (CECTaoistRank taoistRank = begin; taoistRank != end; taoistRank = taoistRank.GetNext())
{
if (isEvil && taoistRank.IsGodRank())
continue;
if (!isEvil && taoistRank.IsEvilRank())
continue;
int rankId = taoistRank.GetID();
if (!m_allRankProfSkills.TryGetValue(rankId, out List<int> rankSkills) ||
rankSkills == null || rankSkills.Count == 0)
{
continue;
}
foreach (int skillId in rankSkills)
{
if (ElementSkill.IsOverridden((uint)skillId))
continue;
if (seen.Add(skillId))
result.Add(skillId);
}
}
}
CollectRankRange(CECTaoistRank.GetBaseRankBegin(), CECTaoistRank.GetBaseRankEnd());
CollectRankRange(CECTaoistRank.GetGodRankBegin(), CECTaoistRank.GetGodRankEnd());
CollectRankRange(CECTaoistRank.GetEvilRankBegin(), CECTaoistRank.GetEvilRankEnd());
result.Sort();
return result;
}
public CECHostSkillModel()
{
m_allProfSkills = new Dictionary<int, ElementSkill>();
m_skillLearnNPCNID = 0;
m_bReceivedNPCGreeting = false;
m_bInitialized = false;
}
// NPC技能学习相关 / Skill-learn NPC helpers
public bool IsSkillLearnNPC(int nid) => nid == m_skillLearnNPCNID;
public bool IsSkillLearnNPCExsit() => m_skillLearnNPCNID != 0;
public bool IsReceivedNPCGreeting() => m_bReceivedNPCGreeting;
public void SetReceivedNPCGreeting(bool received) => m_bReceivedNPCGreeting = received;
public void OnNpcGreeting(int idObject)
{
// cmd_npc_greeting.idObject is the NPC/player id (nid)
if (idObject == m_skillLearnNPCNID && m_skillLearnNPCNID != 0)
{
m_bReceivedNPCGreeting = true;
//BMLogger.LogError($"[Skill] Received NPC_GREETING from skill-learn NPC nid={m_skillLearnNPCNID}");
}
}
public void SendHelloToSkillLearnNPC()
{
if (m_skillLearnNPCNID != 0)
{
// C++: g_pGame->GetGameSession()->c2s_CmdNPCSevHello(m_skillLearnNPCNID);
Network.UnityGameSession.c2s_CmdNPCSevHello(m_skillLearnNPCNID);
//BMLogger.LogError($"[Skill] Sent SEVNPC_HELLO to skill-learn NPC nid={m_skillLearnNPCNID}");
}
}
public enumEvilGod GetSkillEvilGod(int skillID)
{
CECSkill skill = new CECSkill(skillID, 1);
int rank = skill.GetRank();
CECTaoistRank taoistRank = CECTaoistRank.GetTaoistRank(rank);
if (taoistRank.IsGodRank())
{
return enumEvilGod.SKILL_GOD;
}
else if (taoistRank.IsEvilRank())
{
return enumEvilGod.SKILL_EVIL;
}
else
{
return enumEvilGod.SKILL_BASE;
}
}
static CECHostPlayer TryGetHostPlayer() => CECGameRun.Instance?.GetHostPlayer();
public enumSkillLearnedState GetSkillLearnedState(int skillID)
{
CECHostPlayer host = TryGetHostPlayer();
if (host == null)
{
return ElementSkill.IsOverridden((uint)skillID)
? enumSkillLearnedState.SKILL_OVERRIDDEN
: enumSkillLearnedState.SKILL_NOT_LEARNED;
}
CECSkill pSkill = host.GetNormalSkill(skillID);
if (pSkill != null)
{
if (pSkill.GetSkillLevel() < pSkill.GetMaxLevel())
{
return enumSkillLearnedState.SKILL_LEARNED;
}
else
{
return enumSkillLearnedState.SKILL_FULL;
}
}
else
{
if (ElementSkill.IsOverridden((uint)skillID))
{
return enumSkillLearnedState.SKILL_OVERRIDDEN;
}
else
{
return enumSkillLearnedState.SKILL_NOT_LEARNED;
}
}
}
public void Initialize()
{
Initialize(null);
}
/// <param name="professionOverride">When set (anim test scene), filters catalog by this profession instead of querying host.</param>
public void Initialize(int? professionOverride)
{
// Çå¿ÕËùÓм¼ÄÜ£¬·ÀÖ¹ÒòΪ¶à¸ö½ÇÉ«µÇ¼µ¼ÖÂÖØ¸´¼ÓÔØ¼¼ÄÜ
Release();
InitAllSkillsOfCurProf(professionOverride);
FindAllNPCsOfCurProf();
HashSet<int> rootSkills = GetRootSkillSet();
InitSkillTreeHeightMap(rootSkills);
InitSkillTreeRootMap(rootSkills);
m_bInitialized = true;
// ÖØÐ´¦ÀíNPCLIST
ProcessServiceList();
}
public void ProcessServiceList()
{
if (m_npcListData == null)
{
BMLogger.LogError("CECHostSkillModel::ProcessServiceList, m_npcListData is null.");
return;
}
if (m_npcListData.Size > 0)
{
byte[] data = m_npcListData.RawBuffer;
int headerSize = Marshal.SizeOf(typeof(cmd_header));
int offset = headerSize;
int bodySize = m_npcListData.Size - offset;
byte[] bodyBytes = new byte[bodySize];
Buffer.BlockCopy(data, offset, bodyBytes, 0, bodySize);
cmd_scene_service_npc_list npcList = default;
npcList.count = GPDataTypeHelper.FromBytes<uint>(bodyBytes);
offset = sizeof(uint);
int NpcEntrySize = Marshal.SizeOf<cmd_scene_service_npc_list.NpcEntry>();
npcList.list = new cmd_scene_service_npc_list.NpcEntry[npcList.count];
for (int z = 0; z < npcList.count; z++)
{
npcList.list[z] = GPDataTypeHelper.FromBytes<cmd_scene_service_npc_list.NpcEntry>(bodyBytes, offset);
offset += NpcEntrySize;
}
//BMLogger.LogError("ProcessServiceList npcList.count:" + npcList.count);
//BMLogger.LogError("ProcessServiceList m_allProfNPCs.count:" + m_allProfNPCs.Count);
int i;
bool sawProfSkillNpcInList = false;
for (i = 0; i < npcList.count; i++)
{
int tid = npcList.list[i].tid;
//BMLogger.LogError("ProcessServiceList tid:" + tid);
if (m_allProfNPCs.Contains(tid))
{
sawProfSkillNpcInList = true;
//BMLogger.LogError("m_skillLearnNPCNID : " + m_skillLearnNPCNID);
//BMLogger.LogError("npcList.list[i].nid : " + npcList.list[i].nid);
if (m_skillLearnNPCNID != npcList.list[i].nid)
{
m_skillLearnNPCNID = npcList.list[i].nid;
m_bReceivedNPCGreeting = false; // new NPC -> need greeting again
SetCurServiceSkills(tid);
var change = new CECSkillPanelChange(CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC, 0, 0);
//NotifyObservers(change);
break;
}
else
{
// Same trainer instance as before — still refresh service skills (re-enter world / list refresh).
SetCurServiceSkills(tid);
var change = new CECSkillPanelChange(CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC, 0, 0);
break;
}
}
}
if (i == npcList.count && m_skillLearnNPCNID != 0 && !sawProfSkillNpcInList)
{
m_skillLearnNPCNID = 0;
SetCurServiceSkills(0);
var change = new CECSkillPanelChange(CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC, 0, 0);
//NotifyObservers(change);
}
// Do not Clear m_npcListData: Initialize() may run ProcessServiceList again after Release();
// clearing here left npcDataSize 0 on world re-entry. New packets replace m_npcListData in RecvNPCServiceList.
}
}
private readonly HashSet<int> m_curServiceSkills = new HashSet<int>();
public string GetSkillIcon(int skillID)
{
CECSkill skill = new CECSkill(skillID, 1);
return (skill.GetIconFile());
}
public void SetCurServiceSkills(int tid)
{
//BMLogger.LogError("SetCurServiceSkills " + tid);
m_curServiceSkills.Clear();
if (tid == 0)
return;
var pDB = ElementDataManProvider.GetElementDataMan();
// Read NPC_ESSENCE from element data
DATA_TYPE dt = default;
var dataprt = pDB.get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dataprt == null)
return;
var npcEssence = (NPC_ESSENCE)dataprt;
var dataprt2 = pDB.get_data_ptr(npcEssence.id_skill_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dataprt2 == null)
return;
var skillService = (NPC_SKILL_SERVICE)dataprt2;
// Copy all non-zero skill ids into m_curServiceSkills
foreach (int skillId in skillService.id_skills)
{
if (skillId != 0)
{ m_curServiceSkills.Add(skillId); }
}
//BMLogger.LogError("SetCurServiceSkills m_curServiceSkills count:" + m_curServiceSkills.Count);
//BMLogger.LogError("SetCurServiceSkills skillService.id_skills count:" + skillService.id_skills.Length);
}
public enumSkillFitLevelState GetSkillFitLevel(int skillID)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
BMLogger.LogError("skillID not exist in m_allProfSkills");
return default;
}
CECHostPlayer host = TryGetHostPlayer();
if (host == null)
{
return enumSkillFitLevelState.SKILL_NOT_FIT_LEVEL;
}
int maxLevel = host.GetMaxLevelSofar();
int rank = host.GetBasicProps().iLevel2;
int realmLevel = host.GetRealmLevel();
return GetSkillFitLevel(skillID, maxLevel, rank, realmLevel);
}
enumSkillFitLevelState GetSkillFitLevel(int skillID, int maxLevel, int rank, int realmLevel)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
BMLogger.LogError("skillID not exist in m_allProfSkills");
return default;
}
int skillLevel = 1; //½«ÒªÑ§Ï°µÄ¼¼Äܼ¶±ð
CECSkill pSkill = TryGetHostPlayer()?.GetNormalSkill(skillID);
if (pSkill != null)
{
skillLevel = pSkill.GetSkillLevel() + 1;
if (skillLevel > pSkill.GetMaxLevel())
{
return enumSkillFitLevelState.SKILL_NOT_FIT_LEVEL;
}
}
s = ElementSkill.Create((uint)skillID, skillLevel);
if (s.GetRequiredLevel() > maxLevel)
{
return enumSkillFitLevelState.SKILL_NOT_FIT_LEVEL;
}
// ÐÞÕæµÈ¼¶²»¹»
CECTaoistRank curTaoistRank = CECTaoistRank.GetTaoistRank(rank);
CECTaoistRank reqTaoistRank = CECTaoistRank.GetTaoistRank(s.GetRank());
if ((curTaoistRank.IsEvilRank() && reqTaoistRank.IsGodRank()) ||
(curTaoistRank.IsGodRank() && reqTaoistRank.IsEvilRank()) ||
(curTaoistRank.GetID() < reqTaoistRank.GetID()))
{
return enumSkillFitLevelState.SKILL_NOT_FIT_LEVEL;
}
// ¾³½ç²»¹»
if (s.GetRequiredRealmLevel() > realmLevel)
{
return enumSkillFitLevelState.SKILL_NOT_FIT_LEVEL;
}
return enumSkillFitLevelState.SKILL_FIT_LEVEL;
}
public int CheckLearnCondition(int skillID)
{
CECHostPlayer host = TryGetHostPlayer();
return host != null ? host.CheckSkillLearnCondition(skillID, true) : 0;
}
public StringBuilder GetSkillDescription(int skillID, int level)
{
StringBuilder tmp = new StringBuilder();
return CECSkill.GetDesc(skillID, level, tmp, 1024);
}
public int GetRequiredBook(int skillID, int level)
{
int itemId = ElementSkill.GetRequiredBook((uint)skillID, level);
return itemId;
}
public void RecvNPCServiceList(Octets Data)
{
m_npcListData = Data;
if (!m_bInitialized)
{
return;
}
ProcessServiceList();
}
private void InitSkillTreeRootMap(IEnumerable<int> rootSkills)
{
foreach (int rootSkillID in rootSkills)
{
InitializeRootOfSkillTree(rootSkillID);
}
}
public int GetSkillCurrentLevel(int skillID)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
BMLogger.LogError("skillID not exist in m_allProfSkills");
return 0;
}
CECSkill pSkill = TryGetHostPlayer()?.GetNormalSkill(skillID);
if (pSkill != null)
{
return pSkill.GetSkillLevel();
}
return 0;
}
private void InitializeRootOfSkillTree(int rootSkillID)
{
var skillRootMap = GetSkillRootMap(rootSkillID);
var toTravelSkills = new Queue<int>();
toTravelSkills.Enqueue(rootSkillID);
while (toTravelSkills.Count > 0)
{
int skillID = toTravelSkills.Dequeue();
var juniors = GetJunior(skillID);
foreach (var (id, level) in juniors)
{
int juniorSkillID = (int)id;
skillRootMap[juniorSkillID] = rootSkillID;
toTravelSkills.Enqueue(juniorSkillID);
}
}
}
private Dictionary<int, int> GetSkillRootMap(int rootSkillID)
{
var skill = m_allProfSkills[rootSkillID];
var taoistRank = CECTaoistRank.GetTaoistRank(skill.GetRank());
if (taoistRank.IsEvilRank())
return m_evilRootMap;
else if (taoistRank.IsGodRank())
return m_godRootMap;
else
return m_baseRootMap;
}
private void InitSkillTreeHeightMap(IEnumerable<int> rootSkills)
{
foreach (var rootSkillID in rootSkills)
{
m_treeHeightMap[rootSkillID] = GetSkillTreeHeight(rootSkillID);
}
}
private int GetSkillTreeHeight(int rootSkillID)
{
var juniors = GetJunior(rootSkillID);
int maxHeight = 0;
foreach (var skill in juniors)
{
int subHeight = GetSkillTreeHeight((int)skill.Key);
if (subHeight > maxHeight)
{
maxHeight = subHeight;
}
}
return 1 + maxHeight;
}
public Dictionary<uint, int> GetJunior(int skillID)
{
if (!m_allProfSkills.TryGetValue(skillID, out var skill))
{
BMLogger.LogError($"Skill {skillID} not found in m_allProfSkills");
}
var juniors = skill.GetJunior();
var ret = new Dictionary<uint, int>();
foreach (var (id, level) in juniors)
{
if (id != 0)
ret[id] = level;
}
return ret;
}
private HashSet<int> GetRootSkillSet()
{
var rootSkills = new HashSet<int>();
foreach (var kvp in m_allProfSkills)
if (kvp.Value.GetJunior().Count != 0)
rootSkills.Add(kvp.Key);
foreach (var kvp in m_allProfSkills)
foreach (var (id, level) in kvp.Value.GetJunior())
rootSkills.Remove((int)id);
return rootSkills;
}
private void FindAllNPCsOfCurProf()
{
DATA_TYPE dt = DATA_TYPE.DT_NPC_ESSENCE;
elementdataman pDB = ElementDataManProvider.GetElementDataMan();
var map = pDB.GetAllDataTypeWithType(ID_SPACE.ID_SPACE_ESSENCE, dt);
//BMLogger.LogError("Hoang Dev map Count :" + map.Length);
foreach (var obj in map)
{
NPC_ESSENCE npcEssence = (NPC_ESSENCE)obj;
if (npcEssence.id_skill_service != 0 &&
(npcEssence.combined_switch & (uint)NPC_COMBINED_SWITCH.NCS_IGNORE_DISTANCE_CHECK) != 0)
{
NPC_SKILL_SERVICE skillService = (NPC_SKILL_SERVICE)pDB.get_data_ptr(npcEssence.id_skill_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
bool profCorrect = false;
for (int i = 0; i < skillService.id_skills.Length; i++)
{
if (skillService.id_skills[i] != 0)
{
ElementSkill pSkill = ElementSkill.Create(skillService.id_skills[i], 1);
if (pSkill == null)
{
//BMLogger.LogError($"Hoang Dev pSkill is null for skill {i} :" + skillService.id_skills[i]);
continue;
}
CECHostPlayer host = TryGetHostPlayer();
if (host != null && pSkill.GetCls() == host.GetProfession())
{
// NPCǰְҵܣҪ¼NPCID
profCorrect = true;
break;
}
}
}
if (profCorrect)
{
//BMLogger.LogError("m_allProfNPCs.Add " + (int)npcEssence.id);
m_allProfNPCs.Add((int)npcEssence.id);
}
//BMLogger.LogError("Hoang Dev skillService.id_skills.Length :" + skillService.id_skills.Length);
}
}
}
public void InitAllSkillsOfCurProf()
{
InitAllSkillsOfCurProf(null);
}
public void InitAllSkillsOfCurProf(int? professionOverride)
{
// --- B1: Thu thập toàn bộ skill từ các NPC có cung cấp dịch vụ học skill ---
HashSet<uint> npcSkills = new HashSet<uint>();
{
elementdataman pDB = ElementDataManProvider.GetElementDataMan();
DATA_TYPE dt = DATA_TYPE.DT_NPC_ESSENCE;
// uint id = pDB.get_id_with_data_type(ID_SPACE.ID_SPACE_ESSENCE, dt);
var map = pDB.GetAllDataTypeWithType(ID_SPACE.ID_SPACE_ESSENCE, dt);
foreach (var obj in map)
{
NPC_ESSENCE npcEssence = (NPC_ESSENCE)obj;
if (npcEssence.id_skill_service != 0 &&
(npcEssence.combined_switch & (uint)NPC_COMBINED_SWITCH.NCS_IGNORE_DISTANCE_CHECK) != 0)
{
NPC_SKILL_SERVICE skillService = (NPC_SKILL_SERVICE)pDB.get_data_ptr(
npcEssence.id_skill_service, ID_SPACE.ID_SPACE_ESSENCE, ref dt
);
for (int i = 0; i < skillService.id_skills.Length; i++)
{
uint skillId = skillService.id_skills[i];
if (skillId != 0 &&
CECComboSkillState.Instance.GetInherentSkillByID(skillId) == null)
{
npcSkills.Add(skillId);
}
}
}
}
}
var hostPlayer = TryGetHostPlayer();
int playerProfession = professionOverride ?? (hostPlayer != null ? hostPlayer.GetProfession() : -1);
// --- B2: Duyệt tất cả skill, lọc skill theo class hiện tại của người chơi ---
uint curID = 0;
while ((curID = ElementSkill.NextSkill(curID)) != 0)
{
ElementSkill pSkill = ElementSkill.Create(curID, 1);
int cls = pSkill.GetCls();
int playerCls = playerProfession;
bool isSameClass = (cls == playerCls || cls == 255);
bool isProvidedByNPC = npcSkills.Contains(curID);
if (isSameClass && isProvidedByNPC)
{
m_allProfSkills[(int)curID] = pSkill;
if (!m_allRankProfSkills.ContainsKey(pSkill.GetRank()))
m_allRankProfSkills[pSkill.GetRank()] = new List<int>();
m_allRankProfSkills[pSkill.GetRank()].Add((int)curID);
}
}
foreach (var kvp in m_allRankProfSkills)
{
kvp.Value.Sort((lhs, rhs) =>
{
var lSkill = ElementSkill.Create((uint)lhs, 1);
var rSkill = ElementSkill.Create((uint)rhs, 1);
bool result;
if (lSkill.GetType() == (byte)skill_type.TYPE_PASSIVE &&
rSkill.GetType() != (byte)skill_type.TYPE_PASSIVE)
{
result = false;
}
else if (lSkill.GetType() != (byte)skill_type.TYPE_PASSIVE &&
rSkill.GetType() == (byte)skill_type.TYPE_PASSIVE)
{
result = true;
}
else
{
result = lSkill.GetShowOrder() < rSkill.GetShowOrder();
}
return result ? -1 : 1;
});
}
}
private void Release()
{
m_allProfSkills.Clear();
// Dọn sạch tất cả dictionary / map
m_allProfSkills.Clear();
m_allRankProfSkills.Clear();
m_evilRootMap.Clear();
m_godRootMap.Clear();
m_baseRootMap.Clear();
m_treeHeightMap.Clear();
m_allProfNPCs.Clear();
m_curServiceSkills.Clear();
m_skillLearnNPCNID = 0;
m_bInitialized = false;
}
public string GetSkillName(int skillID)
{
CECSkill skill = new CECSkill(skillID, 1);
return (skill.GetNameDisplay());
}
public bool CheckPreItem(int itemID)
{
CECHostPlayer host = TryGetHostPlayer();
return host != null && host.GetPack().FindItem(itemID) != -1;
}
public bool IsSkillServedByNPC(int skillID)
{
return m_curServiceSkills.Contains(skillID);
}
public int GetSkillSp(int skillID, int level)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
BMLogger.LogError("skillID not exist in m_allProfSkills");
return 0;
}
return ElementSkill.GetRequiredSp((uint)skillID, level);
}
public int GetSkillMoney(int skillID, int level)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
BMLogger.LogError("skillID not exist in m_allProfSkills");
return 0;
}
return ElementSkill.GetRequiredMoney((uint)skillID, level);
}
public Dictionary<uint, int> GetRequiredSkill(int skillID, int level)
{
Dictionary<uint, int> requiredSkill = new();
ElementSkill s = ElementSkill.Create((uint)skillID, level);
// giả định GetRequiredSkill() trả về List<KeyValuePair<uint,int>> hoặc IReadOnlyList<...>
Dictionary<uint, int> skills = s.GetRequiredSkill();
if (skills == null || skills.Count == 0)
return null;
foreach (var skill in skills)
{
if (skill.Key != 0)
{
requiredSkill.Add(skill.Key, skill.Value);
}
}
return requiredSkill;
}
public bool CheckPreSkillLevel(int skillID, int level)
{
if (GetSkillLearnedState(skillID) == enumSkillLearnedState.SKILL_OVERRIDDEN)
{
// Èç¹û¸ÃǰÌá¼¼Äܱ»¸²¸Ç£¬ÔòǰÌá¼¼ÄÜÒ»¶¨Âú×ã
return true;
}
return GetSkillCurrentLevel(skillID) >= level;
}
// Called when a skill is learned / 当学习新技能后调用
public void OnLearnSkill(int skillID, int skillLevel)
{
if (!m_allProfSkills.ContainsKey(skillID))
{
return;
}
// 检查学习新技能后是否有技能被覆盖 / Check if any skills are overridden after learning the new skill
bool newOverridden = false;
var juniors = GetJunior(skillID);
if (juniors.Count > 0)
{
newOverridden = true;
}
if (newOverridden)
{
CECSkillPanelChange change = new CECSkillPanelChange(
CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN,
skillID,
skillLevel);
EventBus.Publish(change);
}
else
{
CECSkillPanelChange change = new CECSkillPanelChange(
CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP,
skillID,
skillLevel);
EventBus.Publish(change);
}
}
}
public enum enumSkillFitLevelState
{
SKILL_FIT_LEVEL, // ȼ / Skill meets level, cultivation, realm requirements
SKILL_NOT_FIT_LEVEL, // ܲȼ / Skill does not meet level, cultivation, realm requirements
}
public enum enumSkillLearnedState
{
SKILL_NOT_LEARNED, // δѧϰ / Skill not learned
SKILL_LEARNED, // ѧϰ / Skill learned but not at max level
SKILL_FULL, // / Skill at max level
SKILL_OVERRIDDEN, // ѱ / Skill has been overridden
}
public enum enumEvilGod
{
SKILL_BASE, // ͨ / Normal skill
SKILL_EVIL, // ɼ / Immortal skill
SKILL_GOD, // ħ / Demonic skill
}
public struct CECSkillPanelChange
{
public enum enumChangeMask
{
CHANGE_SKILL_LEVEL_UP, // Skill level up
CHANGE_SKILL_OVERRIDDEN, // Skill overridden
CHANGE_SKILL_NPC // NPC providing skill changed
}
public enumChangeMask m_changeMask;
public int m_skillID;
public int m_skillLevel;
public CECSkillPanelChange(enumChangeMask mask, int id, int level)
{
m_changeMask = mask;
m_skillID = id;
m_skillLevel = level;
}
}
}