Files
test/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs
T
2026-04-06 13:39:39 +07:00

4175 lines
171 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.PerfectWorld.Scripts.Vfx;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Skills;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Runtime.InteropServices;
using PerfectWorld.Scripts.Managers.BrewMonster.Managers;
using CSNetwork;
using ModelRenderer.Scripts.Common;
using Unity.VisualScripting;
using DG.Tweening.Plugins;
using PerfectWorld.Scripts.Managers;
namespace BrewMonster
{
public abstract partial class CECPlayer : CECObject
{
[SerializeField] protected Transform parentModel;
[SerializeField] protected TextMeshProUGUI txtName;
[SerializeField] protected Transform pointCam;
[ResetStatic]
private static PLAYER_ACTION[] _default_actions;
[ResetStatic]
private static PLAYER_ACTION[] _turning_actions;
protected PLAYER_ACTION[] m_PlayerActions;
[SerializeField] internal INFO m_PlayerInfo;
public CECModel m_pPlayerCECModel;
protected GameObject m_pPlayerModel => m_pPlayerCECModel.m_pPlayerModel;
public bool IsPlayerModelReady
{
get;
protected set;
}
protected float rotationSpeed = 5;
internal int m_iMoveMode; // Player's move mode
[SerializeField] internal int m_idSelTarget;
[SerializeField] internal int m_idCurHover; // ID of object under cursor
protected int m_iShape; // Ñ¡ÖÐÄ¿±êµÄID
protected uint m_dwStates; // Player's basic states
protected PVPINFO m_pvp; // pvp information
// 当前攻击方式 // Action type for attack animation
protected uint m_uAttackType;
protected int[] m_aEquips;
protected ROLEEXTPROP m_ExtProps; // Extend properties
protected int m_iFashionWeaponType;
protected float m_fTouchRad = 0.3f; // Touch radius
protected bool m_bWeaponAttached;
protected bool m_bFight;
protected int m_iBattleCamp = Player_camp_in_battle.GP_BATTLE_CAMP_NONE; // Battle this player belongs to
byte m_factionPVPMask; // pvp mask
protected uint m_dwResFlags; // pvp mask
protected ROLEBASICPROP m_BasicProps;
public int m_iMoveEnv = Move_environment.MOVEENV_GROUND; // Move environment
public bool m_bWalkRun = true;
public bool m_bInSanctuary = true;
public A3DAABB m_aabbServer = new A3DAABB(); // Óë·þÎñÆ÷±£³ÖÒ»ÖµÄaabb£¬ ²»ÊÜËõ·ÅÓ°Ïì
public A3DAABB m_aabb = new A3DAABB(); // Player's aabb£¬ÓÃÓÚÏÔʾµÄaabb£¬ÊÜËõ·ÅÓ°Ïì
protected bool m_bCastShadow; // flag indicates whether it will cast shadow
public int m_iProfession; // Profession
public float m_fScaleBySkill;
public int m_iGender; // Gender
protected bool m_bFashionMode;
public bool m_bShowWeapon;
public uint[] m_aExtStates = new uint[OBJECT_EXT_STATE_COUNT]; // Visible extend states from server
public uint[] m_aExtStatesShown = new uint[OBJECT_EXT_STATE_COUNT]; // Visible extend states currently shown
private QueueActionEvent queueActionEvent;
protected static PLAYER_LEVELEXP_CONFIG _player_levelup_exp;
protected CECPlayerActionController m_pActionController;
protected enumWingType m_wingType = enumWingType.WINGTYPE_FLYSWORD;
protected int m_idCurSkillTarget;
protected CECSkill m_pCurSkill;
protected int m_idFaction; // ID of player's faction
protected int m_idForce; // id of the player's force
protected BATTLEINFO m_BattleInfo; // Battle information / 战斗信息
protected int NUM_WEAPON_TYPE = 15;
public static readonly int[] m_sciStateIDForStateAction = { 117 };
private static Dictionary<uint, PLAYER_ACTION_INFO_CONFIG> _default_skill_actions
= new Dictionary<uint, PLAYER_ACTION_INFO_CONFIG>();
protected int m_iBoothState = 0; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth
public int m_idFRole = GNETRoles._R_UNMEMBER; // ID of player's faction role
protected int m_idCountry = 0; // ¹úÕ½ÕóÓª id
public static int MAX_REINCARNATION = 2;
protected List<int> m_aCurEffects = new List<int>(); // Current effects
protected byte m_ReincarnationCount = 0;
protected string m_strName; // Player name
// 需要是可能 || Need is possible
protected bool m_bHangerOn = false;
protected int m_iCurAction;
protected bool m_bAboutToDie = false;
public bool m_bCandHangerOn = false;
public bool m_bPetInSanctuary = false; // true, the pet pet of the player is in sanctuary
//The ID of the currently summoned pet
protected int m_idCurPet = 0;
public List<IconState> m_aIconStates = new List<IconState>();
protected byte m_byPariahLvl = 0; // Pariah level
public RIDINGPET m_RidingPet; // Riding pet information
public GameObject m_pPetModel = null; // Pet model
public RIDINGPET m_CandPet;// ID of candidate pet
A3DVECTOR3 m_vNamePos; // Æï³Ë×´Ì¬Íæ¼ÒÐÕÃûµÄµ÷Õû
// ÒÀ¸½ÀàÐÍ
AttachMode m_AttachMode = AttachMode.enumAttachNone;
// ÒÀ¸½Õß»ò±»ÒÀ¸½Õßid
protected int m_iBuddyId;
protected int m_idCandBuddy; // ID of candidate buddy
protected EC_ManPlayer m_pPlayerMan => EC_ManMessageMono.Instance?.GetECManPlayer; // Player manager
protected Transform playerTransform => _objectTransform ??= transform;
protected Transform m_HH_chibang = null;
protected Transform m_HH_feijian = null;
protected Transform m_CC_chibang = null;
protected Transform m_CC_feijian = null;
protected Transform m_Wing = null;
protected Transform m_Wing2 = null;
protected Vector3 m_delta_CC_to_HH = Vector3.zero;
public MOVECONST m_MoveConst; // Const used when moving control
public Move_Mode m_MoveMode;
public MOVECONST[] aMoveConsts = new MOVECONST[(int)PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER]
{
// ÎäÏÀ
// fStepHei fMinAirHei fMinWaterHei fShoreDepth fWaterSurf
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ·¨Ê¦
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// Î×ʦ
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// Ñý¾«
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ÑýÊÞ
new MOVECONST(0.8f, 1.6f, 0.3f, 1.8f, 0.7f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
// ´Ì¿Í
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// Óðâ
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ÓðÁé
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ½£Áé
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ÷ÈÁé
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// Ò¹Ó°
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
// ÔÂÏÉ
new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f),
new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f),
};
public A3DVECTOR3[] aExts = new A3DVECTOR3[(int)PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER]
{
new A3DVECTOR3(0.4f, 0.9f, 0.4f), // ÎäÏÀ
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ·¨Ê¦
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Î×ʦ
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Ñý¾«
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.5f, 1.05f, 0.5f), // ÑýÊÞ
new A3DVECTOR3(0.3f, 0.9f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ´Ì¿Í
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Óðâ
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÓðÁé
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ½£Áé
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÷ÈÁé
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Ò¹Ó°
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÔÂÏÉ
new A3DVECTOR3(0.3f, 0.85f, 0.3f),
};
public string[] m_aShapeChineseName = new string[]
{
//human
"武侠男",
"武侠女",
"法师男",
"法师女",
// 汐族 巫师
"巫师男",
"巫师女",
// 妖族
"",
"妖精",
"妖兽男",
"",
// 汐族 刺客
"刺客男",
"刺客女",
// 羽族
"羽芒男",
"羽芒女",
"羽灵男",
"羽灵女",
// 灵族
"剑灵男",
"剑灵女",
"魅灵男",
"魅灵女",
// 职业变身模型
"白虎",
"火狐狸",
"影族变身男",
"影族变身女",
// 技能变身模型(此ID不可变,新模型请往后添加)
"金钱蛙",
"婚礼童男",
"婚礼童女",
"园艺区哨兵",
"树鸡",
"小魔虎",
"红色松鼠",
"陆化的海龟",
"新娘的表哥",
"哨兵傀儡",
"企鹅帝王",
"企鹅皇后",
"雪兔",
"泰迪熊",
"红色松鼠大",
"树鸡大",
"园艺区哨兵愤怒",
"园艺区哨兵沮丧",
"园艺区哨兵失落",
"雪兔电光",
"龙",
// 职业变身新模型
"熊猫",
"蝶羽狐",
// 默认摆摊模型
"男",
"女",
// 胧族
"夜影男",
"夜影女",
"月仙男",
"月仙女",
// 胧族职业变身
"胧族变身夜影男",
"胧族变身夜影女",
"胧族变身月仙男",
"胧族变身月仙女",
};
public static class Effect_type
{
public const int EFF_FACEPILL = 1;
}
private BaseVfxObject _levelUpVfx;
protected GameObject[] m_pModels = new GameObject[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
protected int[] m_aShapeID = new int[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
protected enum PLAYERMODEL_TYPE
{
PLAYERMODEL_MAJOR,
PLAYERMODEL_PROFESSION, // player profession related
PLAYERMODEL_DUMMYTYPE2, // player buff related
PLAYERMODEL_DUMMYTYPE3, // not use
PLAYERMODEL_MAX,
PLAYERMODEL_TYPEALL
};
public int PLAYERMODEL_GETTYPE(int iShape) => ((iShape & 0xff) >> 6);
public int PLAYERMODEL_GETID(int iShape) => (iShape & 0x3f);
protected GameObject GetDummyModel(int i) => (i!=(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR&&i<(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX) ? m_pModels[i]:null;
protected GameObject GetMajorModel() => m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR];
protected GameObject GetPetModel() => m_pPetModel;
protected CECModel GetPlayerModel() => m_pPlayerCECModel;
protected const int OBJECT_EXT_STATE_COUNT = 6;
protected bool IsMajorModel(GameObject pModel) => GetMajorModel() != null && pModel == GetMajorModel();
public enum WeaponHangerPosition
{
WEAPON_HANGER_HAND, // 左手
WEAPON_HANGER_SHOULDER, // 右手
};
WeaponHangerPosition m_weaponHangerPos = WeaponHangerPosition.WEAPON_HANGER_HAND;
protected void Awake()
{
m_PlayerActions = _default_actions;
m_iShape = 0;
m_aEquips = new int[(int)IndexOfIteminEquipmentInventory.SIZE_ALL_EQUIPIVTR];
queueActionEvent = new QueueActionEvent("", null, false, null, 200);
}
/// <summary>This function will get the coressponding model player for the player based on the profession and gender </summary>
public async Task SetPlayerModel(byte profession, byte gender)
{
// PC prefab used first child as model root; runtime spawns may have no children — avoid GetChild(0) OOB.
// PC 预制体用第一个子物体作模型根;运行时生成可能没有子物体 — 避免 GetChild(0) 越界
if (transform.childCount > 0)
parentModel = transform.GetChild(0);
else
parentModel = transform;
txtName = GetComponentInChildren<TextMeshProUGUI>();
if (transform.childCount >= 3)
{
pointCam = transform.GetChild(2);
}
// Initialize CECModel for hook system
// 初始化CECModel以支持挂点系统
await InitializePlayerCECModel(profession,gender);
// Cleanup old model if exists
// 清理旧模型(如果存在)
if (m_pPlayerCECModel != null && m_pPlayerModel != null)
{
}
Debug.Log($"[CECPlayer] SetPlayerModel: profession: {profession}, gender: {gender}");
Debug.Log($"[CECPlayer] SetPlayerModel: m_pPlayerCECModel: {m_pPlayerCECModel}");
Debug.Log($"[CECPlayer] SetPlayerModel: m_pPlayerModel: {m_pPlayerModel}");
Scene scene = SceneManager.GetActiveScene();
SceneManager.MoveGameObjectToScene(m_pPlayerModel, scene);
m_pPlayerModel.transform.SetParent(parentModel);
m_pPlayerModel.transform.localPosition = Vector3.zero;
m_pPlayerModel.SetActive(true);
m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR] = m_pPlayerModel;
m_iShape = 0;
// Set the player model ready flag
IsPlayerModelReady = true;
// Update visual components after model is set (with delay to ensure NamedAnimancerComponent is available)
// 设置模型后更新视觉组件(延迟以确保NamedAnimancerComponent可用)
StartCoroutine(UpdateVisualComponentsDelayed());
// Attach weapon after model is set
AttachWeapon();
RecreateActionController();
}
protected async Task<bool> QueueLoadDummyModel(int iShape, bool bAtOnce)
{
int iShapeType = PLAYERMODEL_GETTYPE(iShape);
int iShapeID = PLAYERMODEL_GETID(iShape);
// If model already loaded, use it directly.
if(m_aShapeID[iShapeType] == iShapeID && m_pModels[iShapeType])
{
ApplyShapeModelChange(m_pModels[iShapeType]);
return true;
}
// try to load a new dummy model
// if (bAtOnce || !IsLoadThreadReady())
// {
// CECModel* pDummyModel = NULL;
// if (!LoadDummyModel(iShape, &pDummyModel) || !pDummyModel)
// return false;
// if (!SetDummyLoadResult(iShape, pDummyModel))
// {
// A3DRELEASE(pDummyModel);
// return false;
// }
// }
// else
// {
// int iType = (m_iCID == OCID_HOST_NAVIGATER) ? MTL_ECM_HOST_NAVIGATER_DUMMY:MTL_ECM_PLAYER_DUMMY;
// QueueECModelForLoad(
// iType,
// m_PlayerInfo.cid,
// m_dwBornStamp,
// GetPos(),
// NULL,
// iShape);
// }
//not sure we need the check for IsLoadThreadReady()
GameObject pDummyModel = new GameObject("DummyModel");
pDummyModel = await NPCManager.Instance.GetDummyModel(iShapeID);
Scene scene = SceneManager.GetActiveScene();
SceneManager.MoveGameObjectToScene(pDummyModel, scene);
pDummyModel.transform.SetParent(parentModel);
pDummyModel.transform.localPosition = Vector3.zero;
pDummyModel.SetActive(true);
m_pModels[iShapeType] = pDummyModel;
m_aShapeID[iShapeType] = iShapeID;
ApplyShapeModelChange(pDummyModel);
return true;
}
protected void ApplyShapeModelChange(GameObject pModel)
{
// store and reset the attach state
int iBuddyId = m_iBuddyId;
bool bHangerOn = m_bHangerOn;
if (m_AttachMode != AttachMode.enumAttachNone) DetachBuddy(null, false);
// logic transform but no model changed
if(!pModel) pModel = GetMajorModel();
OnModelChange(pModel);
if(pModel && m_pPlayerModel && m_pPlayerModel != pModel)
{
// sync the position
//pModel->SetPos(m_pPlayerModel->GetPos());
// pModel->SetDirAndUp(m_pPlayerModel->GetDir(), m_pPlayerModel->GetUp());
pModel.transform.position = m_pPlayerModel.transform.position;
pModel.transform.rotation = m_pPlayerModel.transform.rotation;
// if (m_pPlayerModel.transform.forward != Vector3.zero)
// {
// Quaternion lookRot = Quaternion.LookRotation(m_pPlayerModel.transform.forward, m_pPlayerModel.transform.up);
// transform.rotation = lookRot;
// }
// TODO:sync wing
// CECModel* pWing = m_pPlayerModel->GetChildModel(_wing);
// m_pPlayerModel->RemoveChildModel(_wing, false);
// CECModel* pWing2 = m_pPlayerModel->GetChildModel(_wing2);
// m_pPlayerModel->RemoveChildModel(_wing2, false);
// if (m_wingType == WINGTYPE_FLYSWORD || m_wingType == WINGTYPE_WING) {
// if (pWing) {
// pModel->AddChildModel(
// _wing,
// false,
// UsingWing() ? "HH_chibang" : "HH_feijian",
// pWing,
// UsingWing() ? "CC_chibang" : "CC_feijian");
// }
// } else if (m_wingType == WINGTYPE_DOUBLEWHEEL) {
// if (pWing) {
// pModel->AddChildModel(
// _wing,
// false,
// _hh_left_foot,
// pWing,
// _cc_fenghuolun);
// }
// if (pWing2) {
// pModel->AddChildModel(
// _wing2,
// false,
// _hh_right_foot,
// pWing2,
// _cc_fenghuolun);
// }
// }
ShowWing(IsFlying());
// TODO: sync the effect
// typedef abase::hash_map<AString, GFXRECORD>::iterator GFXIter;
// for(GFXIter i=m_GfxRecords.begin();i!=m_GfxRecords.end();++i)
// {
// const GFXRECORD& rec = i->second;
// m_pPlayerModel->RemoveGfx(rec.strPath, rec.strHook);
// if (!pModel->GetGfx(rec.strPath, rec.strHook)){
// pModel->PlayGfx(rec.strPath, rec.strHook, rec.fScale);
// }
// }
}
// TODO:change the target
if (m_pPlayerModel != pModel){
// ClearShowExtendStates();
// if (IsMajorModel(m_pPlayerModel)){
// RemoveEquipGfx();
// }
DetachWeapon();
m_pPlayerModel.SetActive(false);
m_pPlayerCECModel.m_pPlayerModel = pModel;
pModel.SetActive(true);
AttachWeapon();
if (pModel != null){
//ShowExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
}
if (IsMajorModel(m_pPlayerModel)){
//AddEquipGfx();
}
RecreateActionController();
// RecreateBodyController();
}
// different ground mode
SetUseGroundNormal( ShouldUseGroundNormalForCurrentShapeModel() );
PlayAction(GetMoveStandAction(false, IsFighting()), true);
// Update NPCVisual's namedAnimancer reference when model changes
// 当模型更改时更新NPCVisual的namedAnimancer引用
UpdateVisualComponents();
// Todo: restore the attach state
// if (iBuddyId)
// {
// if( !bHangerOn )
// AttachBuddy(iBuddyId);
// else
// {
// CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(iBuddyId);
// if( pBuddy ) pBuddy->AttachBuddy(m_PlayerInfo.cid);
// }
// }
//TODO: ScaleBody
//ScaleBody(m_fScaleBySkill);
// սЧʱģѼأgfxɲš
// TODO: chariotwar
// CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
// if (IsHostPlayer() && pHost && pHost->GetBattleInfo().IsChariotWar())
// {
// CChariot* pChariot = pHost->GetChariot();
// if (pChariot && pChariot->IsUpdateState())
// {
// PlayGfx(res_GFXFile(RES_GFX_LEVELUP), NULL, 4.0, PLAYERMODEL_TYPEALL);
// BubbleText(BUBBLE_LEVELUP, 0);
// pChariot->UpdateState(0,0);// ָս־
// }
// }
}
bool ShouldUseGroundNormalForCurrentShapeModel()
{
return IsShapeModelChanged() && !IsTransofrmModelLikeHuman(GetProfession(), GetGender(), GetShapeID());
}
static bool IsTransofrmModelLikeHuman(int nChar, int nGender, int nModelID){
bool result = false;
int[] likeHumanModelArray = null;
int likeHumanModelCount = 0;
switch (nChar)
{
case (int)PROFESSION.PROF_YEYING:
if ((int)GENDER.GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = s_LikeHumanModel.Length;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
case (int)PROFESSION.PROF_YUEXIAN:
if ((int)GENDER.GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
}
if (likeHumanModelCount > 0){
// const int *begin = likeHumanModelArray;
// const int *end = likeHumanModelArray + likeHumanModelCount;
// if (std::find(begin, end, _GetProfessionTransformModelID(nChar, nGender, nModelID)) != end){
// result = true;
// }
foreach (int model in likeHumanModelArray)
{
if (model == nModelID)
{
result = true;
break;
}
}
}
return result;
}
protected virtual bool IsShapeModelChanged()
{
return m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR] != m_pPlayerModel;
}
/// <summary>
/// Update visual components (NPCVisual, PlayerVisual) when model changes
/// 当模型更改时更新视觉组件(NPCVisual、PlayerVisual
/// </summary>
private void UpdateVisualComponents()
{
// Use the current active player model as the search root
// 使用当前活动的玩家模型作为搜索根
GameObject modelRoot = m_pPlayerModel;
if (modelRoot == null)
{
BMLogger.LogWarning("CECPlayer: UpdateVisualComponents - _pPlayerModel is null, cannot update visual components");
return;
}
// Update NPCVisual if it exists
// 如果存在NPCVisual则更新它
NPCVisual npcVisual = GetComponent<NPCVisual>();
if (npcVisual != null)
{
npcVisual.RefreshNamedAnimancer(modelRoot);
}
// Update PlayerVisual if it exists
// 如果存在PlayerVisual则更新它
PlayerVisual playerVisual = GetComponentInChildren<PlayerVisual>();
if (playerVisual != null)
{
playerVisual.RefreshNamedAnimancer(modelRoot);
}
}
/// <summary>
/// Delayed update of visual components to ensure NamedAnimancerComponent is available
/// 延迟更新视觉组件以确保NamedAnimancerComponent可用
/// </summary>
private IEnumerator UpdateVisualComponentsDelayed()
{
// Wait one frame for NamedAnimancerComponent to be available
// 等待一帧以确保NamedAnimancerComponent可用
yield return null;
if (m_pPlayerModel == null)
yield break;
UpdateVisualComponents();
}
private async Task InitializePlayerCECModel(byte profession, byte gender)
{
if(m_pPlayerCECModel!= null && m_pPlayerCECModel.m_pPlayerModel != null)
{
m_pPlayerCECModel.InvalidateHookCache();
}
// Get or create CECModel instance
// 获取或创建CECModel实例
if (m_pPlayerCECModel == null)
{
m_pPlayerCECModel = new CECModel();
}
m_pPlayerCECModel.m_pPlayerModel = await NPCManager.Instance.GetModelPlayer(profession, gender);
// Find SkeletonBuilder component on model GameObject
// 在模型GameObject上查找SkeletonBuilder组件
SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren<SkeletonBuilder>();
if (skeletonBuilder == null)
{
// SkeletonBuilder might not be built yet, try to find it after a frame
// SkeletonBuilder可能尚未构建,尝试在一帧后查找
StartCoroutine(InitializePlayerCECModelDelayed());
return;
}
// Set references on CECModel
// 在CECModel上设置引用
m_pPlayerCECModel.SetSkeletonBuilder(skeletonBuilder);
m_pPlayerCECModel.SetTransform(m_pPlayerModel.transform);
// Initialize skeleton builder (ensures hooks are available)
// 初始化骨架构建器(确保挂点可用)
m_pPlayerCECModel.InitializeSkeletonBuilder();
}
public void OnModelChange(GameObject changeModel)
{
RefreshCECModel(changeModel);
}
public void RefreshCECModel(GameObject changeModel)
{
if (changeModel == null)
{
return;
}
m_pPlayerCECModel.SetSkeletonBuilder(changeModel.GetComponentInChildren<SkeletonBuilder>());
m_pPlayerCECModel.SetTransform(changeModel.transform);
m_pPlayerCECModel.InitializeSkeletonBuilder();
}
/// <summary>
/// Delayed initialization coroutine for cases where SkeletonBuilder builds after model load
/// 延迟初始化协程,用于SkeletonBuilder在模型加载后构建的情况
/// </summary>
private IEnumerator InitializePlayerCECModelDelayed()
{
// Wait one frame for SkeletonBuilder to be built
// 等待一帧以便SkeletonBuilder被构建
yield return null;
if (m_pPlayerModel == null)
yield break;
SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren<SkeletonBuilder>();
if (skeletonBuilder != null)
{
if (m_pPlayerCECModel == null)
{
m_pPlayerCECModel = new CECModel();
}
m_pPlayerCECModel.SetSkeletonBuilder(skeletonBuilder);
m_pPlayerCECModel.SetTransform(m_pPlayerModel.transform);
// Initialize skeleton builder (ensures hooks are available)
// 初始化骨架构建器(确保挂点可用)
m_pPlayerCECModel.InitializeSkeletonBuilder();
}
else
{
BMLogger.LogWarning($"[CECPlayer] SkeletonBuilder not found on player model after delay. Hook system may not work.");
}
}
public virtual void OnMsgPlayerExtState(ECMSG Msg)
{
if (Convert.ToInt32(Msg.dwParam2) == CommandID.UPDATE_EXT_STATE)
{
cmd_update_ext_state pCmd = GPDataTypeHelper.FromBytes<cmd_update_ext_state>((byte[])Msg.dwParam1);
if (pCmd.id == m_PlayerInfo.cid)
{
SetNewExtendStates(0, pCmd.states, (int)OBJECT_EXT_STATE.OBJECT_EXT_STATE_COUNT);
}
}
else if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY)
{
cmd_icon_state_notify cmd = new cmd_icon_state_notify();
if (!cmd.Initialize((byte[])Msg.dwParam1))
{
return;
}
if (cmd.id == m_PlayerInfo.cid)
{
m_aIconStates = cmd.states;
if (m_aIconStates.Count > 1)
{
m_aIconStates.Sort((a, b) =>
{
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
});
}
}
}
}
public virtual void SetNewExtendStates(int start, uint[] pData, int count)
{
if(pData == null || start + count > OBJECT_EXT_STATE_COUNT)
{
return;
}
ShowExtendStates(start, pData, count);
Array.Copy(pData, start, m_aExtStates, start, count);
if(GetExtState(111))
{
// ת ̫
m_PlayerActions = _turning_actions;
}
else
{
m_PlayerActions = _default_actions;
}
}
void ShowExtendStates(int start, uint[] pData, int count, bool bIgnoreOptimize=false )
{
if(pData == null || start + count > OBJECT_EXT_STATE_COUNT)
{
return;
}
if (!IsAllResReady() || !GetMajorModel())
return;
//TODO: Implement optimization
// if (!bIgnoreOptimize &&
// !CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID()))
// return;
//static const char* szBasePath = "߻\\״̬Ч\\";
const int bitSize = sizeof(uint) * 8;
BMLogger.LogError($"[CECPlayer] ShowExtendStates: start: {start}, count: {count}, bitSize: {bitSize}");
for (int index = 0; index<count; index++)
{
int idState = index + start;
for (int i=0; i < bitSize; i++)
{
int dwMask = 1 << i;
int dwFlag1 = (int)(m_aExtStatesShown[idState] & dwMask);
int dwFlag2 = (int)(pData[index] & dwMask);
if ((dwFlag1 == 0 && dwFlag2 == 0) || (dwFlag1 != 0 && dwFlag2 != 0))
continue;
BMLogger.LogError($"[CECPlayer] ShowExtendStates: idState: {idState}, bitIndex: {i}, i + idState*bitSize: {i + idState * bitSize}");
//TODO: Implement visible state
// const GNET::VisibleState* pvs = GNET::VisibleState::Query(m_iProfession, i + idState*bitSize);
// if (!pvs)
// continue;
// AString strGFXFile = pvs->GetEffect();
// if (!strGFXFile.GetLength())
// continue;
// strGFXFile = szBasePath + strGFXFile;
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState*bitSize))
// continue;
if (dwFlag1 != 0)
{
if (SkillGfxMan.InstanceSub != null)
{
SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx();
}
// //TODO: Implement remove old state
// CECModel *pWeapon = NULL;
// bool bLeft (false);
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
// {
// // Ч
// if (pWeapon)
// {
// const char * gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
// pWeapon->RemoveGfx(strGFXFile, gfxHook);
// }
// }
// else
{
// ģЧ
// RemoveGfx(strGFXFile, pvs->GetHH(), PLAYERMODEL_TYPEALL);
}
}
// else
// {
// // Add new state
// const char* szHH = pvs->GetHH();
// float fScale;
// if (stricmp("HH_Head", szHH) == 0)
// fScale = GetMajorModel()->GetOuterData()[0];
// else if (stricmp("HH_Spine", szHH) == 0)
// fScale = GetMajorModel()->GetOuterData()[1];
// else
// fScale = 1.0f;
// CECModel *pWeapon = NULL;
// bool bLeft (false);
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
// {
// if (pWeapon)
// {
// const char *gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
// pWeapon->PlayGfx(strGFXFile, gfxHook, fScale);
// }
// }
// else
// {
// PlayGfx(strGFXFile, pvs->GetHH(), fScale, PLAYERMODEL_TYPEALL, true);
// }
// }
}
}
Array.Copy(pData, start, m_aExtStatesShown, start, count);
}
bool GetExtState(int n)
{
const int bitSize = sizeof(uint) * 8;
const int totalBitSize = bitSize * OBJECT_EXT_STATE_COUNT;
if(n < 0 || n >= totalBitSize)
return false;
int index = n / bitSize;
int bitOffset = n % bitSize;
return (m_aExtStates[index] & (1 << bitOffset)) != 0;
}
public virtual void SetUpPlayer()
{
m_dwResFlags = 0;
m_iFashionWeaponType = -1;
m_uAttackType = DEFAULT_ACTION_TYPE;
}
public void SetPlayerInfor(INFO playinfo)
{
m_PlayerInfo = playinfo;
}
public INFO GetPlayInfo()
{
return m_PlayerInfo;
}
public void CalcPlayerAABB()
{
int iIndex = m_iProfession * GENDER.NUM_GENDER + m_iGender;
m_aabb.Extents = aExts[iIndex] * m_fScaleBySkill;
m_aabbServer.Extents = aExts[iIndex];
m_MoveConst = aMoveConsts[iIndex];
}
public static async Task<bool> LoadPlayerSkin(GameObject aSkins, int index, string szFile)
{
// these are LOD suffix
string[] suffix1 = { "一?", "二级", "三级" };
string[] suffix2 = { "", "二级", "三级" };
string szSkinFile = "";
if (index == EC_Player_Skin_Const.SKIN_BODY_INDEX || index == EC_Player_Skin_Const.SKIN_HEAD_INDEX)
szSkinFile = $"{szFile}{suffix2[0]}";
else
szSkinFile = $"{szFile}{suffix1[0]}";
aSkins = await AddressableManager.Instance.LoadPrefabAsync(szSkinFile);
if (aSkins == null)
return false;
return true;
}
public static void InitStaticRes()
{
BuildActionList();
DATA_TYPE dt = default;
_player_levelup_exp = (PLAYER_LEVELEXP_CONFIG)ElementDataManProvider.GetElementDataMan()
.get_data_ptr(202, ID_SPACE.ID_SPACE_CONFIG, ref dt);
}
public bool IsDead()
{
return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0;
}
public bool IsInvisible()
{
return (m_dwStates & PlayerNPCState.GP_STATE_INVISIBLE) != 0;
}
public bool IsInSanctuary()
{
return m_bInSanctuary;
}
public bool IsValidAction(int iIndex)
{
return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false;
}
public int GetCharacterID()
{
return m_PlayerInfo.cid;
}
/// <summary>
/// Get player's CECModel instance
/// 获取玩家的CECModel实例
/// </summary>
/// <returns>CECModel instance or null / CECModel实例,未找到返回null</returns>
public CECModel GetPlayerCECModel()
{
return m_pPlayerCECModel;
}
/// <summary>
/// Get hook Transform by name (convenience method)
/// 根据名称获取挂点变换(便捷方法)
/// </summary>
/// <param name="hookName">Hook name / 挂点名称</param>
/// <param name="recursive">Search recursively / 递归搜索</param>
/// <returns>Hook Transform or null / 挂点变换,未找到返回null</returns>
public Transform GetHook(string hookName, bool recursive = true)
{
CECModel model = GetPlayerCECModel();
return model?.GetHook(hookName, recursive);
}
private static void BuildActionList()
{
if (_default_actions == null)
{
Dictionary<string, PLAYER_ACTION_INFO_CONFIG> actionMap =
new Dictionary<string, PLAYER_ACTION_INFO_CONFIG>(100);
Dictionary<string, PLAYER_ACTION_INFO_CONFIG> skillActionMap =
new Dictionary<string, PLAYER_ACTION_INFO_CONFIG>(100);
elementdataman dataman = ElementDataManProvider.GetElementDataMan();
PLAYER_ACTION_INFO_CONFIG data;
int count = dataman.get_data_num(ID_SPACE.ID_SPACE_CONFIG);
DATA_TYPE dt = default;
uint id = 0;
for (int i = 0; i < count; ++i)
{
id = dataman.get_data_id(ID_SPACE.ID_SPACE_CONFIG, i, ref dt);
if (dt != DATA_TYPE.DT_PLAYER_ACTION_INFO_CONFIG)
continue;
data = (PLAYER_ACTION_INFO_CONFIG)dataman.get_data_ptr(id, ID_SPACE.ID_SPACE_CONFIG, ref dt);
if (!string.IsNullOrEmpty(data.ActionName))
{
if (!actionMap.TryAdd(data.ActionName, data))
{
}
}
if (!string.IsNullOrEmpty(data.ActionName))
{
if (!skillActionMap.TryAdd(data.Name, data))
{
}
}
}
///
CECStringTab actionNames = new CECStringTab();
actionNames.Init("actions_player", false);
_default_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
for (int i = 0; i < _default_actions.Length; i++)
{
_default_actions[i].type = (PLAYER_ACTION_TYPE)i;
string szName = actionNames.GetANSIString(i);
if (!string.IsNullOrEmpty(szName))
{
if (actionMap.TryGetValue(szName, out var it))
{
_default_actions[i].data = it;
}
}
}
if (_turning_actions != null) _turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
_turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
if (actionMap.TryGetValue("自身旋转", out PLAYER_ACTION_INFO_CONFIG turningData))
{
for (int i = 0; i < (int)PLAYER_ACTION_TYPE.ACT_MAX; i++)
{
if (i < (int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE ||
i > (int)PLAYER_ACTION_TYPE.ACT_REVIVE)
{
// Dùng hành động xoay thay thế hành động thường
_turning_actions[i].type = (PLAYER_ACTION_TYPE)i;
_turning_actions[i].data = turningData;
}
else
{
// Dùng hành động mặc định
_turning_actions[i] = _default_actions[i];
}
}
}
uint idSkill = 0;
while (true)
{
idSkill = ElementSkill.NextSkill(idSkill);
if (idSkill == 0)
break;
string skillName = ElementSkill.GetName(idSkill);
if (!string.IsNullOrEmpty(skillName))
{
var checkExist = skillActionMap.TryGetValue(skillName, out PLAYER_ACTION_INFO_CONFIG data1);
if (checkExist)
{
if(!_default_skill_actions.ContainsKey(idSkill))
{
_default_skill_actions.Add(idSkill, data1);
}
#if DEBUG_OUTPUT_ACTIONS
for (int n = 0; n < PlayerSkillAction.NUM_WEAPON_TYPE; n++)
{
var suffix = data.action_weapon_suffix[n].suffix;
if (!string.IsNullOrEmpty(suffix))
{
Debug.Log($"{data.action_prefix}_Ò÷³ª_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÆð_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÂä_{suffix}");
}
}
#endif
continue;
}
}
// ❌ not found
// Debug.LogWarning($"CECPlayer::BuildActionList() Failed to find skill action {idSkill}!");
}
}
}
public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false)
{
return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue);
}
public bool PlayAction(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false)
{
return PlayActionWithConfig(iAction, actionConfigID, bRestart, iTransTime, bQueue);
}
private bool PlayActionWithConfig(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200,
bool bQueue = false)
{
if (iAction < 0 || iAction >= (int)PLAYER_ACTION_TYPE.ACT_MAX)
{
return false;
}
if (actionConfigID > 0)
{
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
var p = ElementDataManProvider.GetElementDataMan()
.get_data_ptr((uint)actionConfigID, ID_SPACE.ID_SPACE_CONFIG, ref dt);
if (dt == DATA_TYPE.DT_PLAYER_ACTION_INFO_CONFIG)
{
PLAYER_ACTION actionConfig;
actionConfig.type = (PLAYER_ACTION_TYPE)iAction;
actionConfig.data = (PLAYER_ACTION_INFO_CONFIG)p;
return PlayActionWithConfig(iAction, actionConfig, bRestart, iTransTime, bQueue);
}
else
{
}
}
return PlayActionWithConfig(iAction, m_PlayerActions[iAction], bRestart, iTransTime, bQueue);
}
const int COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX = 3;
private bool PlayActionWithConfig(int iAction, in PLAYER_ACTION actionConfig,
bool bRestart = true, int iTransTime = 200, bool bQueue = false)
{
m_iCurAction = iAction;
PLAYER_ACTION action = actionConfig;
int weapon_type = GetShowingWeaponType();
string szAct = "";
string szShapeName = "";
GetShapeName(ref szShapeName);
if(m_pActionController != null)
{
if (iAction != (int)PLAYER_ACTION_TYPE.ACT_WOUNDED)
{
if (iAction == (int)PLAYER_ACTION_TYPE.ACT_TAKEOFF){
ShowWing(true);
}else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_LANDON){
ShowWing(false);
}
if( action.data.id == 0 )
return false;
if( !bQueue )
{
// update show weapon states.
m_bShowWeapon = action.data.hide_weapon != 0 ? false : true;
}
if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 && iAction <= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_4 )
{
// attack action should not be played by this function
return false;
}
else if( iAction == (int)PLAYER_ACTION_TYPE.ACT_ATTACK_TOSS )
{
// we use toss second part action as a common action
// sprintf(szAct, "%s_%s", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix);
szAct = $"{action.data.ActionPrefix}_{action.data.action_weapon_suffix[weapon_type].Suffix}";
if( !bQueue ){
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
else if( (
iAction >= (int)PLAYER_ACTION_TYPE.ACT_EXP_WAVE &&
iAction <= (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS_END) ||
(iAction >= (int)PLAYER_ACTION_TYPE.ACT_EXP_FIGHT &&
iAction <= (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE) )
{
//
string strFashionAction="";
if (iAction == (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE && InFashionMode())
strFashionAction = GetFashionActionName();
szAct = $"{(string.IsNullOrEmpty(strFashionAction) ? action.data.ActionPrefix : strFashionAction)}_{action.data.action_weapon_suffix[weapon_type].Suffix}";
if( !bQueue ){
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_EXP_FASHIONWEAPON)
{
if (CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType))
{
string strAction = "";
int idEquipment = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WEAPON] & 0x0000ffff;
GetFashionActionNameByID(idEquipment, ref strAction);
if (!string.IsNullOrEmpty(strAction))
{ //by2024 sprintf_s
//sprintf(szAct, "%s_%s", strAction, action.data->action_weapon_suffix[weapon_type].suffix);
szAct = $"{strAction}_{action.data.action_weapon_suffix[weapon_type].Suffix}";
if( !bQueue ){
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
}else{
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
}
}
}
}
else
{
// ͨö
if (m_pPetModel)
{
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
// if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS )
// sprintf(szAct, "վ_");
// else
// sprintf(szAct, "%s_%s", action.data->action_prefix, "");
string szPetAct = "";
if (iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_STAND);
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_RUN)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_RUN);
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_WALK);
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_START)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_START);
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND);
else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP)
szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP);
if( !bQueue )
{
//Play pet action here
// m_pPetModel->PlayActionByName(szPetAct, 1.0f, bRestart, iTransTime, true);
}
else
{
//Play pet action here
// m_pPetModel->QueueAction(szPetAct, iTransTime);
}
// now weapon wanted.
m_bShowWeapon = false;
}
else if (m_bHangerOn)
{
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS )
{
if (m_AttachMode == AttachMode.enumAttachRideOnPlayer)
szAct = "亲吻_双人_通用"; // Kiss_TwoPerson_Common
else if (m_AttachMode == AttachMode.enumAttachHugPlayer)
szAct = "亲吻_抱_通用"; // Kiss_Hug_Common
else if (m_AttachMode == AttachMode.enumAttachRideOnPet)
szAct = "亲吻_双人_通用"; // Kiss_TwoPerson_Common
}
else
{
// if (m_AttachMode == enumAttachRideOnPlayer)
// sprintf(szAct, "%s_%s", action.data->action_prefix, "˫");
// else if (m_AttachMode == enumAttachHugPlayer)
// {
// if( iAction != ACT_RUN )
// sprintf(szAct, "%s", "վ_");
// else
// sprintf(szAct, "%s", "_");
// }
// else if (m_AttachMode == enumAttachRideOnPet)
// sprintf(szAct, "%s_%s", action.data->action_prefix, "˫");
}
// now weapon wanted.
m_bShowWeapon = false;
}
else if (m_AttachMode == AttachMode.enumAttachHugPlayer || m_AttachMode == AttachMode.enumAttachRideOnPlayer)
{
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER )
action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND];
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS )
{
action = m_PlayerActions[GetMoveStandAction(false, false)];
// if (m_AttachMode == enumAttachHugPlayer)
// sprintf(szAct, "%s_%s", action.data->action_prefix, "_");
// else
// sprintf(szAct, "%s_%s", action.data->action_prefix, "_");
}
else
szAct= $"{action.data.ActionPrefix}_抱_通用"; // Hug_Common
// now weapon wanted.
m_bShowWeapon = false;
}
// else
szAct= $"{action.data.ActionPrefix}_{action.data.action_weapon_suffix[weapon_type].Suffix}";
// CECModel pRightHandWeapon = GetRightHandWeapon();
// if( !bQueue )
// {
// PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
// if(pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, bRestart, iTransTime, true, iAction);
// }
// else
// {
// QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
// if(pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), iTransTime, iAction, bRestart ? true : false);
// }
if (m_iBuddyId != 0)
{
if( !m_bHangerOn )
{
CECPlayer pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId);
if (pBuddy)
{
if( iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND ||
iAction == (int)PLAYER_ACTION_TYPE.ACT_RUN || iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK || iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_START ||
iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP || iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_WOUNDED ||
iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS )
{
pBuddy.PlayAction(iAction, bRestart, iTransTime, bQueue);
}
else
pBuddy.PlayAction((int)PLAYER_ACTION_TYPE.ACT_STAND, bRestart, iTransTime, bQueue);
}
}
}
}
}
else // iAction == ACT_WOUNDED
{
PLAYER_ACTION elseAction = m_PlayerActions[iAction];
m_pActionController.PlayWoundActionWithName(ByteToStringUtils.ByteArrayToCP936String(action.data.action_name));
// if (m_pPetModel != null)
// {
// A3DSkinModel pSkinModel = m_pPetModel.GetA3DSkinModel();
// const char* szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED);
// if (!pSkinModel->GetAction(szPetAct))
// {
// szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED2);
// if (!pSkinModel->GetAction(szPetAct))
// szPetAct = NULL;
// if (szPetAct)
// pSkinModel->PlayActionByName(szPetAct, CECModel::ACTCHA_WOUND, 1, 0, false);
// }
// }
}
// if( !bQueue )
// {
// if( !m_bShowWeapon )
// ShowWeapon(false);
// else
// {
// // ʦԾʱҪط
// if(IsUsingMagicWeapon() && (iAction == ACT_JUMP_START || iAction == ACT_JUMP_LAND || iAction == ACT_JUMP_LOOP))
// ShowWeapon(false);
// else
// ShowWeapon(true);
// }
// // ݲŶλ
// UpdateWeaponHangerPosByAction(iAction);
// }
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, iTransTime));
return true;
}
else
{
return false;
}
//var szAct = EC_Utility.BuildActionName(action, weapon_type);
return true;
}
public static void Dispose()
{
_default_actions = null;
_turning_actions = null;
}
public INFO GetPlayerInfo()
{
return m_PlayerInfo;
}
// Get basic properties
public ROLEBASICPROP GetBasicProps() { return m_BasicProps; }
// Get extend properties
public ROLEEXTPROP GetExtendProps() { return m_ExtProps; }
protected override void Update()
{
base.Update();
if (m_CandPet.id != 0 /*&& GetMajorModel()*/)
{
string szPetPath = GetRidingPetFileName(m_CandPet.id);
QueueLoadPetModel(szPetPath, false);
m_CandPet.Reset();
}
}
public void PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage,
uint dwModifier, int nAttackSpeed, ref int piAttackTime, int nSection = 0)
{
if (!IsAllResReady())
return;
if (idSkill == 0)
{
int idWeapon = IsShapeChanged() ? 0 : GetWeaponID();
int nTimeFly = 10;
if (idWeapon != 0)
{
// ¿´¿´ÊDz»ÊÇÔ¶³ÌÎäÆ÷
DATA_TYPE dt = default;
WEAPON_ESSENCE? pWeapon = (WEAPON_ESSENCE)ElementDataManProvider.GetElementDataMan()
.get_data_ptr((uint)idWeapon, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dt == DATA_TYPE.DT_WEAPON_ESSENCE && pWeapon != null && pWeapon.Value.require_projectile != 0)
{
nTimeFly = 700;
if (m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE] != 0)
idWeapon = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE];
}
}
if (CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid))
{
ClearComActFlagAllRankNodes(true);
}
// melee attack
CECAttackEvent pAttack1 = CECAttacksMan.Instance.AddMeleeAttack(
GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
if (pAttack1 != null)
{
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack1)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
else
{
pAttack1.m_bSignaled = true;
}
}
}
else
{
if (skillLevel == 0)
{
if (m_pCurSkill != null)
skillLevel = m_pCurSkill.GetSkillLevel();
else
skillLevel = 1;
}
CECAttackEvent pAttack = null;
// first try to find if there is already a skill attack event in attackman
CECAttackerEvents attackerEvents = CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid);
if (attackerEvents)
{
CECAttackEvent pAttack1 = attackerEvents.Find(idSkill, nSection);
if (pAttack1 != null)
{
// Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
pAttack1.AddTarget(idTarget, dwModifier, nDamage);
goto EXIT;
}
else
{
attackerEvents.Signal();
}
}
if (ElementSkill.IsGoblinSkill((uint)idSkill) &&
ElementSkill.GetType((uint)idSkill) == 2)
{
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
else
{
// begin a skill attack
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
if (pAttack != null)
{
int unusedInt = 0;
pAttack.SetSkillSection(nSection);
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlaySkillAttackAction(idSkill, nAttackSpeed, ref unusedInt, nSection, pAttack)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
pAttack.m_bSignaled = true;
}
else
{
pAttack.m_bSignaled = true;
}
}
EXIT:
// // For skill attacking, time is always set to 0
if (piAttackTime != 0)
piAttackTime = 0;
}
}
protected void ClearComActFlagAllRankNodes(bool v)
{
EventBus.PublishChannel(m_PlayerInfo.cid, new ClearComActFlagAllRankNodesEvent(v));
}
public bool PlayAttackAction(int nAttackSpeed, ref int attackTime, CECAttackEvent attackEvent)
{
//attackTime = 0;
//if (_pPlayerModel == null)
// return false;
int nRand = UnityEngine.Random.Range(0, 4);
string szAct = string.Empty;
string szShapeName = string.Empty;
GetShapeName(ref szShapeName);
int weapon_type = GetShowingWeaponType();
Debug.Log($"[THN]: PlayAttackAction weapon_type: {weapon_type}");
int nTime1 = 0, nTime2 = 0;
int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand;
PLAYER_ACTION action = m_PlayerActions[iAction];
if (string.IsNullOrEmpty(action.data.ActionPrefix))
return false;
ShowWeaponByConfig(action.data);
/* var pRightHandWeapon = GetRightHandWeapon();
bool bHideFX = !CECOptimize.Instance.GFX.CanShowAttack(GetCharacterID(), GetClassID());*/
// ==============================
// Ground Attack
// ==============================
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
// “起? 动作(挥起)
Debug.Log($"[THN]: PlayAttackAction action with weapon type: {weapon_type} and weapon attached: {m_bWeaponAttached}");
szAct = EC_Utility.BuildActionName(action, weapon_type, "起");
int iTransTime = 200;
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, iTransTime, true));
szAct = EC_Utility.BuildActionName(action, weapon_type, "落");
queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, true, attackEvent, iTransTime,false);
EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
//PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);gagága
/*
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
nTime1 = _pPlayerModel.GetComActTimeSpanByName(szAct);
// “收” 动作(挥下)
szAct = $"{action.data.action_prefix}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä";
QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
nTime2 = _pPlayerModel.GetComActTimeSpanByName(szAct);*/
}
// ==============================
// Air Attack
// ==============================
else
{
string szActionMiddleName;
if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) ||
GetProfession() == (int)PROFESSION.PROF_ANGEL ||
GetProfession() == (int)PROFESSION.PROF_ARCHOR ||
GetProfession() == (int)PROFESSION.PROF_MONK ||
GetProfession() == (int)PROFESSION.PROF_GHOST)
{
szActionMiddleName = "空中翅膀"; // tấn công trên không
}
else
{
szActionMiddleName = "空中飞剑"; // rơi xuống hoặc bay
}
szAct = EC_Utility.BuildActionName(action, weapon_type, "起", szActionMiddleName);
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, 200, true));
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
// nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
szAct = EC_Utility.BuildActionName(action, weapon_type, "落", szActionMiddleName);
queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, false, attackEvent, 0, false);
EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
// nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
}
// ==============================
// Kết thúc bằng FightStand
// ==============================
PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND];
szAct = EC_Utility.BuildActionName(stand_action, 0);
int iTranstime = 300;
queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, false, attackEvent, iTranstime, false);
EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
/* QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true);*/
// ==============================
// Điều chỉnh tốc độ phát animation theo tốc độ tấn công
// ==============================
/* if (nAttackSpeed > 0)
{
float vScale = (nTime1 + nTime2) / (float)nAttackSpeed;
if (vScale > 0f)
{
m_pPlayerModel.SetPlaySpeed(vScale);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.SetPlaySpeed(vScale);
}
}
attackTime = nTime1 + nTime2;*/
// ==============================
// Cập nhật vị trí weapon hanger (vũ khí)
// ==============================
//UpdateWeaponHangerPosByAction(iAction);
return true;
}
void GetShapeName(ref string szShapeName)
{
if(IsShapeChanged()) {
//the index and the shape name is different by 2
szShapeName =m_aShapeChineseName[GetShapeID()-2]+"_";
}
else
{
szShapeName = m_aShapeChineseName[m_iProfession*GENDER.NUM_GENDER+m_iGender] +"_";
}
}
public void SetApplyDamage(bool isApplyDamage, CECAttackEvent cECAttackEvent)
{
cECAttackEvent.m_bSignaled = isApplyDamage;
}
public void ShowWeaponByConfig(PLAYER_ACTION_INFO_CONFIG p)
{
m_bShowWeapon = p.hide_weapon != 0 ? false : true;
//ShowWeapon(m_bShowWeapon);
}
public int GetShowingWeaponType()
{
int weapon_type = 0;
if (CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType) &&
m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WEAPON] != 0)
{
weapon_type = (EC_Utility.BinaryEquals(m_iFashionWeaponType, DEFAULT_ACTION_TYPE) || !IsWeaponAttached())
? 10
: m_iFashionWeaponType;
}
else
{
weapon_type = (EC_Utility.BinaryEquals(m_uAttackType, DEFAULT_ACTION_TYPE) || !IsWeaponAttached()) ? 10 : (int)m_uAttackType;
}
return weapon_type;
}
public bool IsWeaponAttached()
{
return m_bWeaponAttached;
}
bool AttachWeapon()
{
bool result = (false);
while (GetMajorModel()){
if (!m_pPlayerCECModel.GetHook(GetLeftWeaponHookPos(m_weaponHangerPos),true) ||
!m_pPlayerCECModel.GetHook(GetRightWeaponHookPos(m_weaponHangerPos),true)){
break;
}
m_bWeaponAttached = true;
break;
}
/*while (GetPlayerModel() && (GetLeftHandWeapon() || GetRightHandWeapon())){
A3DSkinModel *pSkinModel = GetPlayerModel().GetA3DSkinModel();
if (!pSkinModel ||
!pSkinModel.GetSkeleton()){
break;
}
if (!pSkinModel.GetSkeletonHook(GetLeftWeaponHookPos(m_weaponHangerPos),true) ||
!pSkinModel.GetSkeletonHook(GetRightWeaponHookPos(m_weaponHangerPos),true)){
break;
}
if (GetLeftHandWeapon()){
GetPlayerModel().AddChildModel(
_left_hand_weapon,
false,
GetLeftWeaponHookPos(m_weaponHangerPos),
GetLeftHandWeapon(),
GetLeftWeaponOwnHookPos(GetLeftHandWeapon()));
}
if (GetRightHandWeapon()){
GetPlayerModel().AddChildModel(
_right_hand_weapon,
false,
GetRightWeaponHookPos(m_weaponHangerPos),
GetRightHandWeapon(),
GetRightWeaponOwnHookPos(GetRightHandWeapon()));
}
ALog log;
log.Init("EC.log", "My Application Log");
// Anywhere in your code where you want to see the call flow:
log.Log("[HoangDev]Checking execution flow at this point:");
log.LogStackTrace();
log.Release();
m_bWeaponAttached = true;
result = true;
break;
}*/
result = true;
return result;
}
public string GetLeftWeaponHookPos(WeaponHangerPosition p)
{
switch(p)
{
case WeaponHangerPosition.WEAPON_HANGER_HAND:
return _hh_left_hand_weapon;
case WeaponHangerPosition.WEAPON_HANGER_SHOULDER:
return _hh_left_shoulder_weapon;
}
return null;
}
public string GetRightWeaponHookPos(WeaponHangerPosition p)
{
switch(p)
{
case WeaponHangerPosition.WEAPON_HANGER_HAND:
return _hh_right_hand_weapon;
case WeaponHangerPosition.WEAPON_HANGER_SHOULDER:
return _hh_right_shoulder_weapon;
}
return null;
}
public void DetachWeapon()
{
if (IsWeaponAttached()){
// if (GetLeftHandWeapon()){
// GetMajorModel()->RemoveChildModel(_left_hand_weapon, false);
// }
// if (GetRightHandWeapon()){
// GetPlayerModel()->RemoveChildModel(_right_hand_weapon, false);
// }
m_bWeaponAttached = false;
}
}
public bool InFashionMode()
{
return m_bFashionMode;
}
public bool CanShowFashionWeapon(int weapon_type, int fashion_weapon_type)
{
return IsFashionWeaponTypeFit(weapon_type, fashion_weapon_type) && InFashionMode();
}
public bool IsFashionWeaponTypeFit(int weapon_type, int fashion_weapon_type)
{
if (fashion_weapon_type < 0 || fashion_weapon_type >= NUM_WEAPON_TYPE) return false;
FASHION_WEAPON_CONFIG? pConfig = GetFashionConfig();
if (null == pConfig)
{
BMLogger.LogError("CECPlayer::GetFashionConfig, Failed to load fashion weapon config");
return false;
}
int fashion_weapon_mask = (int)pConfig.Value.action_mask[fashion_weapon_type];
return (fashion_weapon_mask & (1 << GetWeaponType(weapon_type))) != 0;
}
public FASHION_WEAPON_CONFIG GetFashionConfig()
{
FASHION_WEAPON_CONFIG? pFashionConfig = null;
if (null == pFashionConfig)
{
elementdataman pDataMan = ElementDataManProvider.GetElementDataMan();
DATA_TYPE DataType = DATA_TYPE.DT_FASHION_WEAPON_CONFIG;
uint tid = pDataMan.get_id_with_data_type(ID_SPACE.ID_SPACE_CONFIG, DataType);
if (tid != 0)
{
pFashionConfig =
(FASHION_WEAPON_CONFIG)pDataMan.get_data_ptr(tid, ID_SPACE.ID_SPACE_CONFIG, ref DataType);
BMLogger.LogError($"HoangDev : get_data_ptr {pFashionConfig.GetType()}");
}
}
return pFashionConfig == null ? default : pFashionConfig.Value;
}
public int GetSelectedTarget()
{
return m_idSelTarget;
}
public float GetTouchRadius()
{
return m_fTouchRad;
}
// Is player in battle
public bool IsInBattle()
{
return m_iBattleCamp != Player_camp_in_battle.GP_BATTLE_CAMP_NONE;
}
// Check whether specified npc in a same battle camp
public bool InSameBattleCamp(CECNPC pNPC)
{
if (!pNPC || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE ||
(m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER && !pNPC.IsInBattleInvaderCamp()) ||
(m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_DEFENDER && !pNPC.IsInBattleDefenderCamp()))
return false;
return true;
}
public int GetBattleCamp() { return m_iBattleCamp; }
public bool InSameBattleCamp(CECPlayer pPlayer)
{
if (!pPlayer || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE ||
m_iBattleCamp != pPlayer.GetBattleCamp())
return false;
return true;
}
public const uint DEFAULT_ACTION_TYPE = 0xFFFFFFFF;
public static int GetWeaponType(int iWeaponType)
{
return iWeaponType == DEFAULT_ACTION_TYPE ? 10 : iWeaponType;
}
public bool IsInFactionPVP() => (m_factionPVPMask & 0x01) != 0;
public bool CanAttackFactionPVPMineCar() => (m_factionPVPMask & 0x02) != 0;
public bool CanAttackFactionPVPMineBase() => (m_factionPVPMask & 0x04) != 0;
public int GetLevelUpExp(int iLevel)
{
return _player_levelup_exp.exp[iLevel - 1];
//return iLevel * iLevel * 500;
}
public override void TurnFaceTo(int idTarget, float dwTime = 200)
{
if (idTarget != 0)
{
if (idTarget == GetCharacterID())
{
return;
}
if (IsWorkMoveRunning() /*&& !IsPlayingCastingSkillAndMoveActions()*/)
{
// ÒÆ¶¯Ê±Ò»°ãÓ¦ÃæÏòÒÆ¶¯·½Ïò¡¢Ö»ÔÚÒÆ¶¯Ê©·¨ÖвÅתÏò
return;
}
}
var target = EC_ManMessageMono.Instance?.GetObject(idTarget, 0)?.gameObject.transform;
if (target == null)
{
//BMLogger.LogError("HoangDev: ko có transform ");
return;
}
Vector3 direction = (target.position - transform.position).normalized;
direction.y = 0f;
int turnSpeed = 5;
if (direction.sqrMagnitude > 0.001f)
{
// T?o rotation mới hướng tới target
Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up);
// Xoay mư?t t? rotation hiện t?i sang rotation m?c tiêu
//transform.rotation = Quaternion.Slerp(
// transform.rotation,
// targetRotation,
// Time.deltaTime * turnSpeed
//);
transform.rotation = targetRotation;
}
}
public virtual bool IsWorkMoveRunning()
{
return false;
}
/* public bool IsPlayingCastingSkillAndMoveActions()
{
return IsPlayingCastingSkillAction() && IsPlayingMoveAction();
}
public bool IsPlayingCastingSkillAction()
{
return m_pActionController ? m_pActionController.IsPlayingCastingSkillAction() : false;
}
bool IsPlayingMoveAction()
{
return m_pActionController ? m_pActionController.IsPlayingMoveAction() : false;
}*/
public int GetMoveStandAction(bool bMove, bool bFight = false)
{
int iMoveEnv = m_iMoveEnv;
//if (m_AttachMode != enumAttachNone)
//{
// bFight = false;
// if (m_bHangerOn)
// iMoveEnv = MOVEENV_GROUND;
//}
int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND;
if (bMove)
{
// Play appropriate actions
if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND)
{
if (m_bWalkRun)
iAction = (int)PLAYER_ACTION_TYPE.ACT_RUN;
else
iAction = (int)PLAYER_ACTION_TYPE.ACT_WALK;
}
else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR)
{
if (/*UsingWing()*/ m_wingType == enumWingType.WINGTYPE_WING)
iAction = (int)PLAYER_ACTION_TYPE.ACT_FLY;
else
iAction = (int)PLAYER_ACTION_TYPE.ACT_FLY_SWORD;
}
else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_WATER)
{
//if (CanCombineWithMoveForSkill())
//{
// iAction = (int)PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL;
//}
//else
{
iAction = (int)PLAYER_ACTION_TYPE.ACT_SWIM;
}
}
}
else
{
// Play appropriate actions
if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND)
{
if (bFight)
iAction = (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND;
else
iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND;
}
else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR)
{
if (/*UsingWing()*/ m_wingType == enumWingType.WINGTYPE_WING)
iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR;
else
iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD;
}
else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_WATER)
iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINWATER;
}
return iAction;
}
public A3DVECTOR3 GetModelMoveDir()
{ // ÒÆ¶¯Ê±¡¢·µ»ØÒƶ¯³¯Ïò£¬¾²Ö¹Ê±¡¢·µ»ØÄ£Ðͳ¯Ïò
return EC_Utility.ToA3DVECTOR3(transform.forward);
}
public void Damaged(int nDamage, uint dwModifier = 0, int skill = 0)
{
if (nDamage == -2)
{
// this message is caused by a help skill, so don't use a wounded action here
/* if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);*/
}
else if (nDamage == -1)
{
// when else player hit this player iDamage is -1,
// Just play a wounded action
if (!OnDamaged(skill))
{
// PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
}
/*if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);*/
}
else
{
// Popup a damage decal
if (nDamage > 0)
{
int p1 = 0;
/*if (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE)
p1 |= 0x0001;
if (dwModifier & CECAttackEvent::MOD_RETORT)
p1 |= 0x0002;*/
if (!OnDamaged(skill))
// PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
DamageTextManager.Instance.ShowDamageText(
transform.position, nDamage, Color.yellow, 1.0f);
/* if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_REBOUND)
BubbleText(BUBBLE_REBOUND, nDamage);
else if (dwModifier & CECAttackEvent::MOD_BEAT_BACK)
BubbleText(BUBBLE_BEAT_BACK, nDamage);
else
BubbleText(BUBBLE_DAMAGE, nDamage, p1);*/
}
/* else if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else
BubbleText(BUBBLE_HITMISSED, 0);*/
}
}
public void StopSkillAttackAction()
{
if (m_pActionController != null)
{
m_pActionController.StopSkillAttackAction();
}
}
public void StopSkillCastAction()
{
if (m_pActionController != null)
{
m_pActionController.StopSkillCastAction();
}
}
public bool PlaySkillCastAction(int idSkill, CECAttackEvent attackEvent = null)
{
string szAct = "";
int weapon_type = GetShowingWeaponType();
int moveEnv = GetMoveEnv();
if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) || data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4)
{
data = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data;
if (data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
return false;
}
}
else
{
return false;
}
}
if (moveEnv == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_吟唱_");
}
else
{
/* if ((*//*UsingWing()*//*m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST))
sprintf(szAct, "%s_¿ÕÖгá°ò_Ò÷³ª_%s", data.action_prefix, data.action_weapon_suffix[weapon_type].suffix);
else
sprintf(szAct, "%s_¿ÕÖзɽ£_Ò÷³ª_%s", data.action_prefix, data.action_weapon_suffix[weapon_type].suffix);*/
}
bool bHideFX = false; /*!CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());*/
if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX))
{
return false;
}
ShowWeaponByConfig(data);
//UpdateWeaponHangerPosBySkillAction(idSkill);// ¸ù¾Ý¼¼Äܲ¥·ÅµÄ¶¯×÷£¬¸ü¸ÄÎäÆ÷Ðü¹ÒλÖã¨Ö»Äܼì²é²»ÅŶӶ¯×÷£©
return true;
}
public bool OnDamaged(int skill)
{
var atkMan = CECAttacksMan.Instance;
if (atkMan == null)
return false;
string name1, name2;
for (int i = 0; i < m_sciStateIDForStateAction.Length; i++)
{
/* if (atkMan.GetSkillStateActionName(skill, m_sciStateIDForStateAction[i], out name1, out name2))
{
m_SkillIDForStateAction = skill;
return true;
}*/
}
return false;
}
public CECSkill GetCurSkill() { return m_pCurSkill; }
public bool IsHangerOn() { return m_bHangerOn; }
public bool IsPlayingAction()
{
return true /*GetLowerBodyAction() != -1*/ ;
}
public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX/* =false */)
{
return m_pActionController != null
&& m_pActionController.PlaySkillCastActionWithName(idSkill, szActName, bNoFX);
}
public bool PlaySkillAttackAction(int idSkill, int nAttackSpeed, ref int piAttackTime, int nSection = 0, CECAttackEvent attackEvent = null)
{
if (m_pPlayerModel == null)
return false;
string szAct = "";
int weapon_type = GetShowingWeaponType();
if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) ||
data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
// Check if it's a target item skill / 检查是否为目标道具技能
if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4)
{
PLAYER_ACTION_INFO_CONFIG? data2 = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data;
if (data2 == null || data2.Value.action_prefix == null || data2.Value.action_prefix.Length == 0 || data2.Value.action_prefix[0] == 0)
return false;
}
else
return false;
}
int nTime1, nTime2;
bool bInfinite = false;
// CECModel pRightHandWeapon = GetRightHandWeapon(); // 获取右手武器 / Get right hand weapon
bool bHideFX = false; // !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
var atkMan = CECAttacksMan.Instance;
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放起_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct); // 获取动作时长 / Get action time span
// pAct = m_pPlayerModel.GetComActByName(szAct);
// if (pAct) bInfinite |= pAct.IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放落_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel.GetComActByName(szAct);
// if (pAct) bInfinite |= pAct.IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
else
{
// 空中动作 / Air action
string szActionMiddleName = null;
if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) ||
(m_iProfession == (int)PROFESSION.PROF_ANGEL) ||
(m_iProfession == (int)PROFESSION.PROF_ARCHOR) ||
(m_iProfession == (int)PROFESSION.PROF_MONK) ||
(m_iProfession == (int)PROFESSION.PROF_GHOST))
{
szActionMiddleName = "_空中翅膀"; // Air with wings / 空中翅膀
}
else
{
szActionMiddleName = "_空中飞剑"; // Air with sword / 空中飞剑
}
szActionMiddleName += "_施放起_";
szAct = EC_Utility.BuildActionName(data, weapon_type, szActionMiddleName);
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX);
// nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel.GetComActByName(szAct);
// if (pAct) bInfinite |= pAct.IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = $"{data.ActionPrefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].Suffix}";
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX);
// nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel.GetComActByName(szAct);
// if (pAct) bInfinite |= pAct.IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
// int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0); // 获取技能执行时间 / Get skill execute time
int nExecuteTime = 2000; // 临时值 / Temporary value
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite)
{
if (nExecuteTime > 0)
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
// m_pPlayerModel.SetPlaySpeed(vScale * 1.2f);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon.SetPlaySpeed(vScale * 1.2f);
}
piAttackTime = nTime1 + nTime2;
}
else
{
// 动作循环,返回技能决定的执行时间 / Action loops, return skill-determined execute time
piAttackTime = nExecuteTime;
}
ShowWeaponByConfig(data);
// UpdateWeaponHangerPosBySkillAction(idSkill); // 根据技能播放的动作,更改武器悬挂位置 / Update weapon hanger position based on skill action
return true;
}
/// <summary>Override in CECHostPlayer to return current team; base returns null.</summary>
public virtual CECTeam GetTeam() { return null; }
public bool IsTeamMember(int idPlayer)
{
var pTeam = GetTeam();
if (pTeam == null) return false;
return pTeam.GetMemberByID(idPlayer) != null;
}
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, CECAttackEvent attackEvent = null)
{
return m_pActionController != null
&& m_pActionController.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent != null ? new bool[] { attackEvent.m_bSignaled } : null, 0);
}
public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0)
{
return m_pActionController != null
&& m_pActionController.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
private void GetSkillSectionActionName(ref string szAct, int idSkill, int nSection)
{
if (nSection != 0)
{
var pAtkMan = CECAttacksMan.Instance;
if (pAtkMan != null && pAtkMan.GetSkillSectionActionSuffix(idSkill, nSection, out string suffix))
{
szAct += "_" + suffix;
}
}
}
protected void OnMsgEnchantResult(ECMSG msg)
{
// 从消息中获取cmd_enchant_result结构 // Get cmd_enchant_result structure from message
cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes<cmd_enchant_result>((byte[])msg.dwParam1);
// 初始化掩码为全1 // Initialize mask to all 1s
uint mask = 0xFFFFFFFF;
// 如果目标不是主机玩家且当前不是主机玩家,则过滤会引起气泡文本的修饰符
// We should filter out these things that will cause bubble texts
CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer();
if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer())
{
mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE |
MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED);
}
// 获取修饰符 // Get modifier
uint dwModifier = (uint)pCmd.attack_flag;
// 获取技能类型 // Get skill type
int nDamage = -2; // 默认为-2,不会引起受伤动作 // Default to -2, will not cause wounded action
if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK)
{
// 只有攻击技能会引起受伤动作,伤害值为-1 // Only attack skill will cause wounded action, when damage is -1
nDamage = -1;
}
else
{
// 其他技能不会引起受伤动作,伤害值设为-2 // Other skills will not cause wounded action, so we set damage to -2
nDamage = -2;
}
// 播放攻击效果 // Play attack effect
int attackTime = 0;
PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage,
dwModifier & mask, 0, ref attackTime, pCmd.section);
}
// 判断是否在飞行 / Check if flying
public bool IsFlying()
{
// 临时实现 / Temporary implementation
return (m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0 ? true : false;
}
public bool IsInvader()
{
return (m_dwStates & PlayerNPCState.GP_STATE_INVADER) != 0;
}
public int GetFactionID() { return m_idFaction; }
public int GetForce() { return m_idForce; }
public bool IsInDuel() { return m_pvp.iDuelState == (int)DuelState.DUEL_ST_INDUEL; }
// Duel state
public enum DuelState
{
DUEL_ST_NONE = 0,
DUEL_ST_PREPARE,
DUEL_ST_INDUEL,
DUEL_ST_STOPPING,
};
public bool IsPariah()
{
return (m_dwStates & PlayerNPCState.GP_STATE_PARIAH) != 0;
}
bool GetSkillStateActionName(int skill, int state, string name1, string name2)
{
/* for (int i = 0; i < (int)m_SkillStateActionVec.size(); i++)
{
if (m_SkillStateActionVec[i].skill == skill && m_SkillStateActionVec[i].state == state)
{
name1 = m_SkillStateActionVec[i].beHitAction;
name2 = m_SkillStateActionVec[i].stayDownAction;
return true;
}
}*/
return false;
}
public virtual bool IsFighting() { return m_bFight; }
public float GetGroundSpeed()
{
// return m_bWalkRun ? g_pGame.GetConfigs().GetHostRunSpeed() : m_ExtProps.mv.walk_speed;
// return 5f;
return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed;
}
// Get move environment
public int GetMoveEnv()
{
return m_iMoveEnv;
}
public bool IsShapeChanged()
{
return m_iShape != 0;
}
// 获取职业 // Get profession
public int GetProfession()
{
return m_iProfession;
}
public int GetLevel()
{
return GetBasicProps().iLevel;
}
// 获取性别 // Get gender
public int GetGender()
{
return m_iGender;
}
// 获取变身类型 // Get shape type
// PLAYERMODEL_GETTYPE(iShape) = (iShape & 0xff) >> 6
public int GetShapeType()
{
return (m_iShape & 0xff) >> 6;
}
// 获取变身ID // Get shape ID
// PLAYERMODEL_GETID(iShape) = iShape & 0x3f
public int GetShapeID()
{
return m_iShape & 0x3f;
}
public int GetWeaponID()
{
return m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON] & 0xffff;
}
public bool IsAllResReady()
{
return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_ALL) == (uint)PlayerResourcesReadyFlag.RESFG_ALL;
}
// Get character ID
public static int GetRealmLayer(int realmLevel) { return realmLevel != 0 ? (realmLevel + 9) / 10 : 0; }
public static int GetRealmSubLevel(int realmLevel) { return realmLevel != 0 ? (realmLevel % 10 != 0 ? realmLevel % 10 : 10) : 0; }
string GetFashionActionName()
{
// ʱװװЯĶ
//
string strAction = "";
int[] local_check_order =
{
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_HEAD,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_BODY,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WRIST,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_LEG,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_FOOT
};
int idEquipment = 0;
for (int i = 0; i < local_check_order.Length; ++ i)
{
// ˳ָװ
idEquipment = m_aEquips[local_check_order[i]] & 0x0000ffff;
GetFashionActionNameByID(idEquipment, ref strAction);
if (!string.IsNullOrEmpty(strAction))
{
// ַǿʱװ
break;
}
}
return strAction;
}
void GetFashionActionNameByID(int idEquipment, ref string strAction)
{
if (idEquipment != 0)
{
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
object pEquip = EC_Game.GetElementDataMan().get_data_ptr(
(uint)idEquipment,
ID_SPACE.ID_SPACE_ESSENCE,
ref dt);
if (pEquip != null && dt == DATA_TYPE.DT_FASHION_ESSENCE)
{
FASHION_ESSENCE pEssence = (FASHION_ESSENCE)pEquip;
strAction = ByteToStringUtils.ByteArrayToCP936String(pEssence.wear_action);
}
}
}
protected bool PlayGfx(string szPath, string szHook, float fScale /*1.0f*/, uint iShapeTypeMask /*(1<<PLAYERMODEL_MAJOR)*/, bool bForceNoRecord = false)
{
// bool bPlayed(false);
// bool bSkipRecord = (iShapeTypeMask != PLAYERMODEL_TYPEALL) || bForceNoRecord;
// for(int i=0;i<PLAYERMODEL_MAX;i++)
// {
// if (m_pModels[i] && (iShapeTypeMask & (1<<i)))
// {
// if (IsCurrentModel(m_pModels[i])){
// m_pModels[i].PlayGfx(szPath, szHook, fScale);
// bPlayed = true;
// }
// if(bSkipRecord) continue;
// A3DGFXEx* pGfx = m_pModels[i].GetGfx(szPath, szHook);
// if (pGfx && pGfx.IsInfinite()){
// GFXRECORD rec;
// rec.strPath = szPath;
// rec.strHook = szHook;
// rec.fScale = fScale;
// AString key = rec.strPath + rec.strHook;
// m_GfxRecords[key] = rec;
// bSkipRecord = true;
// }
// }
// }
PlayLevelUpGfx(szPath);
return false;
}
private async void PlayLevelUpGfx(string path)
{
// Usage: Load the prefab asynchronously using AddressableManager
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
if (prefab != null)
{
BMLogger.Log($"[GFX Spawn] Loading GFX: {path}, Prefab Name: {prefab.name}");
if (_levelUpVfx != null)
{
if (_levelUpVfx.IsPlaying())
{
BMLogger.Log($"[GFX Spawn] Reusing existing GFX (already playing): {path}");
return;
}
BMLogger.Log($"[GFX Spawn] Replaying existing GFX: {path}");
_levelUpVfx.Play();
return;
}
// Instantiate at player's current position and rotation
BMLogger.Log($"[GFX Spawn] Instantiating new GFX: {path}, Prefab Name: {prefab.name}");
_levelUpVfx = Instantiate(prefab, transform).GetComponent<BaseVfxObject>();
_levelUpVfx.Play();
// vfx.transform.SetParent(transform); transform.position, prefab.transform.rotation
_levelUpVfx.transform.localPosition = Vector3.zero;
}
else
{
BMLogger.LogError($"Failed to load level up effect prefab at: {path}");
}
}
// Get booth state
public int GetBoothState() { return m_iBoothState; }
// Check whether player has effect of specified type
public bool HasEffectType(int iEffType)
{
int i;
switch (iEffType)
{
case Effect_type.EFF_FACEPILL:
{
elementdataman pDataMan = EC_Game.GetElementDataMan();
// Get item data type
for (i = 0; i < m_aCurEffects.Count; i++)
{
DATA_TYPE DataType = pDataMan.get_data_type((uint)m_aCurEffects[i], ID_SPACE.ID_SPACE_ESSENCE);
if (DataType == DATA_TYPE.DT_FACEPILL_ESSENCE)
return true;
}
break;
}
}
return false;
}
public byte GetReincarnationCount() { return m_ReincarnationCount; }
public string GetName()
{
return m_strName;
}
/// <summary>Set player display name (used when base info is received, e.g. else player).</summary>
protected void SetPlayerName(string name)
{
m_strName = name ?? "";
if (gameObject != null)
gameObject.name = m_strName;
}
public enumWingType GetWingType() { return m_wingType; }
// Set part extend properties
public void SetPartExtendProps(int iPropIdx, object pData)
{
BMLogger.LogError($"HoangDev: SetPartExtendProps iPropIdx={iPropIdx} pData={pData} ");
switch (iPropIdx)
{
case (int)ExtendPropertyClass.EXTPROPIDX_BASE:
m_ExtProps.bs = (ROLEEXTPROP_BASE)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_MOVE:
m_ExtProps.mv = (ROLEEXTPROP_MOVE)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_ATTACK:
m_ExtProps.ak = (ROLEEXTPROP_ATK)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_DEF:
m_ExtProps.df = (ROLEEXTPROP_DEF)pData;
break;
default:
//ASSERT(0);
return;
}
}
#region Team
// Get team to which this player belongs to
// public CECTeam GetTeam() { return m_pTeam; }
#endregion
public static bool IsMoveStandAction(int action)
{
// tương đương: const static int s_MoveStandAction[]
PLAYER_ACTION_TYPE[] s_MoveStandAction =
{
PLAYER_ACTION_TYPE.ACT_RUN,
PLAYER_ACTION_TYPE.ACT_WALK,
PLAYER_ACTION_TYPE.ACT_FLY,
PLAYER_ACTION_TYPE.ACT_FLY_SWORD,
PLAYER_ACTION_TYPE.ACT_SWIM,
PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL,
PLAYER_ACTION_TYPE.ACT_STAND,
PLAYER_ACTION_TYPE.ACT_FIGHTSTAND,
PLAYER_ACTION_TYPE.ACT_HANGINAIR,
PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD,
PLAYER_ACTION_TYPE.ACT_HANGINWATER,
};
int begin = 0;
int end = s_MoveStandAction.Length - 1;
for (int i = begin; i < end; i++)
{
if ((int)s_MoveStandAction[i] == action)
return true;
}
return false;
}
public int GetLowerBodyAction()
{
return m_pActionController?.GetLowerBodyAction() ?? -1;
}
// Check water moving environment
public bool CheckWaterMoveEnv(A3DVECTOR3 vPos, float fWaterHei, float fGndHei)
{
bool bRet = false;
/* if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf - m_aabb.Extents.y)
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f)
/*
if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
//@note : modify the water test. By Kuiwu[12/10/2005]
if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf - 0.001f)
{
bRet = true;
}
//else if (vPos.y + m_aabb.Extents.y < fWaterHei- m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.2f )
else if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.01f)
{
bRet = true;
}
return bRet;
}
public bool IsAboutToDie() { return m_bAboutToDie; }
public void SetAboutToDie(bool bFlag) { m_bAboutToDie = bFlag; }
// Show / hide wing
public void ShowWing(bool bShow)
{
if (m_pPlayerModel)
{
// var pWing = FindChildRecursive(m_pPlayerModel.transform, _wing);
if (m_Wing != null)
{
m_Wing.gameObject.SetActive(bShow);
}
// var pWing2 = FindChildRecursive(m_pPlayerModel.transform, _wing2);
// m_Wing2.gameObject.SetActive(bShow);
}
}
// Get current pet id
public int GetCurPetID() { return m_idCurPet; }
// Set current pet id
public void SetCurPetID(int id) { m_idCurPet = id; }
// Get player name color
public uint GetNameColor()
{
uint dwNameCol = NameColor.NAMECOL_MAUVE;
if (IsInBattle()) // Player is in battle
{
if (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER)
dwNameCol = NameColor.NAMECOL_BC_RED;
else // (m_iBattleCamp == GP_BATTLE_CAMP_DEFENDER)
dwNameCol = NameColor.NAMECOL_BC_BLUE;
}
else if (IsPariah())
{
switch (m_byPariahLvl)
{
case 0: dwNameCol = NameColor.NAMECOL_RED0; break;
case 1: dwNameCol = NameColor.NAMECOL_RED1; break;
default: dwNameCol = NameColor.NAMECOL_RED2; break;
}
}
else if (IsInvader())
dwNameCol = NameColor.NAMECOL_PINK;
else if (m_pvp.bEnable)
dwNameCol = NameColor.NAMECOL_WHITE;
return dwNameCol;
}
// Riding pet info.
public struct RIDINGPET
{
public int id;
public ushort color;
public void Reset()
{
id = 0;
color = 0;
}
public bool GetColor(ref Color clr)
{
// Get the current pets dye/color
return id > 0 && GetColor(color, ref clr);
}
public static bool GetColor(ushort c, ref Color clr)
{
// Check whether the current pet has been dyed; if so, return the dyed color.
bool bRet = false;
if ((c & (1 << (Marshal.SizeOf(c) * 8 - 1))) != 0)
{
// unsigned short: if the highest bit is 1, it means the pet has been dyed;
// in this case, the dyed color can be retrieved.
clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3);
bRet = true;
}
return bRet;
}
public static Color GetDefaultColor()
{
return new Color(255f / 255f, 255f / 255f, 255f / 255f);
}
};
public bool IsRidingOnPet() { return m_RidingPet.id != 0; }
// Get riding pet info.
public RIDINGPET GetRidingPetInfo() { return m_RidingPet; }
public void RideOnPet(int id, ushort color)
{
m_CandPet.id = id;
m_CandPet.color = color;
m_RidingPet.id = id;
m_RidingPet.color = color;
}
public void GetOffPet(bool bResetData)
{
int iBuddyId = 0;
m_CandPet.Reset();
SetNamePos(new A3DVECTOR3(0.0f));
if (m_AttachMode != AttachMode.enumAttachNone)
{
iBuddyId = m_iBuddyId;
DetachBuddy(null, bResetData);
}
if (m_pPetModel)
{
GameObject.Destroy(m_pPetModel);
m_pPetModel = null;
}
if (bResetData)
m_RidingPet.Reset();
// Re-calculate player's AABB
CalcPlayerAABB();
//SetUseGroundNormal(ShouldUseGroundNormalForCurrentShapeModel());
SetPos(GetPosVector3());
//if (iBuddyId != 0)
// AttachBuddy(iBuddyId);
//else
PlayAction(GetMoveStandAction(false, IsFighting()), true);
}
void SetNamePos(A3DVECTOR3 vPos) { m_vNamePos = vPos; }
// Player Attach mode
public enum AttachMode
{
enumAttachNone,
enumAttachRideOnPet,
enumAttachRideOnPlayer,
enumAttachHugPlayer,
};
void DetachBuddy(CECPlayer pBuddy, bool bResetData)
{
if (m_AttachMode == AttachMode.enumAttachNone)
return;
if (m_bHangerOn)
{
if (!pBuddy) pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId);
if (pBuddy)
pBuddy.DetachBuddy(this, bResetData);
else
{
if (bResetData)
{
m_AttachMode = AttachMode.enumAttachNone;
m_bHangerOn = false;
m_iBuddyId = 0;
}
}
}
else
{
if (!pBuddy) pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId);
if (m_AttachMode == AttachMode.enumAttachRideOnPlayer)
{
//if (m_pPlayerModel) m_pPlayerModel.RemoveChildModel(_hanger_ride, false);
}
else if (m_AttachMode == AttachMode.enumAttachHugPlayer)
{
//if (m_pPlayerModel) m_pPlayerModel.RemoveChildModel(_hanger_hug, false);
}
else if (m_AttachMode == AttachMode.enumAttachRideOnPet)
{
if (m_pPetModel)
{
//A3DSkinModelHanger* pHanger = m_pPetModel.GetA3DSkinModel().GetSkinModelHanger(_hanger_ride);
//if (pHanger) pHanger.SetOffsetMat(a3d_IdentityMatrix());
//m_pPetModel.RemoveChildModel(_hanger_ride2, false);
}
}
if (bResetData)
{
m_AttachMode = AttachMode.enumAttachNone;
m_bHangerOn = false;
m_iBuddyId = 0;
}
if (pBuddy)
{
if (bResetData)
{
pBuddy.m_AttachMode = AttachMode.enumAttachNone;
pBuddy.m_bHangerOn = false;
pBuddy.m_iBuddyId = 0;
}
pBuddy.SetPos(pBuddy.GetPosVector3());
pBuddy.SetDirAndUp(pBuddy.transform.forward, pBuddy.transform.up);
pBuddy.PlayAction(GetMoveStandAction(false, IsFighting()), true);
}
PlayAction(GetMoveStandAction(IsPlayingMoveAction(), IsFighting()), true);
}
}
public virtual void SetPos(Vector3 pos)
{
playerTransform.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 bool IsPlayingMoveAction()
{
return m_iCurAction == (int)PLAYER_ACTION_TYPE.ACT_STAND;
}
public void OnMsgPlayerMount(ECMSG Msg)
{
cmd_player_mounting pCmd = GPDataTypeHelper.FromBytes<cmd_player_mounting>((byte[])Msg.dwParam1);
if (pCmd.mount_id != 0)
RideOnPet(pCmd.mount_id, pCmd.mount_color);
else
GetOffPet(true);
}
// Build riding pet file name
string GetRidingPetFileName(int idPet)
{
string szDef = "Models/NPCs/宠物/骑宠/骑宠马/骑宠马白.ecm";
DATA_TYPE DataType = new DATA_TYPE();
var pDataPtr = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)idPet, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
if (DataType != DATA_TYPE.DT_PET_ESSENCE)
return szDef;
PET_ESSENCE pData = (PET_ESSENCE)pDataPtr;
if (pData.file_model[0] == 0)
return szDef;
return ByteToStringUtils.ByteArrayToUTF8String(pData.file_model);
}
public async void QueueLoadPetModel(string szPetPath, bool bAtOnce)
{
var modelPet = await LoadPetModel(szPetPath);
if (modelPet == null)
{
return;
}
SetPetLoadResult(modelPet);
}
public async Task<GameObject> LoadPetModel(string szPetPath)
{
var pPetModel = CECGameRun.Instance.GetPetMount();
if(pPetModel == null)
{
return null;
}
try
{
var model = await AddressableManager.Instance.LoadPrefabAsync(AFile.NormalizePath(szPetPath.ToLower(), true));
if(model == null)
{
model = GameObject.CreatePrimitive(PrimitiveType.Capsule);
}
var obModel = GameObject.Instantiate(model);
obModel.transform.SetParent(pPetModel.transform);
AddressableManager.Instance.ReleaseAsset(szPetPath);
}
catch
{
var model = GameObject.CreatePrimitive(PrimitiveType.Capsule);
var obModel = GameObject.Instantiate(model);
obModel.transform.SetParent(pPetModel.transform);
AddressableManager.Instance.ReleaseAsset(szPetPath);
//return null;
}
return pPetModel;
}
bool SetPetLoadResult(GameObject pPetModel)
{
if (m_RidingPet.id == 0 /*|| !GetMajorModel() || m_CandPet.id != 0*/ || !pPetModel)
return false;
if (m_pPetModel)
{
RIDINGPET pet = m_RidingPet;
GetOffPet(true);
m_RidingPet = pet;
}
A3DVECTOR3 vCurPos = GetPos();
m_aabbServer.Center = vCurPos + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f);
m_aabbServer.CompleteMinsMaxs();
m_pPetModel = pPetModel;
// ½«³èÎïÑÕÉ«ÉèÖõ½Ä£ÐÍÉÏ
//SetRidingPetColor(m_RidingPet.color);
SetUseGroundNormal(true);
//m_pPetModel.SetAffectedByParent(false);
m_pPetModel.transform.position = EC_Utility.ToVector3(vCurPos);
//m_pPetModel.SetDirAndUp(GetDir(), GetUp());
//int iIndex;
//A3DSkeletonHook* pHook = GetMajorModel().GetA3DSkinModel().GetSkeleton().GetHook(_cc_ride, &iIndex);
//if (pHook) pHook.SetFixDirFlag(true);
int iBuddyId = m_iBuddyId;
if (m_AttachMode != AttachMode.enumAttachNone)
DetachBuddy(null, true);
m_pPetModel.transform.SetParent(transform);
//m_pPetModel.AddChildModel(_hanger_ride, false, _hh_ride, GetMajorModel(), _cc_ride);
//m_pPetModel.GetA3DSkinModel().Update(0);
//if (iBuddyId != 0)
// AttachBuddy(iBuddyId);
//else
PlayAction(GetMoveStandAction(false, IsFighting()), true);
return true;
}
protected void RecreateActionController()
{
if (m_pPlayerModel == null){
m_pActionController = null;
return;
}
if (m_pActionController == null){
m_pActionController = new CECPlayerActionController();
}
m_pActionController.Bind(this, m_pPlayerCECModel);
}
protected bool ShouldUseModel()
{
if (!IsElsePlayer()){
return true;
}
bool result = (true);
//switch (m_iMemUsage){
//case CECMemSimplify::MEMUSAGE_NOMODEL:
// result = g_pGame->GetGameRun()->GetMemSimplify()->IsMostImportant(this);
// break;
//case CECMemSimplify::MEMUSAGE_NOMODEL_UNIMPORTANT:
// result = g_pGame->GetGameRun()->GetMemSimplify()->IsImportant(this);
// break;
//}
return result;
}
protected async Task<bool> LoadPlayerSkeleton(bool bAtOnce)
{
int[] aEnabledEquips = new int[InventoryConst.SIZE_ALL_EQUIPIVTR];
for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++)
{
// TODO: m_i64EquipDisabled — zero slot when disabled: ((1L << i) & m_i64EquipDisabled) != 0 ? 0 : m_aEquips[i]
aEnabledEquips[i] = m_aEquips[i];
}
string szPetPath = null;
if (m_RidingPet.id != 0)
szPetPath = GetRidingPetFileName(m_RidingPet.id);
int[] aEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK];
uint EquipMask = 0;
if (aEnabledEquips[InventoryConst.EQUIPIVTR_WEAPON] > 0)
EquipMask |= 1 << InventoryConst.EQUIPIVTR_WEAPON;
if (aEnabledEquips[InventoryConst.EQUIPIVTR_FASHION_WEAPON] > 0)
EquipMask |= 1 << InventoryConst.EQUIPIVTR_FASHION_WEAPON;
Array.Copy(aEnabledEquips, aEquips, InventoryConst.IVTRSIZE_EQUIPPACK);
DecideWeaponLoad(aEquips, EquipMask);
// Same pipeline as SetPlayerModel / TransformShape: NPCManager model load + optional pet + dummy shape.
int shapeSnapshot = m_iShape;
try
{
await SetPlayerModel((byte)m_iProfession, (byte)m_iGender);
}
catch (Exception ex)
{
BMLogger.LogError($"CECPlayer::LoadPlayerSkeleton, SetPlayerModel failed: {ex.Message}");
return false;
}
SetPlayerLoadedResult(default(EC_PLAYERLOADRESULT));
if (!string.IsNullOrEmpty(szPetPath))
{
GameObject petGo = await LoadPetModel(szPetPath);
SetPetLoadResult(petGo);
}
if (shapeSnapshot != 0 && !await QueueLoadDummyModel(shapeSnapshot, bAtOnce))
{
BMLogger.LogError("CECPlayer::LoadPlayerSkeleton, failed to call QueueLoadDummyModel() !");
return false;
}
BMLogger.Log($"CECPlayer::LoadPlayerSkeleton completed, shapeSnapshot: {shapeSnapshot}");
return true;
}
void DecideWeaponLoad(int[] pEquipmentID, uint Mask)
{
bool bNormalWeaponChanged = ((1 << InventoryConst.EQUIPIVTR_WEAPON) & Mask) != 0;
bool bFashionWeaponChanged = ((1 << InventoryConst.EQUIPIVTR_FASHION_WEAPON) & Mask) != 0;
WEAPON_ESSENCE pWeapon = new WEAPON_ESSENCE();
FASHION_ESSENCE pFashion = new FASHION_ESSENCE();
WEAPON_SUB_TYPE pSubType = new WEAPON_SUB_TYPE();
int[] Index = {InventoryConst.EQUIPIVTR_WEAPON, InventoryConst.EQUIPIVTR_FASHION_WEAPON};
for (int i = 0; i < 2; ++i)
{
int idEquipment = pEquipmentID[Index[i]];
idEquipment &= 0x0000ffff;
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
if (idEquipment != 0)
{
var pEquip =ElementDataManProvider.GetElementDataMan().get_data_ptr( // TODO: Implement this
(uint)idEquipment,
ID_SPACE.ID_SPACE_ESSENCE,
ref dt);
if (dt == DATA_TYPE.DT_WEAPON_ESSENCE)
{
pWeapon = (WEAPON_ESSENCE)pEquip;
pSubType =(WEAPON_SUB_TYPE)ElementDataManProvider.GetElementDataMan().get_data_ptr(
pWeapon.id_sub_type,
ID_SPACE.ID_SPACE_ESSENCE,
ref dt);
if (dt != DATA_TYPE.DT_WEAPON_SUB_TYPE) pSubType = new WEAPON_SUB_TYPE();
}
else if (dt == DATA_TYPE.DT_FASHION_ESSENCE) pFashion = (FASHION_ESSENCE)pEquip;
}
}
// bool bCanShowFashionWeaponBefore = CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType);
// bool bCanShowFashionWeapon = false;
//var pGameUI = GameUIManagerProvider.GetGameUIManager().GetInGameUIMan();
// ͨı
// if (bNormalWeaponChanged)
// {
// // ʱװı
// if (bFashionWeaponChanged)
// {
// // װʱװͨ
// if (pSubType != null && pFashion != null)
// {
// if (CanShowFashionWeapon((int)pSubType.action_type, (int)pFashion.action_type))
// {
// CLEAR_WEAPON(InventoryConst.EQUIPIVTR_WEAPON);
// }
// else
// {
// CLEAR_WEAPON(InventoryConst.EQUIPIVTR_FASHION_WEAPON);
// }
// }
// // װͨ
// else if(pSubType && !pFashion)
// {
// }
// // װʱװ
// else if (!pSubType && pFashion)
// {
// if (CanShowFashionWeapon(m_uAttackType, pFashion->action_type))
// {
// CLEAR_WEAPON(EQUIPIVTR_WEAPON);
// }
// else
// {
// CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
// }
// }
// // ûװ
// else
// {
// }
// if (pSubType) RECORD_NORMAL_WEAPON(
// pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type);
// if (pFashion) RECORD_FASHION_WEAPON(
// pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type);
// }
// else
// {
// // װͨ
// if (pSubType)
// {
// bCanShowFashionWeapon = CanShowFashionWeapon(pSubType->action_type, m_iFashionWeaponType);
// if (bCanShowFashionWeapon)
// {
// CLEAR_WEAPON(EQUIPIVTR_WEAPON);
// if (!bCanShowFashionWeaponBefore)
// SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]);
// }
// RECORD_NORMAL_WEAPON(
// pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type);
// }
// // ͨ
// else
// {
// bCanShowFashionWeapon = CanShowFashionWeapon(DEFAULT_ACTION_TYPE, m_iFashionWeaponType);
// if (bCanShowFashionWeapon)
// {
// CLEAR_WEAPON(EQUIPIVTR_WEAPON);
// if (!bCanShowFashionWeaponBefore)
// SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]);
// }
// RECORD_NORMAL_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE);
// }
// }
// }
// else if (bFashionWeaponChanged)
// {
// // װʱװ
// if (pFashion)
// {
// bCanShowFashionWeapon = CanShowFashionWeapon(m_uAttackType, pFashion->action_type);
// if (!bCanShowFashionWeapon)
// {
// if (pGameUI && this == g_pGame->GetGameRun()->GetHostPlayer() && InFashionMode())
// pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM);
// CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
// if (bCanShowFashionWeaponBefore)
// SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]);
// }
// // ʾʱװ˴Ҫm_stoneWeapon
// else CLEAR_WEAPON(EQUIPIVTR_WEAPON);
// RECORD_FASHION_WEAPON(
// pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type);
// }
// // ʱװ
// else
// {
// if (0 != m_aEquips[EQUIPIVTR_WEAPON])
// {
// CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON);
// if (bCanShowFashionWeaponBefore)
// SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]);
// }
// RECORD_FASHION_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE);
// }
// }
// if (bCanShowFashionWeaponBefore && !bCanShowFashionWeapon
// && pGameUI && !bFashionWeaponChanged && bNormalWeaponChanged && this == g_pGame->GetGameRun()->GetHostPlayer())
// pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM);
}
protected bool SetPlayerLoadedResult(EC_PLAYERLOADRESULT ret)
{
OnAllResourceReady();
return true;
}
protected void OnAllResourceReady()
{
CECHostSkillModel.Instance.Initialize();
}
// Is resources ready ?
protected bool IsSkeletonReady() { return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_SKELETON) != 0 ? true : false; }
// Set resources ready flag
protected void SetResReadyFlag(uint dwFlag, bool bSet)
{
if (bSet)
{
m_dwResFlags |= dwFlag;
}
else
m_dwResFlags &= ~dwFlag;
}
public virtual void Release()
{
//TODO: Implement this latter
// DetachBuddy();
// // Clear extend states before model is released
// ClearShowExtendStates();
// ::memset(m_aExtStates, 0, sizeof(m_aExtStates));
// m_aIconStates.clear();
// if (m_pPateName)
// {
// delete m_pPateName;
// m_pPateName = NULL;
// }
// if (m_pPateMarry)
// {
// delete m_pPateMarry;
// m_pPateMarry = NULL;
// }
// if (m_pPateForce)
// {
// delete m_pPateForce;
// m_pPateForce = NULL;
// }
// if (m_pPateTitle)
// {
// delete m_pPateTitle;
// m_pPateTitle = NULL;
// }
// if (m_pPateLastWords1)
// {
// delete m_pPateLastWords1;
// m_pPateLastWords1 = NULL;
// }
// if (m_pPateLastWords2)
// {
// delete m_pPateLastWords2;
// m_pPateLastWords2 = NULL;
// }
// if (m_pPateTeamReq)
// {
// delete m_pPateTeamReq;
// m_pPateTeamReq = NULL;
// }
// if (m_pPateBooth)
// {
// delete m_pPateBooth;
// m_pPateBooth = NULL;
// }
// if (m_pPateFaction)
// {
// delete m_pPateFaction;
// m_pPateFaction = NULL;
// }
// if (m_pFactionDecal)
// {
// delete m_pFactionDecal;
// m_pFactionDecal = NULL;
// }
// if (m_pPateCountry)
// {
// delete m_pPateCountry;
// m_pPateCountry = NULL;
// }
// if (m_pCountryDecal)
// {
// delete m_pCountryDecal;
// m_pCountryDecal = NULL;
// }
// if (m_pBubbleTexts)
// {
// delete m_pBubbleTexts;
// m_pBubbleTexts = NULL;
// }
// if (m_pLevelUpGFX)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pLevelUpGFX);
// m_pLevelUpGFX = NULL;
// }
// if (m_pPetCureGFX)
// {
// A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
// if (pGFXExMan)
// pGFXExMan->CacheReleasedGfx(m_pPetCureGFX);
// m_pPetCureGFX = NULL;
// m_pPetCureGFXtate = -1;
// }
// for (int i = 0; i < sizeof(m_pMonsterSpiritGFX) / sizeof(m_pMonsterSpiritGFX[0]); ++i) {
// A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
// if (pGFXExMan)
// pGFXExMan->CacheReleasedGfx(m_pMonsterSpiritGFX[i]);
// m_pMonsterSpiritGFX[i] = NULL;
// }
// if (m_pWaterWaveStill)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveStill);
// m_pWaterWaveStill = NULL;
// }
// if (m_pWaterWaveMove)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveMove);
// m_pWaterWaveMove = NULL;
// }
// if (m_pAirBubble)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pAirBubble);
// m_pAirBubble = NULL;
// }
// if (m_pSwimBubble)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pSwimBubble);
// m_pSwimBubble = NULL;
// }
// if (m_pTransformGfx)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pTransformGfx);
// m_pTransformGfx = NULL;
// }
// if (m_pDuelStateGFX)
// {
// g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pDuelStateGFX);
// m_pDuelStateGFX = NULL;
// }
// if (m_pPetModel)
// {
// m_pPetModel->RemoveChildModel(_hanger_ride, false);
// A3DRELEASE(m_pPetModel);
// }
// ClearBoothModel();
// for (MOEffectMAP::iterator it = m_mapMOEffect.begin();it != m_mapMOEffect.end();++it)
// {
// A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan();
// pGFXExMan->CacheReleasedGfx(it->second);
// }
// m_mapMOEffect.clear();
// // Release face model
// ReleaseFaceModel();
// // Release player model
// ReleasePlayerModel();
// // Clear resource ready flags
// SetResReadyFlag(RESFG_ALL, false);
// m_bAboutToDie = false;
}
public void CloneSimplePropertyTo(CECPlayer player)
{
//TOdo: Complete this function(remove all commented code)
player.transform.position = m_pPlayerModel.transform.position;
player.transform.rotation = m_pPlayerModel.transform.rotation;
player.SetGroundNormal(GetGroundNormal());
player.SetUseGroundNormal(GetUseGroundNormal());
// CECPlayer
player.m_PlayerInfo = GetPlayerInfo();
player.SetBornStamp(GetBornStamp());
player.name = GetName();
//player.SetProps(&GetBasicProps(), &GetExtendProps());
player.m_iGender = GetGender();
player.m_iProfession = GetProfession();
//player.m_pvp = GetPVPInfo();
//player.m_aIconStates = GetIconStates();
player.SetMoneyAmount(GetMoneyAmount());
player.m_iMaxMoney = GetMaxMoneyAmount();
//player.m_i64EquipDisabled = m_i64EquipDisabled;
//player.SetBoothState(GetBoothState());
//player.m_factionPVPMask= m_factionPVPMask;
//player.m_RidingPet = GetRidingPetInfo();
//player.m_iBattleCamp = GetBattleCamp();
//player.m_dwGMFlags = m_dwGMFlags;
//player.SetSpouse(GetSpouse());
player.m_idForce = GetForce();
//player.SetCountry(GetCountry());
//player.SetMoveMode(GetMoveMode());
//player.SetMoveEnv(GetMoveEnv());
//player.SetWalkRunFlag(GetWalkRunFlag());
player.m_MoveConst = m_MoveConst;
player.m_aabbServer = m_aabbServer;
player.m_aabb = m_aabb;
player.m_dwStates = m_dwStates;
//player.m_dwStates2 = m_dwStates2;
player.m_fTouchRad = GetTouchRadius();
//player.m_byPariahLvl = GetPariahLevel();
//player.SetBoothName(GetBoothName());
// player.m_CustomizeFactor = m_CustomizeFactor;
// player.ChangeCustomizeData(m_CustomizeData);
// for (int i=0; i < GetEffectCount(); i++)
// player.ApplyEffect(GetEffect(i), true);
// player.SetFactionID(GetFactionID());
player.SetCurPetID(GetCurPetID());
// player.SetCurrentTitle(GetCurrentTitle());
// player.SetReputation(GetReputation());
// player.SetFashionMode(InFashionMode());
// player.SetFRoleID(GetFRoleID());
// player.SetMeridiansProp(GetMeridiansProp());
// player->SetReincarnationCount(GetReincarnationCount());
// player.SetRealmLevel(GetRealmLevel());
// player.ScaleBody(GetScaleBySkill());
// player.SetTeamRequire(GetTeamRequire(), false);
player.SetNewExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
// player.m_GoblinRenderCnt = m_GoblinRenderCnt;
// player.m_bRenderGoblin = m_bRenderGoblin;
}
public int GetOriginalShapeID()
{
return m_iShape;
}
public async Task TransformShape(byte iShape, bool bLoadAtOnce = false/* =false */)
{
SetShape(iShape);
//a_LogOutput(1, "CECPlayer::TransformShape(iShape=%d)(iShapeType=%d,iShapeID=%d)", iShape, PLAYERMODEL_GETTYPE(iShape), PLAYERMODEL_GETID(iShape));
if (!GetMajorModel()) return;
if (IsShapeChanged())
{
m_bWeaponAttached = false;
// change to a dummy model, may cause an asynchronous loading
await QueueLoadDummyModel(m_iShape, bLoadAtOnce);
}
else
{
m_bWeaponAttached = true;
// back to major model is a synchronous operation
ApplyShapeModelChange(GetMajorModel());
}
OnModelChange(GetMajorModel());
}
void SetShape(byte iShape)
{
// The shape id from the server is a 8-bit number
// The meaning of each bit:
// | 7 6 | 5 4 3 2 1 0 |
// |-TYPE-|-----Model ID-----|
int iNewShape = (iShape & 0xff); // only accept 8bit
// ԾɵShapeݽ
FixOldShapeInfo(ref iNewShape);
// ְҵModel IDҪת
if( PLAYERMODEL_GETTYPE(iNewShape) == (int)PLAYERMODEL_TYPE.PLAYERMODEL_PROFESSION )
{
int iRealID = _GetProfessionTransformModelID(
m_iProfession, m_iGender, PLAYERMODEL_GETID(iNewShape));
iNewShape = 0x40 | iRealID;
}
// ְҵModel IDΪEC_Resource.hֵʲ
else
{
}
// store the original data into 8~15 bit
m_iShape = iNewShape | ((iShape & 0xff) << 8);
}
void FixOldShapeInfo(ref int iShape)
{
// ǸʱshapeΪ0ûб0ְҵ
if(iShape != 0 && PLAYERMODEL_GETTYPE(iShape) == 0)
iShape |= 0x40;
}
public int _GetProfessionTransformModelID(int nChar, int nGender, int nModelID)
{
int result = 0;
switch (nChar){
case (int)PROFESSION.PROF_HAG: //
result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_FOX2 : (int)ModelResourceType.RES_MOD_ORC_FOX;
break;
case (int)PROFESSION.PROF_ORC: //
result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_PANDER : (int)ModelResourceType.RES_MOD_ORC_TIGER;
break;
case (int)PROFESSION.PROF_MONK: // ʦ
case (int)PROFESSION.PROF_GHOST: // ̿
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_SHADOW_FISH_M : (int)ModelResourceType.RES_MOD_SHADOW_FISH_F;
break;
case (int)PROFESSION.PROF_YEYING: // ҹӰ
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_M : (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_F;
break;
case (int)PROFESSION.PROF_YUEXIAN: //
result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M : (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F;
break;
}
return result;
}
}
public struct PlayActionEvent
{
public string AnimationName;
public int ITransTime;
public bool IsForceStopPrevious;
public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false)
{
this.AnimationName = shapeName + animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
}
public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false)
{
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
}
}
public struct PLAYER_ACTION
{
public PLAYER_ACTION_TYPE type;
public PLAYER_ACTION_INFO_CONFIG data;
};
public class QueueActionEvent
{
public string AnimationName;
public int ITransTime;
public Action<bool, CECAttackEvent> SetFlag;
public CECAttackEvent AttackEvent;
public bool IsHitAnim;
public bool IsForceStopPrevious;
public QueueActionEvent(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
{
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
}
public void SetData(string shapeName, string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
{
this.AnimationName = shapeName + animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
}
public void SetData(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false)
{
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
}
}
public enum PLAYER_ACTION_TYPE
{
// 0
ACT_STAND = 0, // Đứng
ACT_FIGHTSTAND, // Đứng chiến đ?u
ACT_WALK, // Đi b?
ACT_RUN, // Ch?y
ACT_JUMP_START, // Bắt đ?u nh?y
// 5
ACT_JUMP_LOOP, // Nh?y trên không lặp l?i
ACT_JUMP_LAND, // Nh?y tiếp đ?t
ACT_SWIM, // Bơi
ACT_HANGINWATER, // Lơ lửng trong nước
ACT_TAKEOFF, // C?t cánh (should be ACT_TAKEOFF_WING)
// 10
ACT_HANGINAIR, // Treo trên không (should be ACT_HANGINAIR_WING)
ACT_FLY, // Bay (should be ACT_FLY_WING)
ACT_FLYDOWN, // Bay xuống cao (should be ACT_FLYDOWN_WING_HIGH)
ACT_FLYDOWN_WING_LOW, // Bay xuống th?p (should be ACT_FLYDOWN_WING_LOW)
ACT_LANDON, // H? cánh (should be ACT_LAND_WING)
// 15
ACT_TAKEOFF_SWORD, // Kiếm bay - c?t cánh
ACT_HANGINAIR_SWORD, // Kiếm bay - treo không trung
ACT_FLY_SWORD, // Kiếm bay - tiến tới
ACT_FLYDOWN_SWORD_HIGH, // Kiếm bay - rơi cao
ACT_FLYDOWN_SWORD_LOW, // Kiếm bay - rơi th?p
// 20
ACT_LANDON_SWORD, // Kiếm bay - h? cánh
ACT_SITDOWN, // Ngồi
ACT_SITDOWN_LOOP, // Ngồi lặp l?i
ACT_STANDUP, // Đứng dậy
ACT_WOUNDED, // B? thương
// 25
ACT_GROUNDDIE, // Chết trên mặt đ?t
ACT_GROUNDDIE_LOOP, // Chết trên đ?t (loop)
ACT_WATERDIE, // Chết trong nước
ACT_WATERDIE_LOOP, // Chết trong nước (loop)
ACT_AIRDIE_ST, // Chết trên không (bắt đ?u)
// 30
ACT_AIRDIE, // Chết trên không (loop rơi)
ACT_AIRDIE_ED, // Chết trên không (ch?m đ?t)
ACT_AIRDIE_LAND_LOOP, // Chết rơi đ?t (loop)
ACT_REVIVE, // Hồi sinh
ACT_CUSTOMIZE, // Động tác tùy chỉnh
// 35
ACT_STRIKEBACK, // B? đánh lùi
ACT_STRIKEDOWN, // B? đánh ngã
ACT_STRIKEDOWN_LOOP, // B? đánh ngã (loop)
ACT_STRIKEDOWN_STANDUP, // B? đánh ngã rồi đứng dậy
ACT_PICKUP, // Nhặt đ?
// 40
ACT_PICKUP_LOOP, // Nhặt đ? (loop)
ACT_PICKUP_STANDUP, // Nhặt đ? đứng dậy
ACT_PICKUP_MATTER, // Nhặt vật th?
ACT_GAPE, // Há miệng
ACT_LOOKAROUND, // Nhìn quanh
// 45
ACT_PLAYWEAPON, // Vung vũ khí
ACT_EXP_WAVE, // Vẫy tay
ACT_EXP_NOD, // Gật đ?u
ACT_EXP_SHAKEHEAD, // Lắc đ?u
ACT_EXP_SHRUG, // Nhún vai
// 50
ACT_EXP_LAUGH, // Cười lớn
ACT_EXP_ANGRY, // Tức giận
ACT_EXP_STUN, // Choáng
ACT_EXP_DEPRESSED, // Buồn bã
ACT_EXP_KISSHAND, // Hôn tay
// 55
ACT_EXP_SHY, // Ng?i ngùng
ACT_EXP_SALUTE, // Chào
ACT_EXP_SITDOWN, // Ngồi xuống
ACT_EXP_SITDOWN_LOOP, // Ngồi xuống (loop)
ACT_EXP_SITDOWN_STANDUP, // Ngồi xuống rồi đứng dậy
// 60
ACT_EXP_ASSAULT, // T?n công
ACT_EXP_THINK, // Suy nghĩ
ACT_EXP_DEFIANCE, // Thách thức
ACT_EXP_VICTORY, // Chiến thắng
ACT_EXP_KISS, // Hôn
// 65
ACT_EXP_KISS_LOOP, // Hôn (loop)
ACT_EXP_KISS_END, // Kết thúc hôn
ACT_ATTACK_1, // T?n công 1
ACT_ATTACK_2, // T?n công 2
ACT_ATTACK_3, // T?n công 3
// 70
ACT_ATTACK_4, // T?n công 4
ACT_ATTACK_TOSS, // Ném vũ khí
ACT_TRICK_RUN, // Chiêu khi ch?y
ACT_TRICK_JUMP, // Chiêu khi nh?y
ACT_FLY_GLIDE, // Lư?n
// 75
ACT_FLY_GLIDE_SWORD, // Kiếm bay - lư?n
ACT_EXP_FIGHT, // Tư th? chiến đ?u
ACT_EXP_ATTACK1, // T?n công diễn xu?t 1
ACT_EXP_ATTACK2, // T?n công diễn xu?t 2
ACT_EXP_ATTACK3, // T?n công diễn xu?t 3
// 80
ACT_EXP_ATTACK4, // T?n công diễn xu?t 4
ACT_EXP_DEFENCE, // Phòng th?
ACT_EXP_FALL, // Té ngã
ACT_EXP_FALLONGROUND, // Ngã xuống đ?t
ACT_EXP_LOOKAROUND, // Nhìn quanh
// 85
ACT_EXP_DANCE, // Nh?y múa
ACT_EXP_FASHIONWEAPON, // Động tác vũ khí thời trang
ACT_USEITEM, // Dùng item
ACT_USEITMELOOP, // Dùng item (loop)
ACT_TWO_KISS, // Hôn đôi
// 90
ACT_USING_TARGET_ITEM, // Dùng đ?o c?
ACT_SWIM_FOR_MOVESKILL, // Bơi trong lúc dùng skill di chuyển
ACT_MAX,
ACT_CASTSKILL // Ch? là placeholder cho skill actions
}
public struct ClearComActFlagAllRankNodesEvent
{
public bool v;
public ClearComActFlagAllRankNodesEvent(bool value)
{
v = value;
}
}
[Serializable]
public struct INFO
{
public int cid; // Character ID
public int crc_c; // customized data crc
public int crc_e; // Equipment data crc
public INFO(int cid, int crc_c, int crc_)
{
this.cid = cid;
this.crc_c = crc_c;
this.crc_e = crc_;
}
}
public
enum enumWingType
{
WINGTYPE_WING, // 飞行器类型:翅膀
WINGTYPE_FLYSWORD, // 飞行器类型:飞剑
WINGTYPE_DOUBLEWHEEL, // 飞行器类型:双脚飞行器
};
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
};
// Battle type / 战斗类型
public enum BattleType
{
BT_NONE = 0, // No battle / 无战斗
BT_GUILD = 1, // Guild war / 帮派战
BT_COUNTRY = 2, // Country war / 国战
BT_CHARIOT = 3, // Chariot war / 战车战
};
// Score rank entry for country battle live show / 国战直播显示分数排行条目
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ScoreRankEntry
{
public int idPlayer; // Player ID / 玩家ID
public int iScore; // Score / 分数
public int iKillCount; // Kill count / 击杀数
public int iDeathCount; // Death count / 死亡数
};
// Death entry for country battle live show / 国战直播显示死亡条目
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeathEntry
{
public int idKiller; // Killer ID / 击杀者ID
public int idVictim; // Victim ID / 受害者ID
public int iTime; // Death time / 死亡时间
};
// Battle information / 战斗信息
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BATTLEINFO
{
public int nType; // Battle type / 战斗类型 (BattleType)
public int idBattle; // Battle id / 战斗ID
public int iResult; // Battle result / 战斗结果 (0 = no result, 1 = win, 2 = lose, 3 = draw)
public int iResultCnt; // Result time counter / 结果时间计数器
public int iMaxScore_I; // Maximum score of invader / 攻击方最大分数
public int iMaxScore_D; // Maximum score of defender / 防守方最大分数
public int iScore_I; // Score of invader / 攻击方分数
public int iScore_D; // Score of defender / 防守方分数
public int iEndTime; // Battle end time / 战斗结束时间
// 国战专用数据 / Country war specific data
public int iOffenseCountry; // Offense country / 攻击方国家
public int iDefenceCountry; // Defence country / 防守方国家
public int iReviveTimes; // 剩余复活次数 / Remaining revive times
[MarshalAs(UnmanagedType.U1)]
public bool bFlagCarrier; // 是否是旗手 / Is flag carrier
public int iCarrierID; // 扛旗者IDbFlagCarrier为false时有效)/ Carrier ID (valid when bFlagCarrier is false)
public A3DVECTOR3 posCarrier; // 扛旗者位置(bFlagCarrier为false时有效)/ Carrier position (valid when bFlagCarrier is false)
[MarshalAs(UnmanagedType.U1)]
public bool bCarrierInvader; // 扛旗者是攻击方(bFlagCarrier为false时有效)/ Carrier is invader (valid when bFlagCarrier is false)
public int iCombatTime; // 战斗时间(秒)/ Combat time (seconds)
public int iAttendTime; // 参加战场时间(秒)/ Attend time (seconds)
public int iKillCount; // 击杀次数 / Kill count
public int iDeathCount; // 死亡次数 / Death count
public int iCountryKillCount; // 同国家击杀次数 / Same country kill count
public int iCountryDeathCount;// 同国家死亡次数 / Same country death count
public int iAttackerCount; // 攻击方人数 / Attacker count
public int iDefenderCount; // 防守方人数 / Defender count
public int iStrongHoldCount; // 据点个数 / Stronghold count
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] iStrongHoldState; // 据点占领状态 8 == ARRAY_SIZE(COUNTRY_CONFIG::stronghold) / Stronghold occupation state
// Score rank containers (using List instead of std::vector) / 分数排行容器(使用List代替std::vector
public List<ScoreRankEntry> OffenseRanks; // Offense ranks / 攻击方排行
public List<ScoreRankEntry> DefenceRanks; // Defence ranks / 防守方排行
// Death containers (using List instead of std::vector) / 死亡容器(使用List代替std::vector
public List<DeathEntry> OffenseDeaths; // Offense deaths / 攻击方死亡
public List<DeathEntry> DefenceDeaths; // Defence deaths / 防守方死亡
// 战车 / Chariot
public int iChariot; // 战车id / Chariot id
public int iEnergy; // 能量 / Energy
public int iScoreSelf; // 自己成绩 / Self score
public int iMultiKill; // 连杀 / Multi kill
// Initialize arrays and lists / 初始化数组和列表
public void Initialize()
{
if (iStrongHoldState == null)
iStrongHoldState = new int[8];
if (OffenseRanks == null)
OffenseRanks = new List<ScoreRankEntry>();
if (DefenceRanks == null)
DefenceRanks = new List<ScoreRankEntry>();
if (OffenseDeaths == null)
OffenseDeaths = new List<DeathEntry>();
if (DefenceDeaths == null)
DefenceDeaths = new List<DeathEntry>();
}
// Set country battle live show info / 设置国战直播显示信息
// TODO: Implement when cmd_countrybattle_live_show_result is available
// 当cmd_countrybattle_live_show_result可用时实现
public void SetCountryBattleLiveShowInfo(/*const S2C::cmd_countrybattle_live_show_result& cmd*/)
{
// TODO: Implement SetCountryBattleLiveShowInfo
// 实现SetCountryBattleLiveShowInfo
}
// Check if in guild war / 检查是否在帮派战中
public bool IsGuildWar()
{
return nType == (int)BattleType.BT_GUILD;
}
// Check if in country war / 检查是否在国战中
public bool IsCountryWar()
{
return nType == (int)BattleType.BT_COUNTRY;
}
// Check if is flag carrier / 检查是否是旗手
public bool IsFlagCarrier()
{
return IsCountryWar() && bFlagCarrier;
}
// Check if in chariot war / 检查是否在战车战中
public bool IsChariotWar()
{
return nType == (int)BattleType.BT_CHARIOT;
}
// Reset battle info / 重置战斗信息
public void Reset()
{
nType = (int)BattleType.BT_NONE;
idBattle = 0;
iResult = 0;
iResultCnt = 0;
iMaxScore_I = 0;
iMaxScore_D = 0;
iScore_I = 0;
iScore_D = 0;
iEndTime = 0;
iOffenseCountry = 0;
iDefenceCountry = 0;
iReviveTimes = 0;
bFlagCarrier = false;
iCarrierID = 0;
posCarrier = new A3DVECTOR3(0, 0, 0);
bCarrierInvader = false;
iCombatTime = 0;
iAttendTime = 0;
iKillCount = 0;
iDeathCount = 0;
iCountryKillCount = 0;
iCountryDeathCount = 0;
iAttackerCount = 0;
iDefenderCount = 0;
iStrongHoldCount = 0;
if (iStrongHoldState != null)
{
for (int i = 0; i < iStrongHoldState.Length; i++)
iStrongHoldState[i] = 0;
}
OffenseRanks?.Clear();
DefenceRanks?.Clear();
OffenseDeaths?.Clear();
DefenceDeaths?.Clear();
iChariot = 0;
iEnergy = 0;
iScoreSelf = 0;
iMultiKill = 0;
}
};
public enum PlayerResourcesReadyFlag
{
RESFG_SKELETON = 0x01,
RESFG_SKIN = 0x02,
RESFG_CUSTOM = 0x04,
RESFG_ASSEMBLED = 0x08,
RESFG_ALL = 0x0f,
};
public static class Duel_state // Duel state
{
public const int DUEL_ST_NONE = 0,
DUEL_ST_PREPARE = 1,
DUEL_ST_INDUEL = 2,
DUEL_ST_STOPPING = 3;
}
//// Move mode
public class Move_Mode
{
public const int MOVE_STAND = 0,
MOVE_MOVE = 1, // Normal move, walk, run, swim or fly
MOVE_JUMP = 2,
MOVE_FREEFALL = 3,
MOVE_SLIDE = 4;
}
public class EC_Player_Skin_Const
{
// Skin index
public static byte SKIN_BODY_INDEX = 0;
public static byte SKIN_UPPER_BODY_INDEX = 1;
public static byte SKIN_WRIST_INDEX = 2;
public static byte SKIN_LOWER_INDEX = 3;
public static byte SKIN_FOOT_INDEX = 4;
public static byte SKIN_HEAD_INDEX = 5;
public static byte SKIN_FASHION_UPPER_BODY_INDEX = 6;
public static byte SKIN_FASHION_WRIST_INDEX = 7;
public static byte SKIN_FASHION_LOWER_INDEX = 8;
public static byte SKIN_FASHION_FOOT_INDEX = 9;
public static byte NUM_SKIN_INDEX = 10;
}
public enum enumSkinShow
{
enumSkinShowNone = 0,
enumSkinShowUpperBody,
enumSkinShowWrist,
enumSkinShowLowerBody,
enumSkinShowFoot,
enumSkinShowUpperAndLower,
enumSkinShowUpperAndWrist,
enumSkinShowLowerAndFoot,
enumSkinShowUpperLowerAndWrist,
enumSkinShowArmet,
enumSkinShowHand,
};
/// <summary>
/// Place holder for riding pet. Not test logic yet.
/// </summary>
public struct RIDINGPET
{
public int id;
public ushort color;
public RIDINGPET(bool isReset = true)
{
id = 0;
color = 0;
}
public bool GetColor(Color clr)
{
// ȡǰȾɫɫ
return id > 0 && GetColor(color, clr);
}
public static bool GetColor(ushort c, Color clr)
{
// ѯǰǷȾɫȾɫرȾ֮ɫ
bool bRet = false;
if ((c & (1 << (8 - 1))) != 0)
{
// unsigned short λΪ1ʱʾȾɫʱɻȡɫ
clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3);
bRet = true;
}
return bRet;
}
public static Color GetDefaultColor()
{
return new Color(255, 255, 255);
}
};
}