using BrewMonster; using BrewMonster.Assets.PerfectWorld.Scripts.Players; using BrewMonster.Assets.PerfectWorld.Scripts.Skills; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using BrewMonster.Scripts.Player; using BrewMonster.Scripts.Skills; using CSNetwork; using CSNetwork.Common; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using NUnit.Framework; using PerfectWorld.Scripts.Managers; using PerfectWorld.Scripts.Managers.BrewMonster.Managers; using PerfectWorld.Scripts.Player; using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Text; using TMPro; using Unity.VisualScripting; using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; using static Unity.Burst.Intrinsics.X86.Avx; using static UnityEditor.PlayerSettings; using Scene = UnityEngine.SceneManagement.Scene; using Trace_reason = CECHPWorkTrace.Trace_reason; using Host_work_ID = BrewMonster.Scripts.CECHPWork.Host_work_ID; using BrewMonster.Scripts; public partial class CECHostPlayer : CECPlayer { [SerializeField] private CharacterController controller; [SerializeField] private Joystick joystick; [SerializeField] private Button btnJump; [SerializeField] private Button btnRun; private PlayerStateMachine _playerStateMachine; private PlayerMoveState _moveState; private PlayerIdleState _idleState; public CECHostMove m_MoveCtrl; private CECHPWorkMan m_pWorkMan; // Host work manager private uint m_dwLIES; // Logic-influence extend states private FACTION_FORTRESS_ENTER m_fortressEnter; // ½øÈë»ùµØÐÅÏ¢ private PVPINFO m_pvp; // pvp information private bool m_bInSanctuary = false; // true, player is in sanctuary private int m_idFaction = 0; // ID of player's faction public bool m_bPrepareFight = false; // true, prepare to fight private int m_iJumpCount = 0; private bool m_bJumpInWater = false; public A3DVECTOR3 m_vVelocity; // Velocity private int m_iRoleCreateTime; private int m_iRoleLastLoginTime; // Role last login time private int m_iAccountTotalCash; private List m_aTabSels = new List(); private List m_aPtSkills = new List(); private List m_aPsSkills = new List(); private List m_aEquipSkills = new List(); private List m_aGoblinSkills = new List(); private bool m_bEnterGame; public CECSkill m_pPrepSkill; private float playerSpeed = 5.0f; private float jumpHeight = 1.5f; private float gravityValue = -9.81f; private StateAnim stateAnim = StateAnim.Idle; private Vector3 playerVelocity; private bool isGrounded = false; private bool isRun = false; private Vector3 m_vLastSevPos; public CDR_INFO m_CDRInfo; public GNDINFO m_GndInfo; private int m_idUCSelTarget; // Uncertificately selected object's ID public float m_fVertSpeed = 0f; CECActionSwitcherBase m_pActionSwitcher; // ====== Ground cast config ====== [Header("Ground Cast")] [Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")] [SerializeField] private float extraGroundDistance = 1f; [Tooltip("Bớt bán kính một chút để tránh tự va vào capsule (epsilon)")] [SerializeField] private float radiusEpsilon = 0.005f; [Tooltip("Layer mặt đất")] [SerializeField] private LayerMask groundMask = 1 << 6; [Tooltip("Layer mặt đất")] [SerializeField] private float slopeToleranceDeg = 2f; // cache tùy chọn (không bắt buộc) float ccRadius, ccSkin; RaycastHit lastGroundHit; Camera mainCam; private void Awake() { base.Awake(); _moveState = new PlayerMoveState(this); _idleState = new PlayerIdleState(this); _playerStateMachine = new PlayerStateMachine(); m_MoveCtrl = new CECHostMove(this); // Cache: không bắt buộc, nhưng gọn tay và ít gọi property lặp. if (controller != null) { ccRadius = controller.radius; ccSkin = controller.skinWidth; } } public bool LoadResources() { RoleInfo RoleInfo = UnityGameSession.Instance.GetRoleInfo(); m_iProfession = RoleInfo.occupation; m_iGender = RoleInfo.gender; m_iRoleCreateTime = RoleInfo.create_time; m_iRoleLastLoginTime = RoleInfo.lastlogin_time; m_iAccountTotalCash = RoleInfo.cash_add; if (!LoadPlayerSkeleton(true)) { BMLogger.LogError("HoangDev CECHostPlayer::LoadResources, Failed to load skeleton"); return false; } return true; } private bool LoadPlayerSkeleton(bool bAtOnce) { EC_PLAYERLOADRESULT Ret = default; if (bAtOnce /*|| !IsLoadThreadReady()*/) { // Under normal circumstances, only HostPlayer can reach here /* if (!LoadPlayerModel(m_iProfession, m_iGender, m_CustomizeData.bodyID, aEquips, szPetPath, Ret, false, false)) { a_LogOutput(1, "CECPlayer::Init, failed to call LoadPlayerModel() !"); return false; }*/ SetPlayerLoadedResult(Ret); /* if (IsShapeChanged() && !QueueLoadDummyModel(m_iShape, true)) { // ignore the dummy model loading failure a_LogOutput(1, "CECPlayer::Init, failed to call QueueLoadDummyModel() !"); }*/ } return true; } private bool SetPlayerLoadedResult(EC_PLAYERLOADRESULT ret) { OnAllResourceReady(); return true; } private void OnAllResourceReady() { CECHostSkillModel.Instance.Initialize(); } private void Start() { mainCam = Camera.main; if (mainCam == null) { mainCam = FindFirstObjectByType(); } _playerStateMachine.InitState(_idleState); // btnJump.onClick.AddListener(HandleJump); } private void Update() { #if UNITY_EDITOR if (Input.GetKeyDown(KeyCode.C)) { ApplySkillShortcut(1); } #endif //Debug.Log($"(ulong)Time.deltaTime * 1000 {(ulong)(Time.deltaTime * 1000)}"); m_MoveCtrl.Tick((ulong)(Time.deltaTime * 1000)); // Nếu có thay đổi runtime, có thể lấy lại mỗi vài giây/Start nếu bạn thích: // ccRadius = controller.radius; ccSkin = controller.skinWidth; _playerStateMachine.UpdateState(); if (Input.GetMouseButtonDown(0) && mainCam != null) { int idTraceTarget = 0, idSelTarget = 0; bool bForceAttack = false; int iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_NONE; bool bWikiMonster = false; Ray ray = mainCam.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { CECObject clickedObject = hit.collider.gameObject.GetComponent(); if (clickedObject != null) { int idObject = CECObject.GetObjectID(clickedObject); if (idObject != 0) { CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idObject); if (pNPC != null) { if (!pNPC.IsDead() /* && m_idSelTarget == idObject*/) { idTraceTarget = idObject; idSelTarget = idObject; } if (idTraceTarget != 0) { if (AttackableJudge(idObject, bForceAttack) == 1) iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_ATTACK; else if (pNPC.IsServerNPC()) { if (!IsInBattle() || InSameBattleCamp(pNPC)) iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_TALK; } } } } } } // Tell server we select a target if (idSelTarget != 0 && m_idSelTarget != idSelTarget) { m_idUCSelTarget = idSelTarget; SelectTarget(m_idUCSelTarget); } if (idTraceTarget != 0) { if (iTraceReason == CECHPWorkTrace.Trace_reason.TRACE_ATTACK) { if (!CanDo(ActionCanDo.CANDO_MELEE)) return; NormalAttackObject(idTraceTarget, bForceAttack); } } } m_pWorkMan?.Tick(Time.deltaTime); } public void StopMovement() { m_MoveCtrl.SendStopMoveCmd(transform.position, 5f, (int)GPMoveMode.GP_MOVE_WALK); } public void HandleMovement() { // 1) Kiểm tra grounded bằng SphereCast ngắn dựa trên radius + skinWidth isGrounded = GroundCheck(out lastGroundHit); m_GndInfo.bOnGround = isGrounded; // 2) Input tạm thời: giữ nguyên như bạn if (UnityEngine.Input.GetKeyDown(KeyCode.LeftShift)) SetStatusRun(true); if (UnityEngine.Input.GetKeyUp(KeyCode.LeftShift)) SetStatusRun(false); if (UnityEngine.Input.GetKeyDown(KeyCode.Space)) HandleJump(); // 3) Trọng lực / sticky if (isGrounded && playerVelocity.y < 0f) { // Đè nhẹ để bám đất (tránh nhấp-nháy) playerVelocity.y = -2f; } else { playerVelocity.y += gravityValue * Time.deltaTime; } // 4) Chuyển động phẳng float x = joystick.Horizontal; float z = joystick.Vertical; Vector3 move = new Vector3(x, 0, z); move = Vector3.ClampMagnitude(move, 1f); if (move != Vector3.zero) { Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up); controller.Move(finalMove * Time.deltaTime); transform.forward = move; m_MoveCtrl.GroundMove(Time.deltaTime); m_MoveCtrl.SendMoveCmd(transform.position, controller.velocity, (int)GPMoveMode.GP_MOVE_RUN); m_aabb.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); m_aabb.CompleteMinsMaxs(); m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(transform.position) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); m_aabbServer.CompleteMinsMaxs(); } else { } } private void JoystickRelease(JoystickRealeaseEvent joystickRealeaseEvent) { _playerStateMachine.ChangeState(_idleState); } public bool GroundCheck(out RaycastHit hit) { float radius = controller.radius; float skin = controller.skinWidth; float height = controller.height; // Tâm capsule theo world Vector3 cWorld = transform.TransformPoint(controller.center); float hemi = Mathf.Max(0f, (height * 0.5f) - radius); // Hai điểm top/bottom của capsule nhân vật (đang đứng) Vector3 pTop = cWorld + Vector3.up * hemi; Vector3 pBottom = cWorld - Vector3.up * hemi; // Ta tạo một "đoạn capsule ngắn" gần đáy để sweep xuống // Nhấc đoạn bắt đầu lên 1 chút để không bắt đầu trong trạng thái giao nhau Vector3 startBottom = pBottom + Vector3.up * (skin + 0.01f); Vector3 startTop = startBottom + Vector3.up * (radius * 2f - 0.02f); // chiều cao đoạn ngắn ~2*radius float castRadius = Mathf.Max(0f, radius - radiusEpsilon); float castDistance = skin + extraGroundDistance; // quãng sweep ngắn bool hitSomething = Physics.CapsuleCast( startTop, startBottom, castRadius, Vector3.down, out hit, castDistance, groundMask, QueryTriggerInteraction.Ignore ); if (!hitSomething) return false; // Lọc theo slope limit float maxSlope = controller.slopeLimit + slopeToleranceDeg; float slope = Vector3.Angle(hit.normal, Vector3.up); if (slope > maxSlope) return false; return true; } private void HandleJump() { if (isGrounded) { playerVelocity.y = Mathf.Sqrt(jumpHeight * -2f * gravityValue); } } public void ProcessMessage(in ECMSG Msg) { var msg = (int)Msg.dwMsg; //Debug.LogError("HoangDev : ProcessMessageProcessMessageProcessMessage " + msg); switch (msg) { case int value when value == EC_MsgDef.MSG_HST_CORRECTPOS: OnMsgHstCorrectPos(Msg); break; case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break; case int value when value == EC_MsgDef.MSG_HST_IVTRINFO: { OnMsgHstIvtrInfo(Msg); break; } case int value when value == EC_MsgDef.MSG_HST_OWNITEMINFO: { OnMsgHstOwnItemInfo(Msg); break; } case int value when value == EC_MsgDef.MSG_HST_TASKDATA: { OnMsgHstTaskData(Msg); //Debug.LogError("[Dat]- OnMsgHstTaskData"); break; } case int value when value == EC_MsgDef.MSG_HST_ITEMOPERATION: OnMsgHstItemOperation(Msg); break; case int value when value == EC_MsgDef.MSG_HST_PICKUPITEM: OnMsgHstPickupItem(Msg); break; case int value when value == EC_MsgDef.MSG_HST_SELTARGET: OnMsgHstSelTarget(Msg); break; case int value when value == EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break; case int value when value == EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break; case int value when value == EC_MsgDef.MSG_HST_HURTRESULT: OnMsgHstHurtResult(Msg); break; case int value when value == EC_MsgDef.MSG_HST_INFO00: OnMsgHstInfo00(Msg); break; case int value when value == EC_MsgDef.MSG_HST_SKILLDATA: OnMsgHstSkillData(Msg); break; case int value when value == EC_MsgDef.MSG_HST_DIED: OnMsgHstDied(Msg); break; case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break; } } 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()) { /* for (int i = 0; i < HostConstants.NUM_HOSTSCSETS1; i++) { if (hostPlayer.m_aSCSets1[i] != null) { hostPlayer.m_aSCSets1[i].RemoveSkillShortcuts(); } } for (int i = 0; i < HostConstants.NUM_HOSTSCSETS2; i++) { if (hostPlayer.m_aSCSets2[i] != null) { hostPlayer.m_aSCSets2[i].RemoveSkillShortcuts(); } }*/ // Release passive skills 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 (hostPlayer.HostIsReady()) { hostPlayer.ConvertSkillShortcut(skillSCConfigArray1); hostPlayer.AssignSkillShortcut(skillSCConfigArray1, hostPlayer.m_aSCSets1); hostPlayer.ConvertSkillShortcut(skillSCConfigArray2); hostPlayer.AssignSkillShortcut(skillSCConfigArray2, hostPlayer.m_aSCSets2); hostPlayer.ConvertComboSkill(); hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray1); hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray1, hostPlayer.m_aSCSets1); hostPlayer.ValidateSkillGrpShortcut(skillGrpSCConfigArray2); hostPlayer.AssignSkillGrpShortcut(skillGrpSCConfigArray2, hostPlayer.m_aSCSets2); } if (hostPlayer.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(); hostPlayer.UpdateSkillRelatedUI(); }*/ } public bool HostIsReady() { return true /*m_bEnterGame*/; } private void OnMsgHstDied(in ECMSG msg) { EventBus.PublishChannel(GetCharacterID(), new CECPlayer.CleearComActFlagAllRankNodesEvent(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); // 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; m_BasicProps.iLevel2 = level2; /*if (CanPlayTaoistEffect(lastLevel2, level2, bFirstTime)){ PlayTaoistEffect(); }*/ } 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) { BMLogger.LogError($"HoangDev pAttacker.OnMsgAttackHostResult "); pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed); } } //CECAutoPolicy::GetInstance().SendEvent_BeHurt(pCmd.idAttacker); } public void OnMsgHstAttackResult(ECMSG Msg) { BMLogger.LogError($"HoangDev OnMsgHstAttackResult "); 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 void OnMsgHstPickupItem(in ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); 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 // Create new inventory item data var newItem = new EC_IvtrItem { Package = where, Slot = index, m_tid = type, m_expire_date = expire_date, State = 0, m_iCount = (int)amount, Crc = 0, Content = null }; // Add item to inventory EC_Inventory.SetItem(where, 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(); } } break; case CommandID.PICKUP_ITEM: { int tid = BitConverter.ToInt32(data, 0); int expire_date = BitConverter.ToInt32(data, 4); uint iAmount = 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 = new EC_IvtrItem { Package = byPackage, Slot = bySlot, m_tid = tid, m_expire_date = expire_date, State = 0, m_iCount = (int)iAmount, Crc = 0, Content = null }; // Add item to inventory EC_Inventory.SetItem(byPackage, 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; } } } 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 bool success = EC_Inventory.RemoveItem(byPackage, 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 invItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, true); var equipItem = EC_Inventory.GetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, true); if (invItem != null) { invItem.Package = EC_Inventory.IVTRTYPE_EQUIPPACK; invItem.Slot = index_equip; EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_EQUIPPACK, index_equip, invItem); } if (equipItem != null) { equipItem.Package = EC_Inventory.IVTRTYPE_PACK; equipItem.Slot = index_inv; EC_Inventory.SetItem(EC_Inventory.IVTRTYPE_PACK, index_inv, equipItem); } // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindObjectOfType(); if (ui != null) { ui.RefreshAll(); } 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); EC_Inventory.LogInventoryPacket("OWN_ITEM_INFO", data, hostId); 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: { EC_Inventory.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.TryParseInventoryDetail(data, out var pkg, out var size, out var items)) { EC_Inventory.UpdatePack(pkg, size, items); } // check if we got the item from the Equipment Pack. If so, we have to load the equipment items if (byPackage == EC_Inventory.IVTRTYPE_EQUIPPACK) { UpdateEquipSkins(); } } break; } case CommandID.GET_OWN_MONEY: { if (data != null) { try { var money = 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.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.LogWarning("HoangDev : OnMsgHstCorrectPos"); byte[] buf = (byte[])Msg.dwParam1; // chỗ bạn 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(); Debug.LogWarning("HoangDev :pCmd.pos " + pCmd.pos); SetPos(pCmd.pos); } public void HandleRevive(short sReviveType, A3DVECTOR3 pos) { // Move to revive position and play revive animation PlayAction((int)PLAYER_ACTION_TYPE.ACT_REVIVE); // Clear any running dead work if exists m_pWorkMan?.FinishRunningWork(CECHPWork.Host_work_ID.WORK_DEAD); // Clear corpse state so player is alive again m_dwStates &= ~(uint)PlayerNPCState.GP_STATE_CORPSE; } public void OnMsgHstGoto(in ECMSG Msg) { Debug.Log("HoangDev :OnMsgHstGoto"); PopupManager.Instance.OnPlayerRevived(); // p1 is a byte[] buffer; parse into cmd_notify_hostpos then set position byte[] buf = (byte[])Msg.dwParam1; cmd_notify_hostpos pCmd = GPDataTypeHelper.FromBytes(buf); SetPos(new Vector3(pCmd.vPos.x, pCmd.vPos.y, pCmd.vPos.z)); } // Message MSG_HST_SELTARGET handler void OnMsgHstSelTarget(ECMSG Msg) { //BMLogger.LogError("HoangDev: OnMsgHstSelTarget"); if (Convert.ToInt32(Msg.dwParam2) == CommandID.SELECT_TARGET) { var data = (byte[])Msg.dwParam1; cmd_select_target pCmd = GPDataTypeHelper.FromBytes(data); m_idSelTarget = pCmd.idTarget; m_idUCSelTarget = 0; } else if (Convert.ToInt32(Msg.dwParam2) == CommandID.UNSELECT) { m_idSelTarget = 0; } } public void SetPos(Vector3 pos) { transform.position = pos; m_aabb.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); m_aabb.CompleteMinsMaxs(); m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); m_aabbServer.CompleteMinsMaxs(); } public void SetStatusRun(bool value) { if (!isGrounded) { Debug.LogError("Player not in ground"); return; } isRun = value; } public void InitCharacter(cmd_self_info_1 role) { SetUpPlayer(); controller = GetComponent(); if (!controller) { BMLogger.LogError("HostPlayer InitCharacter no CharacterController"); } //if (role.name != null && role.name.ByteArray != null) //{ // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); //} SetPlayerInfor(new INFO(role.cid, role.crc_e, role.crc_c)); SetModelHostPlayer(); Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); string roleName = Encoding.Unicode.GetString(UnityGameSession.Instance.GetRoleInfo().name.ByteArray); if (txtName != null) txtName.text = roleName; EventBus.Publish(new InfoHostPlayer(roleName)); transform.position = pos; m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL; joystick = FindAnyObjectByType(); EventBus.Subscribe(JoystickRelease); EventBus.Subscribe(JoystickStartDrag); if (TryGetComponent(out var visual)) { visual.InitPlayerEventDoneHandler(); } m_aabb.Center = GPDataTypeHelper.g_vOrigin; m_aabb.Extents.Set(0.3f, 0.9f, 0.3f); m_aabbServer = m_aabb; CalcPlayerAABB(); SetPos(pos); m_CDRInfo.fStepHeight = 0.8f; //m_CDRInfo.vTPNormal = GroundCheck(out RaycastHit hit) ? hit.normal : Vector3.zero; m_CDRInfo.vExtent = EC_Utility.ToVector3(m_aabbServer.Extents); // Create work manager m_pWorkMan = new CECHPWorkMan(this); LoadResources(); if (m_pWorkMan == null) { return; } if (true /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/) { m_pActionSwitcher = new CECActionSwitcher(this); } else m_pActionSwitcher = new CECActionSwitcherBase(this); UnityGameSession.c2s_CmdGetAllData(true, true, false); // TODO: Move this to right flow later , it's just for test now UnityGameSession.c2s_CmdSendEnterPKPrecinct(); } private void JoystickStartDrag(JoystickPressEvent joystickPressEvent) { _playerStateMachine.ChangeState(_moveState); } private void OnDestroy() { EventBus.Unsubscribe(JoystickRelease); EventBus.Unsubscribe(JoystickStartDrag); } public void InitCharacter(info_player_1 role) { string roleName = "(Error decoding name)"; //if (role.name != null && role.name.ByteArray != null) //{ // roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length); //} Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z); if (txtName != null) txtName.text = roleName; transform.position = pos; SetModelHostPlayer(); //Debug.LogError("Pos Character = " + pos); } #region Task public void OnMsgHstTaskData(ECMSG Msg) { int cmd = Convert.ToInt32(Msg.dwParam2); if (cmd == CommandID.TASK_DATA) { //Debug.Log("[Dat]- OnMsgHstTaskData- TASK_DATA"); //a_LogOutput(1, "[Dat]- EC_HostMsg- OnMsgHstTaskData- TASK_DATA"); //cmd_task_data* pCmd = (cmd_task_data*)Msg.dwParam1; //ASSERT(pCmd); //int iActiveListSize = (int)pCmd.active_list_size; //BYTE* pData = (BYTE*)pCmd + sizeof(size_t); //void* pActiveListbuf = pData; //pData += iActiveListSize; //int iFinishedListSize = *(int*)pData; //pData += sizeof(int); //void* pFinishedListBuf = pData; //pData += iFinishedListSize; //int iFinishTimeListSize = *(int*)pData; //pData += sizeof(int); //void* pFinishTimeListBuf = pData; //pData += iFinishTimeListSize; //int iFinishedCountListSize = *(int*)pData; //pData += sizeof(int); //void* pFinishedCountListBuf = pData; //pData += iFinishedCountListSize; //int iStorageTasksListSize = *(int*)pData; //pData += sizeof(int); //void* pStorageTaskListBuf = pData; //pData += iStorageTasksListSize; //A3DRELEASE(m_pTaskInterface); //todo //var m_pTaskInterface = new CECTaskInterface(this); //if (!m_pTaskInterface.Init(null, 0, null, 0, // null, 0, null, 0, null, 0)) //{ // //a_LogOutput(1, "CECHostPlayer::OnMsgHstTaskData, failed to initialize task interface"); // return; //} //m_pTaskInterface.CheckPQEnterWorldInit(); //// check if player has equipped goblin //if (m_pEquipPack.GetItem(EQUIPIVTR_GOBLIN) != NULL) //{ // CECIvtrGoblin* pIvtrGoblin = (CECIvtrGoblin*)m_pEquipPack.GetItem(EQUIPIVTR_GOBLIN); // m_pGoblin = new CECHostGoblin(); // m_pGoblin.Init(pIvtrGoblin.GetTemplateID(), pIvtrGoblin, this); //} //// Note: this command now is also used as the end flag of responding //// for GET_ALL_DATA request //g_pGame.GetGameSession().LoadConfigData(); //// ¸ù¾Ý×°±¸°ü¹ü¸üÐÂ×°±¸¼¼Äܵ½¼¼ÄÜÁбí //if (UpdateEquipSkills()) // UpdateEquipSkillCoolDown(); } else if (cmd == CommandID.TASK_VAR_DATA) { //cmd_task_var_data* pCmd = (cmd_task_var_data*)Msg.dwParam1; //ASSERT(pCmd); //if (m_pTaskInterface) // OnServerNotify(m_pTaskInterface, pCmd.data, pCmd.size); //else // ASSERT(m_pTaskInterface); } } #endregion 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 CECActionSwitcherBase GetActionSwitcher() { return m_pActionSwitcher; } private float A3d_Magnitude(A3DVECTOR3 v) { return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } public int GetCharacterID() { 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) { float fDist = A3d_Magnitude(vTargetPos - vHostPos); switch (iReason) { case 1: // melee { float fRange; if (fMaxCut >= 0.0f) { float fCutDist = m_ExtProps.ak.AttackRange * 0.3f; if (fCutDist > fMaxCut) fCutDist = fMaxCut; fRange = m_ExtProps.ak.AttackRange - fCutDist; } else { fRange = m_ExtProps.ak.AttackRange * 0.7f; } // TO DO: fix later fRange = 1f; if (fDist - fTargetRad <= fRange) return true; break; } //case 2: // cast magic //{ // if (m_pPrepSkill) // { // float fRange = m_pPrepSkill.GetCastRange(m_ExtProps.ak.AttackRange, GetPrayDistancePlus()); // if (fRange > 0.0f) // { // if (fDist - fTargetRad <= fRange) // return true; // } // else // return true; // } // break; //} case 3: // talk { if (fDist - fTargetRad <= 5.0f) return true; break; } default: // no special reason { if (fDist < (fTargetRad + m_fTouchRad) * 3.0f) return true; break; } } return false; } public void RemoveObjectFromTabSels(CECObject pObject) { for (int i = 0; i < m_aTabSels.Count; i++) { if (m_aTabSels[i] == pObject) { m_aTabSels.RemoveAt(i); break; } } } public bool CanTouchTarget(A3DVECTOR3 vTargetPos, float fTargetRad, int iReason, float fMaxCut = 1.0f) { A3DVECTOR3 vector = new A3DVECTOR3(gameObject.transform.position.x, gameObject.transform.position.y, gameObject.transform.position.z); return CanTouchTarget(vector, vTargetPos, fTargetRad, iReason, fMaxCut); } public bool IsRooting() { var mask = (uint)(Logic_Influence_Extned_states.LIES_ROOT | Logic_Influence_Extned_states.LIES_SLEEP | Logic_Influence_Extned_states.LIES_STUN); return (m_dwLIES & mask) != 0; } bool IsInFortress() { return m_fortressEnter.role_in_war != 0; } bool IsPVPOpen() { return m_pvp.bEnable; } // Get faction ID int GetFactionID() { return m_idFaction; } public bool IsJumping() { return m_iJumpCount > 0; } public bool IsPlayingAction(int iAction) { if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK && _playerStateMachine.State is PlayerMoveState) { return true; } if (iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND && _playerStateMachine.State is PlayerIdleState) { return true; } return false; } public void ResetJump() { m_iJumpCount = 0; m_bJumpInWater = false; } // Get move speed public float GetFlySpeed() { return m_ExtProps.mv.flight_speed; } public float GetSwimSpeed() { return m_ExtProps.mv.swim_speed; } 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) // return ReturnToTargetTown(0, bCombo); //if (idSkill == ID_SUMMONPLAYER_SKILL) // return SummonPlayer(idSelTarget, bCombo); //if (!CanDo(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 && m_pCurSkill->IsCharging() && // m_pCurSkill->GetSkillID() == pSkill->GetSkillID()) //{ // m_pCurSkill->EndCharging(); // g_pGame->GetGameSession()->c2s_CmdContinueAction(); // return true; //} //int iCon = CheckSkillCastCondition(pSkill); //if (iCon) //{ // 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() == CECSkill::TYPE_ATTACK || pSkill->GetType() == CECSkill::TYPE_CURSE) //{ // if (idSelTarget == m_PlayerInfo.cid) // { // // Host cannot spell negative effect magic to himself. // g_pGame->GetGameRun()->AddFixedChannelMsg(FIXMSG_TARGETWRONG, GP_CHAT_FIGHT); // return false; // } // else if (idSelTarget) // { // if (AttackableJudge(idSelTarget, bForceAttack) != 1) // return false; // } //} //// Check whether target type match int idCastTarget = idSelTarget; int iTargetType = pSkill.GetTargetType(); //if (pSkill->GetType() == CECSkill::TYPE_BLESS || // pSkill->GetType() == CECSkill::TYPE_NEUTRALBLESS) //{ // if (!iTargetType || !ISPLAYERID(idSelTarget)) // idCastTarget = m_PlayerInfo.cid; // // In some case, we shouldn't add bless effect to other players // if (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 = glb_BuildBLSMask(); // if (pSkill->GetRangeType() == CECSkill::RANGE_POINT) // { // if (!IsTeamMember(idCastTarget)) // { // if (byBLSMask & GP_BLSMASK_SELF) // idCastTarget = m_PlayerInfo.cid; // else // { // CECElsePlayer* pPlayer = (CECElsePlayer*)g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idCastTarget); // if (!pPlayer) // { // // Ä¿±êÏûʧ // return false; // } // if (pPlayer->IsInvader() || pPlayer->IsPariah()) // { // if (byBLSMask & GP_BLSMASK_NORED) // idCastTarget = m_PlayerInfo.cid; // } // if (!IsFactionMember(pPlayer->GetFactionID())) // { // if (byBLSMask & GP_BLSMASK_NOMAFIA) // idCastTarget = m_PlayerInfo.cid; // } // if (!IsFactionAllianceMember(pPlayer->GetFactionID())) // { // if (byBLSMask & GP_BLSMASK_NOALLIANCE) // idCastTarget = m_PlayerInfo.cid; // } // if (GetForce() != pPlayer->GetForce()) // { // if (byBLSMask & GP_BLSMASK_NOFORCE) // 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()) // { // CECElsePlayer* pPlayer = m_pPlayerMan->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) // 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) //{ // // Target shoundn't be a corpse ? // int iAliveFlag = 0; // if (iTargetType == 1) // iAliveFlag = 1; // else if (iTargetType == 2) // iAliveFlag = 2; // CECObject* pObject = g_pGame->GetGameRun()->GetWorld()->GetObject(idCastTarget, iAliveFlag); // if (!pObject) // return false; //} //if (!IsMeleeing() && !IsSpellingMagic() && // (!iTargetType || idCastTarget == m_PlayerInfo.cid)) //{ // // Cast this skill need't checking cast distance // if (!pSkill->ReadyToCast()) // return false; // // Prepare to cast skill, if skill isn't INSTANT and FLASHMOVE, // // we must stop moving and stand // if (!pSkill->IsInstant() && pSkill->GetType() != CECSkill::TYPE_FLASHMOVE) // { // if (!NaturallyStopMoving()) // return false; // Couldn't stop naturally, so cancel casting skill // } // else if (pSkill->GetType() == CECSkill::TYPE_FLASHMOVE) // { // if (!CanDo(CANDO_FLASHMOVE)) // return false; // } m_pPrepSkill = pSkill; //CastSkill(m_idSelTarget, 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 bool CastSkill(int idTarget, bool bForceAttack, CECObject pTarget = null) { byte byPVPMask = glb_BuildPVPMask(bForceAttack); UnityGameSession.c2s_CmdCastSkill(m_pPrepSkill.GetSkillID(), byPVPMask, 1, idTarget); return true; } public byte glb_BuildPVPMask(bool bForceAttack) { byte byMask = 0; if (bForceAttack) byMask |= (byte)PVPMask.GP_PVPMASK_FORCE; else { /* CECConfigs pConfigs = EC_Game.GetConfigs(); if (pConfigs->GetGameSettings().bAtk_Player) { byMask |= GP_PVPMASK_FORCE; if (pConfigs->GetGameSettings().bAtk_NoMafia) byMask |= GP_PVPMASK_NOMAFIA; if (pConfigs->GetGameSettings().bAtk_NoWhite) byMask |= GP_PVPMASK_NOWHITE; if (pConfigs->GetGameSettings().bAtk_NoAlliance) byMask |= GP_PVPMASK_NOALLIANCE; if (pConfigs->GetGameSettings().bAtk_NoForce) byMask |= GP_PVPMASK_NOFORCE; }*/ } return byMask; } public bool SelectTarget(int idTarget) { //BMLogger.LogError("HoangDev: HostPlayer SelectTarget"); bool bRet = false; bool canDo = CanDo(ActionCanDo.CANDO_CHANGESELECT); bool canselect = CanSelectTarget(idTarget); if (canDo && canselect) { bRet = true; if (idTarget == 0) { //BMLogger.LogError("HoangDev: HostPlayer Unsetlect npc"); UnityGameSession.c2s_CmdUnselect(); } else { //BMLogger.LogError("HoangDev: HostPlayer setlect npc"); UnityGameSession.c2s_CmdSelectTarget(idTarget); } } return bRet; } 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]; } bool CanSelectTarget(int idTarget) { if (idTarget == 0 || idTarget == this.GetCharacterID()) { // 0 means unselect return true; } CECObject pTarget = null; if (GPDataTypeHelper.ISPLAYERID(idTarget)) { EC_ElsePlayer pElsePlayer = (EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget)) as EC_ElsePlayer; if (pElsePlayer != null) { if (CanSafelySelect(pElsePlayer)) { pTarget = pElsePlayer; } } } else if (GPDataTypeHelper.ISNPCID(idTarget)) { CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idTarget); if (pNPC != null) { if (CanSafelySelect(pNPC) && !pNPC.IsDead()) { pTarget = pNPC; } } } return pTarget ? pTarget.IsSelectable() : false; } float SafelySelectDistance() { // ·þÎñÆ÷¶Ô SelectTarget ÓжîÍâ¾àÀëÏÞÖÆ£¬Èýά¾àÀë 150.0¡¢Ë®Æ½¾àÀë 125.0 ÒÔÉϵ쬶¼»áÎÞ·¨Ñ¡ÖÐ // »ùÓÚÒÔÉÏÔ­Òò£¬¿Í»§¶ËÑ¡Ôñ¶ÔÏó¡¢»òÕß¶ÔÒѾ­Ñ¡ÔñµÄ¶ÔÏ󣬶¼È·±£ÆäÔÚ´ËÏÞÖÆ·¶Î§ÄÚ£¬¼´Ñ¡ÔñʱʹÓýÏС¾àÀë¼ì²â return 100.0f; } bool CanSafelySelectWith(float fDistanceToHostPlayer) { return fDistanceToHostPlayer <= SafelySelectDistance(); } bool CanSafelySelect(EC_ElsePlayer pElsePlayer) { // IsSkeletonReady() Ϊ true ʱ, GetDistToHost() ²ÅΪÓÐЧÊý¾Ý // !IsSkeletonReady() ʱ£¬Ò²ÔÊÐíʹÓã¬Ä¿µÄÊDZÜÃâδ¿¼Âǵ½µÄÒâÍâÇé¿ö // ÏÂͬ return pElsePlayer && ( /*!IsSkeletonReady() || */CanSafelySelectWith(pElsePlayer.GetDistToHost())); } bool CanSafelySelect(CECNPC pNPC) { return pNPC && ( /*!IsSkeletonReady() ||*/ CanSafelySelectWith(pNPC.GetDistToHost())); } // Check whether host can do a behavior bool CanDo(int iThing) { bool bRet = true; switch (iThing) { case ActionCanDo.CANDO_SITDOWN: if (IsDead() /*|| IsAboutToDie() */ || IsJumping() /*|| IsTrading() || IsUsingTrashBox()*/ || IsRooting() || /*IsReviving() || IsTalkingWithNPC() || IsChangingFace() ||*/ !m_GndInfo .bOnGround /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()*/ ) bRet = false; break; case ActionCanDo.CANDO_MOVETO: { if (IsDead() /*|| IsSitting() || IsTrading() || IsUsingTrashBox()*/ || IsRooting() /*|| IsReviving() || IsTalkingWithNPC() || IsChangingFace() || IsUsingItem() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsPassiveMove()*/) bRet = false; break; } case ActionCanDo.CANDO_MELEE: if (IsDead() /*|| IsSitting() */ || m_idSelTarget == 0 || m_idSelTarget == m_PlayerInfo.cid || IsJumping() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsTrading() || IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace()*/ || CannotAttack() /*|| GetBoothState() != 0 || m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()*/) bRet = false; break; case ActionCanDo.CANDO_ASSISTSEL: if (IsDead() || !GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || m_idSelTarget == m_PlayerInfo.cid /*|| !m_pTeam || !m_pTeam->GetMemberByID(m_idSelTarget) || m_iBuddyId || IsPassiveMove() || m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT)*/) bRet = false; break; case ActionCanDo.CANDO_FLY: if (IsDead() || IsRooting() /*|| IsSitting() || IsTrading() || IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 || IsFlashMoving() */ || m_pWorkMan.HasWorkRunningOnPriority(CECHPWorkMan.Work_priority.PRIORITY_2) /*|| m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || m_playerLimits.test(PLAYER_LIMIT_NOFLY) || m_BattleInfo.IsChariotWar()*/) bRet = false; break; case ActionCanDo.CANDO_PICKUP: case ActionCanDo.CANDO_GATHER: if (IsDead() /*|| IsAboutToDie() || IsSitting() || IsTrading() || IsUsingTrashBox() || IsReviving() || IsTalkingWithNPC() || IsChangingFace() || GetBoothState() != 0 || GetBuddyState() == 1 || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()*/) bRet = false; break; case ActionCanDo.CANDO_TRADE: if (IsDead() /*|| IsAboutToDie() || IsSitting() */ || IsJumping() /*|| IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsInvisible() || IsPassiveMove()*/) bRet = false; break; case ActionCanDo.CANDO_PLAYPOSE: if (IsDead() /*|| IsAboutToDie() || IsSitting()*/ || IsJumping() || /* IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsShapeChanged() || IsReviving() ||*/ m_iMoveEnv != (int)MoveEnvironment.MOVEENV_GROUND /*|| GetBoothState() != 0 || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || m_BattleInfo.IsChariotWar()*/ ) bRet = false; break; //case ActionCanDo.CANDO_SPELLMAGIC: // if (IsDead() || ISMATTERID(m_idSelTarget) || IsAboutToDie() || IsSitting() || // IsJumping() || IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || CannotAttack() || IsReviving() || GetBoothState() != 0 || // m_iBuddyId || IsRidingOnPet() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) // bRet = false; // break; case ActionCanDo.CANDO_SUMMONPET: if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) || /*IsAboutToDie() || IsSitting() ||*/ IsJumping() || /*IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() ||*/ CannotAttack() /*|| IsReviving() || GetBoothState() != 0 || IsInvisible() || IsGMInvisible() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || m_BattleInfo.IsChariotWar()*/) bRet = false; break; case ActionCanDo.CANDO_REBUILDPET: if (IsDead() || GPDataTypeHelper.ISMATTERID(m_idSelTarget) /*|| IsAboutToDie() || IsSitting() */ || IsJumping() /*|| IsFlashMoving() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace()*/ || CannotAttack() /*|| IsReviving() || GetBoothState() != 0 || m_iBuddyId || IsInvisible() || IsGMInvisible() || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || IsPlayerMoving() || m_BattleInfo.IsChariotWar()*/) bRet = false; break; //case ActionCanDo.CANDO_USEITEM: // if (IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || GetBoothState() != 0 || IsPassiveMove() || m_BattleInfo.IsChariotWar()) // bRet = false; // break; //case ActionCanDo.CANDO_JUMP: // { // if (IsDead() || // m_iJumpCount >= MAX_JUMP_COUNT || // // cannot jump more than one time if shape mode is type2 // (IsJumping() && (GetShapeType() == PLAYERMODEL_DUMMYTYPE2)) || // IsJumpInWater() || m_iMoveEnv == MOVEENV_AIR || IsSitting() || // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || // IsGathering() || IsRooting() || GetBoothState() != 0 || m_bHangerOn || (IsJumping() && IsRidingOnPet()) || // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove() || m_BattleInfo.IsChariotWar()) // bRet = false; // break; // } //case ActionCanDo.CANDO_FOLLOW: // { // if (IsDead() || IsAboutToDie() || IsSitting() || IsMeleeing() || IsReviving() || // IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || // IsSpellingMagic() || GetBoothState() != 0 || m_bHangerOn || IsOperatingPet() || IsRebuildingPet() || // IsUsingItem() || IsPassiveMove()) // bRet = false; // break; // } //case ActionCanDo.CANDO_BOOTH: // if (IsDead() || IsAboutToDie() || IsPlayerMoving() || IsSitting() || IsReviving() || // IsMeleeing() || IsJumping() || IsTrading() || IsUsingTrashBox() || // IsTalkingWithNPC() || IsChangingFace() || IsSpellingMagic() || IsFlying() || // IsUnderWater() || m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsRidingOnPet() || IsInvisible() || // IsPassiveMove()) // bRet = false; // break; //case ActionCanDo.CANDO_FLASHMOVE: // if (IsDead() || IsAboutToDie() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsJumping() || IsFlashMoving() || IsFalling() || IsChangingFace() || GetBoothState() != 0 || IsTakingOff() || // m_pWorkMan->HasWorkRunningOnPriority(CECHPWorkMan::PRIORITY_2) || // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) // bRet = false; // break; //case ActionCanDo.CANDO_BINDBUDDY: // if (IsDead() || IsAboutToDie() || IsJumping() || IsSitting() || // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || // IsGathering() || IsRooting() || GetBoothState() != 0 || // !m_pWorkMan->IsStanding() || m_iBuddyId || // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove() || // m_playerLimits.test(PLAYER_LIMIT_NOBIND)) // bRet = false; // break; //case ActionCanDo.CANDO_DUEL: // if (IsDead() || IsAboutToDie() || IsSitting() || IsFighting() || IsTrading() || // IsReviving() || IsUsingTrashBox() || IsTalkingWithNPC() || IsChangingFace() || // GetBoothState() != 0 || m_iBuddyId || m_pvp.iDuelState != DUEL_ST_NONE || // IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || IsPassiveMove()) // bRet = false; // break; case ActionCanDo.CANDO_CHANGESELECT: //if (m_playerLimits.test(PLAYER_LIMIT_NOCHANGESELECT)) // bRet = false; break; //case ActionCanDo.CANDO_SWITCH_PARALLEL_WORLD: // if (IsDead() || IsAboutToDie() || IsJumping() || IsFighting() || // IsMeleeing() || IsTrading() || IsUsingTrashBox() || IsTalkingWithNPC() || // IsChangingFace() || IsReviving() || IsSpellingMagic() || IsPicking() || // IsGathering() || IsRooting() || GetBoothState() != 0 || // m_iBuddyId || IsOperatingPet() || IsRebuildingPet() || IsUsingItem() || // GetShapeType() == PLAYERMODEL_DUMMYTYPE2 || IsPassiveMove()) // bRet = false; // break; } return bRet; } public int GetProfession() { return m_iProfession; } public void SetSelectedTarget(int id) { m_idSelTarget = id; } 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 true; } //public float GetSwimSpeedSev() //{ // float fSpeedSev = GetSwimSpeed(); // while (true) // { // if (!IsUnderWater()) break; // //CECWorld* pWorld = g_pGame.GetGameRun().GetWorld(); // //if (!pWorld) break; // const A3DVECTOR3 vPos = GetPos(); // float fTerrainHeight = pWorld.GetTerrainHeight(vPos); // float fWaterHeight = pWorld.GetWaterHeight(vPos); // if (fWaterHeight <= fTerrainHeight) break; // float fBorderLine = fWaterHeight - 2.0f; // if (vPos.y <= fBorderLine) break; // // ·þÎñÆ÷¶Ë½«Ë®ÃæÒÔÏÂ2Ã×ÒÔÉÏ´¦ÀíΪ run_speed£¨ÓÐÎÊÌ⣩ // // µ«Î´Ê¹ÓüÓËÙ¼¼ÄÜʱ swim_speed СÓÚ run_speed£¬ // // ¿ÉÒÔÔÚË®ÃæÒÔÏÂ2Ã×ÒÔÉÏ»ñÈ¡³¬¹ý swim_speed µÄËÙ¶È£¬Òò´Ë£¬´Ë´¦È¡Á½Õß½ÏСֵΪºÏÀí×ö·¨ // fSpeedSev = min(m_ExtProps.mv.run_speed, fSpeedSev); // break; // } // return fSpeedSev; //} } public enum StateAnim { Idle = 1, Walk = 2, Run = 3, Jump = 4 } // Mask of some special extend states which will influence host game logic. // Logic Influence Extned states [Flags] public enum Logic_Influence_Extned_states { LIES_SLEEP = 0x0001, LIES_STUN = 0x0002, LIES_ROOT = 0x0004, LIES_NOFGIHT = 0x0008, LIES_DISABLEFIGHT = 0x000B, } // ½øÈë»ùµØÐÅÏ¢ public struct FACTION_FORTRESS_ENTER { public int faction_id; public int role_in_war; // 0 : ÖÐÁ¢»ò²»ÔÚ»ùµØ 1:¹¥·½ 2: ÊØ·½ public int end_time; public FACTION_FORTRESS_ENTER(int faction_id, int role_in_war, int end_time) { this.faction_id = faction_id; this.role_in_war = role_in_war; this.end_time = end_time; } } public struct EXPToUpLevel { public int NeededExp; public EXPToUpLevel(int neededExp) { NeededExp = neededExp; } } public struct NPCINFO { public string Name; // Movement properties public int CurrentHealth; public int MaxHealth; // Attacking properties public int IDNPC; // Attacking properties public NPCINFO(string name, int currentHealth, int maxHealth, int idnpc) { Name = name; CurrentHealth = currentHealth; MaxHealth = maxHealth; IDNPC = idnpc; } }; // PVP infomation public struct PVPINFO { public bool bEnable; // PVP switch public uint dwCoolTime; public uint dwMaxCoolTime; public bool bFreePVP; // Free PVP flag, ignore bEnable flag public bool bInPVPCombat; // true, in PVP combat public int iDuelState; // Duel state public int idDuelOpp; // Duel opponent public int iDuelTimeCnt; // Duel time counter public int iDuelRlt; // Duel result. 0, no defined; 1-win; 2-lose; 3-draw }; // Current ground information public struct GNDINFO { public float fGndHei; // Ground height public float fWaterHei; // Water height public A3DVECTOR3 vGndNormal; // Terrain normal public bool bOnGround; // On ground flag }; public struct InfoHostPlayer { public string NameHostPlayer; public InfoHostPlayer(string name) { NameHostPlayer = name; } } // Behavior id used by CanDo() public static class ActionCanDo { public const int CANDO_SITDOWN = 0, CANDO_MOVETO = 1, CANDO_MELEE = 2, CANDO_ASSISTSEL = 3, CANDO_FLY = 4, CANDO_PICKUP = 5, CANDO_TRADE = 6, CANDO_PLAYPOSE = 7, CANDO_SPELLMAGIC = 8, CANDO_USEITEM = 9, CANDO_JUMP = 10, CANDO_FOLLOW = 11, CANDO_GATHER = 12, CANDO_BOOTH = 13, CANDO_FLASHMOVE = 14, CANDO_BINDBUDDY = 15, CANDO_DUEL = 16, CANDO_SUMMONPET = 17, CANDO_CHANGESELECT = 18, CANDO_REBUILDPET = 19, CANDO_SWITCH_PARALLEL_WORLD = 20; }