731 lines
28 KiB
C#
731 lines
28 KiB
C#
using Animancer;
|
|
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()
|
|
{
|
|
BMLogger.LogError("CECHostSkillModel BeforeSceneLoad Reset");
|
|
Instance = null;
|
|
}
|
|
#endif
|
|
public IReadOnlyDictionary<int, List<int>> GetAllRankProfSkills()
|
|
{
|
|
return m_allRankProfSkills;
|
|
}
|
|
public CECHostSkillModel()
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
public enumSkillLearnedState GetSkillLearnedState(int skillID)
|
|
{
|
|
CECSkill pSkill = CECGameRun.Instance.GetHostPlayer().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()
|
|
{
|
|
//BMLogger.LogError("HoangDev CECHostSkillModel Initialize called");
|
|
// Çå¿ÕËùÓм¼ÄÜ£¬·ÀÖ¹ÒòΪ¶à¸ö½ÇÉ«µÇ¼µ¼ÖÂÖØ¸´¼ÓÔØ¼¼ÄÜ
|
|
Release();
|
|
|
|
InitAllSkillsOfCurProf();
|
|
FindAllNPCsOfCurProf();
|
|
HashSet<int> rootSkills = GetRootSkillSet();
|
|
InitSkillTreeHeightMap(rootSkills);
|
|
InitSkillTreeRootMap(rootSkills);
|
|
|
|
m_bInitialized = true;
|
|
|
|
// ÖØÐ´¦ÀíNPCLIST
|
|
ProcessServiceList();
|
|
}
|
|
public void ProcessServiceList()
|
|
{
|
|
//BMLogger.LogError("HoangDev: 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.
|
|
}
|
|
//BMLogger.LogError("HoangDev: m_npcListData.Size :"+ m_npcListData.Size);
|
|
|
|
}
|
|
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;
|
|
}
|
|
int maxLevel = CECGameRun.Instance.GetHostPlayer().GetMaxLevelSofar();
|
|
int rank = CECGameRun.Instance.GetHostPlayer().GetBasicProps().iLevel2;
|
|
int realmLevel = CECGameRun.Instance.GetHostPlayer().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 = CECGameRun.Instance.GetHostPlayer().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)
|
|
{
|
|
return CECGameRun.Instance.GetHostPlayer().CheckSkillLearnCondition(skillID, true);
|
|
}
|
|
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 = CECGameRun.Instance.GetHostPlayer().GetNormalSkill(skillID);
|
|
if (pSkill != null)
|
|
{
|
|
return pSkill.GetSkillLevel();
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
if (pSkill.GetCls() == CECGameRun.Instance.GetHostPlayer().GetProfession())
|
|
{
|
|
// ��NPC������ǰְҵ���ܣ���Ҫ��¼��NPC��ID
|
|
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()
|
|
{
|
|
// --- 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- 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 = CECGameRun.Instance.GetHostPlayer().GetProfession();
|
|
|
|
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()
|
|
{
|
|
//BMLogger.LogError("HoangDev CECHostSkillModel Release called");
|
|
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)
|
|
{
|
|
return CECGameRun.Instance.GetHostPlayer().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;
|
|
}
|
|
}
|
|
}
|