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;
using BrewMonster.Scripts.ECModel;
namespace BrewMonster
{
public abstract partial class CECPlayer : CECObject, ITickable
{
[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 };
/// Skill id for pending skill/state hit reaction (see skill_state_action.txt).
protected int m_SkillIDForStateAction;
private static Dictionary _default_skill_actions
= new Dictionary();
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 m_aCurEffects = new List(); // 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 m_aIconStates = new List();
protected byte m_byPariahLvl = 0; // Pariah level
public RIDINGPET m_RidingPet; // Riding pet information
public GameObject m_pPetModel = null; // Pet model
public GameObject m_PetModelVisual = null;
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 Dictionary> m_aWeaponSFX = new Dictionary>()
{
{0, new List{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{1, new List{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{2, new List{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
{3, new List{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{4, new List{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
{5, new List{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb"}},
{6, new List{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{7, new List{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{8, new List{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
{9, new List{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{10, new List{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
// {0, new List{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
// {1, new List{"item/weaponattack/2hheavya", "item/weaponattack/2hheavyb", "item/weaponattack/2hheavyc", "item/weaponattack/2hheavyd"}},
// {2, new List{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
// {3, new List{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
// {4, new List{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
// {5, new List{"item/weaponattack/magic", "item/weaponattack/magicb"}},
};
public Dictionary> m_aWeaponHitSFX = new Dictionary>()
{
{0, new List{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
{1, new List{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
{2, new List{"item/weaponattack/hitmace", "item/weaponattack/hitmacebig"}},
{3, new List{"item/weaponattack/hithammer", "item/weaponattack/hithammerbig"}},
{4, new List{"item/weaponattack/hitaxe", "item/weaponattack/hitaxebig"}},
{5, new List{"item/weaponattack/hithammer"}},
{6, new List{"item/weaponattack/hitthrow"}},
{7, new List{"item/weaponattack/hitthrow"}},
{8, new List{"item/weaponattack/hithand"}},
{9, new List{"item/weaponattack/hitthrow"}},
{10, new List{"item/weaponattack/hithand"}},
// {0, new List{"item/weaponattack/hitaxe", "item/weaponattack/hitaxebig"}},
// {1, new List{"item/weaponattack/hithammer", "item/weaponattack/hithammerbig"}},
// {2, new List{"item/weaponattack/hitblade", "item/weaponattack/hitbladebig"}},
// {3, new List{"item/weaponattack/hitdagger"}},
// {4, new List{"item/weaponattack/hitfist"}},
// {5, new List{"item/weaponattack/hithand"}},
// {6, new List{"item/weaponattack/hitstaff"}},
// {7, new List{"item/weaponattack/hitmace", "item/weaponattack/hitmacebig"}},
// {8, new List{"item/weaponattack/hitoriginal"}},
// {9, new List{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
// {10, new List{"item/weaponattack/hittiger"}},
// {11, new List{"item/weaponattack/hitwhip"}},
// {12, new List{"item/weaponattack/hitthrow"}},
// {13, new List{"item/weaponattack/hitbow", "item/weaponattack/hitbowbig"}},
};
public static class Effect_type
{
public const int EFF_FACEPILL = 1;
}
private BaseVfxObject _levelUpVfx;
// [中文] 当前激活的状态效果 GFX,以 (路径+挂点) 为键
// [English] Currently active state-effect GFX objects, keyed by (path + hook)
private Dictionary _stateGfxObjects = new Dictionary();
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;
public 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);
TickInvoker.Instance.RegisterTickable(this);
m_SkillIDForStateAction = 0;
}
protected virtual void OnDestroy()
{
TickInvoker.Instance.UnregisterTickable(this);
}
public override bool Tick(uint dwDeltaTime)
{
if(m_pPlayerCECModel != null)
{
m_pPlayerCECModel.Tick(dwDeltaTime);
}
return true;
}
/// This function will get the coressponding model player for the player based on the profession and gender
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();
if (transform.childCount >= 3)
{
pointCam = transform.GetChild(2);
}
// Initialize CECModel for hook system
// 初始化CECModel以支持挂点系统
await InitializePlayerCECModel(profession,gender);
if (m_pPlayerCECModel == null || m_pPlayerModel == null)
{
throw new InvalidOperationException(
$"SetPlayerModel failed to initialize model. profession={profession}, gender={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 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::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;
}
///
/// Update visual components (NPCVisual, PlayerVisual) when model changes
/// 当模型更改时更新视觉组件(NPCVisual、PlayerVisual)
///
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();
if (npcVisual != null)
{
npcVisual.RefreshNamedAnimancer(modelRoot);
}
// Update PlayerVisual if it exists
// 如果存在PlayerVisual则更新它
PlayerVisual playerVisual = GetComponentInChildren();
if (playerVisual != null)
{
playerVisual.RefreshNamedAnimancer(modelRoot);
}
}
///
/// Delayed update of visual components to ensure NamedAnimancerComponent is available
/// 延迟更新视觉组件以确保NamedAnimancerComponent可用
///
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.SetId(m_PlayerInfo.cid);
if (NPCManager.Instance == null)
{
BMLogger.LogError("[CECPlayer] NPCManager.Instance is null while loading player model.");
return;
}
m_pPlayerCECModel.m_pPlayerModel = await NPCManager.Instance.GetModelPlayer(profession, gender);
if (m_pPlayerCECModel.m_pPlayerModel == null)
{
BMLogger.LogError($"[CECPlayer] GetModelPlayer returned null. profession={profession}, gender={gender}");
return;
}
// Find SkeletonBuilder component on model GameObject
// 在模型GameObject上查找SkeletonBuilder组件
SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren();
CombineActHolder combineActHolder = m_pPlayerModel.GetComponentInChildren();
CombinedActionSO combinedAction = null;
if (combineActHolder != null)
{
try
{
combinedAction = combineActHolder.ActionSO;
}
catch (Exception ex)
{
BMLogger.LogWarning($"[CECPlayer] Failed to read CombineActHolder.ActionSO on '{m_pPlayerModel.name}': {ex.Message}");
}
}
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);
if(combinedAction != null)
{
m_pPlayerCECModel.SetCombinedAction(combinedAction);
}
// 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());
m_pPlayerCECModel.SetTransform(changeModel.transform);
// Keep action map in sync with the currently active model (major/dummy).
// 让动作映射与当前激活模型(主模型/变身模型)保持一致。
CombineActHolder combineActHolder = changeModel.GetComponentInChildren();
if (combineActHolder != null)
{
try
{
if (combineActHolder.ActionSO != null)
{
m_pPlayerCECModel.SetCombinedAction(combineActHolder.ActionSO);
}
else
{
BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: CombineActHolder.ActionSO is null on '{changeModel.name}'.");
}
}
catch (Exception ex)
{
BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: Failed to read CombineActHolder.ActionSO on '{changeModel.name}': {ex.Message}");
}
}
else
{
BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: CombineActHolder not found on '{changeModel.name}'.");
}
m_pPlayerCECModel.InitializeSkeletonBuilder();
}
///
/// Delayed initialization coroutine for cases where SkeletonBuilder builds after model load
/// 延迟初始化协程,用于SkeletonBuilder在模型加载后构建的情况
///
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();
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((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;
// [中文] 策划联入\状态效果\ (状态效果 GFX 的基础路径)
// [English] Designer-integrated state effect GFX base path
const string szBasePath = "gfx/策划联入/状态效果/";
const int bitSize = sizeof(uint) * 8;
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);
// [中文] 两者相同(都激活或都未激活),跳过
// [English] Both unchanged (both on or both off), skip
if ((dwFlag1 == 0 && dwFlag2 == 0) || (dwFlag1 != 0 && dwFlag2 != 0))
continue;
// [中文] 查询可见状态(profession 参数被忽略,仅按 id 查找)
// [English] Query visible state (profession is ignored; keyed by id only)
VisibleState pvs = VisibleState.Query(m_iProfession, i + idState * bitSize);
if (pvs == null)
continue;
string strEffect = pvs.GetEffect();
if (string.IsNullOrEmpty(strEffect))
continue;
string strGFXFile = szBasePath + strEffect;
// [中文] TestProcessPetCureGFX — 宠愈 GFX 系统尚未移植,跳过(等价于始终返回 false)
// [English] TestProcessPetCureGFX — pet-cure GFX system not ported yet; skip (equivalent to always false)
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState * bitSize)) continue;
if (dwFlag1 != 0)
{
// [中文] 移除旧状态效果
// [English] Remove old state GFX
if (SkillGfxMan.InstanceSub != null)
SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx();
bool bLeft = false;
CECModel pWeapon = null;
if (IsWeaponHookPos(pvs.GetHH(), out bLeft, out pWeapon))
{
// [中文] 武器上的效果
// [English] GFX on weapon model
if (pWeapon != null)
{
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
RemoveStateGfxFromModel(pWeapon, strGFXFile, gfxHook);
}
}
else
{
// [中文] 模型上的效果
// [English] GFX on player model
RemoveGfx(strGFXFile, pvs.GetHH(), (uint)PLAYERMODEL_TYPE.PLAYERMODEL_TYPEALL);
}
}
else
{
// [中文] 添加新状态效果
// [English] Add new state GFX
string szHH = pvs.GetHH();
float fScale = 1f;
// [中文] 根据挂点类型获取模型缩放数据
// [English] Determine GFX scale from model outer data based on hook type
/*CECModel majorModel = GetMajorModel()?.GetComponent();
if (majorModel != null && szHH.Equals("HH_Head", StringComparison.OrdinalIgnoreCase))
fScale = majorModel.GetOuterData()[0];
else if (majorModel != null && szHH.Equals("HH_Spine", StringComparison.OrdinalIgnoreCase))
fScale = majorModel.GetOuterData()[1];
else
fScale = 1.0f;*/
bool bLeft = false;
CECModel pWeapon = null;
if (IsWeaponHookPos(szHH, out bLeft, out pWeapon))
{
// [中文] 武器上的效果
// [English] GFX on weapon model
if (pWeapon != null)
{
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
PlayStateGfxOnModel(pWeapon, strGFXFile, gfxHook, fScale);
}
}
else
{
// [中文] 玩家模型上的效果
// [English] GFX on player model
PlayGfx(strGFXFile, pvs.GetHH(), fScale, (uint)PLAYERMODEL_TYPE.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;
}
// [中文] 判断挂点是否为武器挂点,并返回对应武器模型和左右手标志
// [English] Check if hook pos is a weapon hook; output the corresponding weapon model and left-hand flag
protected bool IsWeaponHookPos(string szHH, out bool bLeft, out CECModel pWeapon)
{
bLeft = false;
pWeapon = null;
if (string.IsNullOrEmpty(szHH)) return false;
// [中文] 左手武器挂点(手持或肩部)
// [English] Left-hand weapon hook positions (held or shoulder)
if (szHH.Equals("HH_lefthandweapon", StringComparison.OrdinalIgnoreCase) ||
szHH.Equals("HH_leftsword", StringComparison.OrdinalIgnoreCase))
{
bLeft = true;
pWeapon = GetLeftHandWeapon();
return true;
}
// [中文] 右手武器挂点(手持、肩部或镰刀)
// [English] Right-hand weapon hook positions (held, shoulder, or sickle/nickle)
if (szHH.Equals("HH_righthandweapon", StringComparison.OrdinalIgnoreCase) ||
szHH.Equals("HH_rightsword", StringComparison.OrdinalIgnoreCase) ||
szHH.Equals("HH_weapon", StringComparison.OrdinalIgnoreCase))
{
pWeapon = GetRightHandWeapon();
return true;
}
return false;
}
// [中文] 获取左手武器模型(武器 CECModel 未接入时返回 null)
// [English] Get left-hand weapon model (returns null until weapon CECModel tracking is wired)
protected virtual CECModel GetLeftHandWeapon() => null;
// [中文] 获取右手武器模型(武器 CECModel 未接入时返回 null)
// [English] Get right-hand weapon model (returns null until weapon CECModel tracking is wired)
protected virtual CECModel GetRightHandWeapon() => null;
// [中文] 获取武器上用于挂载 GFX 的挂点名称
// [English] Get the GFX hook position name on the weapon model
protected string GetWeaponGFXHookPos(CECModel pModel, bool bLeft)
{
// [中文] 武器 CECModel 挂点逻辑未接入,暂时返回 null
// [English] Weapon CECModel hook logic not wired yet; return null for now
return null;
}
// [中文] 从玩家模型上移除状态效果 GFX
// [English] Remove a state-effect GFX from the player model
protected void RemoveGfx(string szPath, string szHook, uint iShapeTypeMask)
{
string key = szPath + szHook;
// BMLogger.LogError("HoangDev: RemoveGfx " +szPath );
if (_stateGfxObjects.TryGetValue(key, out GameObject vfx) && vfx != null)
{
Destroy(vfx.gameObject);
_stateGfxObjects.Remove(key);
}
}
public virtual void SetUpPlayer()
{
m_dwResFlags = 0;
m_iFashionWeaponType = -1;
m_uAttackType = DEFAULT_ACTION_TYPE;
}
public void SetPlayerInfor(INFO playinfo)
{
m_PlayerInfo = playinfo;
if (m_pPlayerCECModel != null)
{
m_pPlayerCECModel.SetId(m_PlayerInfo.cid);
}
}
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 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;
}
///
/// Get player's CECModel instance
/// 获取玩家的CECModel实例
///
/// CECModel instance or null / CECModel实例,未找到返回null
public CECModel GetPlayerCECModel()
{
return m_pPlayerCECModel;
}
///
/// Get hook Transform by name (convenience method)
/// 根据名称获取挂点变换(便捷方法)
///
/// Hook name / 挂点名称
/// Search recursively / 递归搜索
/// Hook Transform or null / 挂点变换,未找到返回null
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 actionMap =
new Dictionary(100);
Dictionary skillActionMap =
new Dictionary(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, bool isElsePlayer = false)
{
return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue);
}
public bool PlayAction(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false, bool isElsePlayer = 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_NONE = 0;
const int COMACT_FLAG_MODE_ONCE = 1;
const int COMACT_FLAG_MODE_ONCE_IGNOREGFX = 2;
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 = "";
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);
}
return true;
}
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);
}
return true;
}
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);
}
}
}
return true;
}
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.ByteArrayToUTF8String(action.data.action_name));
return true;
// 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));
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, 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));
m_pActionController.ClearComActFlagAllRankNodes(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;
int weapon_type = GetShowingWeaponType();
Debug.Log("PlayAttackAction: weapon_type=" + weapon_type);
int nTime1 = 0, nTime2 = 0;
int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand;
string soundPath = m_aWeaponSFX[weapon_type][nRand%m_aWeaponSFX[weapon_type].Count];
string hitSoundPath = m_aWeaponHitSFX[weapon_type][nRand%m_aWeaponHitSFX[weapon_type].Count];
bool bHideFX = false;//!CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
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)
{
// “起�? 动作(挥起)
szAct = EC_Utility.BuildActionName(action, weapon_type, "起");
int iTransTime = 200;
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, true, iTransTime, bHideFX, attackEvent,COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
//swing sfx
//workaround for sound effect delay, it need to trigger via weapon combine action
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundPath, Vector3.zero,iTransTime/1000f).Forget();
szAct = EC_Utility.BuildActionName(action, weapon_type, "落");
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
//hit sfx
//workaround for sound effect delay, it need to trigger via weapon combine action
//.1f is a magic number to make sure the sound effect is triggered after the action is finished
SFXManager.Instance.PlaySkillSfxAtPointAsync(hitSoundPath, Vector3.zero,iTransTime/1000f+.1f).Forget();
//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));
m_pActionController.PlayNonSkillActionWithName(iAction, szAct, true, 200);
// 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);
//EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, false, true, false);
// 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;
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTranstime, false, false, true, false);
/* 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)
{
if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0)
BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0);
else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0)
BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0);
else if ((dwModifier & (uint)MOD.MOD_DODGE_DEBUFF) != 0)
BubbleText((int)BubbleTextType.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))
{
BMLogger.LogError(("HoangDev PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);"));
PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
}
if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0)
BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0);
else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0)
BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0);
else if ((dwModifier & (uint)MOD.MOD_DODGE_DEBUFF) != 0)
BubbleText((int)BubbleTextType.BUBBLE_DODGE_DEBUFF, 0);
}
else
{
// Popup a damage decal
if (nDamage > 0)
{
int p1 = 0;
if ((dwModifier & (int)MOD.MOD_CRITICAL_STRIKE) != 0)
p1 |= 0x0001;
if ((dwModifier & (uint)MOD.MOD_RETORT) != 0)
p1 |= 0x0002;
if (!OnDamaged(skill))
{
PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
}
if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0)
BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0);
else if ((dwModifier & (uint)MOD.MOD_REBOUND) != 0)
BubbleText((int)BubbleTextType.BUBBLE_REBOUND, (uint)nDamage);
else if ((dwModifier & (uint)MOD.MOD_BEAT_BACK) != 0)
BubbleText((int)BubbleTextType.BUBBLE_BEAT_BACK, (uint)nDamage);
else
BubbleText((int)BubbleTextType.BUBBLE_DAMAGE, (uint)nDamage, p1);
}
else if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0)
BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0);
else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0)
BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0);
else
BubbleText((int)BubbleTextType.BUBBLE_HITMISSED, 0);
}
}
public void BubbleText(int iIndex, uint dwNum, int p1 = 0)
{
bool bHost = IsHostPlayer();
// if (iIndex == BUBBLE_EXP || iIndex == BUBBLE_SP)
// bHost = false;
Color dwCol = new Color(255, 205, 75);
if (bHost)
{
var pGameRun = EC_Game.GetGameRun();
CECHostPlayer pHost = pGameRun?.GetHostPlayer();
if (iIndex == (int)BubbleTextType.BUBBLE_EXP)
{
bool hasBookExp = pHost != null && pHost.IsReincarnationTomeActive;
int msgId = (int)dwNum > 0
? (hasBookExp ? (int)FixedMsg.FIXMSG_GOT_BOOKEXP : (int)FixedMsg.FIXMSG_GOTEXP)
: (int)FixedMsg.FIXMSG_LOSTEXP;
pGameRun?.AddFixedChannelMsg(msgId, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum);
}
if (iIndex == (int)BubbleTextType.BUBBLE_SP)
pGameRun?.AddFixedChannelMsg((int)FixedMsg.FIXMSG_GOTSP, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum);
if (iIndex == (int)BubbleTextType.BUBBLE_REALMEXP)
pGameRun?.AddFixedChannelMsg((int)FixedMsg.FIXMSG_GOT_REALMEXP, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum);
}
// Chariot / mount (C++): raise bubble by mount dummy AABB * 2.3f. IsInChariot() lives on CECHostPlayer; wire via override or protected hook when ready.
// if (IsInChariot())
// {
// var dummy = GetDummyModel((int)PLAYERMODEL_TYPE.PLAYERMODEL_DUMMYTYPE2);
// if (dummy != null)
// vPos = GetPosVector3() + g_vAxisY * (dummy.GetModelAABB().Extents.y * 2.3f);
// else
// vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f);
// }
// else
// vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f);
Vector3 vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f);
ImageResType bubbleTextType = ImageResType.NUM_IMAGE;
switch (iIndex)
{
case (int)BubbleTextType.BUBBLE_DAMAGE:
if (!bHost)
dwCol = new Color(237, 56, 0);
if ((p1 & 0x0001) != 0)
bubbleTextType = ImageResType.IMG_DEADLYSTRIKE;
else if ((p1 & 0x0002) != 0)
bubbleTextType = ImageResType.IMG_RETORT;
break;
case (int)BubbleTextType.BUBBLE_EXP:
bubbleTextType = ImageResType.IMG_GOTEXP;
// pDecal->SetScreenPos(80, 70);
// pDecal->EnableScreenPos(true);
break;
case (int)BubbleTextType.BUBBLE_SP:
bubbleTextType = ImageResType.IMG_GOTSP;
// pDecal->SetScreenPos(80, 90);
// pDecal->EnableScreenPos(true);
break;
case (int)BubbleTextType.BUBBLE_MONEY:
bubbleTextType = ImageResType.IMG_GOTMONEY;
break;
case (int)BubbleTextType.BUBBLE_LEVELUP:
bubbleTextType = ImageResType.IMG_LEVELUP;
break;
case (int)BubbleTextType.BUBBLE_HITMISSED:
if (!bHost)
dwCol = new Color(237, 56, 0);
bubbleTextType = ImageResType.IMG_HITMISSED;
break;
case (int)BubbleTextType.BUBBLE_INVALIDHIT:
if (!bHost)
dwCol = new Color(237, 56, 0);
bubbleTextType = ImageResType.IMG_INVALIDHIT;
break;
case (int)BubbleTextType.BUBBLE_IMMUNE:
if (!bHost)
dwCol = new Color(237, 56, 0);
bubbleTextType = ImageResType.IMG_IMMUNE;
break;
case (int)BubbleTextType.BUBBLE_HPWARN:
dwCol = new Color(255, 255, 255);
bubbleTextType = ImageResType.IMG_HPWARN;
break;
case (int)BubbleTextType.BUBBLE_MPWARN:
dwCol = new Color(255, 255, 255);
bubbleTextType = ImageResType.IMG_MPWARN;
break;
case (int)BubbleTextType.BUBBLE_REBOUND:
bubbleTextType = ImageResType.IMG_REBOUND;
break;
case (int)BubbleTextType.BUBBLE_BEAT_BACK:
bubbleTextType = ImageResType.IMG_BEAT_BACK;
break;
case (int)BubbleTextType.BUBBLE_ADD:
dwCol = new Color(126, 206, 244);
bubbleTextType = ImageResType.IMG_ADD;
break;
case (int)BubbleTextType.BUBBLE_DODGE_DEBUFF:
if (!bHost)
dwCol = new Color(237, 56, 0);
bubbleTextType = ImageResType.IMG_DODGE_DEBUFF;
break;
default:
bubbleTextType = ImageResType.NUM_IMAGE;
break;
}
FLoatingTextManager.Instance.ShowText(vPos, (int)dwNum, dwCol, 1f, bubbleTextType, this);
}
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;
BMLogger.LogError("HoangDev: OnDamaged skill:"+skill + ", m_sciStateIDForStateAction.Length:"+m_sciStateIDForStateAction.Length);
for (int i = 0; i < m_sciStateIDForStateAction.Length; i++)
{
if (atkMan.GetSkillStateActionName(skill, m_sciStateIDForStateAction[i], out name1, out name2))
{
m_SkillIDForStateAction = skill;
BMLogger.LogError("HoangDev: atkMan.GetSkillStateActionName(ski");
return true;
}
}
BMLogger.LogError(("HoangDev: atkMan.GetSkillStateActionName(ski\" return false;"));
return false;
}
public CECSkill GetCurSkill() { return m_pCurSkill; }
public bool IsHangerOn() { return m_bHangerOn; }
public bool IsPlayingAction()
{
var check = GetLowerBodyAction() != -1 ;
return check;
}
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;
}
/// Override in CECHostPlayer to return current team; base returns null.
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, 0);
}
public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, CECAttackEvent attackEvent = null, uint dwNewFlagMode = 0)
{
return m_pActionController != null
&& m_pActionController.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, attackEvent, 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((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;
}
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<().Play();
return;
};
// path = "gfx/人物/技能/武侠/万剑诀预备.gfx";
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
if (prefab == null)
{
BMLogger.LogWarning($"[StateGFX] Failed to load prefab: {path}");
return;
}
// [中文] 查找挂点骨骼,未找到则回退到玩家根 transform
// [English] Look up the hook bone via SkeletonBuilder; fall back to player root transform if not found
Transform parent = (!string.IsNullOrEmpty(hook)) ? GetHook(hook) : null;
if (parent == null) parent = transform;
GameObject vfx = Instantiate(prefab, parent);
if (vfx == null) return;
vfx.transform.localPosition = Vector3.zero;
_stateGfxObjects[key] = vfx;
// BMLogger.Log($"[HoangDev StateGFX] Playing: {path}, hook: {hook}, scale: {fScale}");
}
// [中文] 在武器 CECModel 上移除状态效果 GFX(武器挂点逻辑未接入,暂存桩)
// [English] Remove state-effect GFX from weapon CECModel (weapon hook not wired yet; stub)
private void RemoveStateGfxFromModel(CECModel model, string path, string hook)
{
// TODO: implement when weapon CECModel GFX tracking is available
}
// [中文] 在武器 CECModel 上播放状态效果 GFX(武器挂点逻辑未接入,暂存桩)
// [English] Play state-effect GFX on weapon CECModel (weapon hook not wired yet; stub)
private void PlayStateGfxOnModel(CECModel model, string path, string hook, float fScale)
{
// TODO: implement when weapon CECModel GFX tracking is available
}
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();
_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;
}
/// Set player display name (used when base info is received, e.g. else player).
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 pet’s 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;
PoolManager.Instance.Despawn(m_PetModelVisual);
}
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((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 LoadPetModel(string szPetPath)
{
var pPetModel = CECGameRun.Instance.GetPetMount();
if(pPetModel == null)
{
return null;
}
try
{
m_PetModelVisual = await PoolManager.Instance.SpawnAsync(AFile.NormalizePath(szPetPath.ToLower(), true), Vector3.zero, Quaternion.identity, memoryReleaseTTL: 0f);
if(m_PetModelVisual == null)
{
m_PetModelVisual = GameObject.CreatePrimitive(PrimitiveType.Capsule);
}
//var obModel = GameObject.Instantiate(model);
m_PetModelVisual.transform.SetParent(pPetModel.transform);
//AddressableManager.Instance.ReleaseAsset(szPetPath);
}
catch
{
var model = GameObject.CreatePrimitive(PrimitiveType.Capsule);
m_PetModelVisual = GameObject.Instantiate(model);
m_PetModelVisual.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 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);
// load all equipments
}
catch (Exception ex)
{
BMLogger.LogError($"CECPlayer::LoadPlayerSkeleton, SetPlayerModel failed: {ex}");
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());
}
}
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 ChannelAct ChannelAct;
public string AnimationName;
public int ITransTime;
public bool IsForceStopPrevious;
public bool IsLoop;
public CECAttackEvent AttackEvent;
public int Rank;
public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false)
{
this.ChannelAct = null;
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
Rank = 0;
}
public PlayActionEvent(ref ChannelAct channelAct, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false, int rank = 0)
{
this.ChannelAct = channelAct;
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
Rank = rank;
}
}
public struct PLAYER_ACTION
{
public PLAYER_ACTION_TYPE type;
public PLAYER_ACTION_INFO_CONFIG data;
};
public class QueueActionEvent
{
public ChannelAct ChannelAct;
public string AnimationName;
public int ITransTime;
public Action SetFlag;
public CECAttackEvent AttackEvent;
public bool IsHitAnim;
public bool IsForceStopPrevious;
public bool IsLoop;
public int Rank;
public QueueActionEvent(string animationName, Action setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.ChannelAct = null;
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
Rank = 0;
}
public QueueActionEvent(ref ChannelAct channelAct, string animationName, Action setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false, int rank = 0)
{
this.ChannelAct = channelAct;
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
Rank = rank;
}
public void SetData(string shapeName, string animationName, Action setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.AnimationName = shapeName + animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
}
public void SetData(string animationName, Action setFlag, bool isHitAnim,
CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false)
{
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
IsLoop = isLoop;
}
}
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, // 飞行器类型:双脚飞行器
};
// Bubble text
public enum BubbleTextType
{
BUBBLE_DAMAGE = 0,
BUBBLE_EXP,
BUBBLE_SP,
BUBBLE_MONEY,
BUBBLE_LEVELUP,
BUBBLE_HITMISSED,
BUBBLE_INVALIDHIT,
BUBBLE_IMMUNE,
BUBBLE_HPWARN,
BUBBLE_MPWARN,
BUBBLE_REBOUND, // ����
BUBBLE_BEAT_BACK, // ����
BUBBLE_ADD, // ��Ѫ�ļӺ�
BUBBLE_DODGE_DEBUFF,
BUBBLE_REALMEXP,
BUBBLE_NUM,
};
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; // 扛旗者ID(bFlagCarrier为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 OffenseRanks; // Offense ranks / 攻击方排行
public List DefenceRanks; // Defence ranks / 防守方排行
// Death containers (using List instead of std::vector) / 死亡容器(使用List代替std::vector)
public List OffenseDeaths; // Offense deaths / 攻击方死亡
public List 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();
if (DefenceRanks == null)
DefenceRanks = new List();
if (OffenseDeaths == null)
OffenseDeaths = new List();
if (DefenceDeaths == null)
DefenceDeaths = new List();
}
// 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,
};
///
/// Place holder for riding pet. Not test logic yet.
///
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);
}
};
}