using BrewMonster.Network; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using PerfectWorld.Scripts.Managers; using PerfectWorld.Scripts.Player; using PerfectWorld.Scripts.Task; using System; using System.IO; using System.Runtime.InteropServices; using System.Text; using TMPro; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; using Scene = UnityEngine.SceneManagement.Scene; public class CECHostPlayer : EC_Player { [SerializeField] private TextMeshPro txtName; [SerializeField] private CharacterController controller; [SerializeField] private Joystick joystick; [SerializeField] private Button btnJump; [SerializeField] private Button btnRun; [SerializeField] private Transform parentModel; PlayerStateMachine _playerStateMachine; PlayerMoveState _moveState; PlayerIdleState _idleState; CECHostMove m_MoveCtrl; CECHPWorkMan m_pWorkMan; // Host work manager uint m_dwLIES; // Logic-influence extend states float playerSpeed = 5.0f; float jumpHeight = 1.5f; float gravityValue = -9.81f; StateAnim stateAnim = StateAnim.Idle; Vector3 playerVelocity; bool isGrounded = false; bool isRun = false; Vector3 m_vLastSevPos; // ====== Ground cast config ====== [Header("Ground Cast")] [Tooltip("Khoảng thêm ngoài skinWidth để SphereCast xuống (m ngắn)")] [SerializeField] private float extraGroundDistance = 0.05f; [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; [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; 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 void SetModelHostPlayer() { m_pPlayerModel = NPCManager.Instance.GetModelPlayer(); Scene scene = SceneManager.GetSceneByName("WorldRender"); SceneManager.MoveGameObjectToScene(m_pPlayerModel, scene); m_pPlayerModel.transform.SetParent(parentModel); m_pPlayerModel.transform.localPosition = Vector3.zero; m_pPlayerModel.SetActive(true); } private void Start() { _playerStateMachine.InitState(_idleState); // btnJump.onClick.AddListener(HandleJump); } private void Update() { //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(); } 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); // 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) { transform.forward = move; m_MoveCtrl.GroundMove(Time.deltaTime); m_MoveCtrl.SendMoveCmd(transform.position, controller.velocity, (int)GPMoveMode.GP_MOVE_RUN); } else { } Vector3 finalMove = (move * playerSpeed) + (playerVelocity.y * Vector3.up); controller.Move(finalMove * Time.deltaTime); } private void JoystickRelease(JoystickRealeaseEvent joystickRealeaseEvent) { _playerStateMachine.ChangeState(_idleState); } private 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) { Debug.LogWarning("HoangDev : ProcessMessageProcessMessageProcessMessage"); var msg = (int)Msg.dwMsg; 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; } } public void OnMsgHstItemOperation(ECMSG Msg) { var data = Msg.dwParam1 as byte[]; int cmd = Convert.ToInt32(Msg.dwParam2); switch (cmd) { 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.PACK_INVENTORY, index_inv, true); var equipItem = EC_Inventory.GetItem(EC_Inventory.PACK_EQUIPMENT, index_equip, true); if (invItem != null) { invItem.Package = EC_Inventory.PACK_EQUIPMENT; invItem.Slot = index_equip; EC_Inventory.SetItem(EC_Inventory.PACK_EQUIPMENT, index_equip, invItem); } if (equipItem != null) { equipItem.Package = EC_Inventory.PACK_INVENTORY; equipItem.Slot = index_inv; EC_Inventory.SetItem(EC_Inventory.PACK_INVENTORY, 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); PerfectWorld.Scripts.Managers.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: { Debug.Log("[Inventory] OWN_IVTR_DATA received"); PerfectWorld.Scripts.Managers.EC_Inventory.LogInventoryPacket("OWN_IVTR_DATA", data, hostId); break; } case CommandID.OWN_IVTR_DETAIL_DATA: { Debug.Log("[Inventory] OWN_IVTR_DETAIL_DATA received"); PerfectWorld.Scripts.Managers.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 (PerfectWorld.Scripts.Managers.EC_IvtrItem.TryParseInventoryDetail(data, out var pkg, out var size, out var items)) { PerfectWorld.Scripts.Managers.EC_Inventory.UpdatePack(pkg, size, items); } } 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 OnMsgHstGoto(in ECMSG Msg) { Debug.Log("HoangDev :OnMsgHstGoto"); cmd_notify_hostpos pCmd = (cmd_notify_hostpos)Msg.dwParam1; } private void SetPos(Vector3 pos) { transform.position = pos; } public void SetStatusRun(bool value) { if (!isGrounded) { Debug.LogError("Player not in ground"); return; } isRun = value; } public void InitCharacter(cmd_self_info_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); //} SetPlayerInfor(new INFO(role.cid, role.crc_e, role.crc_c)); 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); joystick = FindAnyObjectByType(); EventBus.Subscribe(JoystickRelease); EventBus.Subscribe(JoystickStartDrag); if (TryGetComponent(out var visual)) { visual.InitHostPlayerEventDoneHandler(); } // Create work manager m_pWorkMan = new CECHPWorkMan(this); if (m_pWorkMan == null) { return; } } 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 = g_pGame.GetGameRun().GetWorld().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) { // 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 = g_pGame.GetGameRun().GetWorld().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_ST_INDUEL && m_pvp.idDuelOpp == idTarget) // return 1; // else if (m_pvp.iDuelState == 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; } private float A3d_Magnitude(A3DVECTOR3 v) { return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } 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; 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 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 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, }