From 2d85773f0eae54c14a1410b07ef6a486653d7da1 Mon Sep 17 00:00:00 2001 From: NguyenVanDat Date: Tue, 24 Feb 2026 10:57:12 +0700 Subject: [PATCH] REFACTOR CECHostPlayer separate class to partial class --- .../Scripts/Players/EC_HostMsg.cs | 400 -- Assets/Scripts/CECHostPlayer.Combat.cs | 961 ++++ Assets/Scripts/CECHostPlayer.Combat.cs.meta | 2 + Assets/Scripts/CECHostPlayer.Interaction.cs | 265 + .../Scripts/CECHostPlayer.Interaction.cs.meta | 2 + Assets/Scripts/CECHostPlayer.Inventory.cs | 1416 +++++ .../Scripts/CECHostPlayer.Inventory.cs.meta | 2 + Assets/Scripts/CECHostPlayer.Party.cs | 69 + Assets/Scripts/CECHostPlayer.Party.cs.meta | 2 + Assets/Scripts/CECHostPlayer.Pet.cs | 559 ++ Assets/Scripts/CECHostPlayer.Pet.cs.meta | 2 + .../Scripts/CECHostPlayer.PlayerProperty.cs | 79 + .../CECHostPlayer.PlayerProperty.cs.meta | 2 + Assets/Scripts/CECHostPlayer.Skill.cs | 1788 ++++++ Assets/Scripts/CECHostPlayer.Skill.cs.meta | 2 + Assets/Scripts/CECHostPlayer.World.cs | 270 + Assets/Scripts/CECHostPlayer.World.cs.meta | 2 + Assets/Scripts/CECHostPlayer.cs | 4811 +---------------- 18 files changed, 5430 insertions(+), 5204 deletions(-) create mode 100644 Assets/Scripts/CECHostPlayer.Combat.cs create mode 100644 Assets/Scripts/CECHostPlayer.Combat.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.Interaction.cs create mode 100644 Assets/Scripts/CECHostPlayer.Interaction.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.Inventory.cs create mode 100644 Assets/Scripts/CECHostPlayer.Inventory.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.Party.cs create mode 100644 Assets/Scripts/CECHostPlayer.Party.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.Pet.cs create mode 100644 Assets/Scripts/CECHostPlayer.Pet.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.PlayerProperty.cs create mode 100644 Assets/Scripts/CECHostPlayer.PlayerProperty.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.Skill.cs create mode 100644 Assets/Scripts/CECHostPlayer.Skill.cs.meta create mode 100644 Assets/Scripts/CECHostPlayer.World.cs create mode 100644 Assets/Scripts/CECHostPlayer.World.cs.meta diff --git a/Assets/PerfectWorld/Scripts/Players/EC_HostMsg.cs b/Assets/PerfectWorld/Scripts/Players/EC_HostMsg.cs index 5fbbf8c895..68641e8d5a 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_HostMsg.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_HostMsg.cs @@ -87,406 +87,6 @@ namespace BrewMonster } return 0; } - - void OnMsgHstPetOpt(ECMSG Msg) - { - - CECGameRun pGameRun = EC_Game.GetGameRun(); - int header = Convert.ToInt32(Msg.dwParam2); - switch (header) - { - case CommandID.GAIN_PET: - { - cmd_gain_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.AddPet(pCmd.slot_index, pCmd.data); - - // Print a notify - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); - if (pPet != null) - { - if (pPet.IsFollowPet() || pPet.IsCombatPet() || pPet.IsEvolutionPet()) - { - // TO DO: fix later - //pGameRun.AddFixedMessage(FIXMSG_PET_HATCH, pPet.GetName()); - } - else if (pPet.IsSummonPet()) - { - // TO DO: fix later - //pGameRun.AddFixedMessage(FIXMSG_SUMMON_PET_APPEAR, pPet.GetName()); - } - } - - break; - } - - case CommandID.FREE_PET: - { - cmd_free_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - // Print a notify - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); - if (pPet != null) - { - if (pPet.IsFollowPet() || pPet.IsCombatPet() || pPet.IsEvolutionPet()) - { - // TO DO: fix later - //pGameRun.AddFixedMessage(FIXMSG_PET_FREE, pPet.GetName()); - } - else if (pPet.IsSummonPet()) - { - // TO DO: fix later - //pGameRun.AddFixedMessage(FIXMSG_SUMMON_PET_DISAPPEAR, pPet.GetName()); - } - } - - // Remove pet from corral - m_pPetCorral.FreePet(pCmd.slot_index, pCmd.pet_id); - // Update pet shortcuts - UpdateFreedPetSC(pCmd.slot_index); - - break; - } - case CommandID.SUMMON_PET: - { - cmd_summon_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); - //ASSERT(pPet && pPet.GetTemplateID() == pCmd.pet_tid); - m_pPetCorral.SetActivePetIndex(pCmd.slot_index); - m_pPetCorral.SetActivePetNPCID(pCmd.pet_pid); - m_pPetCorral.SetActivePetLifetime(pCmd.life_time); - - if (EC_Game.GetConfigs().GetGameSettings().bPetAutoSkill) - { - for (int i = 0; i < pPet.GetSkillNum(SKILLTYPE.EM_SKILL_DEFAULT); i++) - { - PETSKILL? pSkill = pPet.GetSkill(SKILLTYPE.EM_SKILL_DEFAULT, i); - if (pSkill != null && EC_Game.IsPetAutoSkill(pSkill.Value.idSkill)) - pPet.AddAutoSkill(pSkill.Value.idSkill); - } - } - - // TO DO: fix later - //OnPetSays(pCmd.pet_tid, pCmd.pet_pid, CECPetWords::TW_SUMMON); - //if (pPet.IsCombatPet() || pPet.IsSummonPet() || pPet.IsEvolutionPet()) - // CDlgQuickBarPet::ResetAutoCastSkill(); - break; - } - case CommandID.RECALL_PET: - { - cmd_recall_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - //ASSERT(pCmd.slot_index == m_pPetCorral.GetActivePetIndex()); - - int tid = pCmd.pet_id; - int nid = m_pPetCorral.GetActivePetNPCID(); - - // 宠物有话说 - switch (pCmd.reason) - { - case (char)PET_RECALL_REASON.PET_RECALL_DEFAULT: - //OnPetSays(tid, nid, CECPetWords::TW_RECALL); - break; - - case (char)PET_RECALL_REASON.PET_RECALL_DEATH: - //OnPetSays(tid, nid, CECPetWords::TW_DEAD); - break; - - case (char)PET_RECALL_REASON.PET_RECALL_LIFE_EXHAUST: - //OnPetSays(tid, nid, CECPetWords::TW_DISAPPEAR); - break; - - case (char)PET_RECALL_REASON.PET_RECALL_SACRIFICE: - //OnPetSays(tid, nid, CECPetWords::TW_SACRIFICE); - break; - } - - CECPetData pPet = m_pPetCorral.GetActivePet(); - if (pPet != null) - pPet.OnPetDead(); - - m_pPetCorral.SetActivePetIndex(-1); - m_pPetCorral.SetActivePetNPCID(0); - m_bPetInSanctuary = false; - break; - } - case CommandID.PLAYER_START_PET_OP: - { - cmd_player_start_pet_op pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int iDoWhat; - if (pCmd.op == 0) - iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_SUMMONPET; - else if (pCmd.op == 1) - iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_RECALLPET; - else if (pCmd.op == 2) - iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_BANISHPET; - else if (pCmd.op == 3) - iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_RESTOREPET; - else - iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_UNKNOWN; - - m_PetOptCnt.SetPeriod(pCmd.delay * 50); - m_PetOptCnt.Reset(); - - CECHPWorkConcentrate pWork = (CECHPWorkConcentrate)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE); - pWork.SetDoWhat(iDoWhat); - m_pWorkMan.StartWork_p1(pWork); - break; - } - case CommandID.PLAYER_STOP_PET_OP: - { - if (IsOperatingPet() != 0) - m_pWorkMan.FinishRunningWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE); - - break; - } - case CommandID.PET_RECEIVE_EXP: - { - cmd_pet_receive_exp pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); - if (pPet != null) - { - //ASSERT(pPet.GetTemplateID() == pCmd.pet_id); - pPet.AddExp(pCmd.exp); - } - - break; - } - case CommandID.PET_LEVELUP: - { - cmd_pet_levelup pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); - if (pPet != null) - { - //ASSERT(pPet.GetTemplateID() == pCmd.pet_id); - pPet.LevelUp(pCmd.level, pCmd.exp); - } - - //pGameRun.AddFixedMessage(FIXMSG_PET_LEVELUP, pCmd.level); - break; - } - case CommandID.PET_ROOM: - { - cmd_pet_room pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.UpdatePets(pCmd, (byte[])Msg.dwParam1); - - CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); - - //if (pGameUI.GetDialog("Win_Teach").IsShow()) - // { - // //pGameUI.UpdateTeach(); - // } - - break; - } - case CommandID.PET_ROOM_CAPACITY: - { - cmd_pet_room_capacity pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.MagnifyPetSlots((int)pCmd.capacity); - - if (m_pPetCorral.HasInit()) - { - //pGameRun.AddFixedMessage(FIXMSG_PET_ROOM_SIZE, pCmd.capacity); - } - else - m_pPetCorral.SetHasInit(true); - break; - } - case CommandID.PET_HONOR_POINT: - { - cmd_pet_honor_point pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.index); - if (pPet != null) - pPet.SetIntimacy(pCmd.cur_honor_point); - - break; - } - case CommandID.PET_HUNGER_GAUGE: - { - cmd_pet_hunger_gauge pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.index); - if (pPet != null) - pPet.SetHunger(pCmd.cur_hunge_gauge); - - break; - } - case CommandID.PET_DEAD: - { - cmd_pet_dead pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); - if (pPet != null) - { - pPet.SetHPFactor(0.0f); - pPet.SetHP(0); - pPet.OnPetDead(); - } - - //pGameRun.AddFixedMessage(FIXMSG_PET_DEAD); - break; - } - case CommandID.PET_REVIVE: - { - cmd_pet_revive pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); - if (pPet != null) - pPet.SetHPFactor(pCmd.hp_factor); - - break; - } - case CommandID.PET_HP_NOTIFY: - { - cmd_pet_hp_notify pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); - if (pPet != null) - { - int lastHP = pPet.GetHP(); - - pPet.SetHPFactor(pCmd.hp_factor); - pPet.SetHP(pCmd.cur_hp); - - pPet.SetMPFactor(pCmd.mp_factor); - pPet.SetMP(pCmd.cur_mp); - - // If HP is too low, popup a warning on pet's head - int iLimit = (int)(pPet.CalcMaxHP() * 0.3f); - if (pCmd.cur_hp < lastHP && lastHP != 0 && pCmd.cur_hp < iLimit) - { - CECNPC pNPC = EC_Game.GetGameRun().GetWorld().GetNPCMan().GetNPC(m_pPetCorral.GetActivePetNPCID()); - if (pNPC && pNPC.GetMasterID() == GetCharacterID()) - { - //pNPC.BubbleText(CECNPC::BUBBLE_HPWARN, 0); - } - } - } - - break; - } - case CommandID.PET_AI_STATE: - { - cmd_pet_ai_state pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - // 宠物有话说 - CECPetData pPetData = m_pPetCorral.GetActivePet(); - if (pPetData != null) - { - int tid = pPetData.GetTemplateID(); - int nid = m_pPetCorral.GetActivePetNPCID(); - if (m_pPetCorral.GetMoveMode() != pCmd.move) - { - switch (pCmd.move) - { - case (byte)CECPetCorral.ePet_MovingMode.MOVE_FOLLOW: - { - //OnPetSays(tid, nid, CECPetWords::TW_FOLLOW); - break; - } - case (byte)CECPetCorral.ePet_MovingMode.MOVE_STAND: - { - //OnPetSays(tid, nid, CECPetWords::TW_STOP); - break; - } - } - } - if (m_pPetCorral.GetAttackMode() != pCmd.attack) - { - switch (pCmd.attack) - { - case (byte)CECPetCorral.ePet_AttackingMode.ATK_DEFENSE: - //OnPetSays(tid, nid, CECPetWords::TW_DEFENSIVE); - break; - - case (byte)CECPetCorral.ePet_AttackingMode.ATK_POSITIVE: - //OnPetSays(tid, nid, CECPetWords::TW_OFFENSIVE); - break; - - case (byte)CECPetCorral.ePet_AttackingMode.ATK_PASSIVE: - //OnPetSays(tid, nid, CECPetWords::TW_PASSIVE); - break; - } - } - } - - m_pPetCorral.SetMoveMode(pCmd.move); - m_pPetCorral.SetAttackMode(pCmd.attack); - break; - } - case CommandID.PET_SET_COOLDOWN: - { - cmd_pet_set_cooldown pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.pet_index); - if (pPet != null) - pPet.SetSkillCoolTime(pCmd.cooldown_index, pCmd.cooldown_time); - - break; - } - - case CommandID.SUMMON_PLANT_PET: - { - int size = Marshal.SizeOf(); - if (((byte[])Msg.dwParam1).Length >= size) - { - cmd_summon_plant_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.PlantPetEnter(pCmd); - } - break; - } - - case CommandID.PLANT_PET_DISAPPEAR: - { - int size = Marshal.SizeOf(); - if (((byte[])Msg.dwParam1).Length >= size) - { - cmd_plant_pet_disapper pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.PlantPetDisappear(pCmd); - } - break; - } - - case CommandID.PLANT_PET_HP_NOTIFY: - { - int size = Marshal.SizeOf(); - if (((byte[])Msg.dwParam1).Length >= size) - { - cmd_plant_pet_hp_notify pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pPetCorral.PlantPetInfo(pCmd); - } - break; - } - - case CommandID.PET_PROPERTY: - { - cmd_pet_property pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - CECPetData pPet = m_pPetCorral.GetPetData(pCmd.pet_index); - if (pPet != null) - { - pPet.SetExtendProps(pCmd.prop); - } - break; - } - case CommandID.PET_REBUILD_INHERIT_START: - case CommandID.PET_REBUILD_INHERIT_INFO: - case CommandID.PET_REBUILD_INHERIT_END: - case CommandID.PET_EVOLUTION_DONE: - case CommandID.PET_REBUILD_NATURE_START: - case CommandID.PET_REBUILD_NATURE_INFO: - case CommandID.PET_REBUILD_NATURE_END: - { - CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); - if (pGameUI != null) - { - //((CDlgPreviewPetRebuild*)pGameUI.GetDialog("Win_PreviewPet")).OnServerNotify(Msg.dwParam2, (void*)Msg.dwParam1); - } - break; - } - - default: - break; - } - } - void OnMsgHstSetPlayerLimit(ECMSG Msg) - { - cmd_set_player_limit pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - if (pCmd.index >= 0 && pCmd.index < (int)PLAYER_LIMIT.PLAYER_LIMIT_MAX) - m_playerLimits[pCmd.index] = (pCmd.b != 0); - } } } diff --git a/Assets/Scripts/CECHostPlayer.Combat.cs b/Assets/Scripts/CECHostPlayer.Combat.cs new file mode 100644 index 0000000000..dcdaa842df --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Combat.cs @@ -0,0 +1,961 @@ +锘縰sing BrewMonster.Managers; +using BrewMonster.Network; +using BrewMonster.Scripts; +using BrewMonster.Scripts.World; +using CSNetwork; +using CSNetwork.GPDataType; +using System; +using UnityEngine; +using static BrewMonster.Scripts.CECHPWork; +using static CECPlayerWrapper; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + public void OnMsgHstAttackResult(ECMSG Msg) + { + byte[] data = Msg.dwParam1 as byte[]; + cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); + + int iAttackTime = 0; + TurnFaceTo(pCmd.idTarget); + + PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50, + ref iAttackTime); + + if (iAttackTime != 0) + { + if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork) + { + pCurWork.SetIdleTime(iAttackTime); + } + } + } + + void OnMsgHstAttacked(ECMSG Msg) + { + var m_pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer; + cmd_host_attacked pCmd = GPDataTypeHelper.FromBytes(Msg.dwParam1 as byte[]); + + if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f) + { + /* char cEquip = (char)(pCmd.cEquipment & 0x7f); + CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack.GetItem(cEquip); + if (pEquip) + pEquip.AddCurEndurance(ARMOR_RUIN_SPEED);*/ + } + + // The host player is attacked, we should make an effect here + if (GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker)) + { + EC_ElsePlayer pAttacker = m_pPlayerMan.GetElsePlayer(pCmd.idAttacker); + if (pAttacker) + { + if (!pAttacker.IsDead()) + { + // Face to target + pAttacker.TurnFaceTo(GetPlayerInfo().cid); + } + + int useless_attacktime = 0; + pAttacker.PlayAttackEffect(GetCharacterID(), 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, + pCmd.speed * 50, ref useless_attacktime); + pAttacker.EnterFightState(); + } + } + else if (GPDataTypeHelper.ISNPCID(pCmd.idAttacker)) + { + CECNPC pAttacker = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idAttacker); + if (pAttacker) + { + pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed); + } + } + + //CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker); + } + + private void OnMsgHstHurtResult(ECMSG Msg) + { + //BMLogger.LogError("HoangDev : OnMsgHstHurtResult"); + /* int cmd = Convert.ToInt32(Msg.dwParam2); + if (cmd == CommandID.BE_HURT) + { + cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1; + if (pCmd.damage != 0) + Damaged(pCmd.damage); + } + else if (cmd == CommandID.HURT_RESULT) + { + cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1; + if (pCmd.target_id == m_PlayerInfo.cid) + return; // Host himself will receive BE_HURT, so ignore this. + + if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id)) + { + CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id); + if (pTarget) + pTarget.Damaged(pCmd.damage); + } + else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id)) + { + CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id); + if (pTarget) + pTarget.Damaged(pCmd.damage); + } + }*/ + } + + private void OnMsgHstStartAttack(in ECMSG Msg) + { + cmd_host_start_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + // ASSERT(pCmd); + + // test code... + // g_pGame.GetRTDebug().OutputNotifyMessage(RTDCOL_WARNING, _AL("start attack !")); + + // Check whether target is the one that we have selected + if (m_idSelTarget != pCmd.idTarget) + // g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Target has changed !")); + + // If target turn to be un-attackable, cancel action + if (AttackableJudge(pCmd.idTarget, true) == 0) + { + UnityGameSession.c2s_CmdCancelAction(); + // g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Cannel attacking !")); + return; + } + + // Synchronize ammo amount + // CECIvtrItem* pItem = m_pEquipPack.GetItem(EQUIPIVTR_PROJECTILE); + // if (pItem) + // { + // if (!pCmd.ammo_remain) + // m_pEquipPack.SetItem(EQUIPIVTR_PROJECTILE, NULL); + // else + // pItem.SetAmount(pCmd.ammo_remain); + // } + + CECHPWorkMelee pWork = (CECHPWorkMelee)m_pWorkMan.CreateWork(Host_work_ID.WORK_HACKOBJECT); + m_pWorkMan.StartWork_p1(pWork); + + m_bMelee = true; + // AP_ActionEvent(AP_EVENT_STARTMELEE); + } + + private void OnMsgHstStopAttack(in ECMSG Msg) + { + // using namespace S2C; + // + m_bMelee = false; + // + // // if there is an attack event currently, we should let it fire now. + ClearComActFlagAllRankNodes(true); + + cmd_host_stop_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + // ASSERT(pCmd); + + /* If attack stopped for target is leave too far, trace it and continue + attacking. Stop reason defined as below: + + 0x00: attack is canceled or host want to do some other things. + 0x01: unable to attack anymore (no ammo, weapon is broken etc.) + 0x02: invalid target (target missed or died) + 0x04: target is out of range + */ + if ((pCmd.iReason & 0x04) != 0) + { + if (!m_pWorkMan.IsMovingToPosition() && + !m_pWorkMan.IsTracing()) + { + if (CmdNormalAttack(false, false, 0, -1)) //m_pComboSkill != NULL + { + // AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); + } + else + { + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + } + else + { + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + } + else + { + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); + // AP_ActionEvent(AP_EVENT_STOPMELEE); + } + + // #ifdef _SHOW_AUTOPOLICY_DEBUG + // a_LogOutput(1, "Stop Attack, Reason = %d", pCmd.iReason); + // #endif + } + + private void OnMsgHstSkillResult(ECMSG Msg) + { + cmd_host_skill_attack_result pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + int refFake = 0; + PlayAttackEffect(pCmd.idTarget, pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag, + pCmd.attack_speed * 50, ref refFake, pCmd.section); + } + + private void OnMsgPlayerCastSkill(ECMSG Msg) + { + bool bDoOtherThing = false; + int idTarget = 0; + + bool bActionStartSkill = false; + int iActionTime = 1000; + CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); + + switch (Convert.ToInt32(Msg.dwParam2)) + { + case CommandID.OBJECT_CAST_SKILL: + { + cmd_object_cast_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + if (m_pCurSkill != null) + { + m_pCurSkill.EndCharging(); + } + + m_pCurSkill = GetPositiveSkillByID(pCmd.skill); + if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill); + if (m_pCurSkill == null) + m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill); + if (m_pCurSkill == null) + { + Debug.Assert(m_pCurSkill != null, "Current skill should not be null"); + return; + } + + if (m_pCurSkill.IsChargeable()) + m_pCurSkill.StartCharging(pCmd.time); + + int iWaitTime = -1; + if (m_pCurSkill.GetExecuteTime() >= 0) + iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); + + CECHPWorkSpell pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(Host_work_ID.WORK_SPELLOBJECT); + + pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); + m_pWorkMan.StartWork_p1(pWork); + + // Start time counter for some type skill + // 涓烘煇浜涚被鍨嬬殑鎶鑳藉惎鍔ㄦ椂闂磋鏁板櫒 + if (!m_pCurSkill.IsChargeable()) + { + int iTime = pCmd.time; + if (iTime < 10) iTime = 10; // a_ClampFloor + m_IncantCnt.SetPeriod(iTime); + m_IncantCnt.Reset(); + } + else + { + // make sure the counter is correct shown + // 纭繚璁℃暟鍣ㄦ纭樉绀 + m_IncantCnt.Reset(true); + } + + m_bSpellDSkill = false; + + TurnFaceTo(pCmd.target); + + m_idCurSkillTarget = pCmd.target; + PlaySkillCastAction(m_pCurSkill.GetSkillID()); + + bActionStartSkill = true; + iActionTime = iWaitTime; + + // Special logging for return-to-town skill (167) + // 鍥炲煄鎶鑳(167)鐨勭壒娈婃棩蹇 + if (m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL) + { + Debug.Log( + $"Return-to-town skill (167) cast - State2 should trigger SetReturntown(1) on server"); + } + + break; + } + case CommandID.SKILL_PERFORM: + { + // Skill perform + // 鎶鑳芥墽琛 + m_pPrepSkill = null; + + if (m_pCurSkill != null && m_pCurSkill.IsDurative()) + m_bSpellDSkill = true; + + // Special handling for return-to-town skill (167) + // 鍥炲煄鎶鑳(167)鐨勭壒娈婂鐞 + // When skill 167 reaches State2, server calls SetReturntown(1) which should trigger MSG_HST_GOTO + // 褰撴妧鑳167鍒拌揪State2鏃讹紝鏈嶅姟鍣ㄨ皟鐢⊿etReturntown(1)锛岃繖搴旇瑙﹀彂MSG_HST_GOTO + if (m_pCurSkill != null && m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL) + { + Debug.Log($"Skill 167 (Return to Town) performed - waiting for MSG_HST_GOTO from server"); + } + + break; + } + case CommandID.HOST_STOP_SKILL: + { + m_pPrepSkill = null; + + CECSkill pSkillToMatch = m_pCurSkill; + if (m_pCurSkill != null) + { + ClearComActFlagAllRankNodes(true); + + if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || + m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) + { + bDoOtherThing = true; + idTarget = m_idCurSkillTarget; + } + + m_pCurSkill.EndCharging(); + m_pCurSkill = null; + } + + AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL); + if (pSkillToMatch != null) + { + // m_pWorkMan涓殑褰撳墠浠讳綍Work涓烘渶楂樹紭鍏堢骇鎴栥佹垨 CECHPWorkSpell 澶勪簬鏈楂樹紭鍏堢骇涓旈槦鍒椾腑鏈塂elay鏃堕棿 + // 姝ゆ椂姝ゅ鏃犳硶鍑嗙‘鍖归厤锛岃屽鑷寸殑 CECHPWorkSpell 鎵ц鏃跺皢钀藉悗浜庡叾瀹 CECHPWorkSpell 鎵ц鏈熼棿灏嗘棤娉曞搷搴 + // 鍦ㄨ繖绉嶆柟娉曟墽琛屽畬鎴愬悗锛屾垜浠娇鐢ㄥ洖鍩庢満鍒舵潵 + // If the current Work in m_pWorkMan is the highest priority or CECHPWorkSpell is at the highest priority and there is Delay time in the queue + // At this point, it cannot be accurately matched, causing the CECHPWorkSpell execution to lag behind other CECHPWorkSpell execution and cannot respond + // After this method is executed, we use the return to city mechanism + m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); + } + + StopSkillAttackAction(); + + m_idCurSkillTarget = 0; + break; + } + case CommandID.SELF_SKILL_INTERRUPTED: + { + // Skill interrupted + // 鎶鑳借鎵撴柇 + int skill_id = 0; + m_pPrepSkill = null; + + CECSkill + pSkillToMatch = m_pCurSkill; // 淇濆瓨鎸囬拡鍊硷紝鐢ㄥ湪鍚庨潰鍑芥暟璋冪敤涓 | Save pointer value for later function call + if (m_pCurSkill != null) + { + skill_id = m_pCurSkill.GetSkillID(); + + ClearComActFlagAllRankNodes(false); + + if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || + m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) + { + bDoOtherThing = true; + idTarget = m_idCurSkillTarget; + } + + m_pCurSkill.EndCharging(); + m_pCurSkill = null; + } + + m_idCurSkillTarget = 0; + + + if (pSkillToMatch != null) + { + // 閫昏緫鍚 HOST_STOP_SKILL 鍒嗘敮澶勭悊 | Logic same as HOST_STOP_SKILL branch + m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); + } + + StopSkillCastAction(); + + // Print a notify message + // 鎵撳嵃鎻愮ず娑堟伅 + //EC_Game.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT); + + AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL); + + // 閫氱煡绛栫暐鎶鑳借鎵撴柇 | Notify policy that skill is interrupted + CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id); + break; + } + case CommandID.OBJECT_CAST_INSTANT_SKILL: + { + // Cast instant skill + // 鏂芥斁鍗虫椂鎶鑳 + cmd_object_cast_instant_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + CECSkill pSkill = GetPositiveSkillByID(pCmd.skill); + if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); + if (pSkill == null) + { + Debug.Assert(pSkill != null, "Skill should not be null"); + return; + } + + if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) + TurnFaceTo(pCmd.target); + + PlaySkillCastAction(pSkill.GetSkillID()); + bActionStartSkill = true; + break; + } + case CommandID.OBJECT_CAST_POS_SKILL: + { + // Cast position skill (target position instead of target object) + // 鏂芥斁浣嶇疆鎶鑳斤紙鐩爣浣嶇疆鑰屼笉鏄洰鏍囧璞★級 + cmd_object_cast_pos_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + CECSkill pSkill = GetNormalSkill(pCmd.skill); + if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); + if (pSkill == null) + { + Debug.Assert(pSkill != null, "Skill should not be null"); + break; + } + + TurnFaceTo(pCmd.target); + + if (pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SLEF && + pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SELFSPHERE && + (pSkill.GetSkillID() == 1095 || // 鐬奖鐬柀 | Shadow instant slash + pSkill.GetSkillID() == 1278 || // 榄斅风灛褰辩灛鏂 | Demon Shadow instant slash + pSkill.GetSkillID() == 1279 || // 濡栫灛褰辩灛鏂 | Monster Shadow instant slash + pSkill.GetSkillID() == 2313)) + { + A3DVECTOR3 vPos = pCmd.pos; + if (!IsPosCollideFree(vPos)) + { + // Add a little height to ensure player's AABB won't embed with building + // 娣诲姞涓鐐归珮搴︿互纭繚鐜╁鐨凙ABB涓嶄細宓屽叆寤虹瓚鐗 + vPos += new A3DVECTOR3(0, 1, 0) * 0.1f; + } + + // Ensure we are not under ground + // 纭繚鎴戜滑涓嶅湪鍦颁笅 + A3DVECTOR3 vNormal = new A3DVECTOR3(); + float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal); + if (vPos.y < vTerrainHeight) + vPos.y = vTerrainHeight; + + SetPos(EC_Utility.ToVector3(vPos)); + + m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0); + m_CDRInfo.fYVel = 0.0f; + m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0); + ResetJump(); + + m_MoveCtrl.SetHostLastPos(vPos); + m_MoveCtrl.SetLastSevPos(vPos); + + // Update camera + // 鏇存柊鐩告満 + //UpdateFollowCamera(false, 10); + } + else + { + CECHPWorkFMove pWork = + (CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLASHMOVE); + + // 妫鏌ユ妧鑳芥墽琛屾椂闂达紝闃叉鍑虹幇娴偣鏁0锛屽嚭鐜伴敊璇 | Check skill execute time to prevent float 0 error + int nExecuteTime = pSkill.GetExecuteTime(); + if (nExecuteTime < 50) nExecuteTime = 50; // a_ClampFloor + + if (pSkill.GetSkillID() == 1145 || // 鍒哄鐨勭灛绉绘妧鑳斤紝闇瑕佸鍔犲湴闈㈡晥鏋1145锛氱櫨姝ョ┛鏉ㄧ灛鏂 | Assassin teleport skill + pSkill.GetSkillID() == 1314 || // 榄斅风櫨姝ョ┛鏉ㄧ灛鏂 | Demon hundred steps instant slash + pSkill.GetSkillID() == 1315 || // 濡柭风櫨姝ョ┛鏉ㄧ灛鏂 | Monster hundred steps instant slash + pSkill.GetSkillID() == 1362 || // 褰遍亖鍥炴潹 | Shadow escape return + pSkill.GetSkillID() == 1690 || // 褰遍亖榄斅峰洖鏉 | Shadow escape demon return + pSkill.GetSkillID() == 1691 || // 褰遍亖濡栧洖鏉 | Shadow escape monster return + pSkill.GetSkillID() == 1845 || // 鏄熸箹涔嬬嫄路鐬Щ鎶鑳 | Star Lake Fox teleport + pSkill.GetSkillID() == 1844 || // 鏄熸箹涔嬬嫄路鐬Щ鎶鑳 | Star Lake Fox teleport + pSkill.GetSkillID() == 1815 || // 濡栫簿 椋 | Fairy fly + pSkill.GetSkillID() == 2272 || // 涓姝ョ櫥澶 | One step to heaven + pSkill.GetSkillID() == 2315 || // 鐧炬绌挎潹鐬柀 | Hundred steps instant slash + pSkill.GetSkillID() == 2285 || // 鍥炴潹 | Return + pSkill.GetSkillID() == 2340 || // 绐佽 | Raid + pSkill.GetSkillID() == 2341 || // 绐佽 | Raid + pSkill.GetSkillID() == 2342 || // 绐佽 | Raid + pSkill.GetSkillID() == 2553 || // 椋炵闆 | Arrow rain + pSkill.GetSkillID() == 2740 || // 榄斅烽绠洦 | Demon arrow rain + pSkill.GetSkillID() == 2741 || // 濡栭绠洦 | Monster arrow rain + pSkill.GetSkillID() == 2559 || // 闂數 | Lightning + pSkill.GetSkillID() == 2752 || // 榄斅烽棯鐢 | Demon lightning + pSkill.GetSkillID() == 2753) // 濡栭棯鐢 | Monster lightning + { + A3DVECTOR3 vPos = pCmd.pos; + if (!IsPosCollideFree(vPos)) + { + // Add a little height to ensure player's AABB won't embed with building + // 娣诲姞涓鐐归珮搴︿互纭繚鐜╁鐨凙ABB涓嶄細宓屽叆寤虹瓚鐗 + vPos += new A3DVECTOR3(0, 1, 0) * 0.1f; + } + + // Ensure we are not under ground + // 纭繚鎴戜滑涓嶅湪鍦颁笅 + A3DVECTOR3 vNormal = new A3DVECTOR3(); + float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal); + if (vPos.y < vTerrainHeight) + vPos.y = vTerrainHeight; + + m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0); + m_CDRInfo.fYVel = 0.0f; + m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0); + ResetJump(); + + pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID()); + } + else + { + if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SLEF || + pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SELFSPHERE) + { + m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal; + } + + pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0); + } + + m_pWorkMan.StartWork_p2(pWork); + iActionTime = nExecuteTime; + } + + bActionStartSkill = true; + break; + } + case CommandID.PLAYER_CAST_RUNE_SKILL: + { + // Cast rune skill (item skill) + // 鏂芥斁绗︽枃鎶鑳斤紙鐗╁搧鎶鑳斤級 + cmd_player_cast_rune_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + if (m_pTargetItemSkill != null) + { + // Delete old target item skill + m_pTargetItemSkill = null; + } + + m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); + if (m_pTargetItemSkill == null) + { + Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null"); + return; + } + + m_pCurSkill = m_pTargetItemSkill; + + if (m_pCurSkill.IsChargeable()) + m_pCurSkill.StartCharging(pCmd.time); + + int iWaitTime = -1; + if (m_pCurSkill.GetExecuteTime() >= 0) + iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); + + CECHPWorkSpell pWork = + (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT); + pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); + m_pWorkMan.StartWork_p1(pWork); + + // Start time counter for some type skill + // 涓烘煇浜涚被鍨嬬殑鎶鑳藉惎鍔ㄦ椂闂磋鏁板櫒 + if (!m_pCurSkill.IsChargeable()) + { + int iTime = pCmd.time; + if (iTime < 10) iTime = 10; // a_ClampFloor + m_IncantCnt.SetPeriod(iTime); + m_IncantCnt.Reset(); + } + else + { + // make sure the counter is correct shown + // 纭繚璁℃暟鍣ㄦ纭樉绀 + m_IncantCnt.Reset(true); + } + + m_bSpellDSkill = false; + + TurnFaceTo(pCmd.target); + + m_idCurSkillTarget = pCmd.target; + PlaySkillCastAction(m_pCurSkill.GetSkillID()); + + bActionStartSkill = true; + iActionTime = iWaitTime; + Debug.Log($"Cast rune skill({m_pCurSkill.GetSkillID()})"); + break; + } + case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: + { + // Cast instant rune skill + // 鏂芥斁鍗虫椂绗︽枃鎶鑳 + cmd_player_cast_rune_instant_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + Debug.Assert(pCmd.caster == m_PlayerInfo.cid); + + if (m_pTargetItemSkill != null) + { + // Delete old target item skill + m_pTargetItemSkill = null; + } + + m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); + if (m_pTargetItemSkill == null) + { + Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null"); + return; + } + + if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) + TurnFaceTo(pCmd.target); + + PlaySkillCastAction(m_pTargetItemSkill.GetSkillID()); + bActionStartSkill = true; + break; + } + case CommandID.ERROR_MESSAGE: + bDoOtherThing = true; + break; + + default: + Debug.Assert(false, "Unknown message type in OnMsgPlayerCastSkill"); + break; + } + + if (bActionStartSkill) + AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STARTSKILL, iActionTime); + + if (bDoOtherThing) + { + if (m_pComboSkill != null && !m_pComboSkill.IsStop()) + { + // Continue combo skill + // 缁х画杩炲嚮鎶鑳 + if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled()) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, 0, + m_pComboSkill.GetGroupIndex()); + else + m_pComboSkill.Continue(false); + } + else + { + if (idTarget != 0 && idTarget != m_PlayerInfo.cid) + NormalAttackObject(idTarget, true); + } + } + } + + void OnMsgHstTargetIsFar(ECMSG Msg) + { + // TO DO: fix later + //if(CmdNormalAttack(true, m_pComboSkill != null, 0, -1) ) + // AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); + + if (CmdNormalAttack(true, false, 0, -1)) + { + //AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); + } + } + + private void OnMsgHstDied(in ECMSG msg) + { + // Mark host player as corpse so CECPlayer.IsDead() returns true + m_dwStates |= (uint)PlayerNPCState.GP_STATE_CORPSE; + + EventBus.PublishChannel(GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true)); + PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE); + if (PopupManager.Instance != null) + { + PopupManager.Instance.OnPlayerDied(); + } + } + + private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false) + { + if (idTarget == 0 || idTarget == m_PlayerInfo.cid) + { + // We should have check target isn't dead + return false; + } + + //if (!EC_Game.GetGameRun().GetWorld().GetObject(idTarget, 1)) + // return false; + bool bStartNewWork = false; + + bool bUseAutoPF = false; + //CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); + //if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) + //bUseAutoPF = true; + + CECHPWorkTrace pWorkTrace = null; + CECHPWork pWork = null; + if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) != null) + { + pWorkTrace = pWork as CECHPWorkTrace; + } + else if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT)) != null) + { + if ((pWork as CECHPWorkMelee).GetTarget() == idTarget) + return false; // Host is attacking the target + + pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + bStartNewWork = true; + } + else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) + { + pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + bStartNewWork = true; + } + + if (pWorkTrace != null) + { + pWorkTrace.SetTraceTarget( + pWorkTrace.CreatTraceTarget(idTarget, CECHPWorkTrace.Trace_reason.TRACE_ATTACK, bForceAttack), + bUseAutoPF); + pWorkTrace.SetMoveCloseFlag(bMoreClose); + + if (bStartNewWork) + m_pWorkMan.StartWork_p1(pWorkTrace); + return true; + } + + return false; + } + + public int AttackableJudge(int idTarget, bool bForceAttack) + { + if (CannotAttack()) + return 0; + + //if (CDlgAutoHelp::IsAutoHelp()) + // return 0; + + if (idTarget == 0 || idTarget == m_PlayerInfo.cid) + return -1; + + CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); + if (!pObject) + return -1; + + // If target is pet, it's attacked possibility depends on it's monster + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = (CECNPC)pObject; + int idMaster = pNPC.GetMasterID(); + if (idMaster != 0) + { + // master驴脡脛脺脢脟hostplayer + if (idMaster == m_PlayerInfo.cid) + return 0; + + //// Follow pet cannot be attacked + //if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet()) + // return 0; + + idTarget = idMaster; + pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); + if (!pObject) + return -1; + } + } + + int iRet = 0; + + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = (CECNPC)pObject; + + // If this npc is host's pet, cannot be attacked + if (pNPC.GetMasterID() == m_PlayerInfo.cid) + return 0; + + // If it's a pet and can not be attacked, pet can be attacked only if it's a fighting pet + //if (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked()) + // return 0; + + if (IsInBattle()) // Host is in battle + { + if (InSameBattleCamp(pNPC)) + iRet = 0; + else + { + if (pNPC.IsMonsterNPC()) + iRet = 1; + else if (pNPC.IsServerNPC() && + (IsInFortress() || + pNPC.GetRoleInBattle() == 8)) // 露脭路镁脦帽脨脥NPC碌脛鹿楼禄梅拢卢掳茂脜脡禄霉碌脴禄貌鲁脟脮陆脢卤驴脡脫脙 + iRet = 1; + else + iRet = 0; + } + } + else if (pNPC.IsServerNPC()) + { + // In sanctuary we cannot attack NPCs + if (!IsPVPOpen() || m_bInSanctuary || !bForceAttack) + iRet = 0; + else + iRet = 1; + } + else // Is monster + { + iRet = 1; + } + + if (iRet == 1 && pNPC.GetOwnerFaction() > 0) + { + // 脮毛露脭掳茂脜脡 PVP 脮陆脮霉脰脨陆没脰鹿虏驴路脰鹿楼禄梅 + if (GetFactionID() == pNPC.GetOwnerFaction() || // 虏禄鹿楼禄梅脥卢掳茂鹿脰 + pNPC.IsFactionPVPMineCar() && !CanAttackFactionPVPMineCar() || // 脦脼路篓脭脵鹿楼禄梅脣没掳茂驴贸鲁碌脟茅驴枚 + pNPC.IsFactionPVPMineBase() && !CanAttackFactionPVPMineBase()) + { + // 脦脼路篓脭脵鹿楼禄梅脣没掳茂麓忙驴贸碌茫脟茅驴枚 + iRet = 0; + } + } + } + // TO DO: fix later + //else if (GPDataTypeHelper.ISPLAYERID(idTarget)) + //{ + // // Check duel at first + // if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) + // return 1; + // else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) + // return 0; + + // // In sanctuary we cannot attack other players + // if (m_bInSanctuary) + // return 0; + + // //ASSERT(pObject.GetClassID() == CECObject::OCID_ELSEPLAYER); + // EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject; + // ROLEBASICPROP bp = pPlayer.GetBasicProps(); + // EC_GAME_SETTING gs = g_pGame.GetConfigs().GetGameSettings(); + + // if (m_pvp.bFreePVP) + // { + // if (IsTeamMember(idTarget)) + // return 0; + + // // In free pvp mode, for example, host is in arena. + // if (bForceAttack) + // iRet = 1; + // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) + // iRet = 0; + // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) + // iRet = 0; + // else + // iRet = 1; + // } + // else if (m_iBattleCamp != GP_BATTLE_CAMP_NONE) + // { + // // Host is in battle + // int iCamp = pPlayer.GetBattleCamp(); + // if (iCamp != GP_BATTLE_CAMP_NONE && iCamp != m_iBattleCamp) + // iRet = 1; + // else + // iRet = 0; + // } + // else // Normal mode + // { + // if (IsTeamMember(idTarget)) + // return 0; + + // if (!IsPVPOpen() || !pPlayer.IsPVPOpen() || m_BasicProps.iLevel < EC_MAXNOPKLEVEL || bp.iLevel < EC_MAXNOPKLEVEL) + // iRet = 0; + // else if (bForceAttack) + // iRet = 1; + // else if (!gs.bAtk_Player) + // iRet = 0; + // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) + // iRet = 0; + // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) + // iRet = 0; + // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) + // iRet = 0; + // else + // iRet = 1; + // } + //} + else + { + return -1; + } + + return iRet; + } + public bool CannotAttack() + { + return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0; + } + public bool glb_GetForceAttackFlag(uint pdwParam) + { + /*bool bForceAttack = false; + CECInputCtrl* pInputCtrl = g_pGame.GetGameRun().GetInputCtrl(); + + if (pdwParam) + bForceAttack = pInputCtrl.IsCtrlPressed(*pdwParam); + else + bForceAttack = pInputCtrl.KeyIsBeingPressed(VK_CONTROL); + + return bForceAttack;*/ + return false; + } + // Start normal attacking to selected target + public bool CmdNormalAttack(bool bMoreClose /* false */, bool bCombo /* false */, + int idTarget /* 0 */, int iForceAtk /* -1 */) + { + // StackChecker::ACTrace(2); + + // first of all see if we need to cancel sitdown work. + // if (m_pWorkMan.IsSitting()) + // { + // g_pGame.GetGameSession().c2s_CmdStandUp(); + // return false; + // } + + if (!CanDo(ActionCanDo.CANDO_MELEE)) + return false; + + // if (InSlidingState()) + // return false; + + // if (!bCombo) + // ClearComboSkill(); + + if (idTarget <= 0) + idTarget = m_idSelTarget; + + bool bForceAttack; + if (iForceAtk < 0) + bForceAttack = glb_GetForceAttackFlag(0); + else + bForceAttack = iForceAtk > 0 ? true : false; + + if (AttackableJudge(idTarget, bForceAttack) != 1) + return false; + + return NormalAttackObject(idTarget, bForceAttack, bMoreClose); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Combat.cs.meta b/Assets/Scripts/CECHostPlayer.Combat.cs.meta new file mode 100644 index 0000000000..cbe181b8d1 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Combat.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9117c7fe23c427b4781d9dd334c1aba7 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Interaction.cs b/Assets/Scripts/CECHostPlayer.Interaction.cs new file mode 100644 index 0000000000..c49bd9e17a --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Interaction.cs @@ -0,0 +1,265 @@ +using BrewMonster.Managers; +using BrewMonster.Network; +using BrewMonster.Scripts; +using BrewMonster.UI; +using CSNetwork; +using CSNetwork.GPDataType; +using ModelRenderer.Scripts.GameData; +using PerfectWorld.Scripts; +using PerfectWorld.Scripts.Managers; +using System; +using UnityEngine; +using static BrewMonster.Scripts.CECHPWork; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + private void OnMsgHstNPCGreeting(ECMSG Msg) + { + cmd_npc_greeting pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + if (GPDataTypeHelper.ISNPCID(pCmd.idObject)) + { + // 专锟脚达拷锟斤拷学习锟斤拷锟杰碉拷锟斤拷锟斤拷NPC + //if (CECHostSkillModel::Instance().IsSkillLearnNPC(pCmd.idObject)) + //{ + // CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); + // //m_idSevNPC = pCmd.idObject; + // //m_bTalkWithNPC = true; + // //pGameUI.GetDialog("Win_SkillAction").Show(true); + // //CDlgSkillAction* dlg = dynamic_cast(pGameUI.GetDialog("Win_SkillAction")); + // //dlg.ForceShowDialog(); + // CDlgSkillAction* dlg = dynamic_cast(pGameUI.GetDialog("Win_SkillAction")); + // dlg.SetReceivedNPCGreeting(true); + // return; + //} + + CECNPC pNPC = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idObject); + if (!pNPC || !pNPC.IsServerNPC()) + { + return; + } + + // Check distance again + if (!CanTouchTarget(pNPC.GetPos(), pNPC.GetTouchRadius(), 3)) + return; + + m_idSevNPC = pCmd.idObject; + m_bTalkWithNPC = true; + + // Check way point service on NPC + //TODO: Fix later + //var dwID = (pNPC as CECNPCServer).GetWayPointID(); + //if (dwID != null && !HasWayPoint(dwID)) + //UnityGameSession.c2s_CmdNPCSevWaypoint(); + //g_pGame.GetGameSession().c2s_CmdNPCSevWaypoint(); + + var pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + NPC_ESSENCE? result = (pNPC as CECNPCServer).GetDBEssence(); + if (result != null) + { + pGameUI.PopupNPCDialog(result.Value); + } + } + //else if (GPDataTypeHelper.ISPLAYERID(pCmd.idObject)) + //{ + // EC_ElsePlayer pPlayer = m_pPlayerMan.GetElsePlayer(pCmd.idObject); + + // // Check distance again + // if (!pPlayer || !CanTouchTarget(pPlayer.GetPos(), 0.0f, 3)) + // return; + + // m_idSevNPC = pCmd.idObject; + // m_bTalkWithNPC = true; + // m_iBoothState = 3; + + // g_pGame.GetGameSession().c2s_CmdNPCSevGetContent(GP_NPCSEV_BOOTHSELL); + + // m_pBuyPack.RemoveAllItems(); + // m_pSellPack.RemoveAllItems(); + // m_pEPBoothBPack.RemoveAllItems(); + // m_pEPBoothSPack.RemoveAllItems(); + + // CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); + // pGameUI.PopupBoothDialog(true, false, pCmd.idObject); + //} + else + { + return; + } + } + private void OnMsgPlayerDoEmote(ECMSG Msg) + { + if (!m_pWorkMan.IsStanding() && + !m_pWorkMan.IsBeingBound()) + return; + + int cmd = Convert.ToInt32(Msg.dwParam2); + if (cmd == CommandID.OBJECT_DO_EMOTE) + { + cmd_object_do_emote pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + DoEmote(pCmd.emotion); + + // if( m_iBuddyId ) + // { + // CECPlayer pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId); + // if (pBuddy) + // pBuddy.DoEmote(pCmd.emotion); + // } + + GetTaskInterface().SetEmotion(pCmd.emotion); + } + else if (cmd == CommandID.OBJECT_EMOTE_RESTORE) + { + CECHPWork pWork = m_pWorkMan.GetRunningWork((int)WorkID.WORK_STAND); + if (pWork != null) + { + ((CECHPWorkStand)pWork).SetPoseAction((int)PLAYER_ACTION_TYPE.ACT_STAND, false); + } + } + } + // Do emote action + private bool DoEmote(int idEmote) + { + if (!m_pWorkMan.IsStanding()) + return false; + + CECHPWorkStand pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND) as CECHPWorkStand; + if (pWork == null) + { + Debug.LogError("Null CECHPWorkStand"); + } + + int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; + bool bSession = false; + + // Select action according to pose + switch (idEmote) + { + case (int)RoleExpression.ROLEEXP_WAVE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_WAVE; break; + case (int)RoleExpression.ROLEEXP_NOD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_NOD; break; + case (int)RoleExpression.ROLEEXP_SHAKEHEAD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHAKEHEAD; break; + case (int)RoleExpression.ROLEEXP_SHRUG: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHRUG; break; + case (int)RoleExpression.ROLEEXP_LAUGH: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LAUGH; break; + case (int)RoleExpression.ROLEEXP_ANGRY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ANGRY; break; + case (int)RoleExpression.ROLEEXP_STUN: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_STUN; break; + case (int)RoleExpression.ROLEEXP_DEPRESSED: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEPRESSED; break; + case (int)RoleExpression.ROLEEXP_KISSHAND: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISSHAND; break; + case (int)RoleExpression.ROLEEXP_SHY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHY; break; + case (int)RoleExpression.ROLEEXP_SALUTE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SALUTE; break; + + case (int)RoleExpression.ROLEEXP_SITDOWN: + + iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SITDOWN; + bSession = true; + break; + + case (int)RoleExpression.ROLEEXP_ASSAULT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ASSAULT; break; + case (int)RoleExpression.ROLEEXP_THINK: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_THINK; break; + case (int)RoleExpression.ROLEEXP_DEFIANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFIANCE; break; + case (int)RoleExpression.ROLEEXP_VICTORY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_VICTORY; break; + case (int)RoleExpression.ROLEEXP_GAPE: iAction = (int)PLAYER_ACTION_TYPE.ACT_GAPE; break; + case (int)RoleExpression.ROLEEXP_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS; break; + case (int)RoleExpression.ROLEEXP_FIGHT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FIGHT; break; + case (int)RoleExpression.ROLEEXP_ATTACK1: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK1; break; + case (int)RoleExpression.ROLEEXP_ATTACK2: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK2; break; + case (int)RoleExpression.ROLEEXP_ATTACK3: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK3; break; + case (int)RoleExpression.ROLEEXP_ATTACK4: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK4; break; + case (int)RoleExpression.ROLEEXP_DEFENCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFENCE; break; + case (int)RoleExpression.ROLEEXP_FALL: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALL; break; + case (int)RoleExpression.ROLEEXP_FALLONGROUND: + iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALLONGROUND; break; + case (int)RoleExpression.ROLEEXP_LOOKAROUND: + iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LOOKAROUND; break; + case (int)RoleExpression.ROLEEXP_DANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE; break; + case (int)RoleExpression.ROLEEXP_FASHIONWEAPON: + iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FASHIONWEAPON; break; + case (int)RoleExpression.ROLEEXP_TWO_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS; break; + case (int)RoleExpression.ROLEEXP_FIREWORK: iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_TOSS; break; + default: + break; + } + + pWork.SetPoseAction(iAction, bSession); + + return true; + } + void OnMsgPlayerGather(ECMSG Msg) + { + int cmd = Convert.ToInt32(Msg.dwParam2); + if (cmd == CommandID.PLAYER_GATHER_START) + { + cmd_player_gather_start pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + EC_ManMatter pMatterMan = EC_ManMessageMono.Instance.GetECManMatter;//g_pGame.GetGameRun().GetWorld().GetMatterMan(); + CECMatter pMatter = pMatterMan.GetMatter(pCmd.mid); + // if (pMatter && pMatter.IsMonsterSpiritMine()) { + // CECHPWorkUse* pWork = (CECHPWorkUse*)m_pWorkMan.CreateWork(CECHPWork::WORK_USEITEM); + // if (pWork) { + // pWork.SetParams(pCmd.mid, pCmd.use_time * 1000, pCmd.mid, true); + // m_pWorkMan.StartWork_p1(pWork); + // } + // StartMonsterSpiritConnectGfx(pCmd.mid, pMatter.GetPos()); + // } else { + EC_HPWorkPick pWork = (EC_HPWorkPick)m_pWorkMan.CreateWork(Host_work_ID.WORK_PICKUP); + if (pWork != null) + { + pWork.SetGather(true, pMatter ? pMatter.GetTemplateID() : 0); + m_pWorkMan.StartWork_p1(pWork); + } + // } + + // Start time counter + m_GatherCnt.SetPeriod(pCmd.use_time * 1000); + m_GatherCnt.Reset(); + } + else if (cmd == CommandID.PLAYER_GATHER_STOP) + { + cmd_player_gather_stop pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_PICKUP); + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM); + // StopMonsterSpiritConnectGfx(); + var pDlg = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().GetDialog("Win_Prgs2"); + if (pDlg == null) + { + BMLogger.LogError("Null Win_Prgs2"); + return; + } + + if (pDlg is not DlgWinPrgs2 dlgWinPrgs) + { + BMLogger.LogError("Can not cast Win_Prgs2"); + return; + } + dlgWinPrgs.SetActiveProgress(false); + } + else if (cmd == CommandID.MINE_GATHERED) + { + cmd_mine_gathered pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + // ASSERT(pCmd && pCmd.player_id == m_PlayerInfo.cid); + elementdataman pDataMan = EC_Game.GetElementDataMan(); + DATA_TYPE DataType = pDataMan.get_data_type((uint)pCmd.item_type, ID_SPACE.ID_SPACE_ESSENCE); + if (DataType == DATA_TYPE.DT_MONSTER_SPIRIT_ESSENCE) + { + // StartMonsterSpiritBallGfx(); + // m_CardHolder.gain_times++; + } + } + } + // Is doing session pose ? + private bool DoingSessionPose() + { + var pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND); + if (pCurWork != null) + { + if (((CECHPWorkStand)pCurWork).DoingSessionPose()) + { + return true; + } + } + return false; + } + } +} diff --git a/Assets/Scripts/CECHostPlayer.Interaction.cs.meta b/Assets/Scripts/CECHostPlayer.Interaction.cs.meta new file mode 100644 index 0000000000..3b89f08128 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Interaction.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e28dd00d9a790bb4eb9e05f52c4e6aba \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Inventory.cs b/Assets/Scripts/CECHostPlayer.Inventory.cs new file mode 100644 index 0000000000..c745b5bfee --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Inventory.cs @@ -0,0 +1,1416 @@ +锘縰sing BrewMonster.Managers; +using BrewMonster.Network; +using BrewMonster.Scripts; +using BrewMonster.Scripts.Managers; +using BrewMonster.Scripts.Skills; +using CSNetwork; +using CSNetwork.GPDataType; +using CSNetwork.S2CCommand; +using System; +using BrewMonster.UI; +using PerfectWorld.Scripts.Managers; +using UnityEngine; +using static BrewMonster.Scripts.CECHPWork; +using static BrewMonster.Scripts.Managers.EC_Inventory; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + public void OnMsgHstIvtrInfo(ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + int hostId = Convert.ToInt32(Msg.dwParam3); + + switch (cmd) + { + case CommandID.OWN_IVTR_DATA: + { + LogInventoryPacket("OWN_IVTR_DATA", data, hostId); + break; + } + case CommandID.OWN_IVTR_DETAIL_DATA: + { + // EC_Inventory.LogInventoryPacket("OWN_IVTR_DETAIL_DATA", data, hostId); + // Parse and store + if (data != null && data.Length >= 6) + { + byte byPackage = data[0]; + byte ivtrSize = data[1]; + if (EC_IvtrItemUtils.Instance.TryParseInventoryDetail(data, out var pkg, + out var size, out var items)) + { + var inv = GetInventory(pkg); + if (inv != null) + { + inv.Resize(size); + inv.RemoveAllItems(); + + if (items != null) + { + foreach (var it in items) + { + if (it != null && it.Slot >= 0 && it.Slot < size) + inv.SetItem(it.Slot, it); + } + } + } + } + + // check if we got the item from the Equipment Pack. If so, we have to load the equipment items + if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) + { + UpdateEquipSkins(); + } + } + + break; + } + case CommandID.GET_OWN_MONEY: + { + if (data != null) + { + try + { + var money = GPDataTypeHelper.FromBytes(data); + + SetMoneyAmount(money.amount); + + var ui = GameObject.FindFirstObjectByType(); + if (ui == null) + { + var all = Resources.FindObjectsOfTypeAll(); + if (all != null) + { + for (int i = 0; i < all.Length; i++) + { + var candidate = all[i]; + if (candidate != null && candidate.gameObject.scene.IsValid()) + { + ui = candidate; + break; + } + } + } + } + + if (ui != null) + { + ui.UpdateMoney(money.amount, money.max_amount); + } + else + { + BrewMonster.Scripts.Managers.EC_InventoryUI.CacheMoney(money.amount, money.max_amount); + } + } + catch (Exception ex) + { + Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); + } + } + + break; + } + case CommandID.PLAYER_CASH: + { + if (data != null) + { + try + { + var cash = GPDataTypeHelper.FromBytes(data); + var ui = GameObject.FindFirstObjectByType(); + if (ui == null) + { + var all = Resources.FindObjectsOfTypeAll(); + if (all != null) + { + for (int i = 0; i < all.Length; i++) + { + var candidate = all[i]; + if (candidate != null && candidate.gameObject.scene.IsValid()) + { + ui = candidate; + break; + } + } + } + } + + if (ui != null) + { + ui.UpdateCash(cash.cash_amount); + } + else + { + BrewMonster.Scripts.Managers.EC_InventoryUI.CacheCash(cash.cash_amount); + } + } + catch (Exception ex) + { + Debug.LogWarning($"[Inventory] Failed to parse PLAYER_CASH: {ex.Message}"); + } + } + + break; + } + } + } + + public void OnMsgHstOwnItemInfo(ECMSG Msg) + { + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.OWN_ITEM_INFO: + { + //Debug.Log("[Inventory] OWN_ITEM_INFO received"); + //var data = Msg.dwParam1 as byte[]; + //int hostId = Convert.ToInt32(Msg.dwParam3); + //LogInventoryPacket("OWN_ITEM_INFO", data, hostId); + + //Handmade + var data = Msg.dwParam1 as byte[]; + if (data == null || data.Length == 0) + return; + + byte byPackage = data[0]; + byte bySlot = data[1]; + int type = BitConverter.ToInt32(data, 2); + int expire_date = BitConverter.ToInt32(data, 6); + int state = BitConverter.ToInt32(data, 10); + uint count = BitConverter.ToUInt32(data, 14); + ushort crc = BitConverter.ToUInt16(data, 18); + ushort content_length = BitConverter.ToUInt16(data, 20); + + byte[] content = null; + if (content_length > 0 && 22 + content_length <= data.Length) + { + content = new byte[content_length]; + Buffer.BlockCopy(data, 22, content, 0, content_length); + + string hexDebug = BitConverter.ToString(content); + //Debug.Log($"[OWN_ITEM_INFO] Full Content Hex ({content_length} bytes): {hexDebug}"); + } + + //Debug.Log($"[OWN_ITEM_INFO] Parsed: package={byPackage}, slot={bySlot}, tid={type}, count={count}, content_len={content_length}"); + + EC_Inventory pInventory = GetInventory(byPackage); + EC_IvtrItem newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)count); + + if (newItem != null) + { + newItem.SetProcType(state); + + newItem.GetDetailDataFromLocal(); + if (content != null && content.Length > 0) + { + newItem.SetItemInfo(content, content_length); + } + + pInventory.SetItem(bySlot, newItem); + + //Debug.Log($"[OWN_ITEM_INFO] Fixed Update: Pack {byPackage} Slot {bySlot} - Type {type}"); + } + + if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) + { + UpdateEquipSkins(); + } + else if (byPackage == InventoryConst.IVTRTYPE_PACK) + { + if (newItem.IsEquipment()) + { + // TODO + } + } + + var ui = GameObject.FindFirstObjectByType(); + + if (ui != null) + { + ui.RefreshAll(); + //Debug.Log($"[OWN_ITEM_INFO] Refreshed inventory UI after updating item at package={byPackage}, slot={bySlot}"); + } + + break; + } + case CommandID.EMPTY_ITEM_SLOT: + { + var data = Msg.dwParam1 as byte[]; + + cmd_empty_item_slot pCmd = GPDataTypeHelper.FromBytes(data); + EC_Inventory pInventory = GetPack(pCmd.byPackage); + if (pInventory == null) + return; + + EC_IvtrItem pItem = pInventory.GetItem(pCmd.bySlot); + if (pItem != null) + { + //UpdateRemovedItemSC(pItem->GetTemplateID(), pCmd->byPackage, pCmd->bySlot); + } + + pInventory.SetItem(pCmd.bySlot, null); + + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + } + + break; + } + } + } + + public void OnMsgHstItemOperation(ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.PLAYER_DROP_ITEM: + { + // Parse the drop item data from the server response + if (data != null && data.Length >= 6) + { + byte byPackage = data[0]; + byte bySlot = data[1]; + int count = BitConverter.ToInt32(data, 2); + int tid = BitConverter.ToInt32(data, 6); + byte reason = data[10]; + + Debug.Log( + $"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); + + // Update the inventory by removing the item + var inv = GetInventory(byPackage); + bool success = inv != null && inv.RemoveItem(bySlot, count); + + if (success) + { + Debug.Log( + $"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + } + } + else + { + Debug.LogWarning( + $"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); + } + } + else + { + Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); + } + + break; + } + + case CommandID.EQUIP_ITEM: + { + byte index_inv = data[0]; + byte index_equip = data[1]; + // Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT + var packInv = GetInventory(InventoryConst.IVTRTYPE_PACK); + var equipInv = GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK); + var invItem = packInv?.GetItem(index_inv, true); + var equipItem = equipInv?.GetItem(index_equip, true); + UpdateEquipSkins(); + if (invItem != null) + { + invItem.Package = InventoryConst.IVTRTYPE_EQUIPPACK; + invItem.Slot = index_equip; + equipInv?.SetItem(index_equip, invItem); + } + + if (equipItem != null) + { + equipItem.Package = InventoryConst.IVTRTYPE_PACK; + equipItem.Slot = index_inv; + packInv?.SetItem(index_inv, equipItem); + } + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindObjectOfType(); + if (ui != null) + { + ui.RefreshAll(); + } + + UpdateEquipSkins(); + break; + } + } + } + + public void OnMsgHstPickupItem(in ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + + bool bDoOther = false; + int idItem, iExpireDate = 0, iAmount, iCmdLastSlot, iCmdSlotAmount, iPack, iMsg = -1; + + switch (cmd) + { + case CommandID.HOST_OBTAIN_ITEM: + { + // Parse cmd_host_obtain_item struct data + int type = BitConverter.ToInt32(data, 0); + int expire_date = BitConverter.ToInt32(data, 4); + uint amount = BitConverter.ToUInt32(data, 8); + uint slot_amount = BitConverter.ToUInt32(data, 12); + byte where = data[16]; // Package index + byte index = data[17]; // Slot index in that package + var newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)amount); + + // Add item to inventory + var ivt = GetInventory(where); + ivt.SetItem(index, newItem); + + Debug.Log( + $"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + } + + UpdateEquipSkins(); + } + break; + case CommandID.PICKUP_ITEM: + { + int tid = BitConverter.ToInt32(data, 0); + int expire_date = BitConverter.ToInt32(data, 4); + iAmount = (int)BitConverter.ToUInt32(data, 8); + uint iSlotAmount = BitConverter.ToUInt32(data, 12); + byte byPackage = data[16]; + byte bySlot = data[17]; + + //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + + // Notify pickupItem script about successful pickup + pickupItem pickupScript = pickupItem.Instance; + if (pickupScript != null) + { + //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + + // Notify pickupItem script about successful pickup + pickupScript = UnityEngine.Object.FindFirstObjectByType(); + if (pickupScript != null) + { + pickupScript.OnPickupSuccess(tid); + } + + // Create new inventory item data + var newItem = EC_IvtrItem.CreateItem(tid, expire_date, (int)iAmount); + + // Add item to inventory + var ivt = GetInventory(byPackage); + ivt.SetItem(bySlot, newItem); + + //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + } + } + else + { + Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); + } + + break; + } + case CommandID.TASK_DELIVER_ITEM: + cmd_task_deliver_item pCmd = GPDataTypeHelper.FromBytes(data); + // ASSERT(pCmd); + + idItem = pCmd.type; + iExpireDate = pCmd.expire_date; + iAmount = (int)pCmd.amount; + iCmdLastSlot = pCmd.index; + iCmdSlotAmount = (int)pCmd.slot_amount; + iPack = pCmd.where; + iMsg = (int)FixedMsg.FIXMSG_GAINITEM; + bDoOther = true; + + + // Create new inventory item data + var taskNewItem = EC_IvtrItem.CreateItem(idItem, iExpireDate, (int)iAmount); + + // Add item to inventory + var task_ivt = GetInventory((byte)iPack); + if (!task_ivt.MergeItem(idItem, iExpireDate, iAmount, out var iLastSlot, out var iSlotNum) || + iLastSlot != iCmdLastSlot || iSlotNum != iCmdSlotAmount) + { + return; + } + + task_ivt.SetItem(iCmdLastSlot, taskNewItem); + + //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var task_ui = GameObject.FindFirstObjectByType(); + if (task_ui != null) + { + task_ui.RefreshAll(); + } + + break; + case CommandID.PRODUCE_ONCE: + { + // Parse cmd_produce_once struct data + cmd_produce_once produceCmd = GPDataTypeHelper.FromBytes(data); + + int produceItemId = produceCmd.type; + int produceExpireDate = 0; + uint produceAmount = produceCmd.amount; + byte producePack = produceCmd.where; + byte produceSlot = produceCmd.index; + + Debug.Log( + $"[PRODUCE_ONCE] Received: itemId={produceItemId}, amount={produceAmount}, pack={producePack}, slot={produceSlot}"); + + // Get inventory + var produce_ivt = GetInventory(producePack); + if (produce_ivt == null) + { + Debug.LogWarning($"[PRODUCE_ONCE] Invalid inventory package {producePack}"); + return; + } + + // Check if the slot already has an item + var existingItem = produce_ivt.GetItem(produceSlot, false); + + if (existingItem != null) + { + if (existingItem.m_tid == produceItemId) + { + existingItem.m_iCount = (int)produceAmount; + Debug.Log( + $"[PRODUCE_ONCE] Updated existing item count at slot {produceSlot} to {produceAmount}"); + } + else + { + Debug.LogWarning( + $"[PRODUCE_ONCE] Slot {produceSlot} already has different item (tid={existingItem.m_tid}), not overwriting with {produceItemId}"); + return; + } + } + else + { + var produceNewItem = new EC_IvtrItem + { + Package = producePack, + Slot = produceSlot, + m_tid = produceItemId, + m_expire_date = produceExpireDate, + State = 0, + m_iCount = (int)produceAmount, + Crc = 0, + Content = null + }; + + produce_ivt.SetItem(produceSlot, produceNewItem); + Debug.Log($"[PRODUCE_ONCE] Created new item at slot {produceSlot} with count {produceAmount}"); + } + + // Trigger UI refresh + var produce_ui = GameObject.FindFirstObjectByType(); + if (produce_ui != null) + { + produce_ui.RefreshAll(); + } + + UpdateEquipSkins(); + + // Notify DlgProduce + var dlgProduce = GameObject.FindFirstObjectByType(); + if (dlgProduce != null) + { + dlgProduce.OnProduceOnce(produceCmd); + } + } + break; + } + } + + private void OnMsgHstUseItem(ECMSG Msg) + { + cmd_host_use_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + EC_Inventory pPack = GetPack(pCmd.byPackage); + if (pPack == null) + { + return; + } + + EC_IvtrItem pItem = pPack.GetItem(pCmd.bySlot, false); + if (pItem == null || pItem.GetTemplateID() != pCmd.item_id) + { + return; + } + + pItem.Use(); + + if (pCmd.use_count > 0) + { + bool removed = pPack.RemoveItem(pCmd.bySlot, pCmd.use_count); + if (removed) + { + if (pPack.GetItem(pCmd.bySlot, false) == null) + { + //Debug.Log($"[OnMsgHstUseItem] Item {pCmd.item_id} removed from slot {pCmd.bySlot}"); + } + } + else + { + //Debug.LogError($"[OnMsgHstUseItem] Failed to remove item {pCmd.item_id} from slot {pCmd.bySlot}"); + } + + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + ui.UpdateCooldownOverlays(); + } + else + { + //Debug.LogError("[OnMsgHstUseItem] EC_InventoryUI not found, UI may not update"); + } + } + + if (m_pWorkMan != null) + { + CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM); + if (pWork is CECHPWorkUse useWork) + { + if (useWork.GetItem() == pCmd.item_id) + { + m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM); + } + } + } + } + + public void OnMsgHstProduceItem(in ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + + // Get DlgProduce to notify + var dlgProduce = GameObject.FindFirstObjectByType(); + if (dlgProduce == null) + { + Debug.LogWarning("[OnMsgHstProduceItem] DlgProduce not found"); + return; + } + + switch (cmd) + { + case CommandID.PRODUCE_START: + { + cmd_produce_start pCmd = GPDataTypeHelper.FromBytes(data); + Debug.Log($"[PRODUCE_START] type={pCmd.type}, use_time={pCmd.use_time}, count={pCmd.count}"); + dlgProduce.OnProduceStart(pCmd); + } + break; + case CommandID.PRODUCE_END: + { + Debug.Log("[PRODUCE_END] Production ended"); + dlgProduce.OnProduceEnd(); + } + break; + case CommandID.PRODUCE_NULL: + { + cmd_produce_null pCmd = GPDataTypeHelper.FromBytes(data); + Debug.Log($"[PRODUCE_NULL] type={pCmd.type}"); + dlgProduce.OnProduceNull(pCmd); + } + break; + default: + Debug.LogWarning($"[OnMsgHstProduceItem] Unknown command: {cmd}"); + break; + } + } + + public void OnMsgHstEmbedItem(ECMSG Msg) + { + cmd_embed_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + EC_IvtrItem pEquip = m_pPack.GetItem(pCmd.equip_idx); + EC_IvtrItem pTessera = m_pPack.GetItem(pCmd.chip_idx); + + if (pEquip == null || pTessera == null) + { + return; + } + + m_pPack.RemoveItem(pCmd.chip_idx, 1); + + // Refresh equip's data + // todo make receive request + UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, pCmd.equip_idx); + } + + private void OnMsgEnchantResult(ECMSG msg) + { + // 浠庢秷鎭腑鑾峰彇cmd_enchant_result缁撴瀯 // Get cmd_enchant_result structure from message + cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes((byte[])msg.dwParam1); + + // 鍒濆鍖栨帺鐮佷负鍏1 // Initialize mask to all 1s + uint mask = 0xFFFFFFFF; + + // 濡傛灉鐩爣涓嶆槸涓绘満鐜╁涓斿綋鍓嶄笉鏄富鏈虹帺瀹讹紝鍒欒繃婊や細寮曡捣姘旀场鏂囨湰鐨勪慨楗扮 + // We should filter out these things that will cause bubble texts + CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer(); + if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer()) + { + mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE | + MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED); + } + + // 鑾峰彇淇グ绗 // Get modifier + uint dwModifier = (uint)pCmd.attack_flag; + + // 鑾峰彇鎶鑳界被鍨 // Get skill type + int nDamage = -2; // 榛樿涓-2锛屼笉浼氬紩璧峰彈浼ゅ姩浣 // Default to -2, will not cause wounded action + + if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK) + { + // 鍙湁鏀诲嚮鎶鑳戒細寮曡捣鍙椾激鍔ㄤ綔锛屼激瀹冲间负-1 // Only attack skill will cause wounded action, when damage is -1 + nDamage = -1; + } + else + { + // 鍏朵粬鎶鑳戒笉浼氬紩璧峰彈浼ゅ姩浣滐紝浼ゅ鍊艰涓-2 // Other skills will not cause wounded action, so we set damage to -2 + nDamage = -2; + } + + // 鎾斁鏀诲嚮鏁堟灉 // Play attack effect + int attackTime = 0; + PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage, + dwModifier & mask, 0, ref attackTime, pCmd.section); + } + + public bool HaveHealthStones() + { + var pPack = GetPack(); + var items = new int[] { 36764, 36765, 36766, 36767 }; + for (int i = 0; i < items.Length; ++i) + { + if (pPack.FindItem(items[i]) >= 0) + return true; + } + + return false; + } + + public bool UseItemInPack(int iPack, int iSlot, bool showMsg = true) + { + if (!CanDo(ActionCanDo.CANDO_USEITEM)) + return false; + + EC_Inventory pPack = GetPack(iPack); + if (pPack == null) + return false; + + EC_IvtrItem pItem = pPack.GetItem(iSlot); + if (pItem == null || pItem.IsFrozen()) + return false; + + if (pItem.Use_Persist() && (IsJumping() || IsFalling())) + return false; + + CECGameRun pGameRun = EC_Game.GetGameRun(); + //CECGameSession pSession = g_pGame.GetGameSession(); + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_FIREWORK) + { + if (GetProfession() == (int)PROFESSION.PROF_GHOST && IsInvisible()) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_WHEN_INVISIBLE); + return false; + } + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_INCSKILLABILITY) + { + EC_IvtrIncSkillAbility pIncSkill = pItem as EC_IvtrIncSkillAbility; + //if (pIncSkill != null) + //{ + // var pDBEssence = pIncSkill.GetDBEssence(); + // CECSkill pSkill = GetNormalSkill(pDBEssence.id_skill); + // if (pSkill != null) + // { + // if (pSkill.GetSkillLevel() != pDBEssence.level_required) + // { + // if (showMsg) + // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_LEVEL_INVALID); + // return false; + // } + // if (GetSkillAbilityPercent(pDBEssence.id_skill) >= 100) + // { + // if (showMsg) + // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_ABILITY_FULL); + // return false; + // } + // } + //} + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TRANSMITSCROLL) + { + CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); + if (pGameUI != null && !IsFighting()) + { + // TODO: Implement travel map dialog + //CDlgWorldMap* pMap = (CDlgWorldMap*)pGameUI->GetDialog("Win_WorldMapTravel"); + //pMap->BuildTravelMap(DT_TRANSMITSCROLL_ESSENCE, (void*)iSlot); + //pMap->Show(true); + } + + return true; + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHOPTOKEN) + { + CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); + if (pGameUI != null && !IsFighting()) + { + //CDlgTokenShop* pDlg = dynamic_cast(pGameUI->GetDialog("Win_TokenShop")); + //if (pDlg) + //{ + // pDlg->InitTokenShopItem(pItem->GetTemplateID()); + // pDlg->Show(!pDlg->IsShow()); + //} + } + + return true; + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_UNIVERSAL_TOKEN) + { + // TODO: Implement universal token when available + EC_IvtrUniversalToken pUniversalToken = pItem as EC_IvtrUniversalToken; + //if (pUniversalToken != null && pUniversalToken.HasAnyUsage()) + //{ + // CECUseUniversalTokenCommandManager.Instance.Use(pUniversalToken, pUniversalToken.UsageIndexAt(0)); + // return true; + //} + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE) + { + EC_IvtrTaskDice pTaskDice = pItem as EC_IvtrTaskDice; + if (pTaskDice != null) + { + if (pTaskDice != null) + { + if (IsFlying() && pTaskDice.GetDBEssence().no_use_in_combat == 1) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); + return false; + } + } + } + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) + { + EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; + if (pTargetItem == null) + return false; + + var essence = pTargetItem.GetDBEssence(); + + if (!pTargetItem.IsEssenceLoaded()) + return false; + + if (IsFighting() && essence.use_in_combat == 0) + { + if (showMsg) + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); + return false; + } + + if (essence.use_in_sanctuary_only != 0 && !IsInSanctuary()) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_USE_IN_SANCTUARY_ONLY); + return false; + } + + int iCurrMap = pGameRun.GetWorld().GetInstanceID(); + if (pTargetItem.GetDBEssence().num_area != 0) + { + bool found = false; + for (int i = 0; i < pTargetItem.GetDBEssence().num_area; i++) + { + if (pTargetItem.GetDBEssence().area_id[i] == iCurrMap) + { + found = true; + break; + } + } + + if (!found) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_CURR_MAP); + return false; + } + } + + if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) + return false; + + if (InSlidingState()) + return false; + + if (m_idSelTarget == 0) + return false; + + CECSkill pSkill = pTargetItem.GetTargetSkill(); + if (pSkill == null) + return false; + + if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() && + m_pCurSkill.GetSkillID() == pSkill.GetSkillID()) + { + m_pCurSkill.EndCharging(); + UnityGameSession.c2s_SendCmdContinueAction(); + return true; + } + + int iCon = CheckSkillCastCondition(pSkill); + if (iCon != 0) + { + if (showMsg) + ProcessSkillCondition(iCon); + return false; + } + + bool bForceAttack = glb_GetForceAttackFlag(0); + if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK || + pSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE) + { + if (m_idSelTarget == m_PlayerInfo.cid) + { + if (showMsg) + pGameRun.AddFixedChannelMsg((int)FixedMsg.FIXMSG_TARGETWRONG, + (int)ChatChannel.GP_CHAT_FIGHT); + return false; + } + else if (m_idSelTarget != 0) + { + if (AttackableJudge(m_idSelTarget, bForceAttack) != 1) + return false; + } + } + + int idCastTarget = m_idSelTarget; + int iTargetType = pSkill.GetTargetType(); + + if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS || + pSkill.GetType() == (int)CECSkill.SkillType.TYPE_NEUTRALBLESS) + { + if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) + idCastTarget = m_PlayerInfo.cid; + + if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) + { + byte byBLSMask = EC_Utility.glb_BuildBLSMask(); + + if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_POINT) + { + if (!IsTeamMember(idCastTarget)) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0) + { + idCastTarget = m_PlayerInfo.cid; + } + else + { + EC_ElsePlayer pPlayer = + EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget) as + EC_ElsePlayer; + if (pPlayer == null) + return false; + + if (pPlayer.IsInvader() || pPlayer.IsPariah()) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (!IsFactionMember(pPlayer.GetFactionID())) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (!IsFactionAllianceMember(pPlayer.GetFactionID())) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (GetForce() != pPlayer.GetForce()) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0) + idCastTarget = m_PlayerInfo.cid; + } + } + } + } + + // If host is in dule + if (IsInDuel() && m_idSelTarget == m_pvp.idDuelOpp) + idCastTarget = m_PlayerInfo.cid; + + // If host is in battle + if (IsInBattle()) + { + EC_ElsePlayer pPlayer = + EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget); + if (!InSameBattleCamp(pPlayer)) + idCastTarget = m_PlayerInfo.cid; + } + } + } + else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS) + { + // TODO: Implement pet blessing when petsystem is available + //CECSCPet pPet = EC_Game.GetGameRun().GetWorld().GetPetByID(m_idSelTarget); + //if (pPet == null || pPet.GetMasterID() == GetCharacterID()) + //{ + // CECPetData pPetData = m_pPetCorral.GetActivePet(); + // if (pPetData == null || + // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_COMBAT && + // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_SUMMON && + // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_EVOLUTION) + // return false; + + // idCastTarget = m_pPetCorral.GetActivePetNPCID(); + //} + //if(iTargetType != 0 && idCastTarget == 0) + // return false; + } + + if (iTargetType != 0) + { + int iAliveFlag = 0; + if (iTargetType == 1) + iTargetType = 1; + else if (iTargetType == 2) + iTargetType = 2; + + CECObject pObject = EC_ManMessageMono.Instance.GetObject(idCastTarget, iAliveFlag); + if (pObject == null) + return false; + } + + if (!IsMeleeing() && !IsSpellingMagic() && + (iTargetType == 0 || idCastTarget == m_PlayerInfo.cid)) + { + if (!pSkill.ReadyToCast()) + return false; + + if (!pSkill.IsInstant() && pSkill.GetType() != (int)CECSkill.SkillType.TYPE_FLASHMOVE) + { + if (!NaturallyStopMoving()) + return false; + } + else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE) + { + if (!CanDo(ActionCanDo.CANDO_FLASHMOVE)) + return false; + } + + m_pPrepSkill = pSkill; + } + else if (IsSpellingMagic() && m_pCurSkill == pSkill && !pSkill.ReadyToCast()) + { + return false; + } + } + + if (pItem.IsEquipment()) + { + if (iPack == Inventory_type.IVTRTYPE_EQUIPPACK) + { + // Take off equipment + int iEmpty = m_pPack.SearchEmpty(); + if (iEmpty < 0) + return false; + + UnityGameSession.RequestEquipItemAsync((byte)iEmpty, (byte)iSlot, null); + return true; + } + + EC_IvtrEquip pEquip = pItem as EC_IvtrEquip; + if (pEquip == null) + return false; + + int iReason = 0; + if (!CanUseEquipment(pEquip, ref iReason)) + return false; + + int iFirstFree = -1, iFirstCan = -1; + for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++) + { + if (pItem.CanEquippedTo(i)) + { + if (iFirstCan < 0) + iFirstCan = i; + + if (m_pEquipPack.GetItem(i) == null && iFirstFree < 0) + { + iFirstFree = i; + break; + } + } + } + + int iDst; + if (iFirstFree >= 0) + iDst = iFirstFree; + else if (iFirstCan >= 0) + iDst = iFirstCan; + else + { + Debug.Assert(false); + return false; + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) + { + int iSameIDPos = m_pEquipPack.FindItem(pItem.GetTemplateID()); + if (iSameIDPos >= 0) + { + iDst = iSameIDPos; + } + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_ARROW || + pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) + { + EC_IvtrItem pDstItem = m_pEquipPack.GetItem(iDst); + if (pDstItem == null || pItem.GetTemplateID() != pDstItem.GetTemplateID()) + UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); + else + { + // TODO: Implement c2s_CmdMoveItemToEquip when available + //UnityGameSession.c2s_CmdMoveItemToEquip((byte)iSlot, (byte)iDst); + } + } + else + { + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_GENERALCARD) + { + //TODO: Add general card equip request + EC_IvtrGeneralCard pCard = pItem as EC_IvtrGeneralCard; + if (pCard != null) + { + iDst = InventoryConst.EQUIPIVTR_GENERALCARD1 + pCard.GetEssence().type; + } + } + + UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); + } + + return true; + } + + if (iPack != Inventory_type.IVTRTYPE_PACK) + return false; + + if (!pItem.CheckUseCondition()) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_CANNOTUSE); + return false; + } + + int piMax = -1; + if (pItem.GetCoolTime(out piMax) > 0) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_INCOOLTIME); + return false; + } + + if (pItem.Use_AtkTarget() || pItem.Use_Target()) + { + if (pItem.Use_AtkTarget() && CannotAttack()) + return false; + + if (m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid) + { + if (showMsg) + { + CECStringTab pStrTab = EC_Game.GetFixedMsgs(); + pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_NOTARGET), + (int)ChatChannel.GP_CHAT_SYSTEM); + } + + return false; + } + + float fAattackRange = 10000.0f; + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TOSSMAT) + { + EC_IvtrTossMat pTossMat = pItem as EC_IvtrTossMat; + if (pTossMat != null) + fAattackRange = pTossMat.GetDBEssence().attack_range; + } + else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TANKCALLIN) + { + fAattackRange = 5.0f; + } + else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) + { + EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; + if (pTargetItem != null && pTargetItem.GetTargetSkill() != null) + { + fAattackRange = pTargetItem.GetTargetSkill() + .GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); + } + } + + float fDist = 0, fTargetRag = 0; + CECObject pObject = null; + if (CalcDist(m_idSelTarget, out fDist, out pObject)) + { + return false; + } + + if (GPDataTypeHelper.ISNPCID(m_idSelTarget)) + { + pObject = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(m_idSelTarget); + CECNPC pNPC = pObject as CECNPC; + if (pNPC != null) + fTargetRag = pNPC.GetTouchRadius(); + } + else if (GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) + { + pObject = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(m_idSelTarget); + EC_ElsePlayer pPlayer = pObject as EC_ElsePlayer; + if (pPlayer != null) + fTargetRag = pPlayer.GetTouchRadius(); + } + + if (fDist - fTargetRag > fAattackRange * 0.8f) + { + if (showMsg) + { + CECStringTab pStrTab = EC_Game.GetFixedMsgs(); + pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_TARGETISFAR), + (int)ChatChannel.GP_CHAT_SYSTEM); + } + + return false; + } + + byte byPVPMask = glb_BuildPVPMask(glb_GetForceAttackFlag(0)); + UnityGameSession.c2s_SendCmdUseItemWithTarget((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), + byPVPMask); + } + else + { + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DOUBLEEXP) + { + EC_IvtrDoubleExp pDoubleExp = pItem as EC_IvtrDoubleExp; + if (pDoubleExp != null) + { + if (pDoubleExp.GetDBEssence().double_exp_time + pGameRun.GetRemainDblExpTime() > 3600 * 4) + { + if (showMsg) + { + CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); + //pGameUI.MessageBox("", pGameUI.GetStringFromTable(828), MB_OK, new Color32(1, 1, 1, 0.6)); + } + + return false; + } + } + } + + if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHARPENER) + { + if (showMsg) + pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_SHARPEN_ON_DRAG); + return false; + } + + UnityGameSession.c2s_SendCmdUseItem((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), 1); + } + + return true; + } + + public EC_Inventory GetPack(int iPack) + { + EC_Inventory pInventory = null; + switch (iPack) + { + case Inventory_type.IVTRTYPE_PACK: pInventory = m_pPack; break; + case Inventory_type.IVTRTYPE_EQUIPPACK: pInventory = m_pEquipPack; break; + case Inventory_type.IVTRTYPE_TASKPACK: pInventory = m_pTaskPack; break; + //case Inventory_type.IVTRTYPE_TRASHBOX: pInventory = m_pTrashBoxPack; break; + //case Inventory_type.IVTRTYPE_TRASHBOX2: pInventory = m_pTrashBoxPack2; break; + //case Inventory_type.IVTRTYPE_TRASHBOX3: pInventory = m_pTrashBoxPack3; break; + //case Inventory_type.IVTRTYPE_ACCOUNT_BOX: pInventory = m_pAccountBoxPack; break; + //case Inventory_type.IVTRTYPE_GENERALCARD_BOX: pInventory = m_pGeneralCardPack; break; + //case IVTRTYPE_PACK_CLIENT_GENERALCAR.IVTRTYPE_CLIENT_GENERALCARD_PACK: pInventory = m_pClientGenCardPack; break; + default: + return null; + } + + return pInventory; + } + + public int GetEquippedSuiteItem(int idSuite, ref int[] aItems) + { + int i, iItemCnt = 0; + for (i = 0; i < m_pEquipPack.GetSize(); i++) + { + var pItem = m_pEquipPack.GetItem(i); + if (pItem == null) + { + continue; + } + + EC_IvtrEquip pEquip = (EC_IvtrEquip)pItem; + if (pEquip == null) + { + continue; + } + + if (pEquip.GetSuiteID() != idSuite) + { + continue; + } + + int iReason = 0; + if (!CanUseEquipment(pEquip, ref iReason)) + { + continue; + } + + if (pEquip.CID == (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD) + { + //TODO: Add general card Suite + } + + if (aItems.Length > 0) + { + aItems[iItemCnt] = pEquip.GetTemplateID(); + } + + iItemCnt++; + } + + return iItemCnt; + } + + public bool CanUseEquipment(EC_IvtrEquip pEquip, ref int piReason) + { + int iReason = 0; + if (pEquip == null) + { + iReason = 1; + goto End; + } + + if (GetMaxLevelSofar() < pEquip.LevelReq || + m_ExtProps.bs.strength < pEquip.StrengthReq || + m_ExtProps.bs.agility < pEquip.AgilityReq || + m_ExtProps.bs.vitality < pEquip.VitalityReq || + m_ExtProps.bs.energy < pEquip.EnergyReq /*|| + Reputation < pEquip.ReputationReq*/) //todo Add reputation check + { + iReason = 2; + goto End; + } + + switch (pEquip.CID) //class id + { + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARROW: + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WING: + if (m_iProfession != (int)PROFESSION.PROF_ARCHOR && m_iProfession != (int)PROFESSION.PROF_ANGEL) + iReason = 3; + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FLYSWORD: + //TODO: Add flysword check + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FASHION: + //TODO: Add fashion check + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARMOR: + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_DECORATION: + if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) + iReason = 3; + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WEAPON: + if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) + iReason = 3; + else + { + //TODO: check range weapon arrow + } + + break; + case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD: + // TODO: Add general card check + break; + default: + break; + } + + End: + if (piReason > 0) + { + piReason = iReason; + } + + return iReason == 0 ? true : false; + } + + public bool CanTakeItem(int idItem, int iAmount) + { + bool bCanPick = false; + + if (GPDataTypeHelper.ISMONEYTID(idItem)) + { + if (GetMoneyAmount() < GetMaxMoneyAmount()) + bCanPick = true; + } + else + { + if (IvtrPack.CanAddItem(idItem, iAmount, false) >= 0) + bCanPick = true; + } + + return bCanPick; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Inventory.cs.meta b/Assets/Scripts/CECHostPlayer.Inventory.cs.meta new file mode 100644 index 0000000000..d7c6b61208 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Inventory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9c5087cf8a535ec4db0686ae8fba0ecf \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Party.cs b/Assets/Scripts/CECHostPlayer.Party.cs new file mode 100644 index 0000000000..fcad6c06d3 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Party.cs @@ -0,0 +1,69 @@ +using BrewMonster.Managers; +using BrewMonster.Network; +using CSNetwork; +using CSNetwork.GPDataType; +using System.Runtime.InteropServices; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + private void OnMsgHstJoinTeam(ECMSG Msg) + { + var data = (byte[])Msg.dwParam1; + if (data == null || data.Length < Marshal.SizeOf()) return; + var pCmd = GPDataTypeHelper.FromBytes(data); + var pTeamMan = CECGameRun.Instance?.GetTeamMan(); + if (pTeamMan == null) return; + var pTeam = pTeamMan.GetTeam(pCmd.idLeader); + if (pTeam == null) + pTeam = pTeamMan.CreateTeam(pCmd.idLeader); + if (pTeam == null) return; + if (pCmd.idLeader == m_PlayerInfo.cid) + pTeam.AddMember(pCmd.idLeader); + pTeam.SetPickupFlag(pCmd.wPickFlag); + SetTeam(pTeam); + NotifyUIUpdateTeam(); + } + + private void OnMsgHstLeaveTeam(ECMSG Msg) + { + var data = (byte[])Msg.dwParam1; + if (data == null || data.Length < Marshal.SizeOf()) return; + var pCmd = GPDataTypeHelper.FromBytes(data); + if (m_pTeam == null) return; + var pTeamMan = CECGameRun.Instance?.GetTeamMan(); + if (pTeamMan != null) + pTeamMan.ReleaseTeam(pCmd.idLeader); + SetTeam(null); + NotifyUIUpdateTeam(); + } + + private void OnMsgHstNewTeamMem(ECMSG Msg) + { + var data = (byte[])Msg.dwParam1; + if (data == null || data.Length < Marshal.SizeOf()) return; + var pCmd = GPDataTypeHelper.FromBytes(data); + if (m_pTeam == null) return; + int cid = pCmd.idMember; + m_pTeam.AddMember(cid); + m_pTeam.AddUnknownID(cid); + if (EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(cid, 0) == null && UnityGameSession.Instance != null) + UnityGameSession.c2s_CmdTeamMemberPos(1, new[] { cid }); + NotifyUIUpdateTeam(); + } + private void OnMsgHstTeamMemberData(ECMSG Msg) + { + var data = (byte[])Msg.dwParam1; + if (data == null) return; + try + { + var (header, members) = GPDataTypeHelper.ParseTeamMemberData(data); + if (m_pTeam == null || header.idLeader != m_pTeam.GetLeaderID()) return; + m_pTeam.UpdateTeamData(header, members); + NotifyUIUpdateTeam(); + } + catch { } + } + } +} diff --git a/Assets/Scripts/CECHostPlayer.Party.cs.meta b/Assets/Scripts/CECHostPlayer.Party.cs.meta new file mode 100644 index 0000000000..7419427635 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Party.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2c86a928789ee0f47861a6e0948ad971 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Pet.cs b/Assets/Scripts/CECHostPlayer.Pet.cs new file mode 100644 index 0000000000..dd1bef366f --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Pet.cs @@ -0,0 +1,559 @@ +using BrewMonster.Network; +using BrewMonster.Scripts; +using BrewMonster.Scripts.Pet; +using BrewMonster.UI; +using CSNetwork; +using CSNetwork.GPDataType; +using System; +using System.Runtime.InteropServices; +using BrewMonster.Assets.PerfectWorld.Scripts.Players; +using UnityEngine; +using static BrewMonster.Scripts.Pet.CECPetData; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + private void OnMsgPlayerFly(ECMSG Msg) + { + if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_TAKEOFF) + { + if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) == 0) + { + m_dwStates |= PlayerNPCState.GP_STATE_FLY; + m_bRushFly = false; + + CECHPWorkFly pWork = (CECHPWorkFly)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLYOFF); + if (m_pWorkMan.IsFreeFalling()) + { + pWork.m_bContinueFly = true; + m_pWorkMan.StartWork_p1(pWork); + } + else + { + pWork.m_bContinueFly = false; + m_pWorkMan.StartWork_p2(pWork); + } + } + } + else if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_LANDING) + { + if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0) + { + m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_FLY; + + if (IsDead() || m_bCandHangerOn || IsHangerOn()) + ShowWing(false); + else + { + CECHPWorkFall pWork = + (CECHPWorkFall)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FREEFALL); + pWork.SetFallType(CECHPWorkFall.Fall_type.TYPE_FLYFALL); + m_pWorkMan.StartWork_p1(pWork); + } + + // Below two lines will fix the "host stand in air" bug. + m_iMoveEnv = Move_environment.MOVEENV_GROUND; + m_CDRInfo.vTPNormal.Clear(); + } + } + else // HOST_RUSH_FLY + { + cmd_host_rush_fly pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_bRushFly = pCmd.is_active != 0 ? true : false; + } + } + + void OnMsgHstPetOpt(ECMSG Msg) + { + CECGameRun pGameRun = EC_Game.GetGameRun(); + int header = Convert.ToInt32(Msg.dwParam2); + switch (header) + { + case CommandID.GAIN_PET: + { + cmd_gain_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.AddPet(pCmd.slot_index, pCmd.data); + + // Print a notify + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); + if (pPet != null) + { + if (pPet.IsFollowPet() || pPet.IsCombatPet() || pPet.IsEvolutionPet()) + { + // TO DO: fix later + //pGameRun.AddFixedMessage(FIXMSG_PET_HATCH, pPet.GetName()); + } + else if (pPet.IsSummonPet()) + { + // TO DO: fix later + //pGameRun.AddFixedMessage(FIXMSG_SUMMON_PET_APPEAR, pPet.GetName()); + } + } + + break; + } + + case CommandID.FREE_PET: + { + cmd_free_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + // Print a notify + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); + if (pPet != null) + { + if (pPet.IsFollowPet() || pPet.IsCombatPet() || pPet.IsEvolutionPet()) + { + // TO DO: fix later + //pGameRun.AddFixedMessage(FIXMSG_PET_FREE, pPet.GetName()); + } + else if (pPet.IsSummonPet()) + { + // TO DO: fix later + //pGameRun.AddFixedMessage(FIXMSG_SUMMON_PET_DISAPPEAR, pPet.GetName()); + } + } + + // Remove pet from corral + m_pPetCorral.FreePet(pCmd.slot_index, pCmd.pet_id); + // Update pet shortcuts + UpdateFreedPetSC(pCmd.slot_index); + + break; + } + case CommandID.SUMMON_PET: + { + cmd_summon_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); + //ASSERT(pPet && pPet.GetTemplateID() == pCmd.pet_tid); + m_pPetCorral.SetActivePetIndex(pCmd.slot_index); + m_pPetCorral.SetActivePetNPCID(pCmd.pet_pid); + m_pPetCorral.SetActivePetLifetime(pCmd.life_time); + + if (EC_Game.GetConfigs().GetGameSettings().bPetAutoSkill) + { + for (int i = 0; i < pPet.GetSkillNum(SKILLTYPE.EM_SKILL_DEFAULT); i++) + { + PETSKILL? pSkill = pPet.GetSkill(SKILLTYPE.EM_SKILL_DEFAULT, i); + if (pSkill != null && EC_Game.IsPetAutoSkill(pSkill.Value.idSkill)) + pPet.AddAutoSkill(pSkill.Value.idSkill); + } + } + + // TO DO: fix later + //OnPetSays(pCmd.pet_tid, pCmd.pet_pid, CECPetWords::TW_SUMMON); + //if (pPet.IsCombatPet() || pPet.IsSummonPet() || pPet.IsEvolutionPet()) + // CDlgQuickBarPet::ResetAutoCastSkill(); + break; + } + case CommandID.RECALL_PET: + { + cmd_recall_pet pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + //ASSERT(pCmd.slot_index == m_pPetCorral.GetActivePetIndex()); + + int tid = pCmd.pet_id; + int nid = m_pPetCorral.GetActivePetNPCID(); + + // 锟斤拷锟斤拷锟叫伙拷说 + switch (pCmd.reason) + { + case (char)PET_RECALL_REASON.PET_RECALL_DEFAULT: + //OnPetSays(tid, nid, CECPetWords::TW_RECALL); + break; + + case (char)PET_RECALL_REASON.PET_RECALL_DEATH: + //OnPetSays(tid, nid, CECPetWords::TW_DEAD); + break; + + case (char)PET_RECALL_REASON.PET_RECALL_LIFE_EXHAUST: + //OnPetSays(tid, nid, CECPetWords::TW_DISAPPEAR); + break; + + case (char)PET_RECALL_REASON.PET_RECALL_SACRIFICE: + //OnPetSays(tid, nid, CECPetWords::TW_SACRIFICE); + break; + } + + CECPetData pPet = m_pPetCorral.GetActivePet(); + if (pPet != null) + pPet.OnPetDead(); + + m_pPetCorral.SetActivePetIndex(-1); + m_pPetCorral.SetActivePetNPCID(0); + m_bPetInSanctuary = false; + break; + } + case CommandID.PLAYER_START_PET_OP: + { + cmd_player_start_pet_op pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + int iDoWhat; + if (pCmd.op == 0) + iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_SUMMONPET; + else if (pCmd.op == 1) + iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_RECALLPET; + else if (pCmd.op == 2) + iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_BANISHPET; + else if (pCmd.op == 3) + iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_RESTOREPET; + else + iDoWhat = (int)CECHPWorkConcentrate.eDO_PET.DO_UNKNOWN; + + m_PetOptCnt.SetPeriod(pCmd.delay * 50); + m_PetOptCnt.Reset(); + + CECHPWorkConcentrate pWork = + (CECHPWorkConcentrate)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE); + pWork.SetDoWhat(iDoWhat); + m_pWorkMan.StartWork_p1(pWork); + break; + } + case CommandID.PLAYER_STOP_PET_OP: + { + if (IsOperatingPet() != 0) + m_pWorkMan.FinishRunningWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE); + + break; + } + case CommandID.PET_RECEIVE_EXP: + { + cmd_pet_receive_exp pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); + if (pPet != null) + { + //ASSERT(pPet.GetTemplateID() == pCmd.pet_id); + pPet.AddExp(pCmd.exp); + } + + break; + } + case CommandID.PET_LEVELUP: + { + cmd_pet_levelup pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.slot_index); + if (pPet != null) + { + //ASSERT(pPet.GetTemplateID() == pCmd.pet_id); + pPet.LevelUp(pCmd.level, pCmd.exp); + } + + //pGameRun.AddFixedMessage(FIXMSG_PET_LEVELUP, pCmd.level); + break; + } + case CommandID.PET_ROOM: + { + cmd_pet_room pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.UpdatePets(pCmd, (byte[])Msg.dwParam1); + + CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + + //if (pGameUI.GetDialog("Win_Teach").IsShow()) + // { + // //pGameUI.UpdateTeach(); + // } + + break; + } + case CommandID.PET_ROOM_CAPACITY: + { + cmd_pet_room_capacity pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.MagnifyPetSlots((int)pCmd.capacity); + + if (m_pPetCorral.HasInit()) + { + //pGameRun.AddFixedMessage(FIXMSG_PET_ROOM_SIZE, pCmd.capacity); + } + else + m_pPetCorral.SetHasInit(true); + + break; + } + case CommandID.PET_HONOR_POINT: + { + cmd_pet_honor_point pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.index); + if (pPet != null) + pPet.SetIntimacy(pCmd.cur_honor_point); + + break; + } + case CommandID.PET_HUNGER_GAUGE: + { + cmd_pet_hunger_gauge pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.index); + if (pPet != null) + pPet.SetHunger(pCmd.cur_hunge_gauge); + + break; + } + case CommandID.PET_DEAD: + { + cmd_pet_dead pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); + if (pPet != null) + { + pPet.SetHPFactor(0.0f); + pPet.SetHP(0); + pPet.OnPetDead(); + } + + //pGameRun.AddFixedMessage(FIXMSG_PET_DEAD); + break; + } + case CommandID.PET_REVIVE: + { + cmd_pet_revive pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); + if (pPet != null) + pPet.SetHPFactor(pCmd.hp_factor); + + break; + } + case CommandID.PET_HP_NOTIFY: + { + cmd_pet_hp_notify pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData((int)pCmd.pet_index); + if (pPet != null) + { + int lastHP = pPet.GetHP(); + + pPet.SetHPFactor(pCmd.hp_factor); + pPet.SetHP(pCmd.cur_hp); + + pPet.SetMPFactor(pCmd.mp_factor); + pPet.SetMP(pCmd.cur_mp); + + // If HP is too low, popup a warning on pet's head + int iLimit = (int)(pPet.CalcMaxHP() * 0.3f); + if (pCmd.cur_hp < lastHP && lastHP != 0 && pCmd.cur_hp < iLimit) + { + CECNPC pNPC = EC_Game.GetGameRun().GetWorld().GetNPCMan() + .GetNPC(m_pPetCorral.GetActivePetNPCID()); + if (pNPC && pNPC.GetMasterID() == GetCharacterID()) + { + //pNPC.BubbleText(CECNPC::BUBBLE_HPWARN, 0); + } + } + } + + break; + } + case CommandID.PET_AI_STATE: + { + cmd_pet_ai_state pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + // 锟斤拷锟斤拷锟叫伙拷说 + CECPetData pPetData = m_pPetCorral.GetActivePet(); + if (pPetData != null) + { + int tid = pPetData.GetTemplateID(); + int nid = m_pPetCorral.GetActivePetNPCID(); + if (m_pPetCorral.GetMoveMode() != pCmd.move) + { + switch (pCmd.move) + { + case (byte)CECPetCorral.ePet_MovingMode.MOVE_FOLLOW: + { + //OnPetSays(tid, nid, CECPetWords::TW_FOLLOW); + break; + } + case (byte)CECPetCorral.ePet_MovingMode.MOVE_STAND: + { + //OnPetSays(tid, nid, CECPetWords::TW_STOP); + break; + } + } + } + + if (m_pPetCorral.GetAttackMode() != pCmd.attack) + { + switch (pCmd.attack) + { + case (byte)CECPetCorral.ePet_AttackingMode.ATK_DEFENSE: + //OnPetSays(tid, nid, CECPetWords::TW_DEFENSIVE); + break; + + case (byte)CECPetCorral.ePet_AttackingMode.ATK_POSITIVE: + //OnPetSays(tid, nid, CECPetWords::TW_OFFENSIVE); + break; + + case (byte)CECPetCorral.ePet_AttackingMode.ATK_PASSIVE: + //OnPetSays(tid, nid, CECPetWords::TW_PASSIVE); + break; + } + } + } + + m_pPetCorral.SetMoveMode(pCmd.move); + m_pPetCorral.SetAttackMode(pCmd.attack); + break; + } + case CommandID.PET_SET_COOLDOWN: + { + cmd_pet_set_cooldown pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.pet_index); + if (pPet != null) + pPet.SetSkillCoolTime(pCmd.cooldown_index, pCmd.cooldown_time); + + break; + } + + case CommandID.SUMMON_PLANT_PET: + { + int size = Marshal.SizeOf(); + if (((byte[])Msg.dwParam1).Length >= size) + { + cmd_summon_plant_pet pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.PlantPetEnter(pCmd); + } + + break; + } + + case CommandID.PLANT_PET_DISAPPEAR: + { + int size = Marshal.SizeOf(); + if (((byte[])Msg.dwParam1).Length >= size) + { + cmd_plant_pet_disapper pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.PlantPetDisappear(pCmd); + } + + break; + } + + case CommandID.PLANT_PET_HP_NOTIFY: + { + int size = Marshal.SizeOf(); + if (((byte[])Msg.dwParam1).Length >= size) + { + cmd_plant_pet_hp_notify pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_pPetCorral.PlantPetInfo(pCmd); + } + + break; + } + + case CommandID.PET_PROPERTY: + { + cmd_pet_property pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + CECPetData pPet = m_pPetCorral.GetPetData(pCmd.pet_index); + if (pPet != null) + { + pPet.SetExtendProps(pCmd.prop); + } + + break; + } + case CommandID.PET_REBUILD_INHERIT_START: + case CommandID.PET_REBUILD_INHERIT_INFO: + case CommandID.PET_REBUILD_INHERIT_END: + case CommandID.PET_EVOLUTION_DONE: + case CommandID.PET_REBUILD_NATURE_START: + case CommandID.PET_REBUILD_NATURE_INFO: + case CommandID.PET_REBUILD_NATURE_END: + { + CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + if (pGameUI != null) + { + //((CDlgPreviewPetRebuild*)pGameUI.GetDialog("Win_PreviewPet")).OnServerNotify(Msg.dwParam2, (void*)Msg.dwParam1); + } + + break; + } + + default: + break; + } + } + + /* Is host operating pet ? + return value: + + 0: host doesn't operating pet. + 1: host is summoning pet. + 2: host is recalling pet. + 3: host is banishing pet. + */ + public int IsOperatingPet() + { + CECHPWorkConcentrate pWork = + (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE)) as CECHPWorkConcentrate; + if (pWork != null) + { + if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_SUMMONPET) + return 1; + else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RECALLPET) + return 2; + else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_BANISHPET) + return 3; + else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RESTOREPET) + return 4; + } + + return 0; + } + + // Summon pet + public bool SummonPet(int iPetIdx) + { + if (m_pActionSwitcher != null) + m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_MOUNTPET); + + CECGameRun pGameRun = EC_Game.GetGameRun(); + + CECPetData pPet = m_pPetCorral.GetPetData(iPetIdx); + if (pPet == null) + return false; + + if (!CanDo(ActionCanDo.CANDO_SUMMONPET)) + return false; + + // Couldn't summon daed pet + if (pPet.IsDead()) + { + //pGameRun.AddFixedMessage(FIXMSG_PET_DEAD); + Debug.LogError("FIXMSG_PET_DEAD"); + return false; + } + + // If host could't stop naturally, cancel summoning + if (!NaturallyStopMoving()) + return false; + + // 录矛虏茅碌卤脟掳脢脟路帽陆没脰鹿脮脵禄陆脝茂鲁猫 + if (pPet.IsMountPet() && m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOMOUNT]) + return false; + + if (m_ReincarnationCount != 0) + { + int iLevelRequired = pPet.GetLevel() - 35 - m_ReincarnationCount * 5; + if (m_BasicProps.iLevel < iLevelRequired) + { + CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + if (pGameUI != null) + { + // TO DO: fix later + //string strText = ""; + //strText.Format(pGameUI.GetStringFromTable(10787), iLevelRequired); + //pGameUI.MessageBox("", strText, MB_OK, A3DCOLORRGBA(255, 255, 255, 160)); + } + + return false; + } + } + + UnityGameSession.c2s_CmdPetSummon(iPetIdx); + + return true; + } + public CECPetCorral GetPetCorral() + { + return m_pPetCorral; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Pet.cs.meta b/Assets/Scripts/CECHostPlayer.Pet.cs.meta new file mode 100644 index 0000000000..b1127e2ede --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Pet.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 199b19ff05aa30049aca1caf465398f0 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.PlayerProperty.cs b/Assets/Scripts/CECHostPlayer.PlayerProperty.cs new file mode 100644 index 0000000000..be0fbad0a0 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.PlayerProperty.cs @@ -0,0 +1,79 @@ +using CSNetwork; +using CSNetwork.GPDataType; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + void OnMsgHstExtProp(ECMSG Msg) + { + cmd_own_ext_prop pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + m_ExtProps = pCmd.prop; + m_BasicProps.iStatusPt = (int)pCmd.status_point; + m_BasicProps.iAtkDegree = pCmd.attack_degree; + m_BasicProps.iDefDegree = pCmd.defend_degree; + m_BasicProps.iCritRate = pCmd.crit_rate; + m_BasicProps.iCritDamageBonus = pCmd.crit_damage_bonus; + m_BasicProps.iInvisibleDegree = pCmd.invisible_degree; + m_BasicProps.iAntiInvisibleDegree = pCmd.anti_invisible_degree; + m_BasicProps.iPenetration = pCmd.penetration; + m_BasicProps.iResilience = pCmd.resilience; + m_BasicProps.iVigour = pCmd.vigour; + } + + private void OnMsgHstInfo00(in ECMSG Msg) + { + cmd_self_info_00 pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + bool bFirstTime = m_BasicProps.iLevel == 0 ? true : false; + if (!bFirstTime) + { + int iLimit = (int)(pCmd.iMaxHP * 0.3f); + if (pCmd.iHP < m_BasicProps.iCurHP && m_BasicProps.iCurHP >= iLimit && pCmd.iHP < iLimit) + { + /*if (CECUIHelper::GetGameUIMan().IsShowLowHP()) { + // 脩陋脕驴碌脥脫脷脕脵陆莽脰碌脭貌虏楼路脜脤脴脨搂 + const int GfxLastTime = 10000; // 鲁脰脨酶脢卤录盲10脙毛 + CECUIHelper::GetGameUIMan().GetScreenEffectMan().StartEffect(CECScreenEffect::EFFECT_REDSPARK, GfxLastTime); + }*/ + } + + /*if (pCmd.iHP >= iLimit || pCmd.iHP <= 0) { + // 脩陋脕驴赂脽脫脷脕脵陆莽脰碌禄貌脣脌脥枚拢卢脭貌脥拢脰鹿虏楼路脜脤脴脨搂 + CECUIHelper::GetGameUIMan().GetScreenEffectMan().FinishEffect(CECScreenEffect::EFFECT_REDSPARK); + }*/ + + /*iLimit = (int)(pCmd.iMaxMP * 0.2f); + if (pCmd.iMP < m_BasicProps.iCurMP && m_BasicProps.iCurMP >= iLimit && pCmd.iMP < iLimit) + BubbleText(BUBBLE_MPWARN, 0);*/ + + /*if (m_ExtProps.max_ap != pCmd.iMaxAP) + g_pGame.GetGameRun().AddFixedMessage(FIXMSG_ADDMAXAP, pCmd.iMaxAP - m_ExtProps.max_ap);*/ + } + + m_BasicProps.iLevel = pCmd.sLevel; + SetLevel2(pCmd.Level2, bFirstTime); + m_BasicProps.iExp = pCmd.iExp; + m_BasicProps.iSP = pCmd.iSP; + m_BasicProps.iCurHP = pCmd.iHP; + m_BasicProps.iCurMP = pCmd.iMP; + m_BasicProps.iCurAP = pCmd.iAP; + m_ExtProps.bs.max_hp = pCmd.iMaxHP; + m_ExtProps.bs.max_mp = pCmd.iMaxMP; + m_ExtProps.max_ap = pCmd.iMaxAP; + + EventBus.Publish(new EXPToUpLevel(GetLevelUpExp(pCmd.sLevel))); + EventBus.Publish(pCmd); + EventBus.PublishChannel(GetCharacterID(), pCmd); + // if (pCmd.State != 0 && m_bFight == false) PlayEnterBattleGfx(); + m_bFight = pCmd.State != 0 ? true : false; + + // UpdateGodEvilSprite(); + + /*CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); + CDlgAutoHelp *pDlgHelp = dynamic_cast(pGameUI.GetDialog("Win_WikiPop"));*/ + /*if(pDlgHelp && m_bFight) + pDlgHelp.SetAutoHelpState(false);*/ + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.PlayerProperty.cs.meta b/Assets/Scripts/CECHostPlayer.PlayerProperty.cs.meta new file mode 100644 index 0000000000..5ae6244f3d --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.PlayerProperty.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a19218082b79eef4687286340cd52157 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Skill.cs b/Assets/Scripts/CECHostPlayer.Skill.cs new file mode 100644 index 0000000000..5274471353 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Skill.cs @@ -0,0 +1,1788 @@ +using BrewMonster.Scripts; +using BrewMonster.Scripts.Skills; +using CSNetwork; +using CSNetwork.GPDataType; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using BrewMonster.Assets.PerfectWorld.Scripts.Players; +using BrewMonster.Managers; +using BrewMonster.Network; +using BrewMonster.Scripts.Managers; +using BrewMonster.Scripts.World; +using PerfectWorld.Scripts.Managers; +using UnityEngine; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + public struct SkillShortCutConfig + { + public int setNum; + public int slotNum; + public int skillId; + }; + + public struct SkillGrpShortCutConfig + { + public int setNum; + public int slotNum; + public int groupIndex; + }; + + public CECSkill GetNormalSkill(int id, bool bSenior = false /* false */) + { + CECSkill pSkill = null; + if (ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_PASSIVE || + ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_PRODUCE || + ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_LIVE) + pSkill = GetPassiveSkillByID(id, bSenior); + else + pSkill = GetPositiveSkillByID(id, bSenior); + + if (pSkill == null) // && m_pGoblin) + { + // This is a goblin skill + for (int i = 0; i < m_aGoblinSkills.Count; i++) + { + if (m_aGoblinSkills[i].GetSkillID() == id) + return m_aGoblinSkills[i]; + } + } + + if (pSkill == null) // may be target item skill + { + if (m_pTargetItemSkill != null && m_pTargetItemSkill.GetSkillID() == id) + pSkill = m_pTargetItemSkill; + } + + return pSkill; + } + + public CECComboSkill GetComboSkill() + { + return m_pComboSkill; + } + + private void OnMsgHstSkillData(ECMSG Msg) + { + cmd_skill_data pCmd = default; + pCmd.skill_count = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + int offset = sizeof(uint); + int skillSize = Marshal.SizeOf(); + pCmd.skill_list = new cmd_skill_data.SKILL[pCmd.skill_count]; + for (int i = 0; i < pCmd.skill_count; i++) + { + pCmd.skill_list[i] = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1, offset); + offset += skillSize; + } + + if (pCmd.skill_list == null) + { + BMLogger.LogError("OnMsgHstSkillData: cmd is null"); + return; + } + + List skillSCConfigArray1 = new List(); + List skillSCConfigArray2 = new List(); + List skillGrpSCConfigArray1 = new List(); + List skillGrpSCConfigArray2 = new List(); + + if (HostIsReady()) + { + m_pWorkMan.FinishWork(new CECHPTraceSpellMatcher()); + m_pPrepSkill = null; + m_pCurSkill = null; + ClearComboSkill(); + SaveSkillShortcut(skillSCConfigArray1, m_aSCSets1, (int)Shortcut.NUM_HOSTSCSETS1); + SaveSkillShortcut(skillSCConfigArray2, m_aSCSets2, (int)Shortcut.NUM_HOSTSCSETS2); + SaveSkillGrpShortcut(skillGrpSCConfigArray1, m_aSCSets1, (int)Shortcut.NUM_HOSTSCSETS1); + SaveSkillGrpShortcut(skillGrpSCConfigArray2, m_aSCSets2, (int)Shortcut.NUM_HOSTSCSETS2); + /* + for (int i = 0; i < HostConstants.NUM_HOSTSCSETS1; i++) + { + if (hostPlayer.m_aSCSets1[i] != null) + { + hostPlayer.m_aSCSets1[i].RemoveSkillShortcuts(); + } + } + qqqqqqaaaaaaaaw + for (int i = 0; i < HostConstants.NUM_HOSTSCSETS2; i++) + { + if (hostPlayer.m_aSCSets2[i] != null) + { + hostPlayer.m_aSCSets2[i].RemoveSkillShortcuts(); + } + }*/ + + // Release passive skills + m_aSCSets1 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS1]; + m_aSCSets2 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS2]; + m_aPtSkills.Clear(); + m_aPsSkills.Clear(); + } + + // Load skill data from command + // C++: GNET::ElementSkill::LoadSkillData(pCmd); + ElementSkill.LoadSkillData(pCmd); + // Create skill objects from command data + for (int i = 0; i < pCmd.skill_count; i++) + { + cmd_skill_data.SKILL data = pCmd.skill_list[i]; + CECSkill skill = new CECSkill(data.id_skill, data.level); + + // Categorize skills into positive and passive + int skillType = skill.GetType(); + if (skillType != (int)CECSkill.SkillType.TYPE_PASSIVE && + skillType != (int)CECSkill.SkillType.TYPE_PRODUCE && + skillType != (int)CECSkill.SkillType.TYPE_LIVE) + { + m_aPtSkills.Add(skill); + } + else + { + m_aPsSkills.Add(skill); + } + } + + // Restore and convert shortcuts after loading new skills + if (HostIsReady()) + { + ConvertSkillShortcut(skillSCConfigArray1); + AssignSkillShortcut(skillSCConfigArray1, m_aSCSets1); + ConvertSkillShortcut(skillSCConfigArray2); + AssignSkillShortcut(skillSCConfigArray2, m_aSCSets2); + ConvertComboSkill(); + ValidateSkillGrpShortcut(skillGrpSCConfigArray1); + AssignSkillGrpShortcut(skillGrpSCConfigArray1, m_aSCSets1); + ValidateSkillGrpShortcut(skillGrpSCConfigArray2); + AssignSkillGrpShortcut(skillGrpSCConfigArray2, m_aSCSets2); + } + + if (HostIsReady()) + { + // Update UI when profession changes, save all shortcut configurations + // to remove effects from intermediate skills (invalid pointers) + // C++: CECGameUIMan *pGameUIMan = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); + // pGameUIMan.UpdateSkillRelatedUI(); + CECUIManager.Instance.UpdateSkillRelatedUI(); + } + } + + private void OnMsgHstLearnSkill(ECMSG Msg) + { + cmd_learn_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + CECSkill pSkill = GetNormalSkill(pCmd.skill_id); + if (pSkill != null) + { + if (pCmd.skill_level > 0) + { + pSkill.LevelUp(); + ElementSkill.SetLevel((uint)pCmd.skill_id, pCmd.skill_level); + } + else + { + RemoveNormalSkill(pCmd.skill_id); + } + } + else if (pCmd.skill_level > 0) + { + pSkill = new CECSkill(pCmd.skill_id, pCmd.skill_level); + if (pSkill == null) + { + Debug.Assert(pSkill != null); + return; + } + + if (!pSkill.GetJunior().Empty()) + { + ReplaceJuniorSkill(pSkill); + } + else + { + if (pSkill.GetType() != (int)CECSkill.SkillType.TYPE_PASSIVE && + pSkill.GetType() != (int)CECSkill.SkillType.TYPE_PRODUCE && + pSkill.GetType() != (int)CECSkill.SkillType.TYPE_LIVE) + m_aPtSkills.Add(pSkill); + else + m_aPsSkills.Add(pSkill); + } + + ElementSkill.SetLevel((uint)pCmd.skill_id, pCmd.skill_level); + } + + CECHostSkillModel.Instance.OnLearnSkill(pCmd.skill_id, pCmd.skill_level); + } + + private void OnMsgComboSkillPrepare(ECMSG Msg) + { + cmd_combo_skill_prepare cmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + uint skillID = (uint)cmd.skill_id; + + ComboSkillState comboSkillState = new() + { + skillid = skillID, + arg = new int[ComboSkillState.MAX_COMBO_ARG] + }; + comboSkillState.arg = cmd.args; + /* if (cmd.args != null) + { + Array.Copy(cmd.args, comboSkillState.arg, Math.Min(cmd.args.Length, ComboSkillState.MAX_COMBO_ARG)); + }*/ + + Dictionary comboSkillList = ElementSkill.GetComboSkActivated(comboSkillState); + CECComboSkillState.Instance.SetComboSkillState(comboSkillList, ref comboSkillState); + } + + private void OnMsgContinueComboSkill(ECMSG Msg) + { + bool bMeleeing = ((int)Msg.dwParam1 == 1); + if (bMeleeing != m_bMelee) bMeleeing = m_bMelee; + int iGroupID = (int)Msg.dwParam2; + if (m_pComboSkill != null && m_pComboSkill.GetGroupIndex() == iGroupID && !m_pComboSkill.IsStop()) + m_pComboSkill.Continue(bMeleeing); + } + + private void OnMsgHstCoolTimeData(ECMSG Msg) + { + cmd_cooltime_data pCmd = default; + var data = (byte[])Msg.dwParam1; + pCmd.count = GPDataTypeHelper.FromBytes(data, 0); + long offset = Marshal.SizeOf(typeof(ushort)); + pCmd.list = new item_t[pCmd.count]; + for (int i = 0; i < pCmd.count; i++) + { + pCmd.list[i] = GPDataTypeHelper.FromBytes(data, ref offset); + } + + m_skillCoolTime.Clear(); + + for (int i = 0; i < pCmd.count; i++) + { + item_t item = pCmd.list[i]; + if (item.idx > (int)CoolTimeIndex.GP_CT_SKILL_START) + { + // Is skill cool time + int idSkill = item.idx - (int)CoolTimeIndex.GP_CT_SKILL_START; + + COOLTIME ct = default; + ct.iCurTime = item.cooldown; + ct.iMaxTime = item.max_cooltime; + Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime); + + CECSkill pSkill = GetNormalSkill(idSkill); + if (pSkill != null) + { + pSkill.StartCooling(item.max_cooltime, item.cooldown); + } + /* else if (pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill)) + { + pSkill.StartCooling(item.max_cooltime, item.cooldown); + }*/ + else if (GetEquipSkillByID(idSkill) == null) + { + // Add to goblin skill list + pSkill = new CECSkill(idSkill, 1); + pSkill.StartCooling(item.max_cooltime, item.cooldown); + m_aGoblinSkills.Add(pSkill); + } + + m_skillCoolTime[idSkill] = ct; + } + else if (item.idx >= 0 && item.idx < (int)CoolTimeIndex.GP_CT_MAX) + { + // Other cool time + COOLTIME ct = m_aCoolTimes[item.idx]; + ct.iCurTime = item.cooldown; + ct.iMaxTime = item.max_cooltime; + Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime); + + if (item.idx >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && + item.idx <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) + { + // other player skills should be set public cool down too. + uint mask = (uint)(1 << (item.idx - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0)); + for (int y = 0; y < GetPositiveSkillNum(); y++) + { + CECSkill pSkill = GetPositiveSkillByIndex(y); + if (pSkill != null && ((pSkill.GetCommonCoolDown() & mask) != 0)) + pSkill.StartCooling(item.max_cooltime, item.cooldown); + } + } + } + else + { + BMLogger.LogError("item.idx >= 0: " + (item.idx >= 0)); + } + } + + UpdateEquipSkillCoolDown(); + } + + private void OnMsgHstSetCoolTime(ECMSG Msg) + { + cmd_set_cooldown pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + if (pCmd.cooldown_index < 0) + { + BMLogger.LogError("pCmd.cooldown_index >= 0 :" + (pCmd.cooldown_index >= 0)); + return; + } + + if (pCmd.cooldown_index < (int)CoolTimeIndex.GP_CT_MAX) + { + COOLTIME ct = m_aCoolTimes[pCmd.cooldown_index]; + ct.iCurTime = pCmd.cooldown_time; + ct.iMaxTime = pCmd.cooldown_time; + Math.Min(ct.iCurTime, ct.iMaxTime); + m_aCoolTimes[pCmd.cooldown_index] = ct; + if (pCmd.cooldown_index == (int)CoolTimeIndex.GP_CT_CAST_ELF_SKILL) + { + int i; + for (i = 0; i < m_aGoblinSkills.Count; i++) + { + if (m_aGoblinSkills[i] != null && m_aGoblinSkills[i].GetCoolingCnt() == 0) + { + int fakeRef = 0; + int coolTime = GetCoolTime((int)CoolTimeIndex.GP_CT_CAST_ELF_SKILL, out fakeRef); + m_aGoblinSkills[i].StartCooling(coolTime, coolTime); + } + } + + for (i = 0; i < m_aPsSkills.Count; i++) + { + CECSkill pSkill = GetPassiveSkillByIndex(i); + if (pSkill != null && (pSkill.GetCommonCoolDown() & + (1 << (pCmd.cooldown_index - + (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0))) != 0) + { + int fakeRef = 0; + int coolTime = GetCoolTime(pCmd.cooldown_time, out fakeRef); + pSkill.StartCooling(coolTime, coolTime); + } + } + } + + if (pCmd.cooldown_index >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && + pCmd.cooldown_index <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) + { + // other player skills should be set public cool down too. + uint mask = (uint)(1 << (pCmd.cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0)); + for (int i = 0; i < GetPositiveSkillNum(); i++) + { + CECSkill pSkill = GetPositiveSkillByIndex(i); + int fakeRef = 0; + if (pSkill != null && (pSkill.GetCommonCoolDown() & mask) != 0) + { + int coolTime = GetCoolTime(pCmd.cooldown_index, out fakeRef); + pSkill.StartCooling(coolTime, coolTime); + //pSkill.StartCooling(GetCoolTime(pCmd.cooldown_index, out fakeRef), GetCoolTime(pCmd.cooldown_index, out fakeRef)); + } + } + /*const std::map&inherentSkillMap = CECComboSkillState::Instance().GetInherentSkillMap(); + std::map < unsigned int, CECSkill*>::const_iterator it; + for (it = inherentSkillMap.begin(); it != inherentSkillMap.end(); ++it) + { + it.second.StartCooling(GetCoolTime(pCmd.cooldown_index), GetCoolTime(pCmd.cooldown_index)); + }*/ + } + } + else if (pCmd.cooldown_index > (int)CoolTimeIndex.GP_CT_SKILL_START) + { + int idSkill = pCmd.cooldown_index - (int)CoolTimeIndex.GP_CT_SKILL_START; + + COOLTIME ct; + if (!m_skillCoolTime.TryGetValue(idSkill, out ct)) + { + // Key doesn't exist, create new entry + ct = new COOLTIME(); + m_skillCoolTime[idSkill] = ct; + } + + ct.iCurTime = pCmd.cooldown_time; + ct.iMaxTime = pCmd.cooldown_time; + ct.iCurTime = Math.Clamp(ct.iCurTime, 0, ct.iMaxTime); + m_skillCoolTime[idSkill] = ct; + //Math.Clamp(ct.iCurTime, 0, ct.iMaxTime); + + CECSkill pSkill = GetNormalSkill(idSkill); + if (pSkill != null) + { + pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); + } + /* else if (pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill)) + { + pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); + }*/ + else if (GetEquipSkillByID(idSkill) == null) + { + BMLogger.LogError("HoangDev: pSkill " + pSkill); + } + else + { + pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); + if (pSkill != null) + { + pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); + } + else if (GetEquipSkillByID(idSkill) == null) + { + Debug.LogWarning($"OnMsgHstSetCoolTime: Skill {idSkill} not found in nomal/equip skills"); + } + } + } + else + { + // This is a annoying assert and mean nothing, so we ignore it. + // ASSERT(0); + } + + UpdateEquipSkillCoolDown(pCmd.cooldown_index); + } + + public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */, + int idSelTarget = 0 /* 0 */, int iForceAtk = -1 /* -1 */) + { + //StackChecker::ACTrace(4); + + if (m_pActionSwitcher != null) + m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_CASTSKILL); + + // Return-town skill is very special, handle it separately + // 鍥炲煄鎶鑳介潪甯哥壒娈婏紝鍗曠嫭澶勭悊 + if (idSkill == ID_RETURNTOWN_SKILL) + { + Debug.Log($"ApplySkillShortcut: Skill 167 detected, calling ReturnToTargetTown"); + return ReturnToTargetTown(0, bCombo); + } + + //if (idSkill == ID_SUMMONPLAYER_SKILL) + // return SummonPlayer(idSelTarget, bCombo); + + if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) + return false; + + if (InSlidingState()) + return false; + + if (!bCombo) + ClearComboSkill(); + + if (idSelTarget == 0) + idSelTarget = m_idSelTarget; + + CECSkill pSkill = GetPositiveSkillByID(idSkill); + if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); + if (pSkill == null) pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); + if (pSkill == null) + { + return false; + } + + //// If we press a chargeable skill again when it's being charged, + //// we cast it out at once + if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() && + m_pCurSkill.GetSkillID() == pSkill.GetSkillID()) + { + m_pCurSkill.EndCharging(); + UnityGameSession.c2s_SendCmdContinueAction(); + return true; + } + + int iCon = CheckSkillCastCondition(pSkill); + if (iCon != 0) + { + ProcessSkillCondition(iCon); + return false; + } + + //// Get force attack flag + bool bForceAttack = false; + if (iForceAtk < 0) + bForceAttack = glb_GetForceAttackFlag(0); + else + bForceAttack = iForceAtk > 0 ? true : false; + + //// Check negative effect skill + if (pSkill.GetType() == (int)skill_type.TYPE_ATTACK || pSkill.GetType() == (int)skill_type.TYPE_CURSE) + { + if (idSelTarget == m_PlayerInfo.cid) + { + // Host cannot spell negative effect magic to himself. + //EC_Game.GetGameRun().AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT); + return false; + } + else if (idSelTarget != 0) + { + if (AttackableJudge(idSelTarget, bForceAttack) != 1) + return false; + } + } + + //// Check whether target type match + int idCastTarget = idSelTarget; + int iTargetType = pSkill.GetTargetType(); + + if (pSkill.GetType() == (int)skill_type.TYPE_BLESS || + pSkill.GetType() == (int)skill_type.TYPE_NEUTRALBLESS) + { + if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(idSelTarget)) + idCastTarget = m_PlayerInfo.cid; + + // In some case, we shouldn't add bless effect to other players + if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) + { + // If host has set bless skill filter only to himself, bless skill couldn't add to other players + byte byBLSMask = EC_Utility.glb_BuildBLSMask(); + + if (pSkill.GetRangeType() == (int)range_type.RANGE_POINT) + { + if (!IsTeamMember(idCastTarget)) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0) + idCastTarget = m_PlayerInfo.cid; + else + { + EC_ElsePlayer pPlayer = + (EC_ElsePlayer)EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idCastTarget); + if (pPlayer == null) + { + // 脛驴卤锚脧没脢搂 + return false; + } + + if (pPlayer.IsInvader() || pPlayer.IsPariah()) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (!IsFactionMember(pPlayer.GetFactionID())) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (!IsFactionAllianceMember(pPlayer.GetFactionID())) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0) + idCastTarget = m_PlayerInfo.cid; + } + + if (GetForce() != pPlayer.GetForce()) + { + if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0) + idCastTarget = m_PlayerInfo.cid; + } + } + } + } + + // If host is in duel, bless skill couldn't add to opponent + if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp) + idCastTarget = m_PlayerInfo.cid; + + // If host is in battle, bless skill couldn't add to enemies + if (IsInBattle()) + { + EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget); + if (!InSameBattleCamp(pPlayer)) + idCastTarget = m_PlayerInfo.cid; + } + } + } + /* else if (pSkill.GetType() == CECSkill::TYPE_BLESSPET) + { + CECPet* pPet = g_pGame.GetGameRun().GetWorld().GetNPCMan().GetPetByID(idSelTarget); + if (!pPet || pPet.GetMasterID() == GetCharacterID()) + { + // Spell skill on host's pet + CECPetData* pPetData = m_pPetCorral.GetActivePet(); + if (!pPetData || + pPetData.GetClass() != GP_PET_CLASS_COMBAT && + pPetData.GetClass() != GP_PET_CLASS_SUMMON && + pPetData.GetClass() != GP_PET_CLASS_EVOLUTION) + return false; + + idCastTarget = m_pPetCorral.GetActivePetNPCID(); + } + // Only fighting pet can be blessed. + if (pPet && !pPet.CanBeAttacked()) + return false; + }*/ + else + { + if (iTargetType != 0 && idCastTarget == 0) + return false; + } + + // iTargetType == 4 means target must be pet. The problem is that pet will + // disappear from world after it died, so GetWorld().GetObject() will return + // NULL when host spells revive-pet skill on his dead pet. So, the target + // type of revive-pet skill should be 0 + if (iTargetType != 0) + { + // Target shoundn't be a corpse ? + int iAliveFlag = 0; + if (iTargetType == 1) + iAliveFlag = 1; + else if (iTargetType == 2) + iAliveFlag = 2; + + /* CECObject pObject = EC_Game.GetGameRun().GetWorld().GetObject(idCastTarget, iAliveFlag); + if (!pObject) + return false;*/ + } + + if (!IsMeleeing() && !IsSpellingMagic() && + (iTargetType == 0 || idCastTarget == m_PlayerInfo.cid)) + { + // Cast this skill need't checking cast distance + if (!pSkill.ReadyToCast()) + return false; + + if (!pSkill.IsInstant() && pSkill.GetType() != (int)Skilltype.TYPE_FLASHMOVE) + { + if (!NaturallyStopMoving()) + return false; // Couldn't stop naturally, so cancel casting skill + } + else if (pSkill.GetType() == (int)Skilltype.TYPE_FLASHMOVE) + { + if (!CanDo(ActionCanDo.CANDO_FLASHMOVE)) + return false; + } + + m_pPrepSkill = pSkill; + CastSkill(m_PlayerInfo.cid, bForceAttack); + } + else if (IsSpellingMagic() && m_pCurSkill == pSkill) + { + // If we are casting the same skill and it's in cooling time + return false; + } + else // Have to trace selected object before cast skill + { + if (!pSkill.ReadyToCast()) + return false; + + if (CECCastSkillWhenMove.Instance.IsSkillSupported(pSkill.GetSkillID(), this) && + m_pWorkMan.IsMovingToPosition() && + m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())) + { + m_pPrepSkill = pSkill; + return CastSkill(idCastTarget, bForceAttack); + } + else + { + bool bTraceOK = false; + bool bUseAutoPF = false; + CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); + if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) + bUseAutoPF = true; + + if (idCastTarget == 0) + { + idCastTarget = + GetCharacterID(); // 卤脺脙芒脣虏脪脝碌脠录录脛脺脢卤 idCastTarget 脦陋0碌录脰脗 CECWorkTrace::CreateTraceTarget 路碌禄脴驴脮 + } + + CECHPWork pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + if (pWork != null) + { + CECHPWorkTrace pWorkTrace = (CECHPWorkTrace)(pWork); + if (pWorkTrace.GetTraceReason() == CECHPWorkTrace.Trace_reason.TRACE_SPELL && + pWorkTrace.GetTarget() == idCastTarget && + pWorkTrace.GetPrepSkill() == pSkill) + return false; // We are just doing the same thing + + pWorkTrace.SetTraceTarget( + pWorkTrace.CreatTraceTarget(idCastTarget, CECHPWorkTrace.Trace_reason.TRACE_SPELL, + bForceAttack), + bUseAutoPF); + pWorkTrace.SetPrepSkill(pSkill); + bTraceOK = true; + } + else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) + { + CECHPWorkTrace pWork2 = + (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + pWork2.SetTraceTarget( + pWork2.CreatTraceTarget(idCastTarget, CECHPWorkTrace.Trace_reason.TRACE_SPELL, + bForceAttack), bUseAutoPF); + pWork2.SetPrepSkill(pSkill); + m_pWorkMan.StartWork_p1(pWork2); + bTraceOK = true; + } + + if (!bTraceOK) return false; + // } + //} + } + } + + return true; + } + + public CECSkill GetPrepSkill() + { + return m_pPrepSkill; + } + + public bool CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null) + { + // Check if prep skill is valid, ready to cast, and not currently spelling magic + if (m_pPrepSkill == null || !m_pPrepSkill.ReadyToCast() || IsSpellingMagic()) + { + // Check if skill can change to melee attack + if (m_pPrepSkill != null && m_pPrepSkill.ChangeToMelee()) + { + bool bFlag = m_pPrepSkill.ReadyToCast(); + + // Finish any tracing work + if (m_pWorkMan.IsTracing()) + m_pWorkMan.FinishRunningWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + + // Handle combo skill or normal attack + if (m_pComboSkill != null) + m_pComboSkill.Continue(false); + else + { + // Perform normal attack instead + NormalAttackObject(idTarget, true); + } + } + + m_pPrepSkill = null; + return false; + } + + if (m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK || + m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE) + { + if (idTarget != 0 && AttackableJudge(idTarget, bForceAttack) != 1) + { + m_pPrepSkill = null; + return false; + } + } + + //TODO: Check cast condition - method not yet implemented + int iRet = CheckSkillCastCondition(m_pPrepSkill); + if (iRet != 0) + { + switch (iRet) + { + case 2: // Need MP + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDMP); + break; + case 8: // Need AP + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDAP); + break; + case 10: // Pack full + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_PACKFULL1); + break; + case 20: // Need item + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDITEM); + break; + case 12: // HP unsatisfied + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_HP_UNSATISFIED); + break; + } + + m_pPrepSkill = null; + return false; + } + + byte byPVPMask = glb_BuildPVPMask(bForceAttack); + + Debug.Log($"HoangDev: Cast Skill ID={m_pPrepSkill.GetSkillID()}"); + + // Handle instant skills + if (m_pPrepSkill.IsInstant()) + { + int countTarget = 1; + targetsCastSkill = new int[countTarget]; + targetsCastSkill[0] = idTarget; + UnityGameSession.c2s_CmdCastInstantSkill(m_pPrepSkill.GetSkillID(), byPVPMask, countTarget, + targetsCastSkill); + m_pPrepSkill = null; + } + // Handle flash move skills (鐬Щ鎶鑳) + else if (m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE) + { + // Self or self-sphere range types + if (m_pPrepSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SLEF || + m_pPrepSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SELFSPHERE) + { + A3DVECTOR3 vDir = GetDir(); + float fDist = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); + + // 宸︿晶涔嬬考锛屽乏璺 (Left wing skill - jump left) + if (m_pPrepSkill.GetSkillID() == 1844) + { + vDir = A3d_RotatePosAroundY(-vDir, Mathf.PI / 2); + } + // 鍙充晶涔嬬考锛屽彸璺 (Right wing skill - jump right) + else if (m_pPrepSkill.GetSkillID() == 1845) + { + vDir = A3d_RotatePosAroundY(vDir, Mathf.PI / 2); + } + // 鑼冨洿灏忎簬0鍒欏悗璺 (If range < 0, jump backward) + else if (fDist < 0.0f) + { + vDir = -vDir; + } + + fDist = Mathf.Abs(fDist); + A3DVECTOR3 vDest = m_MoveCtrl.FlashMove(vDir, 100.0f, fDist); + UnityGameSession.c2s_CmdCastPosSkill(m_pPrepSkill.GetSkillID(), EC_Utility.ToVector3(vDest), + byPVPMask, 0, 0); + m_pPrepSkill = null; + } + else + { + // 鍒哄濡傚奖闅忚绫绘妧鑳 (Assassin shadow-following skills) + bool bSuccess = false; + + while (true) + { + // Break if no target or self-target + if (idTarget == 0 || idTarget == GetCharacterID()) + break; + + // Get target object + CECObject pObject = CECWorld.Instance.GetObject(idTarget, 0); + if (pObject == null) break; + + A3DVECTOR3 vHostPos = EC_Utility.ToA3DVECTOR3(transform.position); // GetPos() + A3DVECTOR3 vTargetPos = EC_Utility.ToA3DVECTOR3(pObject.transform.position); // pObject.GetPos() + + // 鍒ゆ柇鎶鑳介噴鏀捐窛绂婚檺鍒舵槸鍚︽弧瓒 (Check if skill cast distance is satisfied) + float fTouchRadius = 0.0f; + + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = pObject as CECNPC; + if (pNPC != null) + fTouchRadius = pNPC.GetTouchRadius(); + else + break; + } + else if (GPDataTypeHelper.ISPLAYERID(idTarget)) + { + EC_ElsePlayer pElsePlayer = pObject as EC_ElsePlayer; + if (pElsePlayer != null) + fTouchRadius = pElsePlayer.GetTouchRadius(); + else + break; + } + else + break; + + if (!CanTouchTarget(vTargetPos, fTouchRadius, 2)) + { + // Target is far - show message + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_TARGETISFAR); + Debug.Log("Target is too far"); + break; + } + + A3DVECTOR3 vMoveDir = vTargetPos - vHostPos; + float fDist = EC_Utility.ToVector3(vMoveDir).magnitude; + + // 璺濈鐩爣澶繎锛屼笉澶勭悊 (Too close to target, don't process) + float fNearDist = 0.0f; + // TODO: Implement IsTooNear + if (IsTooNear(vTargetPos, ref fNearDist)) + { + Debug.Log("Target is too near"); + break; + } + + // 璁$畻瑕佺Щ寰鐨勭洰鏍囦綅缃紙榛樿鍊硷級 (Calculate target position to move to) + vMoveDir.Normalize(); + A3DVECTOR3 vMovePos = vHostPos + vMoveDir * (fDist - fNearDist); + + // TODO: Implement ClampAboveGround + float fClampedHeight = ClampAboveGround(vMovePos); + if (Mathf.Abs(fClampedHeight - vMovePos.y) >= 5.0f) + { + Debug.Log("Would stuck or so"); + break; + } + + vMovePos.y = fClampedHeight; + bool bPosVerified = false; + + // 鐩爣涓哄甫鍑稿寘鐨 NPC 鏃讹紝鍗曠嫭澶勭悊 (Special handling for NPCs with collision) + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + // TODO: Implement CalcCollideFreePos for NPC AABB + CECNPC pNPC = pObject as CECNPC; + A3DAABB aabbNPC = new A3DAABB(); + if (pNPC.GetCHAABB(ref aabbNPC)) + { + A3DVECTOR3 vTestPos; + if (CalcCollideFreePos(aabbNPC, out vTestPos)) + { + vMovePos = vTestPos; + bPosVerified = true; + } + else + { + Debug.Log("Would stuck or so"); + break; + } + } + } + + // TODO: Implement collision checking + if (!bPosVerified && !IsPosCollideFree(vMovePos)) + { + A3DVECTOR3 vTestPos2; + if (!CalcVerticalCollideFreePos(vMovePos, out vTestPos2)) + { + Debug.Log("Would stuck or so"); + break; + } + + vMovePos = vTestPos2; + bPosVerified = true; + } + + //TODO: Implement IsTooNear check for final position + float reffake = 0; + if (IsTooNear(vMovePos, ref reffake)) + { + Debug.Log("Target is too near"); + break; + } + + // 鍙戦佸崗璁 (Send protocol) + UnityGameSession.c2s_CmdCastPosSkill(m_pPrepSkill.GetSkillID(), EC_Utility.ToVector3(vMovePos), + byPVPMask, 1, idTarget); + bSuccess = true; + } + + m_pPrepSkill = null; + return bSuccess; + } + } + else + { + // Regular skill casting + byte byPVPMask2 = glb_BuildPVPMask(bForceAttack); + int targets = 1; + targetsCastSkill = new int[targets]; + targetsCastSkill[0] = idTarget; + UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask2, targets, targetsCastSkill); + } + + return true; + } + + // Return to a target town through skill + // 閫氳繃鎶鑳借繑鍥炵洰鏍囧煄闀 + private bool ReturnToTargetTown(int idTarget, bool bCombo = false) + { + if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) + { + return false; + } + + int idSkill = ID_RETURNTOWN_SKILL; + CECSkill pSkill = GetPositiveSkillByID(idSkill); + if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); + if (pSkill == null) + { + Debug.LogError("ReturnToTargetTown: Skill 167 not found"); + return false; + } + + + if (!bCombo) + { + // ClearComboSkill(); // Uncomment if ClearComboSkill exists + } + + // Check skill cast condition (commented out in ApplySkillShortcut, so skip for now) + // int iCon = CheckSkillCastCondition(pSkill); + // if (iCon) + // { + // ProcessSkillCondition(iCon); + // return false; + // } + + // If this skill is in cooling time or we are casting other skill, return + // 濡傛灉姝ゆ妧鑳藉湪鍐峰嵈鏃堕棿鎴栨垜浠鍦ㄦ柦鏀惧叾浠栨妧鑳斤紝杩斿洖 + if (!pSkill.ReadyToCast() || + !m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())) + { + // If the current Work in m_pWorkMan is CECHPWorkSpell or CECHPWorkFly, it should be executed first + // Otherwise, when receiving OBJECT_CAST_SKILL protocol, CECHPWorkSpell cannot be executed + // This causes CECHostPlayer::IsSpellingMagic() to return false, causing the client to send c2s_CmdCancelAction + // When this CECHPWorkSpell executes, it cannot respond + // After this method is executed, we use the return to city mechanism + // 濡傛灉 m_pWorkMan 涓殑褰撳墠 Work 鏄 CECHPWorkSpell 鎴 CECHPWorkFly锛屽垯搴斿厛鎵ц + // 鍚﹀垯锛屽綋鏀跺埌 OBJECT_CAST_SKILL 鍗忚鏃讹紝CECHPWorkSpell 鏃犳硶鎵ц + // 杩欎細瀵艰嚧 CECHostPlayer::IsSpellingMagic() 杩斿洖 false锛屽鑷村鎴风鍙戦 c2s_CmdCancelAction + // 褰撴 CECHPWorkSpell 鎵ц鏃讹紝瀹冩棤娉曞搷搴 + // 鍦ㄦ鏂规硶鎵ц瀹屾垚鍚庯紝鎴戜滑浣跨敤鍥炲煄鏈哄埗 + Debug.LogError( + $"ReturnToTargetTown: Skill not ready - ReadyToCast={pSkill.ReadyToCast()}, CanCastSkillImmediately={m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())}"); + return false; + } + + m_pPrepSkill = pSkill; + byte byPVPMask = glb_BuildPVPMask(false); + + // Call c2s_CmdCastSkill with target parameter + // 浣跨敤鐩爣鍙傛暟璋冪敤 c2s_CmdCastSkill + int targets = 1; + int[] targetsCastSkill = new int[targets]; + targetsCastSkill[0] = idTarget; + UnityGameSession.c2s_CmdCastSkill(idSkill, byPVPMask, targets, targetsCastSkill); + + + return true; + } + + public int GetPositiveSkillNum() + { + return m_aPtSkills.Count; + } + + public CECSkill GetPositiveSkillByIndex(int n) + { + return m_aPtSkills[n]; + } + + public int GetPassiveSkillNum() + { + return m_aPsSkills.Count; + } + + CECSkill GetPassiveSkillByID(int id, bool bSenior /* false */) + { + CECSkill pSenior = null; + + for (int i = 0; i < m_aPsSkills.Count; i++) + { + if (m_aPsSkills[i].GetSkillID() == id) + return m_aPsSkills[i]; + else if (m_aPsSkills[i].GetJunior().Find((uint)id)) + pSenior = m_aPsSkills[i]; + } + + if (bSenior && pSenior != null) + return pSenior; + + return null; + } + + public CECSkill GetPositiveSkillByID(int id, bool bSenior = false) + { + CECSkill pSenior = null; + + for (int i = 0; i < m_aPtSkills.Count; i++) + { + if (m_aPtSkills[i].GetSkillID() == id) + return m_aPtSkills[i]; + else if (m_aPtSkills[i].GetJunior().Find((uint)id)) + pSenior = m_aPtSkills[i]; + } + + if (bSenior && pSenior != null) + return pSenior; + + return null; + } + + // C# conversion of CECHostPlayer::GetEquipSkillByID + // Assumes: GetEquipSkillNum() returns the count of equipment skills + // GetEquipSkillByIndex(int) returns a CECSkill at the given index + public CECSkill GetEquipSkillByID(int id) + { + CECSkill pRet = null; + + for (int i = 0; i < GetEquipSkillNum(); i++) + { + CECSkill pSkill = GetEquipSkillByIndex(i); + if (pSkill != null && pSkill.GetSkillID() == id) + { + pRet = pSkill; + break; + } + } + + return pRet; + } + + public int GetEquipSkillNum() + { + return m_aEquipSkills.Count; + } + + public CECSkill GetEquipSkillByIndex(int n) + { + return m_aEquipSkills[n]; + } + + // Check skill cast condition + // Returns: 0 if success, error code otherwise + // Error codes: 1=invalid weapon, 2=need mp, 3=invalid state, 6=target wrong, 7=invalid state, + // 8=need ap, 9=not enough ammo, 10=pack full, 11=invalid env, 12=hp unsatisfied, + // 13=combo skill not active, 20=need item + public int CheckSkillCastCondition(CECSkill pSkill) + { + // Check if skill requires an item + if (pSkill.SkillCore != null) + { + int idItem = pSkill.SkillCore.GetItemCost(); + if (idItem > 0 && GetPack().GetItemTotalNum(idItem) <= 0) + { + return 20; // Need item + } + } + + if (pSkill.GetComboSkPreSkill() != 0) + { + if (!CECComboSkillState.Instance.IsActiveComboSkill((uint)pSkill.GetSkillID())) + { + return 13; // Combo skill not active + } + } + + // Build UseRequirement info + UseRequirement Info = new UseRequirement(); + Info.mp = m_BasicProps.iCurMP; + Info.ap = m_BasicProps.iCurAP; + Info.form = m_iShape; // Different from PW, no need to mask + Info.freepackage = m_pPack.GetEmptySlotNum(); + Info.move_env = GetMoveEnv(); + Info.is_combat = IsFighting(); + Info.hp = m_BasicProps.iCurHP; + Info.max_hp = m_ExtProps.bs.max_hp; + Info.combo_state = CECComboSkillState.Instance.GetComboSkillState(); // TODO: Implement GetComboSkillState + + // Get weapon's major class ID + int iReason = 0; + + CECIvtrWeapon pWeapon = + (CECIvtrWeapon)m_pEquipPack.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON); + if (pWeapon == null || pWeapon.GetCurEndurance() == 0) + Info.weapon = 0; + else if (!CanUseEquipment(pWeapon, ref iReason)) + Info.weapon = (iReason == 5) ? (int)pWeapon.GetDBMajorType().id : 0; + else + Info.weapon = (int)pWeapon.GetDBMajorType().id; + + // Get remaining arrow number + CECIvtrArrow pArrow = + (CECIvtrArrow)m_pEquipPack.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE); + if (pArrow != null && CanUseProjectile(pArrow)) + { + Info.arrow = pArrow.GetCount(); + } + + if (pSkill.SkillCore != null) + { + return pSkill.SkillCore.Condition((uint)pSkill.GetSkillID(), Info, pSkill.GetSkillLevel()); + } + + return 0; // Success + } + + // Process skill condition error - display appropriate message + // Returns: true if message was displayed, false otherwise + public bool ProcessSkillCondition(int iCon) + { + int iMsg = -1; + switch (iCon) + { + case 1: iMsg = (int)FixedMsg.FIXMSG_INVALIDWEAPON; break; + case 2: iMsg = (int)FixedMsg.FIXMSG_NEEDMP; break; + case 6: iMsg = (int)FixedMsg.FIXMSG_TARGETWRONG; break; + case 3: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDSTATE; break; + case 7: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDSTATE; break; + case 8: iMsg = (int)FixedMsg.FIXMSG_NEEDAP; break; + case 9: iMsg = (int)FixedMsg.FIXMSG_NOTENOUGHAMMO; break; + case 10: iMsg = (int)FixedMsg.FIXMSG_PACKFULL1; break; + case 11: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDENV; break; + case 20: iMsg = (int)FixedMsg.FIXMSG_NEEDITEM; break; + case 12: iMsg = (int)FixedMsg.FIXMSG_HP_UNSATISFIED; break; + } + + if (iMsg >= 0) + { + // TODO: Implement AddFixedChannelMsg or use existing message system + // EC_Game.GetGameRun().AddFixedChannelMsg(iMsg, GP_CHAT_FIGHT); + Debug.LogWarning($"Skill condition failed: {iMsg}"); + } + + return iMsg >= 0; + } + + // Remove skill reference / 鍒犻櫎鎶鑳藉紩鐢 + void RemoveSkillReference(int idSkill) + { + if (idSkill <= 0) return; + + // Remove reference to self skill / 鍒犻櫎瀵规妧鑳界殑寮曠敤 + if (m_pPrepSkill != null && m_pPrepSkill.GetSkillID() == idSkill) + m_pPrepSkill = null; + + if (m_pCurSkill != null && m_pCurSkill.GetSkillID() == idSkill) + m_pCurSkill = null; + + if (m_pComboSkill != null && m_pComboSkill.FindSkillID(idSkill)) + ClearComboSkill(); + + if (m_pWorkMan != null) + { + CECHPWork pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); + if (pWork != null) + { + CECHPWorkTrace pWorkTrace = pWork as CECHPWorkTrace; + if (pWorkTrace != null && + pWorkTrace.GetTraceReason() == CECHPWorkTrace.Trace_reason.TRACE_SPELL && + pWorkTrace.GetPrepSkill() != null && + pWorkTrace.GetPrepSkill().GetSkillID() == idSkill) + pWorkTrace.Reset(); + } + } + + int i; + + for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS1; i++) + { + if (m_aSCSets1[i] != null) + m_aSCSets1[i].RemoveSkillShortcut(idSkill); + } + + for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) + { + if (m_aSCSets2[i] != null) + m_aSCSets2[i].RemoveSkillShortcut(idSkill); + } + } + + // Remove skill / 鍒犻櫎鎶鑳 + void RemoveNormalSkill(int idSkill) + { + // Delete equipped skills / 鍒犻櫎瑁呭鎶鑳 + + if (idSkill <= 0) return; + + RemoveSkillReference(idSkill); + + // Delete skill list pointer / 鍒犻櫎鎶鑳藉垪琛ㄦ寚閽 + int i; + + for (i = 0; i < m_aPtSkills.Count; i++) + { + if (m_aPtSkills[i].GetSkillID() == idSkill) + { + m_aPtSkills.RemoveAt(i); + return; + } + } + + for (i = 0; i < m_aPsSkills.Count; i++) + { + if (m_aPsSkills[i].GetSkillID() == idSkill) + { + m_aPsSkills.RemoveAt(i); + return; + } + } + + for (i = 0; i < m_aGoblinSkills.Count; i++) + { + if (m_aGoblinSkills[i].GetSkillID() == idSkill) + { + m_aGoblinSkills.RemoveAt(i); + return; + } + } + } + + // Clear combo skill / 娓呴櫎杩炲嚮鎶鑳 + public bool ApplyComboSkill(int iGroup, bool bIgnoreAtkLoop = false, int iForceAtk = -1) + { + ClearComboSkill(); + + CECComboSkill comboSkill = new(); + bool bForceAttack = iForceAtk < 0 ? glb_GetForceAttackFlag(0) : iForceAtk > 0; + if (!comboSkill.Init(this, iGroup, m_idSelTarget, bForceAttack, bIgnoreAtkLoop)) + { + return false; + } + + m_pComboSkill = comboSkill; + m_pComboSkill.Continue(m_bMelee); + return true; + } + + public void ClearComboSkill() + { + if (m_pComboSkill != null) + { + m_pComboSkill = null; + } + } + + // Replace specified skill with it's senior skill / 鐢ㄩ珮绾ф妧鑳芥浛鎹㈡寚瀹氱殑浣庣骇鎶鑳 + void ReplaceJuniorSkill(CECSkill pSeniorSkill) + { + if (pSeniorSkill == null) + { + Debug.Assert(pSeniorSkill != null); + return; + } + + SkillArrayWrapper juniorArray = pSeniorSkill.GetJunior(); + if (juniorArray.Empty()) + { + Debug.Assert(false); + return; + } + + int i; + + // Update shortcuts ... / 鏇存柊蹇嵎鏂瑰紡... + for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS1; i++) + { + if (m_aSCSets1[i] != null) + m_aSCSets1[i].ReplaceSkillID(juniorArray, pSeniorSkill); + } + + for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) + { + if (m_aSCSets2[i] != null) + m_aSCSets2[i].ReplaceSkillID(juniorArray, pSeniorSkill); + } + + // Update skill groups ... / 鏇存柊鎶鑳界粍... + // Note: Combo skill update logic may need to be added here + // Original C++ code had EC_VIDEO_SETTING and combo skill group logic + } + + public int CheckSkillLearnCondition(int idSkill, bool bCheckBook) + { + int iLevel = 1; + CECSkill pSkill = GetNormalSkill(idSkill); + if (pSkill != null) + iLevel = pSkill.GetSkillLevel() + 1; + + if (iLevel == 1 && bCheckBook) + { + // Do we have the skill book ? + int idBook = ElementSkill.GetRequiredBook((uint)idSkill, iLevel); + if (idBook != 0 /*&& m_pPack.FindItem(idBook) < 0*/) + return 8; + } + + // Build player information + LearnRequirement Info; + + Info.level = GetMaxLevelSofar(); + Info.sp = m_BasicProps.iSP; + Info.money = (int)m_iMoneyCnt; + Info.profession = m_iProfession; + Info.rank = m_BasicProps.iLevel2; + Info.realm_level = GetRealmLevel(); + + return ElementSkill.LearnCondition((uint)idSkill, Info, iLevel); + } + + public bool GetSkillCoolTime(int idSkill, out COOLTIME ct) + { + // 鑾峰彇鎶鑳界殑闈炲叕鍏卞喎鍗存椂闂 + bool bFound = false; + ct = new COOLTIME(); + + if (m_skillCoolTime.TryGetValue(idSkill, out ct)) + { + bFound = true; + } + + return bFound; + } + + // Update equipment skill cool down + // 鏇存柊瑁呭鎶鑳藉喎鍗 + public void UpdateEquipSkillCoolDown(int cooldown_index = -1) + { + if (cooldown_index < 0) + { + for (int i = 0; i < GetEquipSkillNum(); ++i) + { + CECSkill pSkill = GetEquipSkillByIndex(i); + + // 妫鏌ユ妧鑳藉喎鍗 + // Check skill cooldown + COOLTIME temp; + if (GetSkillCoolTime(pSkill.GetSkillID(), out temp)) + { + pSkill.StartCooling(temp.iMaxTime, temp.iCurTime); + continue; + } + + // 妫鏌ュ叕鍏卞喎鍗 + // Check common cooldown + int ccd = pSkill.GetCommonCoolDown(); + if (ccd == 0) continue; + for (int j = 0; j < 5; ++j) + { + if ((ccd & (1 << j)) != 0) + { + COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + j]; + pSkill.StartCooling(ct.iMaxTime, ct.iCurTime); + break; + } + } + } + } + else + { + if (cooldown_index > (int)CoolTimeIndex.GP_CT_SKILL_START) + { + int idSkill = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILL_START; + CECSkill pSkill = GetEquipSkillByID(idSkill); + COOLTIME temp; + if (pSkill != null && GetSkillCoolTime(idSkill, out temp)) + pSkill.StartCooling(temp.iMaxTime, temp.iCurTime); + } + else if (cooldown_index >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && + cooldown_index <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) + { + int index = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0; + COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + index]; + uint mask = (uint)(1 << index); + for (int i = 0; i < GetEquipSkillNum(); ++i) + { + CECSkill pSkill = GetEquipSkillByIndex(i); + int ccd = pSkill.GetCommonCoolDown(); + if ((ccd & mask) != 0) + pSkill.StartCooling(ct.iMaxTime, ct.iCurTime); + } + } + } + } + + public CECSkill GetPassiveSkillByIndex(int n) + { + return m_aPsSkills[n]; + } + + public void AssignSkillGrpShortcut(List skillGrpSCConfigArray, CECShortcutSet[] aSCSets) + { + for (int i = 0; i < skillGrpSCConfigArray.Count; i++) + { + SkillGrpShortCutConfig cfg = skillGrpSCConfigArray[i]; + + if (cfg.groupIndex != -1) + { + // C++ kh么ng check null; n岷縰 mu峄憂 an to脿n h啤n th矛 check aSCSets[cfg.setNum] != null + aSCSets[cfg.setNum].CreateSkillGroupShortcut(cfg.slotNum, cfg.groupIndex); + } + } + } + + public void ValidateSkillGrpShortcut(List skillGrpSCConfigArray) + { + for (int i = 0; i < skillGrpSCConfigArray.Count; i++) + { + // C++ 膽ang l岷 VideoSettings trong m峄梚 v貌ng l岷穚 (gi峄 nguy锚n h脿nh vi) + EC_VIDEO_SETTING vs = EC_Game.GetConfigs().GetVideoSettings(); + + SkillGrpShortCutConfig cfg = skillGrpSCConfigArray[i]; + + if (vs.comboSkill[cfg.groupIndex].nIcon == 0) + cfg.groupIndex = -1; // -1 bi峄僽 th峄 shortcut combo-skill kh么ng h峄 l峄 + + skillGrpSCConfigArray[i] = cfg; // c岷 n岷縰 SkillGrpShortCutConfig l脿 struct + } + } + + public void ConvertComboSkill() + { + EC_VIDEO_SETTING vs = EC_Game.GetConfigs().GetVideoSettings(); + + for (int i = 0; i < EC_ConfigConstants.EC_COMBOSKILL_NUM; i++) + { + if (vs.comboSkill[i].nIcon == 0) + continue; + + for (int j = 0; j < EC_ConfigConstants.EC_COMBOSKILL_LEN; j++) + { + int oldSkillId = vs.comboSkill[i].idSkill[j]; + if (oldSkillId == 0) + continue; + + int convertedSkillId = CECSkillConvert.Instance.GetConvertSkill(oldSkillId); + int newSkillId = (convertedSkillId == 0) ? oldSkillId : convertedSkillId; + + // C++: n岷縰 skill t峄搉 t岷, ho岷穋 l脿 -1/-2 (loop / normal attack shortcut) th矛 gi峄 + if (GetNormalSkill(newSkillId) != null || newSkillId == -1 || newSkillId == -2) + { + vs.comboSkill[i].idSkill[j] = (short)newSkillId; + } + else + { + // Kh么ng h峄 l峄 -> clear combo theo oldSkillId, icon v峄 0, tho谩t v貌ng l岷穚 j + vs.comboSkill[i].Clear(oldSkillId); + vs.comboSkill[i].nIcon = 0; + break; + } + } + } + + EC_Game.GetConfigs().SetVideoSettings(vs); + } + + public void AssignSkillShortcut(List skillSCConfigArray, CECShortcutSet[] aSCSets) + { + for (int i = 0; i < skillSCConfigArray.Count; i++) + { + SkillShortCutConfig cfg = skillSCConfigArray[i]; + if (cfg.skillId == 0) + { + BMLogger.LogError("AssignSkillShortcut: skillId is zero"); + } + + CECSkill convertSkill = GetNormalSkill(cfg.skillId); + if (convertSkill != null) + { + // C++ kh么ng check null set => n岷縰 mu峄憂 y h峄噒 th矛 b峄 check n脿y + if (aSCSets[cfg.setNum] != null) + { + aSCSets[cfg.setNum].CreateSkillShortcut(cfg.slotNum, convertSkill); + } + } + } + } + + public void ConvertSkillShortcut(List skillSCConfigArray) + { + for (int i = 0; i < skillSCConfigArray.Count; i++) + { + if (skillSCConfigArray[i].skillId == 0) + { + BMLogger.LogError("ConvertSkillShortcut: skillId is zero"); + } + + int oldSkillId = skillSCConfigArray[i].skillId; + int convertSkillId = CECSkillConvert.Instance.GetConvertSkill(oldSkillId); + + // it->skillId = (convertSkillId == 0) ? it->skillId : convertSkillId; + SkillShortCutConfig cfg = skillSCConfigArray[i]; + cfg.skillId = (convertSkillId == 0) ? oldSkillId : convertSkillId; + skillSCConfigArray[i] = cfg; // needed if SkillShortCutConfig is a struct + } + } + + public void SaveSkillGrpShortcut( + List skillGrpSCConfigArray, + CECShortcutSet[] aSCSets, + int count) + { + for (int i = 0; i < count; i++) + { + if (aSCSets[i] == null) continue; + + for (int j = 0; j < aSCSets[i].GetShortcutNum(); j++) + { + CECShortcut pSC = aSCSets[i].GetShortcut(j); + if (pSC == null || pSC.GetType() != (int)ShortcutType.SCT_SKILLGRP) + continue; + + // C-style cast -> safe cast + if (pSC is not CECSCSkillGrp pSkillGrpSC) + continue; + + SkillGrpShortCutConfig skillGrpSCConfig = new SkillGrpShortCutConfig(); + skillGrpSCConfig.setNum = i; + skillGrpSCConfig.slotNum = j; + skillGrpSCConfig.groupIndex = pSkillGrpSC.GetGroupIndex(); + + skillGrpSCConfigArray.Add(skillGrpSCConfig); + } + } + } + + public void SaveSkillShortcut( + List skillSCConfigArray, + CECShortcutSet[] aSCSets, + int count) + { + for (int i = 0; i < count; i++) + { + if (aSCSets[i] == null) continue; + + for (int j = 0; j < aSCSets[i].GetShortcutNum(); j++) + { + CECShortcut pSC = aSCSets[i].GetShortcut(j); + if (pSC == null || pSC.GetType() != (int)ShortcutType.SCT_SKILL) + continue; + + if (pSC is not CECSCSkill pSkillSC) + continue; + + int iOldSkillId = pSkillSC.GetSkill()?.GetSkillID() ?? 0; + if (iOldSkillId == 0) + continue; + + SkillShortCutConfig skillSCConfig = new SkillShortCutConfig(); + skillSCConfig.setNum = i; + skillSCConfig.slotNum = j; + skillSCConfig.skillId = iOldSkillId; + + skillSCConfigArray.Add(skillSCConfig); + } + } + } + +#if UNITY_EDITOR + /// + /// Cycles through learned skills by removing all shortcuts and adding 2 new skills to slots 0 and 1. + /// If m_startingSkillID is set (>0), uses that specific skill ID and the next one (ID+1). + /// Otherwise, cycles through all learned skills in pairs. + /// + public void CycleSkillShortcuts() + { + // Get shortcut set 1 + CECShortcutSet pSCS = GetShortcutSet1(0); + if (pSCS == null) + { + Debug.LogWarning("CycleSkillShortcuts: Shortcut Set 1 is null"); + return; + } + + // Remove all shortcuts + pSCS.RemoveAllShortcuts(); + + // If starting skill ID is configured, cycle through pairs starting from that ID + if (m_startingSkillID > 0) + { + // Calculate the current skill IDs based on cycle index + // First press: startingID + 0, startingID + 1 (e.g., 5, 6) + // Second press: startingID + 2, startingID + 3 (e.g., 7, 8) + // Third press: startingID + 4, startingID + 5 (e.g., 9, 10) + int currentSkillID1 = m_startingSkillID + (m_currentSkillCycleIndex * 2); + int currentSkillID2 = currentSkillID1 + 1; + BMLogger.LogError($"CycleSkillShortcuts: Trying to add skills {currentSkillID1} and {currentSkillID2}"); + // Find and add first skill + CECSkill pSkill1 = GetPositiveSkillByID(currentSkillID1); + if (pSkill1 != null) + { + pSCS.CreateSkillShortcut(0, pSkill1); + Debug.LogError($"CycleSkillShortcuts: Added skill ID {currentSkillID1} to slot 0"); + } + else + { + Debug.LogError($"CycleSkillShortcuts: Skill with ID {currentSkillID1} not found in learned skills"); + int find = 1; + while (pSkill1 == null || find == 100) + { + m_startingSkillID++; + Debug.LogError($"CycleSkillShortcuts: m_startingSkillID {m_startingSkillID} "); + currentSkillID1 = m_startingSkillID + (m_currentSkillCycleIndex * 2); + pSkill1 = GetPositiveSkillByID(currentSkillID1); + find++; + } + + pSCS.CreateSkillShortcut(0, pSkill1); + } + + // Find and add second skill + CECSkill pSkill2 = GetPositiveSkillByID(currentSkillID2); + if (pSkill2 != null) + { + pSCS.CreateSkillShortcut(1, pSkill2); + Debug.LogError($"CycleSkillShortcuts: Added skill ID {currentSkillID2} to slot 1"); + } + else + { + Debug.LogError($"CycleSkillShortcuts: Skill with ID {currentSkillID2} not found in learned skills"); + int find = 1; + while (pSkill2 == null || find == 100) + { + m_startingSkillID++; + Debug.LogError($"CycleSkillShortcuts: m_startingSkillID {m_startingSkillID} "); + currentSkillID2 = m_startingSkillID + (m_currentSkillCycleIndex * 2) + 1; + pSkill2 = GetPositiveSkillByID(currentSkillID2); + find++; + } + + pSCS.CreateSkillShortcut(1, pSkill2); + } + + // Increment cycle index for next press + m_currentSkillCycleIndex++; + + // Update UI + CDlgQuickBar cDlgQuickBar2 = CECUIManager.Instance?.GetCDlgQuickBar(); + cDlgQuickBar2?.UpdateShortcuts(); + return; + } + + // Original cycling behavior + // Get the list of learned skills + int skillCount = GetPositiveSkillNum(); + + // If no skills learned, just clear shortcuts (already done above) + if (skillCount == 0) + { + // Update UI + CDlgQuickBar cDlgQuickBar1 = CECUIManager.Instance?.GetCDlgQuickBar(); + cDlgQuickBar1?.UpdateShortcuts(); + return; + } + + // Calculate how many pairs we can make + int maxPairs = (skillCount + 1) / 2; // Round up division + + // Wrap around if we've reached the end + if (m_currentSkillCycleIndex >= maxPairs) + { + m_currentSkillCycleIndex = 0; + } + + // Calculate skill indices for this cycle + int skillIndex1 = m_currentSkillCycleIndex * 2; + int skillIndex2 = skillIndex1 + 1; + + // Add first skill to slot 0 + if (skillIndex1 < skillCount) + { + CECSkill pSkill1 = GetPositiveSkillByIndex(skillIndex1); + if (pSkill1 != null) + { + pSCS.CreateSkillShortcut(0, pSkill1); + } + } + + // Add second skill to slot 1 (if available) + if (skillIndex2 < skillCount) + { + CECSkill pSkill2 = GetPositiveSkillByIndex(skillIndex2); + if (pSkill2 != null) + { + pSCS.CreateSkillShortcut(1, pSkill2); + } + } + + // Increment cycle index for next time + m_currentSkillCycleIndex++; + + // Update UI + CDlgQuickBar cDlgQuickBar = CECUIManager.Instance?.GetCDlgQuickBar(); + cDlgQuickBar?.UpdateShortcuts(); + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.Skill.cs.meta b/Assets/Scripts/CECHostPlayer.Skill.cs.meta new file mode 100644 index 0000000000..2e438b2feb --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.Skill.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c8ab82b5b1e1aee45a936ba119de3444 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.World.cs b/Assets/Scripts/CECHostPlayer.World.cs new file mode 100644 index 0000000000..5ff8e8fda1 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.World.cs @@ -0,0 +1,270 @@ +锘縰sing BrewMonster.Network; +using BrewMonster.Scripts; +using CSNetwork; +using CSNetwork.GPDataType; +using System.Runtime.InteropServices; +using Cysharp.Threading.Tasks; +using UnityEngine; +using static BrewMonster.Scripts.CECHPWork; + +namespace BrewMonster +{ + public partial class CECHostPlayer + { + public void OnMsgHstCorrectPos(in ECMSG Msg) + { + //Debug.LogError("HoangDev : OnMsgHstCorrectPos"); + byte[] buf = (byte[])Msg.dwParam1; // ch峄 b岷 l瓢u pDataBuf + GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); + cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Marshal.PtrToStructure( + handle.AddrOfPinnedObject(), typeof(cmd_host_correct_pos)); + handle.Free(); + //cmd_host_correct_pos pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + Debug.LogError("HoangDev :pCmd.pos " + pCmd.pos); + SetPos(pCmd.pos); + m_vVelocity.Clear(); + m_CDRInfo.vAbsVelocity.Clear(); + + m_MoveCtrl.SetMoveStamp(pCmd.stamp); + } + + public void OnMsgHstGoto(in ECMSG Msg) + { + PopupManager.Instance.OnPlayerRevived(); + // p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position + // p1 鏄竴涓 byte[] 缂撳啿鍖猴紱瑙f瀽涓 cmd_notify_hostpos 鐒跺悗璁剧疆浣嶇疆 + byte[] buf = (byte[])Msg.dwParam1; + cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes(buf); + + int idInst = pCmd.tag; + Vector3 vPos = new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z); + int iLine = pCmd.line; + + + // Call Goto method to properly handle teleportation + // 璋冪敤 Goto 鏂规硶鏉ユ纭鐞嗕紶閫 + if (!Goto(idInst, vPos, iLine)) + { + BMLogger.LogError($"OnMsgHstGoto: Failed to teleport to instance {idInst}"); + return; + } + } + + void OnMsgHstWayPoint(ECMSG Msg) + { + //CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + + //if (Convert.ToInt32(Msg.dwParam2) == CommandID.ACTIVATE_WAYPOINT) + //{ + // cmd_activate_waypoint pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + // m_aWayPoints.Add(pCmd.waypoint); + + // // add to waypoints array + // pGameUI.GetMapDlgsMgr().UpdateWayPoints(&pCmd.waypoint, 1, false); + + // // Print a notify message + // const CECMapDlgsMgr::PointMap& aWayPoints = pGameUI.GetMapDlgsMgr().GetTransPoint(); + // CECMapDlgsMgr::PointMap::const_iterator itr = aWayPoints.find(pCmd.waypoint); + // if(itr != aWayPoints.end()) + // { + // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEWWAYPOINT, (itr.second).strName); + + // bool bCanPopUITips = true; + // int count = CECUIConfig::Instance().GetGameUI().GetTaskIDDisableWayPointsUITipsCount(); + // // 录矛虏茅脡铆脡脧脢脟路帽脫脨陆没脰鹿碌炉鲁枚tips碌脛脠脦脦帽 + // for (int i=0;i((byte[])Msg.dwParam1); + if (pCmd.index >= 0 && pCmd.index < (int)PLAYER_LIMIT.PLAYER_LIMIT_MAX) + m_playerLimits[pCmd.index] = (pCmd.b != 0); + } + + private void OnMsgHstPressCancel(ECMSG Msg) + { + CECHPWork pCurWork = null; + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_TRACEOBJECT); + if (pCurWork is CECHPWorkTrace workTrace) + { + workTrace.PressCancel(); + return; + } + + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_HACKOBJECT); + if (pCurWork != null) + { + UnityGameSession.c2s_CmdCancelAction(); + return; + } + + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM); + if (pCurWork != null) + { + UnityGameSession.c2s_CmdCancelAction(); + return; + } + + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_SPELLOBJECT); + if (pCurWork != null) + { + int iState = ((CECHPWorkSpell)pCurWork).GetState(); + if (iState == CECHPWorkSpell.Spell_magic_state.ST_INCANT) + { + UnityGameSession.c2s_CmdCancelAction(); + return; + } + } + + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_PICKUP); + if (pCurWork != null) + { + if (((EC_HPWorkPick)pCurWork).IsGather()) + { + UnityGameSession.c2s_CmdCancelAction(); + return; + } + } + //todo: handle this part + // pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONCENTRATE); + // if (pCurWork !=null){ + // if (IsOperatingPet()){ + // UnityGameSession.c2s_CmdCancelAction(); + // return; + // } + // } + // pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONGREGATE); + // if (pCurWork !=null){ + // if (IsCongregating()){ + // UnityGameSession.c2s_CmdCancelAction(); + // return; + // } + // } + + if (m_bUsingTrashBox || DoingSessionPose()) + { + UnityGameSession.c2s_CmdCancelAction(); + return; + } + + // Cancel current selection + if (m_idSelTarget > 0) + { + SelectTarget(0); + return; + } + + // Some work have lower priority + pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_MOVETOPOS); + if (pCurWork != null) + { + ((CECHPWorkMove)pCurWork).PressCancel(); + return; + } + } + + public void StopMovement() + { + m_MoveCtrl.SendStopMoveCmd(playerTransform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK); + } + + // Return to a target town through skill + // 閫氳繃鎶鑳借繑鍥炵洰鏍囧煄闀 + // This method implements the Goto logic from the original C++ code + // 姝ゆ柟娉曞疄鐜颁簡鍘熷 C++ 浠g爜涓殑 Goto 閫昏緫 + private bool Goto(int idInst, Vector3 vPos, int iParallelWorldID) + { + // Jump to instance (change world/instance) + // 璺宠浆鍒板疄渚嬶紙鏇存敼涓栫晫/瀹炰緥锛 + // Note: JumpToInstance is currently a stub in CECGameRun, so we skip the call for now + // 娉ㄦ剰锛欽umpToInstance 鐩墠鍦 CECGameRun 涓槸涓涓瓨鏍癸紝鎵浠ユ垜浠幇鍦ㄨ烦杩囪皟鐢 + // if (CECGameRun.Instance != null && !CECGameRun.Instance.JumpToInstance(idInst, vPos, iParallelWorldID)) + // { + // Debug.LogError($"CECHostPlayer::Goto, Failed to jump to instance {idInst}"); + // return false; + // } + + // Stop all current work and goto specified position + // 鍋滄鎵鏈夊綋鍓嶅伐浣滃苟杞埌鎸囧畾浣嶇疆 + if (m_pWorkMan != null) + { + // Stop auto-moving if active + // 濡傛灉姝e湪鑷姩绉诲姩鍒欏仠姝 + // Note: IsAutoMoving check would go here if available + // 娉ㄦ剰锛氬鏋滃彲鐢紝IsAutoMoving 妫鏌ュ皢鏀惧湪杩欓噷 + + // Finish all work + // 瀹屾垚鎵鏈夊伐浣 + m_pWorkMan.FinishAllWork(true); + } + + // Add a little height to ensure player's AABB won't embed with building + // 澧炲姞涓鐐归珮搴︿互纭繚鐜╁鐨 AABB 涓嶄細宓屽叆寤虹瓚鐗 + vPos.y += 0.1f; + + // Ensure we are not under ground (terrain height check would go here) + // 纭繚鎴戜滑涓嶄細鍦ㄥ湴涓嬶紙鍦板舰楂樺害妫鏌ュ皢鏀惧湪杩欓噷锛 + // Note: Terrain height check is skipped for now as it requires world access + // 娉ㄦ剰锛氭殏鏃惰烦杩囧湴褰㈤珮搴︽鏌ワ紝鍥犱负瀹冮渶瑕佷笘鐣岃闂 + + // Set position + // 璁剧疆浣嶇疆 + SetPos(vPos); + + // Reset jump state if available + // 濡傛灉鍙敤鍒欓噸缃烦璺冪姸鎬 + // ResetJump(); // Uncomment if ResetJump method exists + + // Update camera if available + // 濡傛灉鍙敤鍒欐洿鏂扮浉鏈 + // UpdateFollowCamera(false, 10); // Uncomment if UpdateFollowCamera method exists + + LitModelHolder.Instance.LoadAllObjectsNearTargetPosition(vPos).Forget(); + return true; + } + + public void SetStatusRun(bool value) + { + if (!isGrounded) + { + Debug.LogError("Player not in ground"); + return; + } + + isRun = value; + } + + public bool IsPlayerMoving() + { + return m_pWorkMan.IsMoving(); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.World.cs.meta b/Assets/Scripts/CECHostPlayer.World.cs.meta new file mode 100644 index 0000000000..89914828e4 --- /dev/null +++ b/Assets/Scripts/CECHostPlayer.World.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 570900be694cc7c4c9c0fc5c399c9a25 \ No newline at end of file diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 8c2f04b5cf..d851a87ef9 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -1,6 +1,4 @@ -using BrewMonster; using BrewMonster.Assets.PerfectWorld.Scripts.Players; -using BrewMonster.Assets.PerfectWorld.Scripts.UI; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.PerfectWorld.Scripts.Vfx; @@ -13,7 +11,6 @@ using BrewMonster.UI; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols.RPCData; -using CSNetwork.S2CCommand; using Cysharp.Threading.Tasks; using ModelRenderer.Scripts.GameData; using PerfectWorld.Scripts; @@ -22,12 +19,9 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using UnityEngine; using UnityEngine.UI; -using static BrewMonster.Scripts.Managers.EC_Inventory; -using static CECPlayerWrapper; using cmd_select_target = CSNetwork.GPDataType.cmd_select_target; using Host_work_ID = BrewMonster.Scripts.CECHPWork.Host_work_ID; using ObjectCoords = System.Collections.Generic.List; @@ -180,8 +174,7 @@ namespace BrewMonster private UnityEngine.InputSystem.Keyboard m_cachedKeyboard; int[] targetsCastSkill; - - + public bool IsChangingFace() { return m_bChangingFace; @@ -455,11 +448,6 @@ namespace BrewMonster // m_pAutoTeam.Tick(Time.deltaTime); } - public void StopMovement() - { - m_MoveCtrl.SendStopMoveCmd(playerTransform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK); - } - //public void HandleMovement() //{ // // 1) Ki峄僲 tra grounded b岷眓g SphereCast ng岷痭 d峄盿 tr锚n radius + skinWidth @@ -511,7 +499,6 @@ namespace BrewMonster // _playerStateMachine.ChangeState(_idleState); m_dwMoveRelDir = 0; } - public bool GroundCheck(out RaycastHit hit) { float radius = controller.radius; @@ -549,7 +536,6 @@ namespace BrewMonster return true; } - private void HandleJump() { if (isGrounded) @@ -557,7 +543,6 @@ namespace BrewMonster playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravityValue); } } - public void ProcessMessage(in ECMSG Msg) { var msg = (int)Msg.dwMsg; @@ -650,66 +635,6 @@ namespace BrewMonster } }*/ } - - private void OnMsgHstJoinTeam(ECMSG Msg) - { - var data = (byte[])Msg.dwParam1; - if (data == null || data.Length < Marshal.SizeOf()) return; - var pCmd = GPDataTypeHelper.FromBytes(data); - var pTeamMan = CECGameRun.Instance?.GetTeamMan(); - if (pTeamMan == null) return; - var pTeam = pTeamMan.GetTeam(pCmd.idLeader); - if (pTeam == null) - pTeam = pTeamMan.CreateTeam(pCmd.idLeader); - if (pTeam == null) return; - if (pCmd.idLeader == m_PlayerInfo.cid) - pTeam.AddMember(pCmd.idLeader); - pTeam.SetPickupFlag(pCmd.wPickFlag); - SetTeam(pTeam); - NotifyUIUpdateTeam(); - } - - private void OnMsgHstLeaveTeam(ECMSG Msg) - { - var data = (byte[])Msg.dwParam1; - if (data == null || data.Length < Marshal.SizeOf()) return; - var pCmd = GPDataTypeHelper.FromBytes(data); - if (m_pTeam == null) return; - var pTeamMan = CECGameRun.Instance?.GetTeamMan(); - if (pTeamMan != null) - pTeamMan.ReleaseTeam(pCmd.idLeader); - SetTeam(null); - NotifyUIUpdateTeam(); - } - - private void OnMsgHstNewTeamMem(ECMSG Msg) - { - var data = (byte[])Msg.dwParam1; - if (data == null || data.Length < Marshal.SizeOf()) return; - var pCmd = GPDataTypeHelper.FromBytes(data); - if (m_pTeam == null) return; - int cid = pCmd.idMember; - m_pTeam.AddMember(cid); - m_pTeam.AddUnknownID(cid); - if (EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(cid, 0) == null && UnityGameSession.Instance != null) - UnityGameSession.c2s_CmdTeamMemberPos(1, new[] { cid }); - NotifyUIUpdateTeam(); - } - - private void OnMsgHstTeamMemberData(ECMSG Msg) - { - var data = (byte[])Msg.dwParam1; - if (data == null) return; - try - { - var (header, members) = GPDataTypeHelper.ParseTeamMemberData(data); - if (m_pTeam == null || header.idLeader != m_pTeam.GetLeaderID()) return; - m_pTeam.UpdateTeamData(header, members); - NotifyUIUpdateTeam(); - } - catch { } - } - private void NotifyUIUpdateTeam() { try @@ -720,1253 +645,11 @@ namespace BrewMonster } catch { } } - - private void OnMsgContinueComboSkill(ECMSG Msg) - { - bool bMeleeing = ((int)Msg.dwParam1 == 1); - if (bMeleeing != m_bMelee) bMeleeing = m_bMelee; - int iGroupID = (int)Msg.dwParam2; - if (m_pComboSkill != null && m_pComboSkill.GetGroupIndex() == iGroupID && !m_pComboSkill.IsStop()) - m_pComboSkill.Continue(bMeleeing); - } - - private void OnMsgComboSkillPrepare(ECMSG Msg) - { - cmd_combo_skill_prepare cmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - uint skillID = (uint)cmd.skill_id; - - ComboSkillState comboSkillState = new() - { - skillid = skillID, - arg = new int[ComboSkillState.MAX_COMBO_ARG] - }; - comboSkillState.arg = cmd.args; - /* if (cmd.args != null) - { - Array.Copy(cmd.args, comboSkillState.arg, Math.Min(cmd.args.Length, ComboSkillState.MAX_COMBO_ARG)); - }*/ - - Dictionary comboSkillList = ElementSkill.GetComboSkActivated(comboSkillState); - CECComboSkillState.Instance.SetComboSkillState(comboSkillList, ref comboSkillState); - } - - private void OnMsgHstLearnSkill(ECMSG Msg) - { - cmd_learn_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - CECSkill pSkill = GetNormalSkill(pCmd.skill_id); - if (pSkill != null) - { - if (pCmd.skill_level > 0) - { - pSkill.LevelUp(); - ElementSkill.SetLevel((uint)pCmd.skill_id, pCmd.skill_level); - } - else - { - RemoveNormalSkill(pCmd.skill_id); - } - } - else if (pCmd.skill_level > 0) - { - pSkill = new CECSkill(pCmd.skill_id, pCmd.skill_level); - if (pSkill == null) - { - Debug.Assert(pSkill != null); - return; - } - - if (!pSkill.GetJunior().Empty()) - { - ReplaceJuniorSkill(pSkill); - } - else - { - if (pSkill.GetType() != (int)CECSkill.SkillType.TYPE_PASSIVE && - pSkill.GetType() != (int)CECSkill.SkillType.TYPE_PRODUCE && - pSkill.GetType() != (int)CECSkill.SkillType.TYPE_LIVE) - m_aPtSkills.Add(pSkill); - else - m_aPsSkills.Add(pSkill); - } - - ElementSkill.SetLevel((uint)pCmd.skill_id, pCmd.skill_level); - } - - CECHostSkillModel.Instance.OnLearnSkill(pCmd.skill_id, pCmd.skill_level); - } - - private void OnMsgHstSetCoolTime(ECMSG Msg) - { - cmd_set_cooldown pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (pCmd.cooldown_index < 0) - { - BMLogger.LogError("pCmd.cooldown_index >= 0 :" + (pCmd.cooldown_index >= 0)); - return; - } - - if (pCmd.cooldown_index < (int)CoolTimeIndex.GP_CT_MAX) - { - COOLTIME ct = m_aCoolTimes[pCmd.cooldown_index]; - ct.iCurTime = pCmd.cooldown_time; - ct.iMaxTime = pCmd.cooldown_time; - Math.Min(ct.iCurTime, ct.iMaxTime); - m_aCoolTimes[pCmd.cooldown_index] = ct; - if (pCmd.cooldown_index == (int)CoolTimeIndex.GP_CT_CAST_ELF_SKILL) - { - int i; - for (i = 0; i < m_aGoblinSkills.Count; i++) - { - if (m_aGoblinSkills[i] != null && m_aGoblinSkills[i].GetCoolingCnt() == 0) - { - int fakeRef = 0; - int coolTime = GetCoolTime((int)CoolTimeIndex.GP_CT_CAST_ELF_SKILL, out fakeRef); - m_aGoblinSkills[i].StartCooling(coolTime, coolTime); - } - } - - for (i = 0; i < m_aPsSkills.Count; i++) - { - CECSkill pSkill = GetPassiveSkillByIndex(i); - if (pSkill != null && (pSkill.GetCommonCoolDown() & (1 << (pCmd.cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0))) != 0) - { - int fakeRef = 0; - int coolTime = GetCoolTime(pCmd.cooldown_time, out fakeRef); - pSkill.StartCooling(coolTime, coolTime); - } - } - } - - if (pCmd.cooldown_index >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && pCmd.cooldown_index <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) - { - // other player skills should be set public cool down too. - uint mask = (uint)(1 << (pCmd.cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0)); - for (int i = 0; i < GetPositiveSkillNum(); i++) - { - CECSkill pSkill = GetPositiveSkillByIndex(i); - int fakeRef = 0; - if (pSkill != null && (pSkill.GetCommonCoolDown() & mask) != 0) - { - int coolTime = GetCoolTime(pCmd.cooldown_index, out fakeRef); - pSkill.StartCooling(coolTime, coolTime); - //pSkill.StartCooling(GetCoolTime(pCmd.cooldown_index, out fakeRef), GetCoolTime(pCmd.cooldown_index, out fakeRef)); - } - } - /*const std::map&inherentSkillMap = CECComboSkillState::Instance().GetInherentSkillMap(); - std::map < unsigned int, CECSkill*>::const_iterator it; - for (it = inherentSkillMap.begin(); it != inherentSkillMap.end(); ++it) - { - it.second.StartCooling(GetCoolTime(pCmd.cooldown_index), GetCoolTime(pCmd.cooldown_index)); - }*/ - } - } - else if (pCmd.cooldown_index > (int)CoolTimeIndex.GP_CT_SKILL_START) - { - int idSkill = pCmd.cooldown_index - (int)CoolTimeIndex.GP_CT_SKILL_START; - - COOLTIME ct; - if (!m_skillCoolTime.TryGetValue(idSkill, out ct)) - { - // Key doesn't exist, create new entry - ct = new COOLTIME(); - m_skillCoolTime[idSkill] = ct; - } - ct.iCurTime = pCmd.cooldown_time; - ct.iMaxTime = pCmd.cooldown_time; - ct.iCurTime = Math.Clamp(ct.iCurTime, 0, ct.iMaxTime); - m_skillCoolTime[idSkill] = ct; - //Math.Clamp(ct.iCurTime, 0, ct.iMaxTime); - - CECSkill pSkill = GetNormalSkill(idSkill); - if (pSkill != null) - { - pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); - } - /* else if (pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill)) - { - pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); - }*/ - else if (GetEquipSkillByID(idSkill) == null) - { - BMLogger.LogError("HoangDev: pSkill " + pSkill); - } - else - { - pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); - if (pSkill != null) - { - pSkill.StartCooling(pCmd.cooldown_time, pCmd.cooldown_time); - } - else if (GetEquipSkillByID(idSkill) == null) - { - Debug.LogWarning($"OnMsgHstSetCoolTime: Skill {idSkill} not found in nomal/equip skills"); - } - } - } - else - { - // This is a annoying assert and mean nothing, so we ignore it. - // ASSERT(0); - } - - UpdateEquipSkillCoolDown(pCmd.cooldown_index); - } - - public CECSkill GetPassiveSkillByIndex(int n) - { - return m_aPsSkills[n]; - } - - private void OnMsgHstCoolTimeData(ECMSG Msg) - { - cmd_cooltime_data pCmd = default; - var data = (byte[])Msg.dwParam1; - pCmd.count = GPDataTypeHelper.FromBytes(data, 0); - long offset = Marshal.SizeOf(typeof(ushort)); - pCmd.list = new item_t[pCmd.count]; - for (int i = 0; i < pCmd.count; i++) - { - pCmd.list[i] = GPDataTypeHelper.FromBytes(data, ref offset); - } - - m_skillCoolTime.Clear(); - - for (int i = 0; i < pCmd.count; i++) - { - item_t item = pCmd.list[i]; - if (item.idx > (int)CoolTimeIndex.GP_CT_SKILL_START) - { - // Is skill cool time - int idSkill = item.idx - (int)CoolTimeIndex.GP_CT_SKILL_START; - - COOLTIME ct = default; - ct.iCurTime = item.cooldown; - ct.iMaxTime = item.max_cooltime; - Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime); - - CECSkill pSkill = GetNormalSkill(idSkill); - if (pSkill != null) - { - pSkill.StartCooling(item.max_cooltime, item.cooldown); - } - /* else if (pSkill = CECComboSkillState::Instance().GetInherentSkillByID(idSkill)) - { - pSkill.StartCooling(item.max_cooltime, item.cooldown); - }*/ - else if (GetEquipSkillByID(idSkill) == null) - { - // Add to goblin skill list - pSkill = new CECSkill(idSkill, 1); - pSkill.StartCooling(item.max_cooltime, item.cooldown); - m_aGoblinSkills.Add(pSkill); - } - m_skillCoolTime[idSkill] = ct; - } - else if (item.idx >= 0 && item.idx < (int)CoolTimeIndex.GP_CT_MAX) - { - // Other cool time - COOLTIME ct = m_aCoolTimes[item.idx]; - ct.iCurTime = item.cooldown; - ct.iMaxTime = item.max_cooltime; - Mathf.Clamp(ct.iCurTime, 0, ct.iMaxTime); - - if (item.idx >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && item.idx <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) - { - // other player skills should be set public cool down too. - uint mask = (uint)(1 << (item.idx - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0)); - for (int y = 0; y < GetPositiveSkillNum(); y++) - { - CECSkill pSkill = GetPositiveSkillByIndex(y); - if (pSkill != null && ((pSkill.GetCommonCoolDown() & mask) != 0)) - pSkill.StartCooling(item.max_cooltime, item.cooldown); - } - } - } - else - { - BMLogger.LogError("item.idx >= 0: " + (item.idx >= 0)); - } - } - - UpdateEquipSkillCoolDown(); - } - - private void OnMsgEnchantResult(ECMSG msg) - { - // 浠庢秷鎭腑鑾峰彇cmd_enchant_result缁撴瀯 // Get cmd_enchant_result structure from message - cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes((byte[])msg.dwParam1); - - // 鍒濆鍖栨帺鐮佷负鍏1 // Initialize mask to all 1s - uint mask = 0xFFFFFFFF; - - // 濡傛灉鐩爣涓嶆槸涓绘満鐜╁涓斿綋鍓嶄笉鏄富鏈虹帺瀹讹紝鍒欒繃婊や細寮曡捣姘旀场鏂囨湰鐨勪慨楗扮 - // We should filter out these things that will cause bubble texts - CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer(); - if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer()) - { - mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE | - MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED); - } - - // 鑾峰彇淇グ绗 // Get modifier - uint dwModifier = (uint)pCmd.attack_flag; - - // 鑾峰彇鎶鑳界被鍨 // Get skill type - int nDamage = -2; // 榛樿涓-2锛屼笉浼氬紩璧峰彈浼ゅ姩浣 // Default to -2, will not cause wounded action - - if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK) - { - // 鍙湁鏀诲嚮鎶鑳戒細寮曡捣鍙椾激鍔ㄤ綔锛屼激瀹冲间负-1 // Only attack skill will cause wounded action, when damage is -1 - nDamage = -1; - } - else - { - // 鍏朵粬鎶鑳戒笉浼氬紩璧峰彈浼ゅ姩浣滐紝浼ゅ鍊艰涓-2 // Other skills will not cause wounded action, so we set damage to -2 - nDamage = -2; - } - - // 鎾斁鏀诲嚮鏁堟灉 // Play attack effect - int attackTime = 0; - PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage, - dwModifier & mask, 0, ref attackTime, pCmd.section); - } - - private void OnMsgPlayerCastSkill(ECMSG Msg) - { - - bool bDoOtherThing = false; - int idTarget = 0; - - bool bActionStartSkill = false; - int iActionTime = 1000; - CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); - - switch (Convert.ToInt32(Msg.dwParam2)) - { - case CommandID.OBJECT_CAST_SKILL: - { - cmd_object_cast_skill pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (m_pCurSkill != null) - { - m_pCurSkill.EndCharging(); - } - m_pCurSkill = GetPositiveSkillByID(pCmd.skill); - if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill); - if (m_pCurSkill == null) - m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill); - if (m_pCurSkill == null) - { - Debug.Assert(m_pCurSkill != null, "Current skill should not be null"); - return; - } - - if (m_pCurSkill.IsChargeable()) - m_pCurSkill.StartCharging(pCmd.time); - - int iWaitTime = -1; - if (m_pCurSkill.GetExecuteTime() >= 0) - iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); - - CECHPWorkSpell pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(Host_work_ID.WORK_SPELLOBJECT); - - pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); - m_pWorkMan.StartWork_p1(pWork); - - // Start time counter for some type skill - // 涓烘煇浜涚被鍨嬬殑鎶鑳藉惎鍔ㄦ椂闂磋鏁板櫒 - if (!m_pCurSkill.IsChargeable()) - { - int iTime = pCmd.time; - if (iTime < 10) iTime = 10; // a_ClampFloor - m_IncantCnt.SetPeriod(iTime); - m_IncantCnt.Reset(); - } - else - { - // make sure the counter is correct shown - // 纭繚璁℃暟鍣ㄦ纭樉绀 - m_IncantCnt.Reset(true); - } - - m_bSpellDSkill = false; - - TurnFaceTo(pCmd.target); - - m_idCurSkillTarget = pCmd.target; - PlaySkillCastAction(m_pCurSkill.GetSkillID()); - - bActionStartSkill = true; - iActionTime = iWaitTime; - - // Special logging for return-to-town skill (167) - // 鍥炲煄鎶鑳(167)鐨勭壒娈婃棩蹇 - if (m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL) - { - Debug.Log($"Return-to-town skill (167) cast - State2 should trigger SetReturntown(1) on server"); - } - break; - } - case CommandID.SKILL_PERFORM: - { - // Skill perform - // 鎶鑳芥墽琛 - m_pPrepSkill = null; - - if (m_pCurSkill != null && m_pCurSkill.IsDurative()) - m_bSpellDSkill = true; - - // Special handling for return-to-town skill (167) - // 鍥炲煄鎶鑳(167)鐨勭壒娈婂鐞 - // When skill 167 reaches State2, server calls SetReturntown(1) which should trigger MSG_HST_GOTO - // 褰撴妧鑳167鍒拌揪State2鏃讹紝鏈嶅姟鍣ㄨ皟鐢⊿etReturntown(1)锛岃繖搴旇瑙﹀彂MSG_HST_GOTO - if (m_pCurSkill != null && m_pCurSkill.GetSkillID() == ID_RETURNTOWN_SKILL) - { - Debug.Log($"Skill 167 (Return to Town) performed - waiting for MSG_HST_GOTO from server"); - } - - break; - } - case CommandID.HOST_STOP_SKILL: - { - m_pPrepSkill = null; - - CECSkill pSkillToMatch = m_pCurSkill; - if (m_pCurSkill != null) - { - ClearComActFlagAllRankNodes(true); - - if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || - m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) - { - bDoOtherThing = true; - idTarget = m_idCurSkillTarget; - } - - m_pCurSkill.EndCharging(); - m_pCurSkill = null; - } - - AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL); - if (pSkillToMatch != null) - { - // m_pWorkMan涓殑褰撳墠浠讳綍Work涓烘渶楂樹紭鍏堢骇鎴栥佹垨 CECHPWorkSpell 澶勪簬鏈楂樹紭鍏堢骇涓旈槦鍒椾腑鏈塂elay鏃堕棿 - // 姝ゆ椂姝ゅ鏃犳硶鍑嗙‘鍖归厤锛岃屽鑷寸殑 CECHPWorkSpell 鎵ц鏃跺皢钀藉悗浜庡叾瀹 CECHPWorkSpell 鎵ц鏈熼棿灏嗘棤娉曞搷搴 - // 鍦ㄨ繖绉嶆柟娉曟墽琛屽畬鎴愬悗锛屾垜浠娇鐢ㄥ洖鍩庢満鍒舵潵 - // If the current Work in m_pWorkMan is the highest priority or CECHPWorkSpell is at the highest priority and there is Delay time in the queue - // At this point, it cannot be accurately matched, causing the CECHPWorkSpell execution to lag behind other CECHPWorkSpell execution and cannot respond - // After this method is executed, we use the return to city mechanism - m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); - } - - StopSkillAttackAction(); - - m_idCurSkillTarget = 0; - break; - } - case CommandID.SELF_SKILL_INTERRUPTED: - { - // Skill interrupted - // 鎶鑳借鎵撴柇 - int skill_id = 0; - m_pPrepSkill = null; - - CECSkill - pSkillToMatch = m_pCurSkill; // 淇濆瓨鎸囬拡鍊硷紝鐢ㄥ湪鍚庨潰鍑芥暟璋冪敤涓 | Save pointer value for later function call - if (m_pCurSkill != null) - { - skill_id = m_pCurSkill.GetSkillID(); - - ClearComActFlagAllRankNodes(false); - - if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) || - m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork()) - { - bDoOtherThing = true; - idTarget = m_idCurSkillTarget; - } - - m_pCurSkill.EndCharging(); - m_pCurSkill = null; - } - - m_idCurSkillTarget = 0; - - - if (pSkillToMatch != null) - { - // 閫昏緫鍚 HOST_STOP_SKILL 鍒嗘敮澶勭悊 | Logic same as HOST_STOP_SKILL branch - m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch)); - } - - StopSkillCastAction(); - - // Print a notify message - // 鎵撳嵃鎻愮ず娑堟伅 - //EC_Game.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT); - - AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STOPSKILL); - - // 閫氱煡绛栫暐鎶鑳借鎵撴柇 | Notify policy that skill is interrupted - CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id); - break; - } - case CommandID.OBJECT_CAST_INSTANT_SKILL: - { - // Cast instant skill - // 鏂芥斁鍗虫椂鎶鑳 - cmd_object_cast_instant_skill pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - CECSkill pSkill = GetPositiveSkillByID(pCmd.skill); - if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); - if (pSkill == null) - { - Debug.Assert(pSkill != null, "Skill should not be null"); - return; - } - - if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) - TurnFaceTo(pCmd.target); - - PlaySkillCastAction(pSkill.GetSkillID()); - bActionStartSkill = true; - break; - } - case CommandID.OBJECT_CAST_POS_SKILL: - { - // Cast position skill (target position instead of target object) - // 鏂芥斁浣嶇疆鎶鑳斤紙鐩爣浣嶇疆鑰屼笉鏄洰鏍囧璞★級 - cmd_object_cast_pos_skill pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - CECSkill pSkill = GetNormalSkill(pCmd.skill); - if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill); - if (pSkill == null) - { - Debug.Assert(pSkill != null, "Skill should not be null"); - break; - } - - TurnFaceTo(pCmd.target); - - if (pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SLEF && - pSkill.GetRangeType() != (int)CECSkill.RangeType.RANGE_SELFSPHERE && - (pSkill.GetSkillID() == 1095 || // 鐬奖鐬柀 | Shadow instant slash - pSkill.GetSkillID() == 1278 || // 榄斅风灛褰辩灛鏂 | Demon Shadow instant slash - pSkill.GetSkillID() == 1279 || // 濡栫灛褰辩灛鏂 | Monster Shadow instant slash - pSkill.GetSkillID() == 2313)) - { - A3DVECTOR3 vPos = pCmd.pos; - if (!IsPosCollideFree(vPos)) - { - // Add a little height to ensure player's AABB won't embed with building - // 娣诲姞涓鐐归珮搴︿互纭繚鐜╁鐨凙ABB涓嶄細宓屽叆寤虹瓚鐗 - vPos += new A3DVECTOR3(0, 1, 0) * 0.1f; - } - - // Ensure we are not under ground - // 纭繚鎴戜滑涓嶅湪鍦颁笅 - A3DVECTOR3 vNormal = new A3DVECTOR3(); - float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal); - if (vPos.y < vTerrainHeight) - vPos.y = vTerrainHeight; - - SetPos(EC_Utility.ToVector3(vPos)); - - m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0); - m_CDRInfo.fYVel = 0.0f; - m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0); - ResetJump(); - - m_MoveCtrl.SetHostLastPos(vPos); - m_MoveCtrl.SetLastSevPos(vPos); - - // Update camera - // 鏇存柊鐩告満 - //UpdateFollowCamera(false, 10); - } - else - { - CECHPWorkFMove pWork = - (CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLASHMOVE); - - // 妫鏌ユ妧鑳芥墽琛屾椂闂达紝闃叉鍑虹幇娴偣鏁0锛屽嚭鐜伴敊璇 | Check skill execute time to prevent float 0 error - int nExecuteTime = pSkill.GetExecuteTime(); - if (nExecuteTime < 50) nExecuteTime = 50; // a_ClampFloor - - if (pSkill.GetSkillID() == 1145 || // 鍒哄鐨勭灛绉绘妧鑳斤紝闇瑕佸鍔犲湴闈㈡晥鏋1145锛氱櫨姝ョ┛鏉ㄧ灛鏂 | Assassin teleport skill - pSkill.GetSkillID() == 1314 || // 榄斅风櫨姝ョ┛鏉ㄧ灛鏂 | Demon hundred steps instant slash - pSkill.GetSkillID() == 1315 || // 濡柭风櫨姝ョ┛鏉ㄧ灛鏂 | Monster hundred steps instant slash - pSkill.GetSkillID() == 1362 || // 褰遍亖鍥炴潹 | Shadow escape return - pSkill.GetSkillID() == 1690 || // 褰遍亖榄斅峰洖鏉 | Shadow escape demon return - pSkill.GetSkillID() == 1691 || // 褰遍亖濡栧洖鏉 | Shadow escape monster return - pSkill.GetSkillID() == 1845 || // 鏄熸箹涔嬬嫄路鐬Щ鎶鑳 | Star Lake Fox teleport - pSkill.GetSkillID() == 1844 || // 鏄熸箹涔嬬嫄路鐬Щ鎶鑳 | Star Lake Fox teleport - pSkill.GetSkillID() == 1815 || // 濡栫簿 椋 | Fairy fly - pSkill.GetSkillID() == 2272 || // 涓姝ョ櫥澶 | One step to heaven - pSkill.GetSkillID() == 2315 || // 鐧炬绌挎潹鐬柀 | Hundred steps instant slash - pSkill.GetSkillID() == 2285 || // 鍥炴潹 | Return - pSkill.GetSkillID() == 2340 || // 绐佽 | Raid - pSkill.GetSkillID() == 2341 || // 绐佽 | Raid - pSkill.GetSkillID() == 2342 || // 绐佽 | Raid - pSkill.GetSkillID() == 2553 || // 椋炵闆 | Arrow rain - pSkill.GetSkillID() == 2740 || // 榄斅烽绠洦 | Demon arrow rain - pSkill.GetSkillID() == 2741 || // 濡栭绠洦 | Monster arrow rain - pSkill.GetSkillID() == 2559 || // 闂數 | Lightning - pSkill.GetSkillID() == 2752 || // 榄斅烽棯鐢 | Demon lightning - pSkill.GetSkillID() == 2753) // 濡栭棯鐢 | Monster lightning - { - A3DVECTOR3 vPos = pCmd.pos; - if (!IsPosCollideFree(vPos)) - { - // Add a little height to ensure player's AABB won't embed with building - // 娣诲姞涓鐐归珮搴︿互纭繚鐜╁鐨凙ABB涓嶄細宓屽叆寤虹瓚鐗 - vPos += new A3DVECTOR3(0, 1, 0) * 0.1f; - } - - // Ensure we are not under ground - // 纭繚鎴戜滑涓嶅湪鍦颁笅 - A3DVECTOR3 vNormal = new A3DVECTOR3(); - float vTerrainHeight = CECWorld.Instance.GetTerrainHeight(vPos, ref vNormal); - if (vPos.y < vTerrainHeight) - vPos.y = vTerrainHeight; - - m_CDRInfo.vTPNormal = vPos.y <= vTerrainHeight + 0.1f ? vNormal : new A3DVECTOR3(0); - m_CDRInfo.fYVel = 0.0f; - m_CDRInfo.vAbsVelocity = new A3DVECTOR3(0); - ResetJump(); - - pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID()); - } - else - { - if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SLEF || - pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SELFSPHERE) - { - m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal; - } - - pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0); - } - - m_pWorkMan.StartWork_p2(pWork); - iActionTime = nExecuteTime; - } - - bActionStartSkill = true; - break; - } - case CommandID.PLAYER_CAST_RUNE_SKILL: - { - // Cast rune skill (item skill) - // 鏂芥斁绗︽枃鎶鑳斤紙鐗╁搧鎶鑳斤級 - cmd_player_cast_rune_skill pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - if (m_pTargetItemSkill != null) - { - // Delete old target item skill - m_pTargetItemSkill = null; - } - - m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); - if (m_pTargetItemSkill == null) - { - Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null"); - return; - } - - m_pCurSkill = m_pTargetItemSkill; - - if (m_pCurSkill.IsChargeable()) - m_pCurSkill.StartCharging(pCmd.time); - - int iWaitTime = -1; - if (m_pCurSkill.GetExecuteTime() >= 0) - iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime(); - - CECHPWorkSpell pWork = - (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT); - pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime); - m_pWorkMan.StartWork_p1(pWork); - - // Start time counter for some type skill - // 涓烘煇浜涚被鍨嬬殑鎶鑳藉惎鍔ㄦ椂闂磋鏁板櫒 - if (!m_pCurSkill.IsChargeable()) - { - int iTime = pCmd.time; - if (iTime < 10) iTime = 10; // a_ClampFloor - m_IncantCnt.SetPeriod(iTime); - m_IncantCnt.Reset(); - } - else - { - // make sure the counter is correct shown - // 纭繚璁℃暟鍣ㄦ纭樉绀 - m_IncantCnt.Reset(true); - } - - m_bSpellDSkill = false; - - TurnFaceTo(pCmd.target); - - m_idCurSkillTarget = pCmd.target; - PlaySkillCastAction(m_pCurSkill.GetSkillID()); - - bActionStartSkill = true; - iActionTime = iWaitTime; - Debug.Log($"Cast rune skill({m_pCurSkill.GetSkillID()})"); - break; - } - case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: - { - // Cast instant rune skill - // 鏂芥斁鍗虫椂绗︽枃鎶鑳 - cmd_player_cast_rune_instant_skill pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - Debug.Assert(pCmd.caster == m_PlayerInfo.cid); - - if (m_pTargetItemSkill != null) - { - // Delete old target item skill - m_pTargetItemSkill = null; - } - - m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level); - if (m_pTargetItemSkill == null) - { - Debug.Assert(m_pTargetItemSkill != null, "Target item skill should not be null"); - return; - } - - if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid) - TurnFaceTo(pCmd.target); - - PlaySkillCastAction(m_pTargetItemSkill.GetSkillID()); - bActionStartSkill = true; - break; - } - case CommandID.ERROR_MESSAGE: - bDoOtherThing = true; - break; - - default: - Debug.Assert(false, "Unknown message type in OnMsgPlayerCastSkill"); - break; - } - - if (bActionStartSkill) - AP.AP_ActionEvent((int)AP_EVENT.AP_EVENT_STARTSKILL, iActionTime); - - if (bDoOtherThing) - { - if (m_pComboSkill != null && !m_pComboSkill.IsStop()) - { - // Continue combo skill - // 缁х画杩炲嚮鎶鑳 - if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled()) - EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL, MANAGER_INDEX.MAN_PLAYER, 0, 0, m_pComboSkill.GetGroupIndex()); - else - m_pComboSkill.Continue(false); - } - else - { - if (idTarget != 0 && idTarget != m_PlayerInfo.cid) - NormalAttackObject(idTarget, true); - } - } - } - - private void OnMsgHstSkillResult(ECMSG Msg) - { - cmd_host_skill_attack_result pCmd = - GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int refFake = 0; - PlayAttackEffect(pCmd.idTarget, pCmd.idSkill, 0, pCmd.iDamage, (uint)pCmd.attack_flag, - pCmd.attack_speed * 50, ref refFake, pCmd.section); - } - - private void OnMsgHstSkillData(ECMSG Msg) - { - cmd_skill_data pCmd = default; - pCmd.skill_count = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int offset = sizeof(uint); - int skillSize = Marshal.SizeOf(); - pCmd.skill_list = new cmd_skill_data.SKILL[pCmd.skill_count]; - for (int i = 0; i < pCmd.skill_count; i++) - { - pCmd.skill_list[i] = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1, offset); - offset += skillSize; - } - - if (pCmd.skill_list == null) - { - BMLogger.LogError("OnMsgHstSkillData: cmd is null"); - return; - } - - List skillSCConfigArray1 = new List(); - List skillSCConfigArray2 = new List(); - List skillGrpSCConfigArray1 = new List(); - List skillGrpSCConfigArray2 = new List(); - - if (HostIsReady()) - { - m_pWorkMan.FinishWork(new CECHPTraceSpellMatcher()); - m_pPrepSkill = null; - m_pCurSkill = null; - ClearComboSkill(); - SaveSkillShortcut(skillSCConfigArray1, m_aSCSets1, (int)Shortcut.NUM_HOSTSCSETS1); - SaveSkillShortcut(skillSCConfigArray2, m_aSCSets2, (int)Shortcut.NUM_HOSTSCSETS2); - SaveSkillGrpShortcut(skillGrpSCConfigArray1, m_aSCSets1, (int)Shortcut.NUM_HOSTSCSETS1); - SaveSkillGrpShortcut(skillGrpSCConfigArray2, m_aSCSets2, (int)Shortcut.NUM_HOSTSCSETS2); - /* - for (int i = 0; i < HostConstants.NUM_HOSTSCSETS1; i++) - { - if (hostPlayer.m_aSCSets1[i] != null) - { - hostPlayer.m_aSCSets1[i].RemoveSkillShortcuts(); - } - } - qqqqqqaaaaaaaaw - for (int i = 0; i < HostConstants.NUM_HOSTSCSETS2; i++) - { - if (hostPlayer.m_aSCSets2[i] != null) - { - hostPlayer.m_aSCSets2[i].RemoveSkillShortcuts(); - } - }*/ - - // Release passive skills - m_aSCSets1 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS1]; - m_aSCSets2 = new CECShortcutSet[HostCfgConstants.NUM_HOSTSCSETS2]; - m_aPtSkills.Clear(); - m_aPsSkills.Clear(); - } - - // Load skill data from command - // C++: GNET::ElementSkill::LoadSkillData(pCmd); - ElementSkill.LoadSkillData(pCmd); - // Create skill objects from command data - for (int i = 0; i < pCmd.skill_count; i++) - { - cmd_skill_data.SKILL data = pCmd.skill_list[i]; - CECSkill skill = new CECSkill(data.id_skill, data.level); - - // Categorize skills into positive and passive - int skillType = skill.GetType(); - if (skillType != (int)CECSkill.SkillType.TYPE_PASSIVE && - skillType != (int)CECSkill.SkillType.TYPE_PRODUCE && - skillType != (int)CECSkill.SkillType.TYPE_LIVE) - { - m_aPtSkills.Add(skill); - } - else - { - m_aPsSkills.Add(skill); - } - } - // Restore and convert shortcuts after loading new skills - if (HostIsReady()) - { - ConvertSkillShortcut(skillSCConfigArray1); - AssignSkillShortcut(skillSCConfigArray1, m_aSCSets1); - ConvertSkillShortcut(skillSCConfigArray2); - AssignSkillShortcut(skillSCConfigArray2, m_aSCSets2); - ConvertComboSkill(); - ValidateSkillGrpShortcut(skillGrpSCConfigArray1); - AssignSkillGrpShortcut(skillGrpSCConfigArray1, m_aSCSets1); - ValidateSkillGrpShortcut(skillGrpSCConfigArray2); - AssignSkillGrpShortcut(skillGrpSCConfigArray2, m_aSCSets2); - } - - if (HostIsReady()) - { - // Update UI when profession changes, save all shortcut configurations - // to remove effects from intermediate skills (invalid pointers) - // C++: CECGameUIMan *pGameUIMan = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); - // pGameUIMan.UpdateSkillRelatedUI(); - CECUIManager.Instance.UpdateSkillRelatedUI(); - } - } - public void AssignSkillGrpShortcut(List skillGrpSCConfigArray, CECShortcutSet[] aSCSets) - { - for (int i = 0; i < skillGrpSCConfigArray.Count; i++) - { - SkillGrpShortCutConfig cfg = skillGrpSCConfigArray[i]; - - if (cfg.groupIndex != -1) - { - // C++ kh么ng check null; n岷縰 mu峄憂 an to脿n h啤n th矛 check aSCSets[cfg.setNum] != null - aSCSets[cfg.setNum].CreateSkillGroupShortcut(cfg.slotNum, cfg.groupIndex); - } - } - } - public void ValidateSkillGrpShortcut(List skillGrpSCConfigArray) - { - for (int i = 0; i < skillGrpSCConfigArray.Count; i++) - { - // C++ 膽ang l岷 VideoSettings trong m峄梚 v貌ng l岷穚 (gi峄 nguy锚n h脿nh vi) - EC_VIDEO_SETTING vs = EC_Game.GetConfigs().GetVideoSettings(); - - SkillGrpShortCutConfig cfg = skillGrpSCConfigArray[i]; - - if (vs.comboSkill[cfg.groupIndex].nIcon == 0) - cfg.groupIndex = -1; // -1 bi峄僽 th峄 shortcut combo-skill kh么ng h峄 l峄 - - skillGrpSCConfigArray[i] = cfg; // c岷 n岷縰 SkillGrpShortCutConfig l脿 struct - } - } - - public void ConvertComboSkill() - { - EC_VIDEO_SETTING vs = EC_Game.GetConfigs().GetVideoSettings(); - - for (int i = 0; i < EC_ConfigConstants.EC_COMBOSKILL_NUM; i++) - { - if (vs.comboSkill[i].nIcon == 0) - continue; - - for (int j = 0; j < EC_ConfigConstants.EC_COMBOSKILL_LEN; j++) - { - int oldSkillId = vs.comboSkill[i].idSkill[j]; - if (oldSkillId == 0) - continue; - - int convertedSkillId = CECSkillConvert.Instance.GetConvertSkill(oldSkillId); - int newSkillId = (convertedSkillId == 0) ? oldSkillId : convertedSkillId; - - // C++: n岷縰 skill t峄搉 t岷, ho岷穋 l脿 -1/-2 (loop / normal attack shortcut) th矛 gi峄 - if (GetNormalSkill(newSkillId) != null || newSkillId == -1 || newSkillId == -2) - { - vs.comboSkill[i].idSkill[j] = (short)newSkillId; - } - else - { - // Kh么ng h峄 l峄 -> clear combo theo oldSkillId, icon v峄 0, tho谩t v貌ng l岷穚 j - vs.comboSkill[i].Clear(oldSkillId); - vs.comboSkill[i].nIcon = 0; - break; - } - } - } - - EC_Game.GetConfigs().SetVideoSettings(vs); - } - public void AssignSkillShortcut(List skillSCConfigArray, CECShortcutSet[] aSCSets) - { - for (int i = 0; i < skillSCConfigArray.Count; i++) - { - SkillShortCutConfig cfg = skillSCConfigArray[i]; - if (cfg.skillId == 0) - { - BMLogger.LogError("AssignSkillShortcut: skillId is zero"); - } - CECSkill convertSkill = GetNormalSkill(cfg.skillId); - if (convertSkill != null) - { - // C++ kh么ng check null set => n岷縰 mu峄憂 y h峄噒 th矛 b峄 check n脿y - if (aSCSets[cfg.setNum] != null) - { - aSCSets[cfg.setNum].CreateSkillShortcut(cfg.slotNum, convertSkill); - } - } - } - } - public void ConvertSkillShortcut(List skillSCConfigArray) - { - for (int i = 0; i < skillSCConfigArray.Count; i++) - { - if (skillSCConfigArray[i].skillId == 0) - { - BMLogger.LogError("ConvertSkillShortcut: skillId is zero"); - } - - int oldSkillId = skillSCConfigArray[i].skillId; - int convertSkillId = CECSkillConvert.Instance.GetConvertSkill(oldSkillId); - - // it->skillId = (convertSkillId == 0) ? it->skillId : convertSkillId; - SkillShortCutConfig cfg = skillSCConfigArray[i]; - cfg.skillId = (convertSkillId == 0) ? oldSkillId : convertSkillId; - skillSCConfigArray[i] = cfg; // needed if SkillShortCutConfig is a struct - } - } - public void SaveSkillGrpShortcut( - List skillGrpSCConfigArray, - CECShortcutSet[] aSCSets, - int count) - { - for (int i = 0; i < count; i++) - { - if (aSCSets[i] == null) continue; - - for (int j = 0; j < aSCSets[i].GetShortcutNum(); j++) - { - CECShortcut pSC = aSCSets[i].GetShortcut(j); - if (pSC == null || pSC.GetType() != (int)ShortcutType.SCT_SKILLGRP) - continue; - - // C-style cast -> safe cast - if (pSC is not CECSCSkillGrp pSkillGrpSC) - continue; - - SkillGrpShortCutConfig skillGrpSCConfig = new SkillGrpShortCutConfig(); - skillGrpSCConfig.setNum = i; - skillGrpSCConfig.slotNum = j; - skillGrpSCConfig.groupIndex = pSkillGrpSC.GetGroupIndex(); - - skillGrpSCConfigArray.Add(skillGrpSCConfig); - } - } - } - - public void SaveSkillShortcut( - List skillSCConfigArray, - CECShortcutSet[] aSCSets, - int count) - { - for (int i = 0; i < count; i++) - { - if (aSCSets[i] == null) continue; - - for (int j = 0; j < aSCSets[i].GetShortcutNum(); j++) - { - CECShortcut pSC = aSCSets[i].GetShortcut(j); - if (pSC == null || pSC.GetType() != (int)ShortcutType.SCT_SKILL) - continue; - - if (pSC is not CECSCSkill pSkillSC) - continue; - - int iOldSkillId = pSkillSC.GetSkill()?.GetSkillID() ?? 0; - if (iOldSkillId == 0) - continue; - - SkillShortCutConfig skillSCConfig = new SkillShortCutConfig(); - skillSCConfig.setNum = i; - skillSCConfig.slotNum = j; - skillSCConfig.skillId = iOldSkillId; - - skillSCConfigArray.Add(skillSCConfig); - } - } - } - -#if UNITY_EDITOR - /// - /// Cycles through learned skills by removing all shortcuts and adding 2 new skills to slots 0 and 1. - /// If m_startingSkillID is set (>0), uses that specific skill ID and the next one (ID+1). - /// Otherwise, cycles through all learned skills in pairs. - /// - public void CycleSkillShortcuts() - { - // Get shortcut set 1 - CECShortcutSet pSCS = GetShortcutSet1(0); - if (pSCS == null) - { - Debug.LogWarning("CycleSkillShortcuts: Shortcut Set 1 is null"); - return; - } - - // Remove all shortcuts - pSCS.RemoveAllShortcuts(); - - // If starting skill ID is configured, cycle through pairs starting from that ID - if (m_startingSkillID > 0) - { - // Calculate the current skill IDs based on cycle index - // First press: startingID + 0, startingID + 1 (e.g., 5, 6) - // Second press: startingID + 2, startingID + 3 (e.g., 7, 8) - // Third press: startingID + 4, startingID + 5 (e.g., 9, 10) - int currentSkillID1 = m_startingSkillID + (m_currentSkillCycleIndex * 2); - int currentSkillID2 = currentSkillID1 + 1; - BMLogger.LogError($"CycleSkillShortcuts: Trying to add skills {currentSkillID1} and {currentSkillID2}"); - // Find and add first skill - CECSkill pSkill1 = GetPositiveSkillByID(currentSkillID1); - if (pSkill1 != null) - { - pSCS.CreateSkillShortcut(0, pSkill1); - Debug.LogError($"CycleSkillShortcuts: Added skill ID {currentSkillID1} to slot 0"); - } - else - { - Debug.LogError($"CycleSkillShortcuts: Skill with ID {currentSkillID1} not found in learned skills"); - int find = 1; - while (pSkill1 == null || find == 100) - { - m_startingSkillID++; - Debug.LogError($"CycleSkillShortcuts: m_startingSkillID {m_startingSkillID} "); - currentSkillID1 = m_startingSkillID + (m_currentSkillCycleIndex * 2); - pSkill1 = GetPositiveSkillByID(currentSkillID1); - find++; - } - pSCS.CreateSkillShortcut(0, pSkill1); - } - - // Find and add second skill - CECSkill pSkill2 = GetPositiveSkillByID(currentSkillID2); - if (pSkill2 != null) - { - pSCS.CreateSkillShortcut(1, pSkill2); - Debug.LogError($"CycleSkillShortcuts: Added skill ID {currentSkillID2} to slot 1"); - } - else - { - Debug.LogError($"CycleSkillShortcuts: Skill with ID {currentSkillID2} not found in learned skills"); - int find = 1; - while (pSkill2 == null || find == 100) - { - m_startingSkillID++; - Debug.LogError($"CycleSkillShortcuts: m_startingSkillID {m_startingSkillID} "); - currentSkillID2 = m_startingSkillID + (m_currentSkillCycleIndex * 2) +1; - pSkill2 = GetPositiveSkillByID(currentSkillID2); - find++; - } - pSCS.CreateSkillShortcut(1, pSkill2); - } - - // Increment cycle index for next press - m_currentSkillCycleIndex++; - - // Update UI - CDlgQuickBar cDlgQuickBar2 = CECUIManager.Instance?.GetCDlgQuickBar(); - cDlgQuickBar2?.UpdateShortcuts(); - return; - } - - // Original cycling behavior - // Get the list of learned skills - int skillCount = GetPositiveSkillNum(); - - // If no skills learned, just clear shortcuts (already done above) - if (skillCount == 0) - { - // Update UI - CDlgQuickBar cDlgQuickBar1 = CECUIManager.Instance?.GetCDlgQuickBar(); - cDlgQuickBar1?.UpdateShortcuts(); - return; - } - - // Calculate how many pairs we can make - int maxPairs = (skillCount + 1) / 2; // Round up division - - // Wrap around if we've reached the end - if (m_currentSkillCycleIndex >= maxPairs) - { - m_currentSkillCycleIndex = 0; - } - - // Calculate skill indices for this cycle - int skillIndex1 = m_currentSkillCycleIndex * 2; - int skillIndex2 = skillIndex1 + 1; - - // Add first skill to slot 0 - if (skillIndex1 < skillCount) - { - CECSkill pSkill1 = GetPositiveSkillByIndex(skillIndex1); - if (pSkill1 != null) - { - pSCS.CreateSkillShortcut(0, pSkill1); - } - } - - // Add second skill to slot 1 (if available) - if (skillIndex2 < skillCount) - { - CECSkill pSkill2 = GetPositiveSkillByIndex(skillIndex2); - if (pSkill2 != null) - { - pSCS.CreateSkillShortcut(1, pSkill2); - } - } - - // Increment cycle index for next time - m_currentSkillCycleIndex++; - - // Update UI - CDlgQuickBar cDlgQuickBar = CECUIManager.Instance?.GetCDlgQuickBar(); - cDlgQuickBar?.UpdateShortcuts(); - } -#endif - public bool HostIsReady() { return m_bEnterGame; } - private void OnMsgHstDied(in ECMSG msg) - { - // Mark host player as corpse so CECPlayer.IsDead() returns true - m_dwStates |= (uint)PlayerNPCState.GP_STATE_CORPSE; - - EventBus.PublishChannel(GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true)); - PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE); - if (PopupManager.Instance != null) - { - PopupManager.Instance.OnPlayerDied(); - } - } - - private void OnMsgHstInfo00(in ECMSG Msg) - { - cmd_self_info_00 pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - bool bFirstTime = m_BasicProps.iLevel == 0 ? true : false; - if (!bFirstTime) - { - int iLimit = (int)(pCmd.iMaxHP * 0.3f); - if (pCmd.iHP < m_BasicProps.iCurHP && m_BasicProps.iCurHP >= iLimit && pCmd.iHP < iLimit) - { - /*if (CECUIHelper::GetGameUIMan().IsShowLowHP()) { - // 脩陋脕驴碌脥脫脷脕脵陆莽脰碌脭貌虏楼路脜脤脴脨搂 - const int GfxLastTime = 10000; // 鲁脰脨酶脢卤录盲10脙毛 - CECUIHelper::GetGameUIMan().GetScreenEffectMan().StartEffect(CECScreenEffect::EFFECT_REDSPARK, GfxLastTime); - }*/ - } - - /*if (pCmd.iHP >= iLimit || pCmd.iHP <= 0) { - // 脩陋脕驴赂脽脫脷脕脵陆莽脰碌禄貌脣脌脥枚拢卢脭貌脥拢脰鹿虏楼路脜脤脴脨搂 - CECUIHelper::GetGameUIMan().GetScreenEffectMan().FinishEffect(CECScreenEffect::EFFECT_REDSPARK); - }*/ - - /*iLimit = (int)(pCmd.iMaxMP * 0.2f); - if (pCmd.iMP < m_BasicProps.iCurMP && m_BasicProps.iCurMP >= iLimit && pCmd.iMP < iLimit) - BubbleText(BUBBLE_MPWARN, 0);*/ - - /*if (m_ExtProps.max_ap != pCmd.iMaxAP) - g_pGame.GetGameRun().AddFixedMessage(FIXMSG_ADDMAXAP, pCmd.iMaxAP - m_ExtProps.max_ap);*/ - } - - m_BasicProps.iLevel = pCmd.sLevel; - SetLevel2(pCmd.Level2, bFirstTime); - m_BasicProps.iExp = pCmd.iExp; - m_BasicProps.iSP = pCmd.iSP; - m_BasicProps.iCurHP = pCmd.iHP; - m_BasicProps.iCurMP = pCmd.iMP; - m_BasicProps.iCurAP = pCmd.iAP; - m_ExtProps.bs.max_hp = pCmd.iMaxHP; - m_ExtProps.bs.max_mp = pCmd.iMaxMP; - m_ExtProps.max_ap = pCmd.iMaxAP; - - EventBus.Publish(new EXPToUpLevel(GetLevelUpExp(pCmd.sLevel))); - EventBus.Publish(pCmd); - EventBus.PublishChannel(GetCharacterID(), pCmd); - // if (pCmd.State != 0 && m_bFight == false) PlayEnterBattleGfx(); - m_bFight = pCmd.State != 0 ? true : false; - - // UpdateGodEvilSprite(); - - /*CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); - CDlgAutoHelp *pDlgHelp = dynamic_cast(pGameUI.GetDialog("Win_WikiPop"));*/ - /*if(pDlgHelp && m_bFight) - pDlgHelp.SetAutoHelpState(false);*/ - } - + void SetLevel2(int level2, bool bFirstTime) { int lastLevel2 = m_BasicProps.iLevel2; @@ -1976,104 +659,11 @@ namespace BrewMonster }*/ } - void OnMsgHstAttacked(ECMSG Msg) - { - var m_pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer; - cmd_host_attacked pCmd = GPDataTypeHelper.FromBytes(Msg.dwParam1 as byte[]); - - if (pCmd.iDamage != 0 && (pCmd.cEquipment & 0x7f) != 0x7f) - { - /* char cEquip = (char)(pCmd.cEquipment & 0x7f); - CECIvtrEquip pEquip = (CECIvtrEquip)m_pEquipPack.GetItem(cEquip); - if (pEquip) - pEquip.AddCurEndurance(ARMOR_RUIN_SPEED);*/ - } - - // The host player is attacked, we should make an effect here - if (GPDataTypeHelper.ISPLAYERID(pCmd.idAttacker)) - { - EC_ElsePlayer pAttacker = m_pPlayerMan.GetElsePlayer(pCmd.idAttacker); - if (pAttacker) - { - if (!pAttacker.IsDead()) - { - // Face to target - pAttacker.TurnFaceTo(GetPlayerInfo().cid); - } - - int useless_attacktime = 0; - pAttacker.PlayAttackEffect(GetCharacterID(), 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, - pCmd.speed * 50, ref useless_attacktime); - pAttacker.EnterFightState(); - } - } - else if (GPDataTypeHelper.ISNPCID(pCmd.idAttacker)) - { - CECNPC pAttacker = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idAttacker); - if (pAttacker) - { - pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed); - } - } - - //CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker); - } - - public void OnMsgHstAttackResult(ECMSG Msg) - { - byte[] data = Msg.dwParam1 as byte[]; - cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); - - int iAttackTime = 0; - TurnFaceTo(pCmd.idTarget); - - PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50, - ref iAttackTime); - - if (iAttackTime != 0) - { - if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork) - { - pCurWork.SetIdleTime(iAttackTime); - } - } - } - /* public override bool IsWorkMoveRunning() { return m_pWorkMan.IsMovingToPosition(); }*/ - private void OnMsgHstHurtResult(ECMSG Msg) - { - //BMLogger.LogError("HoangDev : OnMsgHstHurtResult"); - /* int cmd = Convert.ToInt32(Msg.dwParam2); - if (cmd == CommandID.BE_HURT) - { - cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1; - if (pCmd.damage != 0) - Damaged(pCmd.damage); - } - else if (cmd == CommandID.HURT_RESULT) - { - cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1; - if (pCmd.target_id == m_PlayerInfo.cid) - return; // Host himself will receive BE_HURT, so ignore this. - - if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id)) - { - CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id); - if (pTarget) - pTarget.Damaged(pCmd.damage); - } - else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id)) - { - CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id); - if (pTarget) - pTarget.Damaged(pCmd.damage); - } - }*/ - } - + public bool IsPosCollideFree(A3DVECTOR3 vTargetPos) { bool bAvailable = (false); @@ -2418,590 +1008,6 @@ namespace BrewMonster return vTemp.y; } - public void OnMsgHstPickupItem(in ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - - bool bDoOther = false; - int idItem, iExpireDate = 0, iAmount, iCmdLastSlot, iCmdSlotAmount, iPack, iMsg = -1; - - switch (cmd) - { - case CommandID.HOST_OBTAIN_ITEM: - { - // Parse cmd_host_obtain_item struct data - int type = BitConverter.ToInt32(data, 0); - int expire_date = BitConverter.ToInt32(data, 4); - uint amount = BitConverter.ToUInt32(data, 8); - uint slot_amount = BitConverter.ToUInt32(data, 12); - byte where = data[16]; // Package index - byte index = data[17]; // Slot index in that package - var newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)amount); - - // Add item to inventory - var ivt = GetInventory(where); - ivt.SetItem(index, newItem); - - Debug.Log( - $"[HOST_OBTAIN_ITEM] Successfully added item {type} to package {where}, slot {index} with count {amount}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - } - - UpdateEquipSkins(); - } - break; - case CommandID.PICKUP_ITEM: - { - int tid = BitConverter.ToInt32(data, 0); - int expire_date = BitConverter.ToInt32(data, 4); - iAmount = (int)BitConverter.ToUInt32(data, 8); - uint iSlotAmount = BitConverter.ToUInt32(data, 12); - byte byPackage = data[16]; - byte bySlot = data[17]; - - //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); - - // Notify pickupItem script about successful pickup - pickupItem pickupScript = pickupItem.Instance; - if (pickupScript != null) - { - //Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); - - // Notify pickupItem script about successful pickup - pickupScript = UnityEngine.Object.FindFirstObjectByType(); - if (pickupScript != null) - { - pickupScript.OnPickupSuccess(tid); - } - - // Create new inventory item data - var newItem = EC_IvtrItem.CreateItem(tid, expire_date, (int)iAmount); - - // Add item to inventory - var ivt = GetInventory(byPackage); - ivt.SetItem(bySlot, newItem); - - //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - } - } - else - { - Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); - } - - break; - } - case CommandID.TASK_DELIVER_ITEM: - cmd_task_deliver_item pCmd = GPDataTypeHelper.FromBytes(data); - // ASSERT(pCmd); - - idItem = pCmd.type; - iExpireDate = pCmd.expire_date; - iAmount = (int)pCmd.amount; - iCmdLastSlot = pCmd.index; - iCmdSlotAmount = (int)pCmd.slot_amount; - iPack = pCmd.where; - iMsg = (int)FixedMsg.FIXMSG_GAINITEM; - bDoOther = true; - - - // Create new inventory item data - var taskNewItem = EC_IvtrItem.CreateItem(idItem, iExpireDate, (int)iAmount); - - // Add item to inventory - var task_ivt = GetInventory((byte)iPack); - if (!task_ivt.MergeItem(idItem, iExpireDate, iAmount, out var iLastSlot, out var iSlotNum) || - iLastSlot != iCmdLastSlot || iSlotNum != iCmdSlotAmount) - { - return; - } - task_ivt.SetItem(iCmdLastSlot, taskNewItem); - - //Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var task_ui = GameObject.FindFirstObjectByType(); - if (task_ui != null) - { - task_ui.RefreshAll(); - } - - break; - case CommandID.PRODUCE_ONCE: - { - // Parse cmd_produce_once struct data - cmd_produce_once produceCmd = GPDataTypeHelper.FromBytes(data); - - int produceItemId = produceCmd.type; - int produceExpireDate = 0; - uint produceAmount = produceCmd.amount; - byte producePack = produceCmd.where; - byte produceSlot = produceCmd.index; - - Debug.Log($"[PRODUCE_ONCE] Received: itemId={produceItemId}, amount={produceAmount}, pack={producePack}, slot={produceSlot}"); - - // Get inventory - var produce_ivt = GetInventory(producePack); - if (produce_ivt == null) - { - Debug.LogWarning($"[PRODUCE_ONCE] Invalid inventory package {producePack}"); - return; - } - - // Check if the slot already has an item - var existingItem = produce_ivt.GetItem(produceSlot, false); - - if (existingItem != null) - { - if (existingItem.m_tid == produceItemId) - { - existingItem.m_iCount = (int)produceAmount; - Debug.Log($"[PRODUCE_ONCE] Updated existing item count at slot {produceSlot} to {produceAmount}"); - } - else - { - Debug.LogWarning($"[PRODUCE_ONCE] Slot {produceSlot} already has different item (tid={existingItem.m_tid}), not overwriting with {produceItemId}"); - return; - } - } - else - { - var produceNewItem = new EC_IvtrItem - { - Package = producePack, - Slot = produceSlot, - m_tid = produceItemId, - m_expire_date = produceExpireDate, - State = 0, - m_iCount = (int)produceAmount, - Crc = 0, - Content = null - }; - - produce_ivt.SetItem(produceSlot, produceNewItem); - Debug.Log($"[PRODUCE_ONCE] Created new item at slot {produceSlot} with count {produceAmount}"); - } - - // Trigger UI refresh - var produce_ui = GameObject.FindFirstObjectByType(); - if (produce_ui != null) - { - produce_ui.RefreshAll(); - } - - UpdateEquipSkins(); - - // Notify DlgProduce - var dlgProduce = GameObject.FindFirstObjectByType(); - if (dlgProduce != null) - { - dlgProduce.OnProduceOnce(produceCmd); - } - } - break; - } - } - - public void OnMsgHstProduceItem(in ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - - // Get DlgProduce to notify - var dlgProduce = GameObject.FindFirstObjectByType(); - if (dlgProduce == null) - { - Debug.LogWarning("[OnMsgHstProduceItem] DlgProduce not found"); - return; - } - - switch (cmd) - { - case CommandID.PRODUCE_START: - { - cmd_produce_start pCmd = GPDataTypeHelper.FromBytes(data); - Debug.Log($"[PRODUCE_START] type={pCmd.type}, use_time={pCmd.use_time}, count={pCmd.count}"); - dlgProduce.OnProduceStart(pCmd); - } - break; - case CommandID.PRODUCE_END: - { - Debug.Log("[PRODUCE_END] Production ended"); - dlgProduce.OnProduceEnd(); - } - break; - case CommandID.PRODUCE_NULL: - { - cmd_produce_null pCmd = GPDataTypeHelper.FromBytes(data); - Debug.Log($"[PRODUCE_NULL] type={pCmd.type}"); - dlgProduce.OnProduceNull(pCmd); - } - break; - default: - Debug.LogWarning($"[OnMsgHstProduceItem] Unknown command: {cmd}"); - break; - } - } - - public void OnMsgHstItemOperation(ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) - { - case CommandID.PLAYER_DROP_ITEM: - { - // Parse the drop item data from the server response - if (data != null && data.Length >= 6) - { - byte byPackage = data[0]; - byte bySlot = data[1]; - int count = BitConverter.ToInt32(data, 2); - int tid = BitConverter.ToInt32(data, 6); - byte reason = data[10]; - - Debug.Log( - $"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); - - // Update the inventory by removing the item - var inv = GetInventory(byPackage); - bool success = inv != null && inv.RemoveItem(bySlot, count); - - if (success) - { - Debug.Log( - $"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - } - } - else - { - Debug.LogWarning( - $"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); - } - } - else - { - Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); - } - - break; - } - - case CommandID.EQUIP_ITEM: - { - byte index_inv = data[0]; - byte index_equip = data[1]; - // Update client-side data: move item between PACK_INVENTORY and PACK_EQUIPMENT - var packInv = GetInventory(InventoryConst.IVTRTYPE_PACK); - var equipInv = GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK); - var invItem = packInv?.GetItem(index_inv, true); - var equipItem = equipInv?.GetItem(index_equip, true); - UpdateEquipSkins(); - if (invItem != null) - { - invItem.Package = InventoryConst.IVTRTYPE_EQUIPPACK; - invItem.Slot = index_equip; - equipInv?.SetItem(index_equip, invItem); - } - - if (equipItem != null) - { - equipItem.Package = InventoryConst.IVTRTYPE_PACK; - equipItem.Slot = index_inv; - packInv?.SetItem(index_inv, equipItem); - } - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindObjectOfType(); - if (ui != null) - { - ui.RefreshAll(); - } - - UpdateEquipSkins(); - break; - } - } - } - - public void OnMsgHstOwnItemInfo(ECMSG Msg) - { - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) - { - case CommandID.OWN_ITEM_INFO: - { - //Debug.Log("[Inventory] OWN_ITEM_INFO received"); - //var data = Msg.dwParam1 as byte[]; - //int hostId = Convert.ToInt32(Msg.dwParam3); - //LogInventoryPacket("OWN_ITEM_INFO", data, hostId); - - //Handmade - var data = Msg.dwParam1 as byte[]; - if (data == null || data.Length == 0) - return; - - byte byPackage = data[0]; - byte bySlot = data[1]; - int type = BitConverter.ToInt32(data, 2); - int expire_date = BitConverter.ToInt32(data, 6); - int state = BitConverter.ToInt32(data, 10); - uint count = BitConverter.ToUInt32(data, 14); - ushort crc = BitConverter.ToUInt16(data, 18); - ushort content_length = BitConverter.ToUInt16(data, 20); - - byte[] content = null; - if (content_length > 0 && 22 + content_length <= data.Length) - { - content = new byte[content_length]; - Buffer.BlockCopy(data, 22, content, 0, content_length); - - string hexDebug = BitConverter.ToString(content); - //Debug.Log($"[OWN_ITEM_INFO] Full Content Hex ({content_length} bytes): {hexDebug}"); - } - - //Debug.Log($"[OWN_ITEM_INFO] Parsed: package={byPackage}, slot={bySlot}, tid={type}, count={count}, content_len={content_length}"); - - EC_Inventory pInventory = GetInventory(byPackage); - EC_IvtrItem newItem = EC_IvtrItem.CreateItem(type, expire_date, (int)count); - - if (newItem != null) - { - newItem.SetProcType(state); - - newItem.GetDetailDataFromLocal(); - if (content != null && content.Length > 0) - { - newItem.SetItemInfo(content, content_length); - } - - pInventory.SetItem(bySlot, newItem); - - //Debug.Log($"[OWN_ITEM_INFO] Fixed Update: Pack {byPackage} Slot {bySlot} - Type {type}"); - } - - if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) - { - UpdateEquipSkins(); - } - else if (byPackage == InventoryConst.IVTRTYPE_PACK) - { - if (newItem.IsEquipment()) - { - // TODO - } - } - var ui = GameObject.FindFirstObjectByType(); - - if (ui != null) - { - ui.RefreshAll(); - //Debug.Log($"[OWN_ITEM_INFO] Refreshed inventory UI after updating item at package={byPackage}, slot={bySlot}"); - } - break; - - } - case CommandID.EMPTY_ITEM_SLOT: - { - var data = Msg.dwParam1 as byte[]; - - cmd_empty_item_slot pCmd = GPDataTypeHelper.FromBytes(data); - EC_Inventory pInventory = GetPack(pCmd.byPackage); - if (pInventory == null) - return; - - EC_IvtrItem pItem = pInventory.GetItem(pCmd.bySlot); - if (pItem != null) - { - //UpdateRemovedItemSC(pItem->GetTemplateID(), pCmd->byPackage, pCmd->bySlot); - } - pInventory.SetItem(pCmd.bySlot, null); - - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - } - break; - } - } - } - - public void OnMsgHstIvtrInfo(ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - int hostId = Convert.ToInt32(Msg.dwParam3); - - switch (cmd) - { - case CommandID.OWN_IVTR_DATA: - { - LogInventoryPacket("OWN_IVTR_DATA", data, hostId); - break; - } - case CommandID.OWN_IVTR_DETAIL_DATA: - { - // EC_Inventory.LogInventoryPacket("OWN_IVTR_DETAIL_DATA", data, hostId); - // Parse and store - if (data != null && data.Length >= 6) - { - byte byPackage = data[0]; - byte ivtrSize = data[1]; - if (EC_IvtrItemUtils.Instance.TryParseInventoryDetail(data, out var pkg, - out var size, out var items)) - { - var inv = GetInventory(pkg); - if (inv != null) - { - inv.Resize(size); - inv.RemoveAllItems(); - - if (items != null) - { - foreach (var it in items) - { - if (it != null && it.Slot >= 0 && it.Slot < size) - inv.SetItem(it.Slot, it); - } - } - } - } - - // check if we got the item from the Equipment Pack. If so, we have to load the equipment items - if (byPackage == InventoryConst.IVTRTYPE_EQUIPPACK) - { - UpdateEquipSkins(); - } - } - - break; - } - case CommandID.GET_OWN_MONEY: - { - if (data != null) - { - try - { - var money = GPDataTypeHelper.FromBytes(data); - - SetMoneyAmount(money.amount); - - var ui = GameObject.FindFirstObjectByType(); - if (ui == null) - { - var all = Resources.FindObjectsOfTypeAll(); - if (all != null) - { - for (int i = 0; i < all.Length; i++) - { - var candidate = all[i]; - if (candidate != null && candidate.gameObject.scene.IsValid()) - { - ui = candidate; - break; - } - } - } - } - - if (ui != null) - { - ui.UpdateMoney(money.amount, money.max_amount); - } - else - { - BrewMonster.Scripts.Managers.EC_InventoryUI.CacheMoney(money.amount, money.max_amount); - } - } - catch (Exception ex) - { - Debug.LogWarning($"[Inventory] Failed to parse GET_OWN_MONEY: {ex.Message}"); - } - } - - break; - } - case CommandID.PLAYER_CASH: - { - if (data != null) - { - try - { - var cash = GPDataTypeHelper.FromBytes(data); - var ui = GameObject.FindFirstObjectByType(); - if (ui == null) - { - var all = Resources.FindObjectsOfTypeAll(); - if (all != null) - { - for (int i = 0; i < all.Length; i++) - { - var candidate = all[i]; - if (candidate != null && candidate.gameObject.scene.IsValid()) - { - ui = candidate; - break; - } - } - } - } - - if (ui != null) - { - ui.UpdateCash(cash.cash_amount); - } - else - { - BrewMonster.Scripts.Managers.EC_InventoryUI.CacheCash(cash.cash_amount); - } - } - catch (Exception ex) - { - Debug.LogWarning($"[Inventory] Failed to parse PLAYER_CASH: {ex.Message}"); - } - } - - break; - } - } - } - - public void OnMsgHstCorrectPos(in ECMSG Msg) - { - //Debug.LogError("HoangDev : OnMsgHstCorrectPos"); - byte[] buf = (byte[])Msg.dwParam1; // ch峄 b岷 l瓢u pDataBuf - GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned); - cmd_host_correct_pos pCmd = (cmd_host_correct_pos)Marshal.PtrToStructure( - handle.AddrOfPinnedObject(), typeof(cmd_host_correct_pos)); - handle.Free(); - //cmd_host_correct_pos pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - Debug.LogError("HoangDev :pCmd.pos " + pCmd.pos); - SetPos(pCmd.pos); - m_vVelocity.Clear(); - m_CDRInfo.vAbsVelocity.Clear(); - - m_MoveCtrl.SetMoveStamp(pCmd.stamp); - } - public void HandleRevive(short sReviveType, A3DVECTOR3 pos) { // Move to revive position and play revive animation @@ -3015,172 +1021,6 @@ namespace BrewMonster UnityGameSession.RequesrQueryPlayerCash(); } - public void OnMsgHstGoto(in ECMSG Msg) - { - PopupManager.Instance.OnPlayerRevived(); - // p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position - // p1 鏄竴涓 byte[] 缂撳啿鍖猴紱瑙f瀽涓 cmd_notify_hostpos 鐒跺悗璁剧疆浣嶇疆 - byte[] buf = (byte[])Msg.dwParam1; - cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes(buf); - - int idInst = pCmd.tag; - Vector3 vPos = new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z); - int iLine = pCmd.line; - - - // Call Goto method to properly handle teleportation - // 璋冪敤 Goto 鏂规硶鏉ユ纭鐞嗕紶閫 - if (!Goto(idInst, vPos, iLine)) - { - BMLogger.LogError($"OnMsgHstGoto: Failed to teleport to instance {idInst}"); - return; - } - } - - // Return to a target town through skill - // 閫氳繃鎶鑳借繑鍥炵洰鏍囧煄闀 - // This method implements the Goto logic from the original C++ code - // 姝ゆ柟娉曞疄鐜颁簡鍘熷 C++ 浠g爜涓殑 Goto 閫昏緫 - private bool Goto(int idInst, Vector3 vPos, int iParallelWorldID) - { - // Jump to instance (change world/instance) - // 璺宠浆鍒板疄渚嬶紙鏇存敼涓栫晫/瀹炰緥锛 - // Note: JumpToInstance is currently a stub in CECGameRun, so we skip the call for now - // 娉ㄦ剰锛欽umpToInstance 鐩墠鍦 CECGameRun 涓槸涓涓瓨鏍癸紝鎵浠ユ垜浠幇鍦ㄨ烦杩囪皟鐢 - // if (CECGameRun.Instance != null && !CECGameRun.Instance.JumpToInstance(idInst, vPos, iParallelWorldID)) - // { - // Debug.LogError($"CECHostPlayer::Goto, Failed to jump to instance {idInst}"); - // return false; - // } - - // Stop all current work and goto specified position - // 鍋滄鎵鏈夊綋鍓嶅伐浣滃苟杞埌鎸囧畾浣嶇疆 - if (m_pWorkMan != null) - { - // Stop auto-moving if active - // 濡傛灉姝e湪鑷姩绉诲姩鍒欏仠姝 - // Note: IsAutoMoving check would go here if available - // 娉ㄦ剰锛氬鏋滃彲鐢紝IsAutoMoving 妫鏌ュ皢鏀惧湪杩欓噷 - - // Finish all work - // 瀹屾垚鎵鏈夊伐浣 - m_pWorkMan.FinishAllWork(true); - } - - // Add a little height to ensure player's AABB won't embed with building - // 澧炲姞涓鐐归珮搴︿互纭繚鐜╁鐨 AABB 涓嶄細宓屽叆寤虹瓚鐗 - vPos.y += 0.1f; - - // Ensure we are not under ground (terrain height check would go here) - // 纭繚鎴戜滑涓嶄細鍦ㄥ湴涓嬶紙鍦板舰楂樺害妫鏌ュ皢鏀惧湪杩欓噷锛 - // Note: Terrain height check is skipped for now as it requires world access - // 娉ㄦ剰锛氭殏鏃惰烦杩囧湴褰㈤珮搴︽鏌ワ紝鍥犱负瀹冮渶瑕佷笘鐣岃闂 - - // Set position - // 璁剧疆浣嶇疆 - SetPos(vPos); - - // Reset jump state if available - // 濡傛灉鍙敤鍒欓噸缃烦璺冪姸鎬 - // ResetJump(); // Uncomment if ResetJump method exists - - // Update camera if available - // 濡傛灉鍙敤鍒欐洿鏂扮浉鏈 - // UpdateFollowCamera(false, 10); // Uncomment if UpdateFollowCamera method exists - - LitModelHolder.Instance.LoadAllObjectsNearTargetPosition(vPos).Forget(); - return true; - } - - private void OnMsgHstStartAttack(in ECMSG Msg) - { - cmd_host_start_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - // ASSERT(pCmd); - - // test code... - // g_pGame.GetRTDebug().OutputNotifyMessage(RTDCOL_WARNING, _AL("start attack !")); - - // Check whether target is the one that we have selected - if (m_idSelTarget != pCmd.idTarget) - // g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Target has changed !")); - - // If target turn to be un-attackable, cancel action - if (AttackableJudge(pCmd.idTarget, true) == 0) - { - UnityGameSession.c2s_CmdCancelAction(); - // g_pGame.RuntimeDebugInfo(RTDCOL_WARNING, _AL("Cannel attacking !")); - return; - } - - // Synchronize ammo amount - // CECIvtrItem* pItem = m_pEquipPack.GetItem(EQUIPIVTR_PROJECTILE); - // if (pItem) - // { - // if (!pCmd.ammo_remain) - // m_pEquipPack.SetItem(EQUIPIVTR_PROJECTILE, NULL); - // else - // pItem.SetAmount(pCmd.ammo_remain); - // } - - CECHPWorkMelee pWork = (CECHPWorkMelee)m_pWorkMan.CreateWork(Host_work_ID.WORK_HACKOBJECT); - m_pWorkMan.StartWork_p1(pWork); - - m_bMelee = true; - // AP_ActionEvent(AP_EVENT_STARTMELEE); - } - - private void OnMsgHstStopAttack(in ECMSG Msg) - { - // using namespace S2C; - // - m_bMelee = false; - // - // // if there is an attack event currently, we should let it fire now. - ClearComActFlagAllRankNodes(true); - - cmd_host_stop_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - // ASSERT(pCmd); - - /* If attack stopped for target is leave too far, trace it and continue - attacking. Stop reason defined as below: - - 0x00: attack is canceled or host want to do some other things. - 0x01: unable to attack anymore (no ammo, weapon is broken etc.) - 0x02: invalid target (target missed or died) - 0x04: target is out of range - */ - if ((pCmd.iReason & 0x04) != 0) - { - if (!m_pWorkMan.IsMovingToPosition() && - !m_pWorkMan.IsTracing()) - { - if (CmdNormalAttack(false, false, 0, -1)) //m_pComboSkill != NULL - { - // AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); - } - else - { - m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); - // AP_ActionEvent(AP_EVENT_STOPMELEE); - } - } - else - { - // AP_ActionEvent(AP_EVENT_STOPMELEE); - } - } - else - { - m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_HACKOBJECT); - // AP_ActionEvent(AP_EVENT_STOPMELEE); - } - - // #ifdef _SHOW_AUTOPOLICY_DEBUG - // a_LogOutput(1, "Stop Attack, Reason = %d", pCmd.iReason); - // #endif - } - // Message MSG_HST_SELTARGET handler void OnMsgHstSelTarget(ECMSG Msg) { @@ -3198,17 +1038,6 @@ namespace BrewMonster } } - public void SetStatusRun(bool value) - { - if (!isGrounded) - { - Debug.LogError("Player not in ground"); - return; - } - - isRun = value; - } - public override void SetUpPlayer() { base.SetUpPlayer(); @@ -3219,35 +1048,6 @@ namespace BrewMonster m_bEnterGame = false; } - public CECSkill GetNormalSkill(int id, bool bSenior = false /* false */) - { - CECSkill pSkill = null; - if (ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_PASSIVE || - ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_PRODUCE || - ElementSkill.GetType((uint)id) == (byte)CECSkill.SkillType.TYPE_LIVE) - pSkill = GetPassiveSkillByID(id, bSenior); - else - pSkill = GetPositiveSkillByID(id, bSenior); - - if (pSkill == null) // && m_pGoblin) - { - // This is a goblin skill - for (int i = 0; i < m_aGoblinSkills.Count; i++) - { - if (m_aGoblinSkills[i].GetSkillID() == id) - return m_aGoblinSkills[i]; - } - } - - if (pSkill == null) // may be target item skill - { - if (m_pTargetItemSkill != null && m_pTargetItemSkill.GetSkillID() == id) - pSkill = m_pTargetItemSkill; - } - - return pSkill; - } - public async void InitCharacter(cmd_self_info_1 role) { SetUpPlayer(); @@ -3457,227 +1257,6 @@ namespace BrewMonster //Debug.LogError("Pos Character = " + pos); } - private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false) - { - if (idTarget == 0 || idTarget == m_PlayerInfo.cid) - { - // We should have check target isn't dead - return false; - } - - //if (!EC_Game.GetGameRun().GetWorld().GetObject(idTarget, 1)) - // return false; - bool bStartNewWork = false; - - bool bUseAutoPF = false; - //CECPlayerWrapper* pWrapper = CECAutoPolicy::GetInstance().GetPlayerWrapper(); - //if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) - //bUseAutoPF = true; - - CECHPWorkTrace pWorkTrace = null; - CECHPWork pWork = null; - if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) != null) - { - pWorkTrace = pWork as CECHPWorkTrace; - } - else if ((pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT)) != null) - { - if ((pWork as CECHPWorkMelee).GetTarget() == idTarget) - return false; // Host is attacking the target - - pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - bStartNewWork = true; - } - else if (m_pWorkMan.CanStartWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT)) - { - pWorkTrace = (CECHPWorkTrace)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - bStartNewWork = true; - } - - if (pWorkTrace != null) - { - pWorkTrace.SetTraceTarget( - pWorkTrace.CreatTraceTarget(idTarget, CECHPWorkTrace.Trace_reason.TRACE_ATTACK, bForceAttack), - bUseAutoPF); - pWorkTrace.SetMoveCloseFlag(bMoreClose); - - if (bStartNewWork) - m_pWorkMan.StartWork_p1(pWorkTrace); - return true; - } - - return false; - } - - public int AttackableJudge(int idTarget, bool bForceAttack) - { - if (CannotAttack()) - return 0; - - //if (CDlgAutoHelp::IsAutoHelp()) - // return 0; - - if (idTarget == 0 || idTarget == m_PlayerInfo.cid) - return -1; - - CECObject pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); - if (!pObject) - return -1; - - // If target is pet, it's attacked possibility depends on it's monster - if (GPDataTypeHelper.ISNPCID(idTarget)) - { - CECNPC pNPC = (CECNPC)pObject; - int idMaster = pNPC.GetMasterID(); - if (idMaster != 0) - { - // master驴脡脛脺脢脟hostplayer - if (idMaster == m_PlayerInfo.cid) - return 0; - - //// Follow pet cannot be attacked - //if (pNPC.IsPetNPC() && ((CECPet)pNPC).IsFollowPet()) - // return 0; - - idTarget = idMaster; - pObject = EC_ManMessageMono.Instance.GetObject(idTarget, 1); - if (!pObject) - return -1; - } - } - - int iRet = 0; - - if (GPDataTypeHelper.ISNPCID(idTarget)) - { - CECNPC pNPC = (CECNPC)pObject; - - // If this npc is host's pet, cannot be attacked - if (pNPC.GetMasterID() == m_PlayerInfo.cid) - return 0; - - // If it's a pet and can not be attacked, pet can be attacked only if it's a fighting pet - //if (pNPC.IsPetNPC() && !((CECPet)pNPC).CanBeAttacked()) - // return 0; - - if (IsInBattle()) // Host is in battle - { - if (InSameBattleCamp(pNPC)) - iRet = 0; - else - { - if (pNPC.IsMonsterNPC()) - iRet = 1; - else if (pNPC.IsServerNPC() && - (IsInFortress() || - pNPC.GetRoleInBattle() == 8)) // 露脭路镁脦帽脨脥NPC碌脛鹿楼禄梅拢卢掳茂脜脡禄霉碌脴禄貌鲁脟脮陆脢卤驴脡脫脙 - iRet = 1; - else - iRet = 0; - } - } - else if (pNPC.IsServerNPC()) - { - // In sanctuary we cannot attack NPCs - if (!IsPVPOpen() || m_bInSanctuary || !bForceAttack) - iRet = 0; - else - iRet = 1; - } - else // Is monster - { - iRet = 1; - } - - if (iRet == 1 && pNPC.GetOwnerFaction() > 0) - { - // 脮毛露脭掳茂脜脡 PVP 脮陆脮霉脰脨陆没脰鹿虏驴路脰鹿楼禄梅 - if (GetFactionID() == pNPC.GetOwnerFaction() || // 虏禄鹿楼禄梅脥卢掳茂鹿脰 - pNPC.IsFactionPVPMineCar() && !CanAttackFactionPVPMineCar() || // 脦脼路篓脭脵鹿楼禄梅脣没掳茂驴贸鲁碌脟茅驴枚 - pNPC.IsFactionPVPMineBase() && !CanAttackFactionPVPMineBase()) - { - // 脦脼路篓脭脵鹿楼禄梅脣没掳茂麓忙驴贸碌茫脟茅驴枚 - iRet = 0; - } - } - } - // TO DO: fix later - //else if (GPDataTypeHelper.ISPLAYERID(idTarget)) - //{ - // // Check duel at first - // if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget) - // return 1; - // else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget) - // return 0; - - // // In sanctuary we cannot attack other players - // if (m_bInSanctuary) - // return 0; - - // //ASSERT(pObject.GetClassID() == CECObject::OCID_ELSEPLAYER); - // EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject; - // ROLEBASICPROP bp = pPlayer.GetBasicProps(); - // EC_GAME_SETTING gs = g_pGame.GetConfigs().GetGameSettings(); - - // if (m_pvp.bFreePVP) - // { - // if (IsTeamMember(idTarget)) - // return 0; - - // // In free pvp mode, for example, host is in arena. - // if (bForceAttack) - // iRet = 1; - // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) - // iRet = 0; - // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) - // iRet = 0; - // else - // iRet = 1; - // } - // else if (m_iBattleCamp != GP_BATTLE_CAMP_NONE) - // { - // // Host is in battle - // int iCamp = pPlayer.GetBattleCamp(); - // if (iCamp != GP_BATTLE_CAMP_NONE && iCamp != m_iBattleCamp) - // iRet = 1; - // else - // iRet = 0; - // } - // else // Normal mode - // { - // if (IsTeamMember(idTarget)) - // return 0; - - // if (!IsPVPOpen() || !pPlayer.IsPVPOpen() || m_BasicProps.iLevel < EC_MAXNOPKLEVEL || bp.iLevel < EC_MAXNOPKLEVEL) - // iRet = 0; - // else if (bForceAttack) - // iRet = 1; - // else if (!gs.bAtk_Player) - // iRet = 0; - // else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah()) - // iRet = 0; - // else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID())) - // iRet = 0; - // else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce()) - // iRet = 0; - // else - // iRet = 1; - // } - //} - else - { - return -1; - } - - return iRet; - } - public void ClearAnimation() { EventBus.PublishChannel(GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true)); @@ -3757,11 +1336,6 @@ namespace BrewMonster return m_PlayerInfo.cid; } - public bool CannotAttack() - { - return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0; - } - public bool CanTouchTarget(A3DVECTOR3 vHostPos, A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, float fMaxCut = 1.0f) { @@ -3826,80 +1400,6 @@ namespace BrewMonster return false; } - public bool GetSkillCoolTime(int idSkill, out COOLTIME ct) - { - // 鑾峰彇鎶鑳界殑闈炲叕鍏卞喎鍗存椂闂 - bool bFound = false; - ct = new COOLTIME(); - - if (m_skillCoolTime.TryGetValue(idSkill, out ct)) - { - bFound = true; - } - - return bFound; - } - - // Update equipment skill cool down - // 鏇存柊瑁呭鎶鑳藉喎鍗 - public void UpdateEquipSkillCoolDown(int cooldown_index = -1) - { - if (cooldown_index < 0) - { - - for (int i = 0; i < GetEquipSkillNum(); ++i) - { - CECSkill pSkill = GetEquipSkillByIndex(i); - - // 妫鏌ユ妧鑳藉喎鍗 - // Check skill cooldown - COOLTIME temp; - if (GetSkillCoolTime(pSkill.GetSkillID(), out temp)) - { - pSkill.StartCooling(temp.iMaxTime, temp.iCurTime); - continue; - } - - // 妫鏌ュ叕鍏卞喎鍗 - // Check common cooldown - int ccd = pSkill.GetCommonCoolDown(); - if (ccd == 0) continue; - for (int j = 0; j < 5; ++j) - { - if ((ccd & (1 << j)) != 0) - { - COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + j]; - pSkill.StartCooling(ct.iMaxTime, ct.iCurTime); - break; - } - } - } - } - else - { - if (cooldown_index > (int)CoolTimeIndex.GP_CT_SKILL_START) - { - int idSkill = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILL_START; - CECSkill pSkill = GetEquipSkillByID(idSkill); - COOLTIME temp; - if (pSkill != null && GetSkillCoolTime(idSkill, out temp)) - pSkill.StartCooling(temp.iMaxTime, temp.iCurTime); - } - else if (cooldown_index >= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 && cooldown_index <= (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN4) - { - int index = cooldown_index - (int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0; - COOLTIME ct = m_aCoolTimes[(int)CoolTimeIndex.GP_CT_SKILLCOMMONCOOLDOWN0 + index]; - uint mask = (uint)(1 << index); - for (int i = 0; i < GetEquipSkillNum(); ++i) - { - CECSkill pSkill = GetEquipSkillByIndex(i); - int ccd = pSkill.GetCommonCoolDown(); - if ((ccd & mask) != 0) - pSkill.StartCooling(ct.iMaxTime, ct.iCurTime); - } - } - } - } public void RemoveObjectFromTabSels(CECObject pObject) { for (int i = 0; i < m_aTabSels.Count; i++) @@ -3947,23 +1447,19 @@ namespace BrewMonster { return m_idFaction; } - public void SetPrayDistancePlus(float prayDistancePlus) { m_fPrayDistancePlus = prayDistancePlus; } - public bool IsJumping() { return m_iJumpCount > 0; } - public bool IsFalling() { return m_iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND && m_GndInfo.bOnGround == false; } - public bool IsPlayingAction(int iAction) { if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK) //&& _playerStateMachine.State is PlayerMoveState @@ -3978,7 +1474,6 @@ namespace BrewMonster return false; } - public void ResetJump() { m_iJumpCount = 0; @@ -4033,291 +1528,6 @@ namespace BrewMonster return fSpeedSev; } - public bool ApplySkillShortcut(int idSkill, bool bCombo = false /* false */, - int idSelTarget = 0 /* 0 */, int iForceAtk = -1 /* -1 */) - { - //StackChecker::ACTrace(4); - - if (m_pActionSwitcher != null) - m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_CASTSKILL); - - // Return-town skill is very special, handle it separately - // 鍥炲煄鎶鑳介潪甯哥壒娈婏紝鍗曠嫭澶勭悊 - if (idSkill == ID_RETURNTOWN_SKILL) - { - Debug.Log($"ApplySkillShortcut: Skill 167 detected, calling ReturnToTargetTown"); - return ReturnToTargetTown(0, bCombo); - } - - //if (idSkill == ID_SUMMONPLAYER_SKILL) - // return SummonPlayer(idSelTarget, bCombo); - - if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) - return false; - - if (InSlidingState()) - return false; - - if (!bCombo) - ClearComboSkill(); - - if (idSelTarget == 0) - idSelTarget = m_idSelTarget; - - CECSkill pSkill = GetPositiveSkillByID(idSkill); - if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); - if (pSkill == null) pSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)idSkill); - if (pSkill == null) - { - return false; - } - - //// If we press a chargeable skill again when it's being charged, - //// we cast it out at once - if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() && - m_pCurSkill.GetSkillID() == pSkill.GetSkillID()) - { - m_pCurSkill.EndCharging(); - UnityGameSession.c2s_SendCmdContinueAction(); - return true; - } - - int iCon = CheckSkillCastCondition(pSkill); - if (iCon != 0) - { - ProcessSkillCondition(iCon); - return false; - } - - //// Get force attack flag - bool bForceAttack = false; - if (iForceAtk < 0) - bForceAttack = glb_GetForceAttackFlag(0); - else - bForceAttack = iForceAtk > 0 ? true : false; - - //// Check negative effect skill - if (pSkill.GetType() == (int)skill_type.TYPE_ATTACK || pSkill.GetType() == (int)skill_type.TYPE_CURSE) - { - if (idSelTarget == m_PlayerInfo.cid) - { - // Host cannot spell negative effect magic to himself. - //EC_Game.GetGameRun().AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT); - return false; - } - else if (idSelTarget != 0) - { - if (AttackableJudge(idSelTarget, bForceAttack) != 1) - return false; - } - } - - //// Check whether target type match - int idCastTarget = idSelTarget; - int iTargetType = pSkill.GetTargetType(); - - if (pSkill.GetType() == (int)skill_type.TYPE_BLESS || - pSkill.GetType() == (int)skill_type.TYPE_NEUTRALBLESS) - { - if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(idSelTarget)) - idCastTarget = m_PlayerInfo.cid; - - // In some case, we shouldn't add bless effect to other players - if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) - { - // If host has set bless skill filter only to himself, bless skill couldn't add to other players - byte byBLSMask = EC_Utility.glb_BuildBLSMask(); - - if (pSkill.GetRangeType() == (int)range_type.RANGE_POINT) - { - if (!IsTeamMember(idCastTarget)) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0) - idCastTarget = m_PlayerInfo.cid; - else - { - EC_ElsePlayer pPlayer = - (EC_ElsePlayer)EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idCastTarget); - if (pPlayer == null) - { - // 脛驴卤锚脧没脢搂 - return false; - } - - if (pPlayer.IsInvader() || pPlayer.IsPariah()) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (!IsFactionMember(pPlayer.GetFactionID())) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (!IsFactionAllianceMember(pPlayer.GetFactionID())) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (GetForce() != pPlayer.GetForce()) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0) - idCastTarget = m_PlayerInfo.cid; - } - } - } - } - - // If host is in duel, bless skill couldn't add to opponent - if (IsInDuel() && idSelTarget == m_pvp.idDuelOpp) - idCastTarget = m_PlayerInfo.cid; - - // If host is in battle, bless skill couldn't add to enemies - if (IsInBattle()) - { - EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget); - if (!InSameBattleCamp(pPlayer)) - idCastTarget = m_PlayerInfo.cid; - } - } - } - /* else if (pSkill.GetType() == CECSkill::TYPE_BLESSPET) - { - CECPet* pPet = g_pGame.GetGameRun().GetWorld().GetNPCMan().GetPetByID(idSelTarget); - if (!pPet || pPet.GetMasterID() == GetCharacterID()) - { - // Spell skill on host's pet - CECPetData* pPetData = m_pPetCorral.GetActivePet(); - if (!pPetData || - pPetData.GetClass() != GP_PET_CLASS_COMBAT && - pPetData.GetClass() != GP_PET_CLASS_SUMMON && - pPetData.GetClass() != GP_PET_CLASS_EVOLUTION) - return false; - - idCastTarget = m_pPetCorral.GetActivePetNPCID(); - } - // Only fighting pet can be blessed. - if (pPet && !pPet.CanBeAttacked()) - return false; - }*/ - else - { - if (iTargetType != 0 && idCastTarget == 0) - return false; - } - - // iTargetType == 4 means target must be pet. The problem is that pet will - // disappear from world after it died, so GetWorld().GetObject() will return - // NULL when host spells revive-pet skill on his dead pet. So, the target - // type of revive-pet skill should be 0 - if (iTargetType != 0) - { - // Target shoundn't be a corpse ? - int iAliveFlag = 0; - if (iTargetType == 1) - iAliveFlag = 1; - else if (iTargetType == 2) - iAliveFlag = 2; - - /* CECObject pObject = EC_Game.GetGameRun().GetWorld().GetObject(idCastTarget, iAliveFlag); - if (!pObject) - return false;*/ - } - - if (!IsMeleeing() && !IsSpellingMagic() && - (iTargetType == 0 || idCastTarget == m_PlayerInfo.cid)) - { - // Cast this skill need't checking cast distance - if (!pSkill.ReadyToCast()) - return false; - - if (!pSkill.IsInstant() && pSkill.GetType() != (int)Skilltype.TYPE_FLASHMOVE) - { - if (!NaturallyStopMoving()) - return false; // Couldn't stop naturally, so cancel casting skill - } - else if (pSkill.GetType() == (int)Skilltype.TYPE_FLASHMOVE) - { - if (!CanDo(ActionCanDo.CANDO_FLASHMOVE)) - return false; - } - - m_pPrepSkill = pSkill; - CastSkill(m_PlayerInfo.cid, bForceAttack); - } - else if (IsSpellingMagic() && m_pCurSkill == pSkill) - { - // If we are casting the same skill and it's in cooling time - return false; - } - else // Have to trace selected object before cast skill - { - if (!pSkill.ReadyToCast()) - return false; - - if (CECCastSkillWhenMove.Instance.IsSkillSupported(pSkill.GetSkillID(), this) && - m_pWorkMan.IsMovingToPosition() && - m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())) - { - m_pPrepSkill = pSkill; - return CastSkill(idCastTarget, bForceAttack); - } - else - { - bool bTraceOK = false; - bool bUseAutoPF = false; - CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper(); - if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled() && pWrapper.GetAttackError() >= 2) - bUseAutoPF = true; - - if (idCastTarget == 0) - { - idCastTarget = - GetCharacterID(); // 卤脺脙芒脣虏脪脝碌脠录录脛脺脢卤 idCastTarget 脦陋0碌录脰脗 CECWorkTrace::CreateTraceTarget 路碌禄脴驴脮 - } - - CECHPWork pWork = m_pWorkMan.GetWork(Host_work_ID.WORK_TRACEOBJECT); - if (pWork != null) - { - CECHPWorkTrace pWorkTrace = (CECHPWorkTrace)(pWork); - if (pWorkTrace.GetTraceReason() == Trace_reason.TRACE_SPELL && - pWorkTrace.GetTarget() == idCastTarget && - pWorkTrace.GetPrepSkill() == pSkill) - return false; // We are just doing the same thing - - pWorkTrace.SetTraceTarget( - pWorkTrace.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), - bUseAutoPF); - pWorkTrace.SetPrepSkill(pSkill); - bTraceOK = true; - } - else if (m_pWorkMan.CanStartWork(Host_work_ID.WORK_TRACEOBJECT)) - { - CECHPWorkTrace pWork2 = (CECHPWorkTrace)m_pWorkMan.CreateWork(Host_work_ID.WORK_TRACEOBJECT); - pWork2.SetTraceTarget( - pWork2.CreatTraceTarget(idCastTarget, Trace_reason.TRACE_SPELL, bForceAttack), bUseAutoPF); - pWork2.SetPrepSkill(pSkill); - m_pWorkMan.StartWork_p1(pWork2); - bTraceOK = true; - } - - if (!bTraceOK) return false; - // } - //} - } - } - - return true; - } - - public CECSkill GetPrepSkill() - { - return m_pPrepSkill; - } - public void PrepareNPCService(int idSev) { if (!GPDataTypeHelper.ISNPCID(m_idSevNPC)) @@ -4494,323 +1704,6 @@ namespace BrewMonster m_MoveCtrl.SendStopMoveCmd(); - return true; - } - public bool CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null) - { - // Check if prep skill is valid, ready to cast, and not currently spelling magic - if (m_pPrepSkill == null || !m_pPrepSkill.ReadyToCast() || IsSpellingMagic()) - { - // Check if skill can change to melee attack - if (m_pPrepSkill != null && m_pPrepSkill.ChangeToMelee()) - { - bool bFlag = m_pPrepSkill.ReadyToCast(); - - // Finish any tracing work - if (m_pWorkMan.IsTracing()) - m_pWorkMan.FinishRunningWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - - // Handle combo skill or normal attack - if (m_pComboSkill != null) - m_pComboSkill.Continue(false); - else - { - // Perform normal attack instead - NormalAttackObject(idTarget, true); - } - } - - m_pPrepSkill = null; - return false; - } - - if (m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK || - m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE) - { - if (idTarget != 0 && AttackableJudge(idTarget, bForceAttack) != 1) - { - m_pPrepSkill = null; - return false; - } - } - - //TODO: Check cast condition - method not yet implemented - int iRet = CheckSkillCastCondition(m_pPrepSkill); - if (iRet != 0) - { - switch (iRet) - { - case 2: // Need MP - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDMP); - break; - case 8: // Need AP - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDAP); - break; - case 10: // Pack full - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_PACKFULL1); - break; - case 20: // Need item - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEEDITEM); - break; - case 12: // HP unsatisfied - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_HP_UNSATISFIED); - break; - } - - m_pPrepSkill = null; - return false; - } - - byte byPVPMask = glb_BuildPVPMask(bForceAttack); - - Debug.Log($"HoangDev: Cast Skill ID={m_pPrepSkill.GetSkillID()}"); - - // Handle instant skills - if (m_pPrepSkill.IsInstant()) - { - int countTarget = 1; - targetsCastSkill = new int[countTarget]; - targetsCastSkill[0] = idTarget; - UnityGameSession.c2s_CmdCastInstantSkill(m_pPrepSkill.GetSkillID(), byPVPMask, countTarget, targetsCastSkill); - m_pPrepSkill = null; - } - // Handle flash move skills (鐬Щ鎶鑳) - else if (m_pPrepSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE) - { - // Self or self-sphere range types - if (m_pPrepSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SLEF || - m_pPrepSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_SELFSPHERE) - { - A3DVECTOR3 vDir = GetDir(); - float fDist = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); - - // 宸︿晶涔嬬考锛屽乏璺 (Left wing skill - jump left) - if (m_pPrepSkill.GetSkillID() == 1844) - { - vDir = A3d_RotatePosAroundY(-vDir, Mathf.PI / 2); - } - // 鍙充晶涔嬬考锛屽彸璺 (Right wing skill - jump right) - else if (m_pPrepSkill.GetSkillID() == 1845) - { - vDir = A3d_RotatePosAroundY(vDir, Mathf.PI / 2); - } - // 鑼冨洿灏忎簬0鍒欏悗璺 (If range < 0, jump backward) - else if (fDist < 0.0f) - { - vDir = -vDir; - } - - fDist = Mathf.Abs(fDist); - A3DVECTOR3 vDest = m_MoveCtrl.FlashMove(vDir, 100.0f, fDist); - UnityGameSession.c2s_CmdCastPosSkill(m_pPrepSkill.GetSkillID(), EC_Utility.ToVector3(vDest), - byPVPMask, 0, 0); - m_pPrepSkill = null; - } - else - { - // 鍒哄濡傚奖闅忚绫绘妧鑳 (Assassin shadow-following skills) - bool bSuccess = false; - - while (true) - { - // Break if no target or self-target - if (idTarget == 0 || idTarget == GetCharacterID()) - break; - - // Get target object - CECObject pObject = CECWorld.Instance.GetObject(idTarget, 0); - if (pObject == null) break; - - A3DVECTOR3 vHostPos = EC_Utility.ToA3DVECTOR3(transform.position); // GetPos() - A3DVECTOR3 vTargetPos = EC_Utility.ToA3DVECTOR3(pObject.transform.position); // pObject.GetPos() - - // 鍒ゆ柇鎶鑳介噴鏀捐窛绂婚檺鍒舵槸鍚︽弧瓒 (Check if skill cast distance is satisfied) - float fTouchRadius = 0.0f; - - if (GPDataTypeHelper.ISNPCID(idTarget)) - { - CECNPC pNPC = pObject as CECNPC; - if (pNPC != null) - fTouchRadius = pNPC.GetTouchRadius(); - else - break; - } - else if (GPDataTypeHelper.ISPLAYERID(idTarget)) - { - EC_ElsePlayer pElsePlayer = pObject as EC_ElsePlayer; - if (pElsePlayer != null) - fTouchRadius = pElsePlayer.GetTouchRadius(); - else - break; - } - else - break; - - if (!CanTouchTarget(vTargetPos, fTouchRadius, 2)) - { - // Target is far - show message - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_TARGETISFAR); - Debug.Log("Target is too far"); - break; - } - - A3DVECTOR3 vMoveDir = vTargetPos - vHostPos; - float fDist = EC_Utility.ToVector3(vMoveDir).magnitude; - - // 璺濈鐩爣澶繎锛屼笉澶勭悊 (Too close to target, don't process) - float fNearDist = 0.0f; - // TODO: Implement IsTooNear - if (IsTooNear(vTargetPos, ref fNearDist)) - { - Debug.Log("Target is too near"); - break; - } - - // 璁$畻瑕佺Щ寰鐨勭洰鏍囦綅缃紙榛樿鍊硷級 (Calculate target position to move to) - vMoveDir.Normalize(); - A3DVECTOR3 vMovePos = vHostPos + vMoveDir * (fDist - fNearDist); - - // TODO: Implement ClampAboveGround - float fClampedHeight = ClampAboveGround(vMovePos); - if (Mathf.Abs(fClampedHeight - vMovePos.y) >= 5.0f) - { - Debug.Log("Would stuck or so"); - break; - } - - vMovePos.y = fClampedHeight; - bool bPosVerified = false; - - // 鐩爣涓哄甫鍑稿寘鐨 NPC 鏃讹紝鍗曠嫭澶勭悊 (Special handling for NPCs with collision) - if (GPDataTypeHelper.ISNPCID(idTarget)) - { - // TODO: Implement CalcCollideFreePos for NPC AABB - CECNPC pNPC = pObject as CECNPC; - A3DAABB aabbNPC = new A3DAABB(); - if (pNPC.GetCHAABB(ref aabbNPC)) - { - A3DVECTOR3 vTestPos; - if (CalcCollideFreePos(aabbNPC, out vTestPos)) - { - vMovePos = vTestPos; - bPosVerified = true; - } - else - { - Debug.Log("Would stuck or so"); - break; - } - } - } - - // TODO: Implement collision checking - if (!bPosVerified && !IsPosCollideFree(vMovePos)) - { - A3DVECTOR3 vTestPos2; - if (!CalcVerticalCollideFreePos(vMovePos, out vTestPos2)) - { - Debug.Log("Would stuck or so"); - break; - } - - vMovePos = vTestPos2; - bPosVerified = true; - } - - //TODO: Implement IsTooNear check for final position - float reffake = 0; - if (IsTooNear(vMovePos, ref reffake)) - { - Debug.Log("Target is too near"); - break; - } - - // 鍙戦佸崗璁 (Send protocol) - UnityGameSession.c2s_CmdCastPosSkill(m_pPrepSkill.GetSkillID(), EC_Utility.ToVector3(vMovePos), - byPVPMask, 1, idTarget); - bSuccess = true; - } - - m_pPrepSkill = null; - return bSuccess; - } - } - else - { - // Regular skill casting - byte byPVPMask2 = glb_BuildPVPMask(bForceAttack); - int targets = 1; - targetsCastSkill = new int[targets]; - targetsCastSkill[0] = idTarget; - UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask2, targets, targetsCastSkill); - } - - return true; - } - - // Return to a target town through skill - // 閫氳繃鎶鑳借繑鍥炵洰鏍囧煄闀 - private bool ReturnToTargetTown(int idTarget, bool bCombo = false) - { - - if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) - { - return false; - } - - int idSkill = ID_RETURNTOWN_SKILL; - CECSkill pSkill = GetPositiveSkillByID(idSkill); - if (pSkill == null) pSkill = GetEquipSkillByID(idSkill); - if (pSkill == null) - { - Debug.LogError("ReturnToTargetTown: Skill 167 not found"); - return false; - } - - - if (!bCombo) - { - // ClearComboSkill(); // Uncomment if ClearComboSkill exists - } - - // Check skill cast condition (commented out in ApplySkillShortcut, so skip for now) - // int iCon = CheckSkillCastCondition(pSkill); - // if (iCon) - // { - // ProcessSkillCondition(iCon); - // return false; - // } - - // If this skill is in cooling time or we are casting other skill, return - // 濡傛灉姝ゆ妧鑳藉湪鍐峰嵈鏃堕棿鎴栨垜浠鍦ㄦ柦鏀惧叾浠栨妧鑳斤紝杩斿洖 - if (!pSkill.ReadyToCast() || - !m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())) - { - // If the current Work in m_pWorkMan is CECHPWorkSpell or CECHPWorkFly, it should be executed first - // Otherwise, when receiving OBJECT_CAST_SKILL protocol, CECHPWorkSpell cannot be executed - // This causes CECHostPlayer::IsSpellingMagic() to return false, causing the client to send c2s_CmdCancelAction - // When this CECHPWorkSpell executes, it cannot respond - // After this method is executed, we use the return to city mechanism - // 濡傛灉 m_pWorkMan 涓殑褰撳墠 Work 鏄 CECHPWorkSpell 鎴 CECHPWorkFly锛屽垯搴斿厛鎵ц - // 鍚﹀垯锛屽綋鏀跺埌 OBJECT_CAST_SKILL 鍗忚鏃讹紝CECHPWorkSpell 鏃犳硶鎵ц - // 杩欎細瀵艰嚧 CECHostPlayer::IsSpellingMagic() 杩斿洖 false锛屽鑷村鎴风鍙戦 c2s_CmdCancelAction - // 褰撴 CECHPWorkSpell 鎵ц鏃讹紝瀹冩棤娉曞搷搴 - // 鍦ㄦ鏂规硶鎵ц瀹屾垚鍚庯紝鎴戜滑浣跨敤鍥炲煄鏈哄埗 - Debug.LogError($"ReturnToTargetTown: Skill not ready - ReadyToCast={pSkill.ReadyToCast()}, CanCastSkillImmediately={m_pWorkMan.CanCastSkillImmediately(pSkill.GetSkillID())}"); - return false; - } - - m_pPrepSkill = pSkill; - byte byPVPMask = glb_BuildPVPMask(false); - - // Call c2s_CmdCastSkill with target parameter - // 浣跨敤鐩爣鍙傛暟璋冪敤 c2s_CmdCastSkill - int targets = 1; - int[] targetsCastSkill = new int[targets]; - targetsCastSkill[0] = idTarget; - UnityGameSession.c2s_CmdCastSkill(idSkill, byPVPMask, targets, targetsCastSkill); - - return true; } @@ -4866,9 +1759,6 @@ namespace BrewMonster return (fDist <= fTestDist); } - public int GetPositiveSkillNum() { return m_aPtSkills.Count; } - public CECSkill GetPositiveSkillByIndex(int n) { return m_aPtSkills[n]; } - public int GetPassiveSkillNum() { return m_aPsSkills.Count; } public bool UpdateEquipSkins() { @@ -4943,165 +1833,9 @@ namespace BrewMonster return bRet; } - CECSkill GetPassiveSkillByID(int id, bool bSenior /* false */) - { - CECSkill pSenior = null; - - for (int i = 0; i < m_aPsSkills.Count; i++) - { - if (m_aPsSkills[i].GetSkillID() == id) - return m_aPsSkills[i]; - else if (m_aPsSkills[i].GetJunior().Find((uint)id)) - pSenior = m_aPsSkills[i]; - } - - if (bSenior && pSenior != null) - return pSenior; - - return null; - } - - public CECSkill GetPositiveSkillByID(int id, bool bSenior = false) - { - CECSkill pSenior = null; - - for (int i = 0; i < m_aPtSkills.Count; i++) - { - if (m_aPtSkills[i].GetSkillID() == id) - return m_aPtSkills[i]; - else if (m_aPtSkills[i].GetJunior().Find((uint)id)) - pSenior = m_aPtSkills[i]; - } - - if (bSenior && pSenior != null) - return pSenior; - - return null; - } + public int GetMaxLevelSofar() { return Math.Max(m_ReincarnationTome.max_level, m_BasicProps.iLevel); } - - // C# conversion of CECHostPlayer::GetEquipSkillByID - // Assumes: GetEquipSkillNum() returns the count of equipment skills - // GetEquipSkillByIndex(int) returns a CECSkill at the given index - public CECSkill GetEquipSkillByID(int id) - { - CECSkill pRet = null; - - for (int i = 0; i < GetEquipSkillNum(); i++) - { - CECSkill pSkill = GetEquipSkillByIndex(i); - if (pSkill != null && pSkill.GetSkillID() == id) - { - pRet = pSkill; - break; - } - } - - return pRet; - } - - public int GetEquipSkillNum() - { - return m_aEquipSkills.Count; - } - - public CECSkill GetEquipSkillByIndex(int n) - { - return m_aEquipSkills[n]; - } - - // Check skill cast condition - // Returns: 0 if success, error code otherwise - // Error codes: 1=invalid weapon, 2=need mp, 3=invalid state, 6=target wrong, 7=invalid state, - // 8=need ap, 9=not enough ammo, 10=pack full, 11=invalid env, 12=hp unsatisfied, - // 13=combo skill not active, 20=need item - public int CheckSkillCastCondition(CECSkill pSkill) - { - // Check if skill requires an item - if (pSkill.SkillCore != null) - { - int idItem = pSkill.SkillCore.GetItemCost(); - if (idItem > 0 && GetPack().GetItemTotalNum(idItem) <= 0) - { - return 20; // Need item - } - } - - if (pSkill.GetComboSkPreSkill() != 0) - { - if (!CECComboSkillState.Instance.IsActiveComboSkill((uint)pSkill.GetSkillID())) - { - return 13; // Combo skill not active - } - } - - // Build UseRequirement info - UseRequirement Info = new UseRequirement(); - Info.mp = m_BasicProps.iCurMP; - Info.ap = m_BasicProps.iCurAP; - Info.form = m_iShape; // Different from PW, no need to mask - Info.freepackage = m_pPack.GetEmptySlotNum(); - Info.move_env = GetMoveEnv(); - Info.is_combat = IsFighting(); - Info.hp = m_BasicProps.iCurHP; - Info.max_hp = m_ExtProps.bs.max_hp; - Info.combo_state = CECComboSkillState.Instance.GetComboSkillState(); // TODO: Implement GetComboSkillState - - // Get weapon's major class ID - int iReason = 0; - - CECIvtrWeapon pWeapon = (CECIvtrWeapon)m_pEquipPack.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON); - if (pWeapon == null || pWeapon.GetCurEndurance() == 0) - Info.weapon = 0; - else if (!CanUseEquipment(pWeapon, ref iReason)) - Info.weapon = (iReason == 5) ? (int)pWeapon.GetDBMajorType().id : 0; - else - Info.weapon = (int)pWeapon.GetDBMajorType().id; - - // Get remaining arrow number - CECIvtrArrow pArrow = (CECIvtrArrow)m_pEquipPack.GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE); - if (pArrow != null && CanUseProjectile(pArrow)) - { - Info.arrow = pArrow.GetCount(); - } - - if (pSkill.SkillCore != null) - { - return pSkill.SkillCore.Condition((uint)pSkill.GetSkillID(), Info, pSkill.GetSkillLevel()); - } - - return 0; // Success - } - - // Process skill condition error - display appropriate message - // Returns: true if message was displayed, false otherwise - public bool ProcessSkillCondition(int iCon) - { - int iMsg = -1; - switch (iCon) - { - case 1: iMsg = (int)FixedMsg.FIXMSG_INVALIDWEAPON; break; - case 2: iMsg = (int)FixedMsg.FIXMSG_NEEDMP; break; - case 6: iMsg = (int)FixedMsg.FIXMSG_TARGETWRONG; break; - case 3: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDSTATE; break; - case 7: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDSTATE; break; - case 8: iMsg = (int)FixedMsg.FIXMSG_NEEDAP; break; - case 9: iMsg = (int)FixedMsg.FIXMSG_NOTENOUGHAMMO; break; - case 10: iMsg = (int)FixedMsg.FIXMSG_PACKFULL1; break; - case 11: iMsg = (int)FixedMsg.FIXMSG_SKILL_INVALIDENV; break; - case 20: iMsg = (int)FixedMsg.FIXMSG_NEEDITEM; break; - case 12: iMsg = (int)FixedMsg.FIXMSG_HP_UNSATISFIED; break; - } - - if (iMsg >= 0) - { - // TODO: Implement AddFixedChannelMsg or use existing message system - // EC_Game.GetGameRun().AddFixedChannelMsg(iMsg, GP_CHAT_FIGHT); - Debug.LogWarning($"Skill condition failed: {iMsg}"); - } - - return iMsg >= 0; - } + public bool CanUseProjectile(CECIvtrArrow pArrow) { if (pArrow == null) @@ -5157,8 +1891,6 @@ namespace BrewMonster return pTarget ? pTarget.IsSelectable() : false; } - - float SafelySelectDistance() { // 路镁脦帽脝梅露脭 SelectTarget 脫脨露卯脥芒戮脿脌毛脧脼脰脝拢卢脠媒脦卢戮脿脌毛 150.0隆垄脣庐脝陆戮脿脌毛 125.0 脪脭脡脧碌脛拢卢露录禄谩脦脼路篓脩隆脰脨 @@ -5720,19 +2452,7 @@ namespace BrewMonster return idNewSel; } - public bool glb_GetForceAttackFlag(uint pdwParam) - { - /*bool bForceAttack = false; - CECInputCtrl* pInputCtrl = g_pGame.GetGameRun().GetInputCtrl(); - - if (pdwParam) - bForceAttack = pInputCtrl.IsCtrlPressed(*pdwParam); - else - bForceAttack = pInputCtrl.KeyIsBeingPressed(VK_CONTROL); - - return bForceAttack;*/ - return false; - } + //public float GetSwimSpeedSev() //{ // float fSpeedSev = GetSwimSpeed(); @@ -5759,81 +2479,6 @@ namespace BrewMonster // return fSpeedSev; //} - private void OnMsgHstNPCGreeting(ECMSG Msg) - { - cmd_npc_greeting pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (GPDataTypeHelper.ISNPCID(pCmd.idObject)) - { - // 脳篓脙脜麓娄脌铆脩搂脧掳录录脛脺碌脛脪镁虏脴NPC - //if (CECHostSkillModel::Instance().IsSkillLearnNPC(pCmd.idObject)) - //{ - // CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); - // //m_idSevNPC = pCmd.idObject; - // //m_bTalkWithNPC = true; - // //pGameUI.GetDialog("Win_SkillAction").Show(true); - // //CDlgSkillAction* dlg = dynamic_cast(pGameUI.GetDialog("Win_SkillAction")); - // //dlg.ForceShowDialog(); - // CDlgSkillAction* dlg = dynamic_cast(pGameUI.GetDialog("Win_SkillAction")); - // dlg.SetReceivedNPCGreeting(true); - // return; - //} - - CECNPC pNPC = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(pCmd.idObject); - if (!pNPC || !pNPC.IsServerNPC()) - { - return; - } - - // Check distance again - if (!CanTouchTarget(pNPC.GetPos(), pNPC.GetTouchRadius(), 3)) - return; - - m_idSevNPC = pCmd.idObject; - m_bTalkWithNPC = true; - - // Check way point service on NPC - //TODO: Fix later - //var dwID = (pNPC as CECNPCServer).GetWayPointID(); - //if (dwID != null && !HasWayPoint(dwID)) - //UnityGameSession.c2s_CmdNPCSevWaypoint(); - //g_pGame.GetGameSession().c2s_CmdNPCSevWaypoint(); - - var pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); - NPC_ESSENCE? result = (pNPC as CECNPCServer).GetDBEssence(); - if (result != null) - { - pGameUI.PopupNPCDialog(result.Value); - } - } - //else if (GPDataTypeHelper.ISPLAYERID(pCmd.idObject)) - //{ - // EC_ElsePlayer pPlayer = m_pPlayerMan.GetElsePlayer(pCmd.idObject); - - // // Check distance again - // if (!pPlayer || !CanTouchTarget(pPlayer.GetPos(), 0.0f, 3)) - // return; - - // m_idSevNPC = pCmd.idObject; - // m_bTalkWithNPC = true; - // m_iBoothState = 3; - - // g_pGame.GetGameSession().c2s_CmdNPCSevGetContent(GP_NPCSEV_BOOTHSELL); - - // m_pBuyPack.RemoveAllItems(); - // m_pSellPack.RemoveAllItems(); - // m_pEPBoothBPack.RemoveAllItems(); - // m_pEPBoothSPack.RemoveAllItems(); - - // CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan(); - // pGameUI.PopupBoothDialog(true, false, pCmd.idObject); - //} - else - { - return; - } - } - // Does host player have specified way point ? bool HasWayPoint(uint? wID) { @@ -5851,58 +2496,6 @@ namespace BrewMonster return false; } - void OnMsgHstWayPoint(ECMSG Msg) - { - //CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); - - //if (Convert.ToInt32(Msg.dwParam2) == CommandID.ACTIVATE_WAYPOINT) - //{ - // cmd_activate_waypoint pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - // m_aWayPoints.Add(pCmd.waypoint); - - // // add to waypoints array - // pGameUI.GetMapDlgsMgr().UpdateWayPoints(&pCmd.waypoint, 1, false); - - // // Print a notify message - // const CECMapDlgsMgr::PointMap& aWayPoints = pGameUI.GetMapDlgsMgr().GetTransPoint(); - // CECMapDlgsMgr::PointMap::const_iterator itr = aWayPoints.find(pCmd.waypoint); - // if(itr != aWayPoints.end()) - // { - // g_pGame.GetGameRun().AddFixedMessage(FIXMSG_NEWWAYPOINT, (itr.second).strName); - - // bool bCanPopUITips = true; - // int count = CECUIConfig::Instance().GetGameUI().GetTaskIDDisableWayPointsUITipsCount(); - // // 录矛虏茅脡铆脡脧脢脟路帽脫脨陆没脰鹿碌炉鲁枚tips碌脛脠脦脦帽 - // for (int i=0;i 0 ? true : false; - - if (AttackableJudge(idTarget, bForceAttack) != 1) - return false; - - return NormalAttackObject(idTarget, bForceAttack, bMoreClose); - } - bool IsJumpInWater() { return m_bJumpInWater; @@ -6537,121 +3093,6 @@ namespace BrewMonster } } - void OnMsgHstExtProp(ECMSG Msg) - { - cmd_own_ext_prop pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_ExtProps = pCmd.prop; - m_BasicProps.iStatusPt = (int)pCmd.status_point; - m_BasicProps.iAtkDegree = pCmd.attack_degree; - m_BasicProps.iDefDegree = pCmd.defend_degree; - m_BasicProps.iCritRate = pCmd.crit_rate; - m_BasicProps.iCritDamageBonus = pCmd.crit_damage_bonus; - m_BasicProps.iInvisibleDegree = pCmd.invisible_degree; - m_BasicProps.iAntiInvisibleDegree = pCmd.anti_invisible_degree; - m_BasicProps.iPenetration = pCmd.penetration; - m_BasicProps.iResilience = pCmd.resilience; - m_BasicProps.iVigour = pCmd.vigour; - } - - private void OnMsgPlayerDoEmote(ECMSG Msg) - { - if (!m_pWorkMan.IsStanding() && - !m_pWorkMan.IsBeingBound()) - return; - - int cmd = Convert.ToInt32(Msg.dwParam2); - if (cmd == CommandID.OBJECT_DO_EMOTE) - { - cmd_object_do_emote pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - DoEmote(pCmd.emotion); - - // if( m_iBuddyId ) - // { - // CECPlayer pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId); - // if (pBuddy) - // pBuddy.DoEmote(pCmd.emotion); - // } - - GetTaskInterface().SetEmotion(pCmd.emotion); - } - else if (cmd == CommandID.OBJECT_EMOTE_RESTORE) - { - CECHPWork pWork = m_pWorkMan.GetRunningWork((int)WorkID.WORK_STAND); - if (pWork != null) - { - ((CECHPWorkStand)pWork).SetPoseAction((int)PLAYER_ACTION_TYPE.ACT_STAND, false); - } - } - } - - // Do emote action - private bool DoEmote(int idEmote) - { - if (!m_pWorkMan.IsStanding()) - return false; - - CECHPWorkStand pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND) as CECHPWorkStand; - if (pWork == null) - { - Debug.LogError("Null CECHPWorkStand"); - } - - int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; - bool bSession = false; - - // Select action according to pose - switch (idEmote) - { - case (int)RoleExpression.ROLEEXP_WAVE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_WAVE; break; - case (int)RoleExpression.ROLEEXP_NOD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_NOD; break; - case (int)RoleExpression.ROLEEXP_SHAKEHEAD: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHAKEHEAD; break; - case (int)RoleExpression.ROLEEXP_SHRUG: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHRUG; break; - case (int)RoleExpression.ROLEEXP_LAUGH: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LAUGH; break; - case (int)RoleExpression.ROLEEXP_ANGRY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ANGRY; break; - case (int)RoleExpression.ROLEEXP_STUN: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_STUN; break; - case (int)RoleExpression.ROLEEXP_DEPRESSED: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEPRESSED; break; - case (int)RoleExpression.ROLEEXP_KISSHAND: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISSHAND; break; - case (int)RoleExpression.ROLEEXP_SHY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SHY; break; - case (int)RoleExpression.ROLEEXP_SALUTE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SALUTE; break; - - case (int)RoleExpression.ROLEEXP_SITDOWN: - - iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_SITDOWN; - bSession = true; - break; - - case (int)RoleExpression.ROLEEXP_ASSAULT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ASSAULT; break; - case (int)RoleExpression.ROLEEXP_THINK: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_THINK; break; - case (int)RoleExpression.ROLEEXP_DEFIANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFIANCE; break; - case (int)RoleExpression.ROLEEXP_VICTORY: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_VICTORY; break; - case (int)RoleExpression.ROLEEXP_GAPE: iAction = (int)PLAYER_ACTION_TYPE.ACT_GAPE; break; - case (int)RoleExpression.ROLEEXP_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS; break; - case (int)RoleExpression.ROLEEXP_FIGHT: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FIGHT; break; - case (int)RoleExpression.ROLEEXP_ATTACK1: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK1; break; - case (int)RoleExpression.ROLEEXP_ATTACK2: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK2; break; - case (int)RoleExpression.ROLEEXP_ATTACK3: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK3; break; - case (int)RoleExpression.ROLEEXP_ATTACK4: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_ATTACK4; break; - case (int)RoleExpression.ROLEEXP_DEFENCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DEFENCE; break; - case (int)RoleExpression.ROLEEXP_FALL: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALL; break; - case (int)RoleExpression.ROLEEXP_FALLONGROUND: - iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FALLONGROUND; break; - case (int)RoleExpression.ROLEEXP_LOOKAROUND: - iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_LOOKAROUND; break; - case (int)RoleExpression.ROLEEXP_DANCE: iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE; break; - case (int)RoleExpression.ROLEEXP_FASHIONWEAPON: - iAction = (int)PLAYER_ACTION_TYPE.ACT_EXP_FASHIONWEAPON; break; - case (int)RoleExpression.ROLEEXP_TWO_KISS: iAction = (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS; break; - case (int)RoleExpression.ROLEEXP_FIREWORK: iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_TOSS; break; - default: - break; - } - - pWork.SetPoseAction(iAction, bSession); - - return true; - } - // Get cool time public virtual int GetCoolTime(int iIndex, out int piMax /* NULL */) { @@ -6697,19 +3138,7 @@ namespace BrewMonster return true; } - void OnMsgHstTargetIsFar(ECMSG Msg) - { - // TO DO: fix later - //if(CmdNormalAttack(true, m_pComboSkill != null, 0, -1) ) - // AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); - - if (CmdNormalAttack(true, false, 0, -1)) - { - //AP_ActionEvent(AP_EVENT_MELEEOUTOFRANGE, 1); - } - } - - public enum StateAnim + public enum StateAnim { Idle = 1, Walk = 2, @@ -6846,24 +3275,6 @@ namespace BrewMonster CANDO_REBUILDPET = 19, CANDO_SWITCH_PARALLEL_WORLD = 20; } - public bool CanTakeItem(int idItem, int iAmount) - { - bool bCanPick = false; - - if (GPDataTypeHelper.ISMONEYTID(idItem)) - { - if (GetMoneyAmount() < GetMaxMoneyAmount()) - bCanPick = true; - } - else - { - if (IvtrPack.CanAddItem(idItem, iAmount, false) >= 0) - bCanPick = true; - } - - return bCanPick; - } - public bool FindMineTool(int tidMine, ref int piPack, ref int piIndex, ref int pidTool) { if (tidMine == 0) @@ -6910,68 +3321,6 @@ namespace BrewMonster return bRet; } - void OnMsgPlayerGather(ECMSG Msg) - { - int cmd = Convert.ToInt32(Msg.dwParam2); - if (cmd == CommandID.PLAYER_GATHER_START) - { - cmd_player_gather_start pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - EC_ManMatter pMatterMan = EC_ManMessageMono.Instance.GetECManMatter;//g_pGame.GetGameRun().GetWorld().GetMatterMan(); - CECMatter pMatter = pMatterMan.GetMatter(pCmd.mid); - // if (pMatter && pMatter.IsMonsterSpiritMine()) { - // CECHPWorkUse* pWork = (CECHPWorkUse*)m_pWorkMan.CreateWork(CECHPWork::WORK_USEITEM); - // if (pWork) { - // pWork.SetParams(pCmd.mid, pCmd.use_time * 1000, pCmd.mid, true); - // m_pWorkMan.StartWork_p1(pWork); - // } - // StartMonsterSpiritConnectGfx(pCmd.mid, pMatter.GetPos()); - // } else { - EC_HPWorkPick pWork = (EC_HPWorkPick)m_pWorkMan.CreateWork(Host_work_ID.WORK_PICKUP); - if (pWork != null) - { - pWork.SetGather(true, pMatter ? pMatter.GetTemplateID() : 0); - m_pWorkMan.StartWork_p1(pWork); - } - // } - - // Start time counter - m_GatherCnt.SetPeriod(pCmd.use_time * 1000); - m_GatherCnt.Reset(); - } - else if (cmd == CommandID.PLAYER_GATHER_STOP) - { - cmd_player_gather_stop pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_PICKUP); - m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM); - // StopMonsterSpiritConnectGfx(); - var pDlg = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().GetDialog("Win_Prgs2"); - if (pDlg == null) - { - BMLogger.LogError("Null Win_Prgs2"); - return; - } - - if (pDlg is not DlgWinPrgs2 dlgWinPrgs) - { - BMLogger.LogError("Can not cast Win_Prgs2"); - return; - } - dlgWinPrgs.SetActiveProgress(false); - } - else if (cmd == CommandID.MINE_GATHERED) - { - cmd_mine_gathered pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - // ASSERT(pCmd && pCmd.player_id == m_PlayerInfo.cid); - elementdataman pDataMan = EC_Game.GetElementDataMan(); - DATA_TYPE DataType = pDataMan.get_data_type((uint)pCmd.item_type, ID_SPACE.ID_SPACE_ESSENCE); - if (DataType == DATA_TYPE.DT_MONSTER_SPIRIT_ESSENCE) - { - // StartMonsterSpiritBallGfx(); - // m_CardHolder.gain_times++; - } - } - } public CECCounter GetGatherCnt() { return m_GatherCnt; } @@ -7148,272 +3497,6 @@ namespace BrewMonster } } - // Remove skill reference / 鍒犻櫎鎶鑳藉紩鐢 - void RemoveSkillReference(int idSkill) - { - if (idSkill <= 0) return; - - // Remove reference to self skill / 鍒犻櫎瀵规妧鑳界殑寮曠敤 - if (m_pPrepSkill != null && m_pPrepSkill.GetSkillID() == idSkill) - m_pPrepSkill = null; - - if (m_pCurSkill != null && m_pCurSkill.GetSkillID() == idSkill) - m_pCurSkill = null; - - if (m_pComboSkill != null && m_pComboSkill.FindSkillID(idSkill)) - ClearComboSkill(); - - if (m_pWorkMan != null) - { - CECHPWork pWork = m_pWorkMan.GetWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT); - if (pWork != null) - { - CECHPWorkTrace pWorkTrace = pWork as CECHPWorkTrace; - if (pWorkTrace != null && - pWorkTrace.GetTraceReason() == CECHPWorkTrace.Trace_reason.TRACE_SPELL && - pWorkTrace.GetPrepSkill() != null && - pWorkTrace.GetPrepSkill().GetSkillID() == idSkill) - pWorkTrace.Reset(); - } - } - - int i; - - for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS1; i++) - { - if (m_aSCSets1[i] != null) - m_aSCSets1[i].RemoveSkillShortcut(idSkill); - } - for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) - { - if (m_aSCSets2[i] != null) - m_aSCSets2[i].RemoveSkillShortcut(idSkill); - } - } - - // Remove skill / 鍒犻櫎鎶鑳 - void RemoveNormalSkill(int idSkill) - { - // Delete equipped skills / 鍒犻櫎瑁呭鎶鑳 - - if (idSkill <= 0) return; - - RemoveSkillReference(idSkill); - - // Delete skill list pointer / 鍒犻櫎鎶鑳藉垪琛ㄦ寚閽 - int i; - - for (i = 0; i < m_aPtSkills.Count; i++) - { - if (m_aPtSkills[i].GetSkillID() == idSkill) - { - m_aPtSkills.RemoveAt(i); - return; - } - } - - for (i = 0; i < m_aPsSkills.Count; i++) - { - if (m_aPsSkills[i].GetSkillID() == idSkill) - { - m_aPsSkills.RemoveAt(i); - return; - } - } - - for (i = 0; i < m_aGoblinSkills.Count; i++) - { - if (m_aGoblinSkills[i].GetSkillID() == idSkill) - { - m_aGoblinSkills.RemoveAt(i); - return; - } - } - } - - // Clear combo skill / 娓呴櫎杩炲嚮鎶鑳 - public bool ApplyComboSkill(int iGroup, bool bIgnoreAtkLoop = false, int iForceAtk = -1) - { - ClearComboSkill(); - - CECComboSkill comboSkill = new(); - bool bForceAttack = iForceAtk < 0 ? glb_GetForceAttackFlag(0) : iForceAtk > 0; - if (!comboSkill.Init(this, iGroup, m_idSelTarget, bForceAttack, bIgnoreAtkLoop)) - { - return false; - } - - m_pComboSkill = comboSkill; - m_pComboSkill.Continue(m_bMelee); - return true; - } - - public void ClearComboSkill() - { - if (m_pComboSkill != null) - { - m_pComboSkill = null; - } - } - - // Replace specified skill with it's senior skill / 鐢ㄩ珮绾ф妧鑳芥浛鎹㈡寚瀹氱殑浣庣骇鎶鑳 - void ReplaceJuniorSkill(CECSkill pSeniorSkill) - { - if (pSeniorSkill == null) - { - Debug.Assert(pSeniorSkill != null); - return; - } - SkillArrayWrapper juniorArray = pSeniorSkill.GetJunior(); - if (juniorArray.Empty()) - { - Debug.Assert(false); - return; - } - - int i; - - // Update shortcuts ... / 鏇存柊蹇嵎鏂瑰紡... - for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS1; i++) - { - if (m_aSCSets1[i] != null) - m_aSCSets1[i].ReplaceSkillID(juniorArray, pSeniorSkill); - } - - for (i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++) - { - if (m_aSCSets2[i] != null) - m_aSCSets2[i].ReplaceSkillID(juniorArray, pSeniorSkill); - } - - // Update skill groups ... / 鏇存柊鎶鑳界粍... - // Note: Combo skill update logic may need to be added here - // Original C++ code had EC_VIDEO_SETTING and combo skill group logic - } - - public int CheckSkillLearnCondition(int idSkill, bool bCheckBook) - { - int iLevel = 1; - CECSkill pSkill = GetNormalSkill(idSkill); - if (pSkill != null) - iLevel = pSkill.GetSkillLevel() + 1; - - if (iLevel == 1 && bCheckBook) - { - // Do we have the skill book ? - int idBook = ElementSkill.GetRequiredBook((uint)idSkill, iLevel); - if (idBook != 0 /*&& m_pPack.FindItem(idBook) < 0*/) - return 8; - } - - // Build player information - LearnRequirement Info; - - Info.level = GetMaxLevelSofar(); - Info.sp = m_BasicProps.iSP; - Info.money = (int)m_iMoneyCnt; - Info.profession = m_iProfession; - Info.rank = m_BasicProps.iLevel2; - Info.realm_level = GetRealmLevel(); - - return ElementSkill.LearnCondition((uint)idSkill, Info, iLevel); - } - private void OnMsgHstPressCancel(ECMSG Msg) - { - CECHPWork pCurWork = null; - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_TRACEOBJECT); - if (pCurWork is CECHPWorkTrace workTrace) - { - workTrace.PressCancel(); - return; - } - - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_HACKOBJECT); - if (pCurWork != null) - { - UnityGameSession.c2s_CmdCancelAction(); - return; - } - - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM); - if (pCurWork != null) - { - UnityGameSession.c2s_CmdCancelAction(); - return; - } - - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_SPELLOBJECT); - if (pCurWork != null) - { - int iState = ((CECHPWorkSpell)pCurWork).GetState(); - if (iState == CECHPWorkSpell.Spell_magic_state.ST_INCANT) - { - UnityGameSession.c2s_CmdCancelAction(); - return; - } - } - - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_PICKUP); - if (pCurWork != null) - { - if (((EC_HPWorkPick)pCurWork).IsGather()) - { - UnityGameSession.c2s_CmdCancelAction(); - return; - } - } - //todo: handle this part - // pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONCENTRATE); - // if (pCurWork !=null){ - // if (IsOperatingPet()){ - // UnityGameSession.c2s_CmdCancelAction(); - // return; - // } - // } - // pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_CONGREGATE); - // if (pCurWork !=null){ - // if (IsCongregating()){ - // UnityGameSession.c2s_CmdCancelAction(); - // return; - // } - // } - - if (m_bUsingTrashBox || DoingSessionPose()) - { - UnityGameSession.c2s_CmdCancelAction(); - return; - } - - // Cancel current selection - if (m_idSelTarget > 0) - { - SelectTarget(0); - return; - } - - // Some work have lower priority - pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_MOVETOPOS); - if (pCurWork != null) - { - ((CECHPWorkMove)pCurWork).PressCancel(); - return; - } - } - - // Is doing session pose ? - private bool DoingSessionPose() - { - var pCurWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_STAND); - if (pCurWork != null) - { - if (((CECHPWorkStand)pCurWork).DoingSessionPose()) - { - return true; - } - } - return false; - } - // Start / Stop flying public bool CmdFly(bool bForceFly) { @@ -7454,193 +3537,8 @@ namespace BrewMonster return true; } - void OnMsgPlayerFly(ECMSG Msg) - { - if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_TAKEOFF) - { - if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) == 0) - { - m_dwStates |= PlayerNPCState.GP_STATE_FLY; - m_bRushFly = false; - - CECHPWorkFly pWork = (CECHPWorkFly)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FLYOFF); - if (m_pWorkMan.IsFreeFalling()) - { - pWork.m_bContinueFly = true; - m_pWorkMan.StartWork_p1(pWork); - } - else - { - pWork.m_bContinueFly = false; - m_pWorkMan.StartWork_p2(pWork); - } - } - } - else if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_LANDING) - { - if ((m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0) - { - m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_FLY; - - if (IsDead() || m_bCandHangerOn || IsHangerOn()) - ShowWing(false); - else - { - CECHPWorkFall pWork = (CECHPWorkFall)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_FREEFALL); - pWork.SetFallType(CECHPWorkFall.Fall_type.TYPE_FLYFALL); - m_pWorkMan.StartWork_p1(pWork); - } - - // Below two lines will fix the "host stand in air" bug. - m_iMoveEnv = Move_environment.MOVEENV_GROUND; - m_CDRInfo.vTPNormal.Clear(); - } - } - else // HOST_RUSH_FLY - { - cmd_host_rush_fly pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - m_bRushFly = pCmd.is_active != 0 ? true : false; - } - } public CECCounter GetIncantCnt() { return m_IncantCnt; } - public EC_Inventory GetPack(int iPack) - { - EC_Inventory pInventory = null; - switch (iPack) - { - case Inventory_type.IVTRTYPE_PACK: pInventory = m_pPack; break; - case Inventory_type.IVTRTYPE_EQUIPPACK: pInventory = m_pEquipPack; break; - case Inventory_type.IVTRTYPE_TASKPACK: pInventory = m_pTaskPack; break; - //case Inventory_type.IVTRTYPE_TRASHBOX: pInventory = m_pTrashBoxPack; break; - //case Inventory_type.IVTRTYPE_TRASHBOX2: pInventory = m_pTrashBoxPack2; break; - //case Inventory_type.IVTRTYPE_TRASHBOX3: pInventory = m_pTrashBoxPack3; break; - //case Inventory_type.IVTRTYPE_ACCOUNT_BOX: pInventory = m_pAccountBoxPack; break; - //case Inventory_type.IVTRTYPE_GENERALCARD_BOX: pInventory = m_pGeneralCardPack; break; - //case IVTRTYPE_PACK_CLIENT_GENERALCAR.IVTRTYPE_CLIENT_GENERALCARD_PACK: pInventory = m_pClientGenCardPack; break; - default: - return null; - } - return pInventory; - } - - public int GetEquippedSuiteItem(int idSuite, ref int[] aItems) - { - int i, iItemCnt = 0; - for (i = 0; i < m_pEquipPack.GetSize(); i++) - { - var pItem = m_pEquipPack.GetItem(i); - if (pItem == null) - { - continue; - } - EC_IvtrEquip pEquip = (EC_IvtrEquip)pItem; - if (pEquip == null) - { - continue; - } - if (pEquip.GetSuiteID() != idSuite) - { - continue; - } - int iReason = 0; - if (!CanUseEquipment(pEquip, ref iReason)) - { - continue; - } - if (pEquip.CID == (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD) - { - //TODO: Add general card Suite - } - if (aItems.Length > 0) - { - aItems[iItemCnt] = pEquip.GetTemplateID(); - } - iItemCnt++; - } - return iItemCnt; - } - public bool CanUseEquipment(EC_IvtrEquip pEquip, ref int piReason) - { - int iReason = 0; - if (pEquip == null) - { - iReason = 1; - goto End; - } - if (GetMaxLevelSofar() < pEquip.LevelReq || - m_ExtProps.bs.strength < pEquip.StrengthReq || - m_ExtProps.bs.agility < pEquip.AgilityReq || - m_ExtProps.bs.vitality < pEquip.VitalityReq || - m_ExtProps.bs.energy < pEquip.EnergyReq/*|| - Reputation < pEquip.ReputationReq*/)//todo Add reputation check - { - iReason = 2; - goto End; - } - switch (pEquip.CID)//class id - { - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARROW: - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WING: - if (m_iProfession != (int)PROFESSION.PROF_ARCHOR && m_iProfession != (int)PROFESSION.PROF_ANGEL) - iReason = 3; - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FLYSWORD: - //TODO: Add flysword check - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_FASHION: - //TODO: Add fashion check - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_ARMOR: - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_DECORATION: - if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) - iReason = 3; - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_WEAPON: - if ((pEquip.ProfReq & (1 << m_iProfession)) == 0) - iReason = 3; - else - { - //TODO: check range weapon arrow - } - break; - case (int)EC_IvtrEquip.EQUIP_CLASS_ID.ICID_GENERALCARD: - // TODO: Add general card check - break; - default: - break; - } - - End: - if (piReason > 0) - { - piReason = iReason; - } - return iReason == 0 ? true : false; - } - public void OnMsgHstEmbedItem(ECMSG Msg) - { - cmd_embed_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - EC_IvtrItem pEquip = m_pPack.GetItem(pCmd.equip_idx); - EC_IvtrItem pTessera = m_pPack.GetItem(pCmd.chip_idx); - - if (pEquip == null || pTessera == null) - { - return; - } - - m_pPack.RemoveItem(pCmd.chip_idx, 1); - - // Refresh equip's data - // todo make receive request - UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, pCmd.equip_idx); - } - public CECPetCorral GetPetCorral() - { - return m_pPetCorral; - } - // Get key object(NPC..) coordinates public A3DVECTOR3 GetObjectCoordinates(int idTarget, ref ObjectCoords TargetCoord, ref bool bInTable) { @@ -7718,602 +3616,6 @@ namespace BrewMonster public int GetRealmSubLevel() { return m_RealmLevel % 100; } public static int GetRealmLayer(int realmLevel) { return realmLevel > 0 ? (realmLevel + 9) / 10 : 0; } public static int GetRealmSubLevel(int realmLevel) { return realmLevel > 0 ? (realmLevel % 10 > 0 ? realmLevel % 10 : 10) : 0; } - public bool HaveHealthStones() - { - var pPack = GetPack(); - var items = new int[] { 36764, 36765, 36766, 36767 }; - for (int i = 0; i < items.Length; ++i) - { - if (pPack.FindItem(items[i]) >= 0) - return true; - } - return false; - } - - public bool UseItemInPack(int iPack, int iSlot, bool showMsg = true) - { - if (!CanDo(ActionCanDo.CANDO_USEITEM)) - return false; - - EC_Inventory pPack = GetPack(iPack); - if (pPack == null) - return false; - - EC_IvtrItem pItem = pPack.GetItem(iSlot); - if (pItem == null || pItem.IsFrozen()) - return false; - - if (pItem.Use_Persist() && (IsJumping() || IsFalling())) - return false; - - CECGameRun pGameRun = EC_Game.GetGameRun(); - //CECGameSession pSession = g_pGame.GetGameSession(); - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_FIREWORK) - { - if (GetProfession() == (int)PROFESSION.PROF_GHOST && IsInvisible()) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_WHEN_INVISIBLE); - return false; - } - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_INCSKILLABILITY) - { - EC_IvtrIncSkillAbility pIncSkill = pItem as EC_IvtrIncSkillAbility; - //if (pIncSkill != null) - //{ - // var pDBEssence = pIncSkill.GetDBEssence(); - // CECSkill pSkill = GetNormalSkill(pDBEssence.id_skill); - // if (pSkill != null) - // { - // if (pSkill.GetSkillLevel() != pDBEssence.level_required) - // { - // if (showMsg) - // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_LEVEL_INVALID); - // return false; - // } - // if (GetSkillAbilityPercent(pDBEssence.id_skill) >= 100) - // { - // if (showMsg) - // pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_PRODUCE_ABILITY_FULL); - // return false; - // } - // } - //} - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TRANSMITSCROLL) - { - CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); - if (pGameUI != null && !IsFighting()) - { - // TODO: Implement travel map dialog - //CDlgWorldMap* pMap = (CDlgWorldMap*)pGameUI->GetDialog("Win_WorldMapTravel"); - //pMap->BuildTravelMap(DT_TRANSMITSCROLL_ESSENCE, (void*)iSlot); - //pMap->Show(true); - } - return true; - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHOPTOKEN) - { - CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); - if (pGameUI != null && !IsFighting()) - { - //CDlgTokenShop* pDlg = dynamic_cast(pGameUI->GetDialog("Win_TokenShop")); - //if (pDlg) - //{ - // pDlg->InitTokenShopItem(pItem->GetTemplateID()); - // pDlg->Show(!pDlg->IsShow()); - //} - } - return true; - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_UNIVERSAL_TOKEN) - { - // TODO: Implement universal token when available - EC_IvtrUniversalToken pUniversalToken = pItem as EC_IvtrUniversalToken; - //if (pUniversalToken != null && pUniversalToken.HasAnyUsage()) - //{ - // CECUseUniversalTokenCommandManager.Instance.Use(pUniversalToken, pUniversalToken.UsageIndexAt(0)); - // return true; - //} - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TASKDICE) - { - EC_IvtrTaskDice pTaskDice = pItem as EC_IvtrTaskDice; - if (pTaskDice != null) - { - if (pTaskDice != null) - { - if (IsFlying() && pTaskDice.GetDBEssence().no_use_in_combat == 1) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); - return false; - } - } - } - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) - { - EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; - if (pTargetItem == null) - return false; - - var essence = pTargetItem.GetDBEssence(); - - if (!pTargetItem.IsEssenceLoaded()) - return false; - - if (IsFighting() && essence.use_in_combat == 0) - { - if (showMsg) - if (showMsg) pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_BATTLE); - return false; - } - - if (essence.use_in_sanctuary_only != 0 && !IsInSanctuary()) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_USE_IN_SANCTUARY_ONLY); - return false; - } - - int iCurrMap = pGameRun.GetWorld().GetInstanceID(); - if (pTargetItem.GetDBEssence().num_area != 0) - { - bool found = false; - for (int i = 0; i < pTargetItem.GetDBEssence().num_area; i++) - { - if (pTargetItem.GetDBEssence().area_id[i] == iCurrMap) - { - found = true; - break; - } - } - if (!found) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_CANNOT_USE_IN_CURR_MAP); - return false; - } - } - - if (!CanDo(ActionCanDo.CANDO_SPELLMAGIC)) - return false; - - if (InSlidingState()) - return false; - - if (m_idSelTarget == 0) - return false; - - CECSkill pSkill = pTargetItem.GetTargetSkill(); - if (pSkill == null) - return false; - - if (IsSpellingMagic() && m_pCurSkill != null && m_pCurSkill.IsCharging() && - m_pCurSkill.GetSkillID() == pSkill.GetSkillID()) - { - m_pCurSkill.EndCharging(); - UnityGameSession.c2s_SendCmdContinueAction(); - return true; - } - - int iCon = CheckSkillCastCondition(pSkill); - if (iCon != 0) - { - if (showMsg) - ProcessSkillCondition(iCon); - return false; - } - - bool bForceAttack = glb_GetForceAttackFlag(0); - if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_ATTACK || - pSkill.GetType() == (int)CECSkill.SkillType.TYPE_CURSE) - { - if (m_idSelTarget == m_PlayerInfo.cid) - { - if (showMsg) - pGameRun.AddFixedChannelMsg((int)FixedMsg.FIXMSG_TARGETWRONG, (int)ChatChannel.GP_CHAT_FIGHT); - return false; - } - else if (m_idSelTarget != 0) - { - if (AttackableJudge(m_idSelTarget, bForceAttack) != 1) - return false; - } - } - - int idCastTarget = m_idSelTarget; - int iTargetType = pSkill.GetTargetType(); - - if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS || - pSkill.GetType() == (int)CECSkill.SkillType.TYPE_NEUTRALBLESS) - { - if (iTargetType == 0 || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) - idCastTarget = m_PlayerInfo.cid; - - if (GPDataTypeHelper.ISPLAYERID(idCastTarget) && idCastTarget != m_PlayerInfo.cid) - { - byte byBLSMask = EC_Utility.glb_BuildBLSMask(); - - if (pSkill.GetRangeType() == (int)CECSkill.RangeType.RANGE_POINT) - { - if (!IsTeamMember(idCastTarget)) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_SELF) != 0) - { - idCastTarget = m_PlayerInfo.cid; - } - else - { - EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget) as EC_ElsePlayer; - if (pPlayer == null) - return false; - - if (pPlayer.IsInvader() || pPlayer.IsPariah()) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NORED) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (!IsFactionMember(pPlayer.GetFactionID())) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOMAFIA) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (!IsFactionAllianceMember(pPlayer.GetFactionID())) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOALLIANCE) != 0) - idCastTarget = m_PlayerInfo.cid; - } - - if (GetForce() != pPlayer.GetForce()) - { - if ((byBLSMask & (byte)PVPMask.GP_BLSMASK_NOFORCE) != 0) - idCastTarget = m_PlayerInfo.cid; - } - } - } - } - - // If host is in dule - if (IsInDuel() && m_idSelTarget == m_pvp.idDuelOpp) - idCastTarget = m_PlayerInfo.cid; - - // If host is in battle - if (IsInBattle()) - { - EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(idCastTarget); - if (!InSameBattleCamp(pPlayer)) - idCastTarget = m_PlayerInfo.cid; - - } - } - } - else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_BLESS) - { - // TODO: Implement pet blessing when petsystem is available - //CECSCPet pPet = EC_Game.GetGameRun().GetWorld().GetPetByID(m_idSelTarget); - //if (pPet == null || pPet.GetMasterID() == GetCharacterID()) - //{ - // CECPetData pPetData = m_pPetCorral.GetActivePet(); - // if (pPetData == null || - // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_COMBAT && - // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_SUMMON && - // pPetData.GetClass() != GP_PET_TYPE.GP_PET_CLASS_EVOLUTION) - // return false; - - // idCastTarget = m_pPetCorral.GetActivePetNPCID(); - //} - //if(iTargetType != 0 && idCastTarget == 0) - // return false; - } - - if (iTargetType != 0) - { - int iAliveFlag = 0; - if (iTargetType == 1) - iTargetType = 1; - else if (iTargetType == 2) - iTargetType = 2; - - CECObject pObject = EC_ManMessageMono.Instance.GetObject(idCastTarget, iAliveFlag); - if (pObject == null) - return false; - } - - if (!IsMeleeing() && !IsSpellingMagic() && - (iTargetType == 0 || idCastTarget == m_PlayerInfo.cid)) - { - if (!pSkill.ReadyToCast()) - return false; - - if (!pSkill.IsInstant() && pSkill.GetType() != (int)CECSkill.SkillType.TYPE_FLASHMOVE) - { - if (!NaturallyStopMoving()) - return false; - } - else if (pSkill.GetType() == (int)CECSkill.SkillType.TYPE_FLASHMOVE) - { - if (!CanDo(ActionCanDo.CANDO_FLASHMOVE)) - return false; - } - - m_pPrepSkill = pSkill; - } - else if (IsSpellingMagic() && m_pCurSkill == pSkill && !pSkill.ReadyToCast()) - { - return false; - } - } - if (pItem.IsEquipment()) - { - if (iPack == Inventory_type.IVTRTYPE_EQUIPPACK) - { - // Take off equipment - int iEmpty = m_pPack.SearchEmpty(); - if (iEmpty < 0) - return false; - - UnityGameSession.RequestEquipItemAsync((byte)iEmpty, (byte)iSlot, null); - return true; - } - - EC_IvtrEquip pEquip = pItem as EC_IvtrEquip; - if (pEquip == null) - return false; - - int iReason = 0; - if (!CanUseEquipment(pEquip, ref iReason)) - return false; - - int iFirstFree = -1, iFirstCan = -1; - for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++) - { - if (pItem.CanEquippedTo(i)) - { - if (iFirstCan < 0) - iFirstCan = i; - - if (m_pEquipPack.GetItem(i) == null && iFirstFree < 0) - { - iFirstFree = i; - break; - } - } - } - - int iDst; - if (iFirstFree >= 0) - iDst = iFirstFree; - else if (iFirstCan >= 0) - iDst = iFirstCan; - else - { - Debug.Assert(false); - return false; - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) - { - int iSameIDPos = m_pEquipPack.FindItem(pItem.GetTemplateID()); - if (iSameIDPos >= 0) - { - iDst = iSameIDPos; - } - - } - - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_ARROW || - pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DYNSKILLEQUIP) - { - EC_IvtrItem pDstItem = m_pEquipPack.GetItem(iDst); - if (pDstItem == null || pItem.GetTemplateID() != pDstItem.GetTemplateID()) - UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); - else - { - // TODO: Implement c2s_CmdMoveItemToEquip when available - //UnityGameSession.c2s_CmdMoveItemToEquip((byte)iSlot, (byte)iDst); - } - } - else - { - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_GENERALCARD) - { - //TODO: Add general card equip request - EC_IvtrGeneralCard pCard = pItem as EC_IvtrGeneralCard; - if (pCard != null) - { - iDst = InventoryConst.EQUIPIVTR_GENERALCARD1 + pCard.GetEssence().type; - } - } - UnityGameSession.RequestEquipItemAsync((byte)iSlot, (byte)iDst, null); - } - return true; - } - - if (iPack != Inventory_type.IVTRTYPE_PACK) - return false; - - if (!pItem.CheckUseCondition()) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_CANNOTUSE); - return false; - } - - int piMax = -1; - if (pItem.GetCoolTime(out piMax) > 0) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_ITEM_INCOOLTIME); - return false; - } - - if (pItem.Use_AtkTarget() || pItem.Use_Target()) - { - if (pItem.Use_AtkTarget() && CannotAttack()) - return false; - - if (m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid) - { - if (showMsg) - { - CECStringTab pStrTab = EC_Game.GetFixedMsgs(); - pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_NOTARGET), (int)ChatChannel.GP_CHAT_SYSTEM); - } - return false; - } - - float fAattackRange = 10000.0f; - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TOSSMAT) - { - EC_IvtrTossMat pTossMat = pItem as EC_IvtrTossMat; - if (pTossMat != null) - fAattackRange = pTossMat.GetDBEssence().attack_range; - } - else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TANKCALLIN) - { - fAattackRange = 5.0f; - } - else if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_TARGETITEM) - { - EC_IvtrTargetItem pTargetItem = pItem as EC_IvtrTargetItem; - if (pTargetItem != null && pTargetItem.GetTargetSkill() != null) - { - fAattackRange = pTargetItem.GetTargetSkill().GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); - } - } - - float fDist = 0, fTargetRag = 0; - CECObject pObject = null; - if (CalcDist(m_idSelTarget, out fDist, out pObject)) - { - return false; - } - - if (GPDataTypeHelper.ISNPCID(m_idSelTarget)) - { - pObject = EC_ManMessageMono.Instance.CECNPCMan.GetNPC(m_idSelTarget); - CECNPC pNPC = pObject as CECNPC; - if (pNPC != null) - fTargetRag = pNPC.GetTouchRadius(); - } - else if (GPDataTypeHelper.ISPLAYERID(m_idSelTarget)) - { - pObject = EC_ManMessageMono.Instance.GetECManPlayer.GetElsePlayer(m_idSelTarget); - EC_ElsePlayer pPlayer = pObject as EC_ElsePlayer; - if (pPlayer != null) - fTargetRag = pPlayer.GetTouchRadius(); - } - - if (fDist - fTargetRag > fAattackRange * 0.8f) - { - if (showMsg) - { - CECStringTab pStrTab = EC_Game.GetFixedMsgs(); - pGameRun.AddChatMessage(pStrTab.GetWideString((int)FixedMsg.FIXMSG_TARGETISFAR), (int)ChatChannel.GP_CHAT_SYSTEM); - } - return false; - } - - byte byPVPMask = glb_BuildPVPMask(glb_GetForceAttackFlag(0)); - UnityGameSession.c2s_SendCmdUseItemWithTarget((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), byPVPMask); - } - else - { - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_DOUBLEEXP) - { - EC_IvtrDoubleExp pDoubleExp = pItem as EC_IvtrDoubleExp; - if (pDoubleExp != null) - { - if (pDoubleExp.GetDBEssence().double_exp_time + pGameRun.GetRemainDblExpTime() > 3600 * 4) - { - if (showMsg) - { - CECGameUIMan pGameUI = pGameRun.GetUIManager().GetInGameUIMan(); - //pGameUI.MessageBox("", pGameUI.GetStringFromTable(828), MB_OK, new Color32(1, 1, 1, 0.6)); - } - return false; - } - } - } - if (pItem.GetClassID() == (int)EC_IvtrItem.InventoryClassId.ICID_SHARPENER) - { - if (showMsg) - pGameRun.AddFixedMessage((int)FixedMsg.FIXMSG_SHARPEN_ON_DRAG); - return false; - } - UnityGameSession.c2s_SendCmdUseItem((byte)iPack, (byte)iSlot, pItem.GetTemplateID(), 1); - } - return true; - } - - private void OnMsgHstUseItem(ECMSG Msg) - { - cmd_host_use_item pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - EC_Inventory pPack = GetPack(pCmd.byPackage); - if (pPack == null) - { - return; - } - - EC_IvtrItem pItem = pPack.GetItem(pCmd.bySlot, false); - if (pItem == null || pItem.GetTemplateID() != pCmd.item_id) - { - return; - } - - pItem.Use(); - - if (pCmd.use_count > 0) - { - bool removed = pPack.RemoveItem(pCmd.bySlot, pCmd.use_count); - if (removed) - { - if (pPack.GetItem(pCmd.bySlot, false) == null) - { - //Debug.Log($"[OnMsgHstUseItem] Item {pCmd.item_id} removed from slot {pCmd.bySlot}"); - } - } - else - { - //Debug.LogError($"[OnMsgHstUseItem] Failed to remove item {pCmd.item_id} from slot {pCmd.bySlot}"); - } - - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - ui.UpdateCooldownOverlays(); - } - else - { - //Debug.LogError("[OnMsgHstUseItem] EC_InventoryUI not found, UI may not update"); - } - } - - if (m_pWorkMan != null) - { - CECHPWork pWork = m_pWorkMan.GetRunningWork(Host_work_ID.WORK_USEITEM); - if (pWork is CECHPWorkUse useWork) - { - if (useWork.GetItem() == pCmd.item_id) - { - m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_USEITEM); - } - } - } - } // // Calculate distance to an object and optionally retrieve the object reference @@ -8378,106 +3680,7 @@ namespace BrewMonster //private bool ISNPCID(int id) => ((id & 0x80000000) != 0) && ((id & 0x40000000) == 0); //private bool ISPLAYERID(int id) => id != 0 && (id & 0x80000000) == 0; //private bool ISMATTERID(int id) => ((id) & 0xC0000000) == 0xC0000000; - - - public bool IsPlayerMoving() - { - return m_pWorkMan.IsMoving(); - } - public CECComboSkill GetComboSkill() { return m_pComboSkill; } - - /* Is host operating pet ? - return value: - - 0: host doesn't operating pet. - 1: host is summoning pet. - 2: host is recalling pet. - 3: host is banishing pet. - */ - public int IsOperatingPet() - { - CECHPWorkConcentrate pWork = (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_CONCENTRATE)) as CECHPWorkConcentrate; - if (pWork != null) - { - if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_SUMMONPET) - return 1; - else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RECALLPET) - return 2; - else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_BANISHPET) - return 3; - else if (pWork.GetDoWhat() == (int)CECHPWorkConcentrate.eDO_PET.DO_RESTOREPET) - return 4; - } - return 0; - } - - // Summon pet - public bool SummonPet(int iPetIdx) - { - if (m_pActionSwitcher != null) - m_pActionSwitcher.PostMessge((int)EMsgActionSwitcher.MSG_MOUNTPET); - - CECGameRun pGameRun = EC_Game.GetGameRun(); - - CECPetData pPet = m_pPetCorral.GetPetData(iPetIdx); - if (pPet == null) - return false; - - if (!CanDo(ActionCanDo.CANDO_SUMMONPET)) - return false; - - // Couldn't summon daed pet - if (pPet.IsDead()) - { - //pGameRun.AddFixedMessage(FIXMSG_PET_DEAD); - Debug.LogError("FIXMSG_PET_DEAD"); - return false; - } - - // If host could't stop naturally, cancel summoning - if (!NaturallyStopMoving()) - return false; - - // 录矛虏茅碌卤脟掳脢脟路帽陆没脰鹿脮脵禄陆脝茂鲁猫 - if (pPet.IsMountPet() && m_playerLimits[(int)PLAYER_LIMIT.PLAYER_LIMIT_NOMOUNT]) - return false; - - if (m_ReincarnationCount != 0) - { - int iLevelRequired = pPet.GetLevel() - 35 - m_ReincarnationCount * 5; - if (m_BasicProps.iLevel < iLevelRequired) - { - CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); - if (pGameUI != null) - { - // TO DO: fix later - //string strText = ""; - //strText.Format(pGameUI.GetStringFromTable(10787), iLevelRequired); - //pGameUI.MessageBox("", strText, MB_OK, A3DCOLORRGBA(255, 255, 255, 160)); - } - return false; - } - } - - UnityGameSession.c2s_CmdPetSummon(iPetIdx); - - return true; - } - } - public struct SkillShortCutConfig - { - public int setNum; - public int slotNum; - public int skillId; - }; - - public struct SkillGrpShortCutConfig - { - public int setNum; - public int slotNum; - public int groupIndex; - }; public sealed class CECHPTraceSpellMatcher : CECHPWorkMatcher { public override bool Match(CECHPWork pWork, int priority, bool isDelayWork)