2481 lines
93 KiB
C#
2481 lines
93 KiB
C#
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 BrewMonster.PerfectWorld.Scripts.Vfx;
|
|
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;
|
|
using BrewMonster.Scripts.World;
|
|
|
|
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
|
|
|
|
bool m_bChangingFace; // true, host is changing face
|
|
private int m_iRoleCreateTime;
|
|
private int m_iRoleLastLoginTime; // Role last login time
|
|
private int m_iAccountTotalCash;
|
|
|
|
private List<CECObject> m_aTabSels = new List<CECObject>();
|
|
private List<CECSkill> m_aPtSkills = new List<CECSkill>();
|
|
private List<CECSkill> m_aPsSkills = new List<CECSkill>();
|
|
private List<CECSkill> m_aEquipSkills = new List<CECSkill>();
|
|
private List<CECSkill> m_aGoblinSkills = new List<CECSkill>();
|
|
|
|
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 BaseVfxObject m_pSelectedGFX;
|
|
|
|
public bool IsChangingFace() { return m_bChangingFace; }
|
|
|
|
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<Camera>();
|
|
}
|
|
|
|
_playerStateMachine.InitState(_idleState);
|
|
// btnJump.onClick.AddListener(HandleJump);
|
|
}
|
|
|
|
protected override void Update()
|
|
{
|
|
base.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<CECObject>();
|
|
|
|
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);
|
|
|
|
// Update GFXs
|
|
UpdateGFXs(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<uint>((byte[])Msg.dwParam1);
|
|
int offset = sizeof(uint);
|
|
int skillSize = Marshal.SizeOf<cmd_skill_data.SKILL>();
|
|
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<cmd_skill_data.SKILL>((byte[])Msg.dwParam1, offset);
|
|
offset += skillSize;
|
|
}
|
|
if (pCmd.skill_list == null)
|
|
{
|
|
BMLogger.LogError("OnMsgHstSkillData: cmd is null");
|
|
return;
|
|
}
|
|
|
|
/* List<SkillShortCutConfig> skillSCConfigArray1 = new List<SkillShortCutConfig>();
|
|
List<SkillShortCutConfig> skillSCConfigArray2 = new List<SkillShortCutConfig>();
|
|
List<SkillGrpShortCutConfig> skillGrpSCConfigArray1 = new List<SkillGrpShortCutConfig>();
|
|
List<SkillGrpShortCutConfig> skillGrpSCConfigArray2 = new List<SkillGrpShortCutConfig>();*/
|
|
|
|
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<cmd_self_info_00>((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<CDlgAutoHelp *>(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<cmd_host_attacked>(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<cmd_host_attack_result>(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<EC_InventoryUI>();
|
|
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<pickupItem>();
|
|
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<EC_InventoryUI>();
|
|
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<EC_InventoryUI>();
|
|
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<EC_InventoryUI>();
|
|
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<CSNetwork.GPDataType.cmd_get_own_money>(data);
|
|
var ui = GameObject.FindFirstObjectByType<BrewMonster.Scripts.Managers.EC_InventoryUI>();
|
|
if (ui == null)
|
|
{
|
|
var all = Resources.FindObjectsOfTypeAll<BrewMonster.Scripts.Managers.EC_InventoryUI>();
|
|
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<CSNetwork.GPDataType.player_cash>(data);
|
|
var ui = GameObject.FindFirstObjectByType<BrewMonster.Scripts.Managers.EC_InventoryUI>();
|
|
if (ui == null)
|
|
{
|
|
var all = Resources.FindObjectsOfTypeAll<BrewMonster.Scripts.Managers.EC_InventoryUI>();
|
|
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<cmd_notify_hostpos>(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<cmd_select_target>(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<CharacterController>();
|
|
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<Joystick>();
|
|
EventBus.Subscribe<JoystickRealeaseEvent>(JoystickRelease);
|
|
EventBus.Subscribe<JoystickPressEvent>(JoystickStartDrag);
|
|
if (TryGetComponent<PlayerVisual>(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;
|
|
}
|
|
|
|
LoadGfx();
|
|
}
|
|
|
|
public async void LoadGfx()
|
|
{
|
|
// Load GFX
|
|
var gfxCaster = EC_Game.GetGFXCaster();
|
|
// m_pMoveTargetGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_MOVETARGET));
|
|
m_pSelectedGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_SELECTED));
|
|
// m_pHoverGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_CURSORHOVER));
|
|
// m_pFloatDust = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_FLOATING_DUST));
|
|
|
|
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<JoystickRealeaseEvent>(JoystickRelease);
|
|
EventBus.Unsubscribe<JoystickPressEvent>(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
|
|
|
|
|
|
|
|
#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;
|
|
//}
|
|
|
|
void UpdateGFXs(float dwDeltaTime)
|
|
{
|
|
// if (m_pLevelUpGFX)
|
|
// m_pLevelUpGFX->SetParentTM(GetAbsoluteTM());
|
|
|
|
// if (m_pHoverGFX)// && m_idCurHover != m_idSelTarget)
|
|
// {
|
|
// if (!IsChangingFace() && (ISPLAYERID(m_idCurHover) || ISNPCID(m_idCurHover)))
|
|
// {
|
|
// CECObject* pObject = pWorld->GetObject(m_idCurHover, 1);
|
|
// if (pObject)
|
|
// {
|
|
// if (m_pHoverGFX->GetState() == ST_STOP)
|
|
// m_pHoverGFX->Start();
|
|
//
|
|
// m_pHoverGFX->SetParentTM(pObject->GetAbsoluteTM());
|
|
// }
|
|
// else
|
|
// m_pHoverGFX->Stop();
|
|
// }
|
|
// else
|
|
// m_pHoverGFX->Stop();
|
|
// }
|
|
|
|
if (m_pSelectedGFX)
|
|
{
|
|
if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || GPDataTypeHelper.ISNPCID(m_idSelTarget)))
|
|
{
|
|
var pObject =EC_ManMessageMono.Instance?.GetObject(m_idSelTarget, 1);
|
|
if (pObject)
|
|
{
|
|
if (m_pSelectedGFX.GetState() == GFX_STATE.ST_STOP)
|
|
m_pSelectedGFX.Play();
|
|
|
|
// m_pSelectedGFX.SetParentTM(pObject.GetAbsoluteTM());
|
|
m_pSelectedGFX.transform.parent = pObject.transform;
|
|
m_pSelectedGFX.transform.localPosition = Vector3.zero;
|
|
}
|
|
else
|
|
m_pSelectedGFX.Stop();
|
|
}
|
|
else
|
|
m_pSelectedGFX.Stop();
|
|
}
|
|
|
|
// if (m_pFloatDust)
|
|
// {
|
|
// A3DTerrainWater* pWater = g_pGame->GetGameRun()->GetWorld()->GetTerrainWater();
|
|
//
|
|
// if (pWater->IsUnderWater(m_CameraCoord.GetPos()))
|
|
// {
|
|
// if (m_pFloatDust->GetState() == ST_STOP)
|
|
// {
|
|
// m_pFloatDust->Start(true);
|
|
// m_pFloatDust->TickAnimation(2000);
|
|
// }
|
|
//
|
|
// m_pFloatDust->SetParentTM(GetAbsoluteTM());
|
|
// }
|
|
// else if (m_pFloatDust->GetState() != ST_STOP)
|
|
// m_pFloatDust->Stop();
|
|
// }
|
|
// UpdateMonsterSpiritGfx(dwDeltaTime);
|
|
}
|
|
|
|
// Level up
|
|
public void LevelUp()
|
|
{
|
|
// CECGameSession *pSession = g_pGame->GetGameSession();
|
|
//
|
|
// m_BasicProps.iLevel++;
|
|
// g_pGame->GetGameRun()->AddFixedMessage(FIXMSG_LEVELUP, m_BasicProps.iLevel);
|
|
//
|
|
// // Get all extend properties
|
|
// pSession->c2s_CmdGetExtProps();
|
|
|
|
// if (m_pLevelUpGFX)
|
|
// m_pLevelUpGFX->Start(true);
|
|
PlayGfx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_LEVELUP), null, 1f,1);//PLAYERMODEL_TYPEALL
|
|
|
|
// // Popup notify bubble text
|
|
// BubbleText(BUBBLE_LEVELUP, 0);
|
|
//
|
|
// // Notify my friends that my level changed
|
|
// ACHAR szInfo[40];
|
|
// a_sprintf(szInfo, _AL("L%d"), m_BasicProps.iLevel);
|
|
//
|
|
// for (int i=0; i < m_pFriendMan->GetGroupNum(); i++)
|
|
// {
|
|
// CECFriendMan::GROUP* pGroup = m_pFriendMan->GetGroupByIndex(i);
|
|
// for (int j=0; j < pGroup->aFriends.GetSize(); j++)
|
|
// {
|
|
// CECFriendMan::FRIEND* pFriend = pGroup->aFriends[j];
|
|
// if (pFriend->IsGameOnline())
|
|
// {
|
|
// pSession->SendPrivateChatData(pFriend->GetName(),
|
|
// szInfo, GNET::CHANNEL_USERINFO, pFriend->id);
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// if (GetBasicProps().iLevel==30)
|
|
// {
|
|
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
|
|
// pGameUI->AddChatMessage(pGameUI->GetStringFromTable(9638), GP_CHAT_SYSTEM);
|
|
// }
|
|
// if (GetBasicProps().iLevel>31)
|
|
// {
|
|
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
|
|
// ((CDlgOnlineAward*)pGameUI->GetDialog("Win_AddExp2"))->RestartWhenLevelup();
|
|
// }
|
|
}
|
|
}
|
|
|
|
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;
|
|
} |