Files
vuong dinh hoang 0d18d36fbb remove log
2026-05-31 17:59:52 +07:00

4786 lines
199 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.PerfectWorld.Scripts.Vfx;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Skills;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Runtime.InteropServices;
using PerfectWorld.Scripts.Managers.BrewMonster.Managers;
using CSNetwork;
using ModelRenderer.Scripts.Common;
using Unity.VisualScripting;
using DG.Tweening.Plugins;
using PerfectWorld.Scripts.Managers;
using BrewMonster.Scripts.ECModel;
using Animancer;
using ModelViewer.Common;
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 };
/// <summary>Skill id for pending skill/state hit reaction (see skill_state_action.txt).</summary>
protected int m_SkillIDForStateAction;
private static Dictionary<uint, PLAYER_ACTION_INFO_CONFIG> _default_skill_actions
= new Dictionary<uint, PLAYER_ACTION_INFO_CONFIG>();
protected int m_iBoothState = 0; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth
public int m_idFRole = GNETRoles._R_UNMEMBER; // ID of player's faction role
protected int m_idCountry = 0; // ¹úÕ½ÕóÓª id
public static int MAX_REINCARNATION = 2;
protected List<int> m_aCurEffects = new List<int>(); // Current effects
protected byte m_ReincarnationCount = 0;
protected string m_strName; // Player name
// 需要是可能 || Need is possible
protected bool m_bHangerOn = false;
protected int m_iCurAction;
protected bool m_bAboutToDie = false;
public bool m_bCandHangerOn = false;
public bool m_bPetInSanctuary = false; // true, the pet pet of the player is in sanctuary
//The ID of the currently summoned pet
protected int m_idCurPet = 0;
public List<IconState> m_aIconStates = new List<IconState>();
protected byte m_byPariahLvl = 0; // Pariah level
public RIDINGPET m_RidingPet; // Riding pet information
public GameObject m_pPetModel = null; // Pet model
public 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<int,List<string>> m_aWeaponSFX = new Dictionary<int,List<string>>()
{
{0, new List<string>{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{1, new List<string>{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{2, new List<string>{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
{3, new List<string>{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
{4, new List<string>{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
{5, new List<string>{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb"}},
{6, new List<string>{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{7, new List<string>{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{8, new List<string>{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
{9, new List<string>{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
{10, new List<string>{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
// {0, new List<string>{"item/weaponattack/1hshorta", "item/weaponattack/1hshortb", "item/weaponattack/1hshortc"}},
// {1, new List<string>{"item/weaponattack/2hheavya", "item/weaponattack/2hheavyb", "item/weaponattack/2hheavyc", "item/weaponattack/2hheavyd"}},
// {2, new List<string>{"item/weaponattack/2hlonga", "item/weaponattack/2hlongb", "item/weaponattack/2hlongc", "item/weaponattack/2hlongd"}},
// {3, new List<string>{"item/weaponattack/bow", "item/weaponattack/bowb", "item/weaponattack/drawbow"}},
// {4, new List<string>{"item/weaponattack/fista", "item/weaponattack/fistb", "item/weaponattack/fistc", "item/weaponattack/fistd"}},
// {5, new List<string>{"item/weaponattack/magic", "item/weaponattack/magicb"}},
};
public Dictionary<int,List<string>> m_aWeaponHitSFX = new Dictionary<int,List<string>>()
{
{0, new List<string>{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
{1, new List<string>{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
{2, new List<string>{"item/weaponattack/hitmace", "item/weaponattack/hitmacebig"}},
{3, new List<string>{"item/weaponattack/hithammer", "item/weaponattack/hithammerbig"}},
{4, new List<string>{"item/weaponattack/hitaxe", "item/weaponattack/hitaxebig"}},
{5, new List<string>{"item/weaponattack/hithammer"}},
{6, new List<string>{"item/weaponattack/hitthrow"}},
{7, new List<string>{"item/weaponattack/hitthrow"}},
{8, new List<string>{"item/weaponattack/hithand"}},
{9, new List<string>{"item/weaponattack/hitthrow"}},
{10, new List<string>{"item/weaponattack/hithand"}},
// {0, new List<string>{"item/weaponattack/hitaxe", "item/weaponattack/hitaxebig"}},
// {1, new List<string>{"item/weaponattack/hithammer", "item/weaponattack/hithammerbig"}},
// {2, new List<string>{"item/weaponattack/hitblade", "item/weaponattack/hitbladebig"}},
// {3, new List<string>{"item/weaponattack/hitdagger"}},
// {4, new List<string>{"item/weaponattack/hitfist"}},
// {5, new List<string>{"item/weaponattack/hithand"}},
// {6, new List<string>{"item/weaponattack/hitstaff"}},
// {7, new List<string>{"item/weaponattack/hitmace", "item/weaponattack/hitmacebig"}},
// {8, new List<string>{"item/weaponattack/hitoriginal"}},
// {9, new List<string>{"item/weaponattack/hitsword", "item/weaponattack/hitswordbig"}},
// {10, new List<string>{"item/weaponattack/hittiger"}},
// {11, new List<string>{"item/weaponattack/hitwhip"}},
// {12, new List<string>{"item/weaponattack/hitthrow"}},
// {13, new List<string>{"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<string, GameObject> _stateGfxObjects = new Dictionary<string, GameObject>();
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;
}
/// <summary>This function will get the coressponding model player for the player based on the profession and gender </summary>
public async Task SetPlayerModel(byte profession, byte gender)
{
// PC prefab used first child as model root; runtime spawns may have no children — avoid GetChild(0) OOB.
// PC 预制体用第一个子物体作模型根;运行时生成可能没有子物体 — 避免 GetChild(0) 越界
if (transform.childCount > 0)
parentModel = transform.GetChild(0);
else
parentModel = transform;
txtName = GetComponentInChildren<TextMeshProUGUI>();
if (transform.childCount >= 3)
{
pointCam = transform.GetChild(2);
}
// Initialize CECModel for hook system
// 初始化CECModel以支持挂点系统
await InitializePlayerCECModel(profession,gender);
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<bool> QueueLoadDummyModel(int iShape, bool bAtOnce)
{
int iShapeType = PLAYERMODEL_GETTYPE(iShape);
int iShapeID = PLAYERMODEL_GETID(iShape);
// If model already loaded, use it directly.
if(m_aShapeID[iShapeType] == iShapeID && m_pModels[iShapeType])
{
ApplyShapeModelChange(m_pModels[iShapeType]);
return true;
}
// try to load a new dummy model
// if (bAtOnce || !IsLoadThreadReady())
// {
// CECModel* pDummyModel = NULL;
// if (!LoadDummyModel(iShape, &pDummyModel) || !pDummyModel)
// return false;
// if (!SetDummyLoadResult(iShape, pDummyModel))
// {
// A3DRELEASE(pDummyModel);
// return false;
// }
// }
// else
// {
// int iType = (m_iCID == OCID_HOST_NAVIGATER) ? MTL_ECM_HOST_NAVIGATER_DUMMY:MTL_ECM_PLAYER_DUMMY;
// QueueECModelForLoad(
// iType,
// m_PlayerInfo.cid,
// m_dwBornStamp,
// GetPos(),
// NULL,
// iShape);
// }
//not sure we need the check for IsLoadThreadReady()
GameObject pDummyModel = new GameObject("DummyModel");
pDummyModel = await NPCManager.Instance.GetDummyModel(iShapeID);
Scene scene = SceneManager.GetActiveScene();
SceneManager.MoveGameObjectToScene(pDummyModel, scene);
pDummyModel.transform.SetParent(parentModel);
pDummyModel.transform.localPosition = Vector3.zero;
pDummyModel.SetActive(true);
m_pModels[iShapeType] = pDummyModel;
m_aShapeID[iShapeType] = iShapeID;
ApplyShapeModelChange(pDummyModel);
return true;
}
protected void ApplyShapeModelChange(GameObject pModel)
{
// store and reset the attach state
int iBuddyId = m_iBuddyId;
bool bHangerOn = m_bHangerOn;
if (m_AttachMode != AttachMode.enumAttachNone) DetachBuddy(null, false);
// logic transform but no model changed
if(!pModel) pModel = GetMajorModel();
OnModelChange(pModel);
if(pModel && m_pPlayerModel && m_pPlayerModel != pModel)
{
// sync the position
//pModel->SetPos(m_pPlayerModel->GetPos());
// pModel->SetDirAndUp(m_pPlayerModel->GetDir(), m_pPlayerModel->GetUp());
pModel.transform.position = m_pPlayerModel.transform.position;
pModel.transform.rotation = m_pPlayerModel.transform.rotation;
// if (m_pPlayerModel.transform.forward != Vector3.zero)
// {
// Quaternion lookRot = Quaternion.LookRotation(m_pPlayerModel.transform.forward, m_pPlayerModel.transform.up);
// transform.rotation = lookRot;
// }
// TODO:sync wing
// CECModel* pWing = m_pPlayerModel->GetChildModel(_wing);
// m_pPlayerModel->RemoveChildModel(_wing, false);
// CECModel* pWing2 = m_pPlayerModel->GetChildModel(_wing2);
// m_pPlayerModel->RemoveChildModel(_wing2, false);
// if (m_wingType == WINGTYPE_FLYSWORD || m_wingType == WINGTYPE_WING) {
// if (pWing) {
// pModel->AddChildModel(
// _wing,
// false,
// UsingWing() ? "HH_chibang" : "HH_feijian",
// pWing,
// UsingWing() ? "CC_chibang" : "CC_feijian");
// }
// } else if (m_wingType == WINGTYPE_DOUBLEWHEEL) {
// if (pWing) {
// pModel->AddChildModel(
// _wing,
// false,
// _hh_left_foot,
// pWing,
// _cc_fenghuolun);
// }
// if (pWing2) {
// pModel->AddChildModel(
// _wing2,
// false,
// _hh_right_foot,
// pWing2,
// _cc_fenghuolun);
// }
// }
ShowWing(IsFlying());
// TODO: sync the effect
// typedef abase::hash_map<AString, GFXRECORD>::iterator GFXIter;
// for(GFXIter i=m_GfxRecords.begin();i!=m_GfxRecords.end();++i)
// {
// const GFXRECORD& rec = i->second;
// m_pPlayerModel->RemoveGfx(rec.strPath, rec.strHook);
// if (!pModel->GetGfx(rec.strPath, rec.strHook)){
// pModel->PlayGfx(rec.strPath, rec.strHook, rec.fScale);
// }
// }
}
// TODO:change the target
if (m_pPlayerModel != pModel){
// ClearShowExtendStates();
// if (IsMajorModel(m_pPlayerModel)){
// RemoveEquipGfx();
// }
DetachWeapon();
m_pPlayerModel.SetActive(false);
m_pPlayerCECModel.m_pPlayerModel = pModel;
pModel.SetActive(true);
AttachWeapon();
if (pModel != null){
//ShowExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT);
}
if (IsMajorModel(m_pPlayerModel)){
//AddEquipGfx();
}
RecreateActionController();
// RecreateBodyController();
}
// different ground mode
SetUseGroundNormal( ShouldUseGroundNormalForCurrentShapeModel() );
PlayAction(GetMoveStandAction(false, IsFighting()), true);
// Update NPCVisual's namedAnimancer reference when model changes
// 当模型更改时更新NPCVisual的namedAnimancer引用
UpdateVisualComponents();
// Todo: restore the attach state
// if (iBuddyId)
// {
// if( !bHangerOn )
// AttachBuddy(iBuddyId);
// else
// {
// CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(iBuddyId);
// if( pBuddy ) pBuddy->AttachBuddy(m_PlayerInfo.cid);
// }
// }
//TODO: ScaleBody
//ScaleBody(m_fScaleBySkill);
// սЧʱģѼأgfxɲš
// TODO: chariotwar
// CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
// if (IsHostPlayer() && pHost && pHost->GetBattleInfo().IsChariotWar())
// {
// CChariot* pChariot = pHost->GetChariot();
// if (pChariot && pChariot->IsUpdateState())
// {
// PlayGfx(res_GFXFile(RES_GFX_LEVELUP), NULL, 4.0, PLAYERMODEL_TYPEALL);
// BubbleText(BUBBLE_LEVELUP, 0);
// pChariot->UpdateState(0,0);// ָս־
// }
// }
}
bool ShouldUseGroundNormalForCurrentShapeModel()
{
return IsShapeModelChanged() && !IsTransofrmModelLikeHuman(GetProfession(), GetGender(), GetShapeID());
}
static bool IsTransofrmModelLikeHuman(int nChar, int nGender, int nModelID){
bool result = false;
int[] likeHumanModelArray = null;
int likeHumanModelCount = 0;
switch (nChar)
{
case (int)PROFESSION.PROF_YEYING:
if ((int)GENDER.GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = s_LikeHumanModel.Length;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
case (int)PROFESSION.PROF_YUEXIAN:
if ((int)GENDER.GENDER_MALE == nGender){
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}else{
const int LIKE_HUMAN_MODEL_COUNT = 1;
int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F};
likeHumanModelArray = s_LikeHumanModel;
likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT;
}
break;
}
if (likeHumanModelCount > 0){
// const int *begin = likeHumanModelArray;
// const int *end = likeHumanModelArray + likeHumanModelCount;
// if (std::find(begin, end, _GetProfessionTransformModelID(nChar, nGender, nModelID)) != end){
// result = true;
// }
foreach (int model in likeHumanModelArray)
{
if (model == nModelID)
{
result = true;
break;
}
}
}
return result;
}
protected virtual bool IsShapeModelChanged()
{
return m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR] != m_pPlayerModel;
}
/// <summary>
/// Update visual components (NPCVisual, PlayerVisual) when model changes
/// 当模型更改时更新视觉组件(NPCVisual、PlayerVisual
/// </summary>
private void UpdateVisualComponents()
{
// Use the current active player model as the search root
// 使用当前活动的玩家模型作为搜索根
GameObject modelRoot = m_pPlayerModel;
if (modelRoot == null)
{
BMLogger.LogWarning("CECPlayer: UpdateVisualComponents - _pPlayerModel is null, cannot update visual components");
return;
}
// Update NPCVisual if it exists
// 如果存在NPCVisual则更新它
NPCVisual npcVisual = GetComponent<NPCVisual>();
if (npcVisual != null)
{
npcVisual.RefreshNamedAnimancer(modelRoot);
}
// Update PlayerVisual if it exists
// 如果存在PlayerVisual则更新它
PlayerVisual playerVisual = GetComponentInChildren<PlayerVisual>();
if (playerVisual != null)
{
playerVisual.RefreshNamedAnimancer(modelRoot);
}
}
/// <summary>
/// Delayed update of visual components to ensure NamedAnimancerComponent is available
/// 延迟更新视觉组件以确保NamedAnimancerComponent可用
/// </summary>
private IEnumerator UpdateVisualComponentsDelayed()
{
// Wait one frame for NamedAnimancerComponent to be available
// 等待一帧以确保NamedAnimancerComponent可用
yield return null;
if (m_pPlayerModel == null)
yield break;
UpdateVisualComponents();
}
private async Task InitializePlayerCECModel(byte profession, byte gender)
{
if(m_pPlayerCECModel!= null && m_pPlayerCECModel.m_pPlayerModel != null)
{
m_pPlayerCECModel.InvalidateHookCache();
}
// Get or create CECModel instance
// 获取或创建CECModel实例
if (m_pPlayerCECModel == null)
{
m_pPlayerCECModel = new CECModel();
}
m_pPlayerCECModel.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<SkeletonBuilder>();
CombineActHolder combineActHolder = m_pPlayerModel.GetComponentInChildren<CombineActHolder>();
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.SetNamedAnimancerComponent(m_pPlayerModel.GetComponentInChildren<NamedAnimancerComponent>());
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<SkeletonBuilder>());
m_pPlayerCECModel.SetNamedAnimancerComponent(changeModel.GetComponentInChildren<NamedAnimancerComponent>());
m_pPlayerCECModel.SetTransform(changeModel.transform);
// Keep action map in sync with the currently active model (major/dummy).
// 让动作映射与当前激活模型(主模型/变身模型)保持一致。
CombineActHolder combineActHolder = changeModel.GetComponentInChildren<CombineActHolder>();
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();
}
/// <summary>
/// Delayed initialization coroutine for cases where SkeletonBuilder builds after model load
/// 延迟初始化协程,用于SkeletonBuilder在模型加载后构建的情况
/// </summary>
private IEnumerator InitializePlayerCECModelDelayed()
{
// Wait one frame for SkeletonBuilder to be built
// 等待一帧以便SkeletonBuilder被构建
yield return null;
if (m_pPlayerModel == null)
yield break;
SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren<SkeletonBuilder>();
if (skeletonBuilder != null)
{
if (m_pPlayerCECModel == null)
{
m_pPlayerCECModel = new CECModel();
}
m_pPlayerCECModel.SetSkeletonBuilder(skeletonBuilder);
m_pPlayerCECModel.SetNamedAnimancerComponent(m_pPlayerModel.GetComponentInChildren<NamedAnimancerComponent>());
m_pPlayerCECModel.SetTransform(m_pPlayerModel.transform);
// Initialize skeleton builder (ensures hooks are available)
// 初始化骨架构建器(确保挂点可用)
m_pPlayerCECModel.InitializeSkeletonBuilder();
}
else
{
BMLogger.LogWarning($"[CECPlayer] SkeletonBuilder not found on player model after delay. Hook system may not work.");
}
}
public virtual void OnMsgPlayerExtState(ECMSG Msg)
{
if (Convert.ToInt32(Msg.dwParam2) == CommandID.UPDATE_EXT_STATE)
{
cmd_update_ext_state pCmd = GPDataTypeHelper.FromBytes<cmd_update_ext_state>((byte[])Msg.dwParam1);
if (pCmd.id == m_PlayerInfo.cid)
{
SetNewExtendStates(0, pCmd.states, (int)OBJECT_EXT_STATE.OBJECT_EXT_STATE_COUNT);
}
}
else if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY)
{
cmd_icon_state_notify cmd = new cmd_icon_state_notify();
if (!cmd.Initialize((byte[])Msg.dwParam1))
{
return;
}
if (cmd.id == m_PlayerInfo.cid)
{
m_aIconStates = cmd.states;
if (m_aIconStates.Count > 1)
{
m_aIconStates.Sort((a, b) =>
{
if (a.id < b.id) return -1;
if (a.id > b.id) return 1;
return 0;
});
}
}
}
}
public virtual void SetNewExtendStates(int start, uint[] pData, int count)
{
if(pData == null || start + count > OBJECT_EXT_STATE_COUNT)
{
return;
}
ShowExtendStates(start, pData, count);
Array.Copy(pData, start, m_aExtStates, start, count);
if(GetExtState(111))
{
// ת ̫
m_PlayerActions = _turning_actions;
}
else
{
m_PlayerActions = _default_actions;
}
}
void ShowExtendStates(int start, uint[] pData, int count, bool bIgnoreOptimize=false )
{
if(pData == null || start + count > OBJECT_EXT_STATE_COUNT)
{
return;
}
if (!IsAllResReady() || !GetMajorModel())
{
// #region agent log
LogPanelAnimeScene.AgentDebugLog("ShowExtendStates:blocked", "resource gate", "H5",
$"{{\"isAllResReady\":{IsAllResReady().ToString().ToLower()},\"hasMajorModel\":{(GetMajorModel() != null).ToString().ToLower()},\"isModelReady\":{IsPlayerModelReady.ToString().ToLower()}}}");
// #endregion
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<CECModel>();
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;
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<bool> LoadPlayerSkin(GameObject aSkins, int index, string szFile)
{
// these are LOD suffix
string[] suffix1 = { "一?", "二级", "三级" };
string[] suffix2 = { "", "二级", "三级" };
string szSkinFile = "";
if (index == EC_Player_Skin_Const.SKIN_BODY_INDEX || index == EC_Player_Skin_Const.SKIN_HEAD_INDEX)
szSkinFile = $"{szFile}{suffix2[0]}";
else
szSkinFile = $"{szFile}{suffix1[0]}";
aSkins = await AddressableManager.Instance.LoadPrefabAsync(szSkinFile);
if (aSkins == null)
return false;
return true;
}
public static void InitStaticRes()
{
BuildActionList();
DATA_TYPE dt = default;
_player_levelup_exp = (PLAYER_LEVELEXP_CONFIG)ElementDataManProvider.GetElementDataMan()
.get_data_ptr(202, ID_SPACE.ID_SPACE_CONFIG, ref dt);
}
public bool IsDead()
{
return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0;
}
public bool IsInvisible()
{
return (m_dwStates & PlayerNPCState.GP_STATE_INVISIBLE) != 0;
}
public bool IsInSanctuary()
{
return m_bInSanctuary;
}
public bool IsValidAction(int iIndex)
{
return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false;
}
public int GetCharacterID()
{
return m_PlayerInfo.cid;
}
/// <summary>
/// Get player's CECModel instance
/// 获取玩家的CECModel实例
/// </summary>
/// <returns>CECModel instance or null / CECModel实例,未找到返回null</returns>
public CECModel GetPlayerCECModel()
{
return m_pPlayerCECModel;
}
/// <summary>
/// Get hook Transform by name (convenience method)
/// 根据名称获取挂点变换(便捷方法)
/// </summary>
/// <param name="hookName">Hook name / 挂点名称</param>
/// <param name="recursive">Search recursively / 递归搜索</param>
/// <returns>Hook Transform or null / 挂点变换,未找到返回null</returns>
public Transform GetHook(string hookName, bool recursive = true)
{
CECModel model = GetPlayerCECModel();
return model?.GetHook(hookName, recursive);
}
private static void BuildActionList()
{
if (_default_actions == null)
{
Dictionary<string, PLAYER_ACTION_INFO_CONFIG> actionMap =
new Dictionary<string, PLAYER_ACTION_INFO_CONFIG>(100);
Dictionary<string, PLAYER_ACTION_INFO_CONFIG> skillActionMap =
new Dictionary<string, PLAYER_ACTION_INFO_CONFIG>(100);
elementdataman dataman = ElementDataManProvider.GetElementDataMan();
PLAYER_ACTION_INFO_CONFIG data;
int count = dataman.get_data_num(ID_SPACE.ID_SPACE_CONFIG);
DATA_TYPE dt = default;
uint id = 0;
for (int i = 0; i < count; ++i)
{
id = dataman.get_data_id(ID_SPACE.ID_SPACE_CONFIG, i, ref dt);
if (dt != DATA_TYPE.DT_PLAYER_ACTION_INFO_CONFIG)
continue;
data = (PLAYER_ACTION_INFO_CONFIG)dataman.get_data_ptr(id, ID_SPACE.ID_SPACE_CONFIG, ref dt);
if (!string.IsNullOrEmpty(data.ActionName))
{
if (!actionMap.TryAdd(data.ActionName, data))
{
}
}
if (!string.IsNullOrEmpty(data.ActionName))
{
if (!skillActionMap.TryAdd(data.Name, data))
{
}
}
}
///
CECStringTab actionNames = new CECStringTab();
actionNames.Init("actions_player", false);
_default_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
for (int i = 0; i < _default_actions.Length; i++)
{
_default_actions[i].type = (PLAYER_ACTION_TYPE)i;
string szName = actionNames.GetANSIString(i);
if (!string.IsNullOrEmpty(szName))
{
if (actionMap.TryGetValue(szName, out var it))
{
_default_actions[i].data = it;
}
}
}
if (_turning_actions != null) _turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
_turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX];
if (actionMap.TryGetValue("自身旋转", out PLAYER_ACTION_INFO_CONFIG turningData))
{
for (int i = 0; i < (int)PLAYER_ACTION_TYPE.ACT_MAX; i++)
{
if (i < (int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE ||
i > (int)PLAYER_ACTION_TYPE.ACT_REVIVE)
{
// Dùng hành động xoay thay thế hành động thường
_turning_actions[i].type = (PLAYER_ACTION_TYPE)i;
_turning_actions[i].data = turningData;
}
else
{
// Dùng hành động mặc định
_turning_actions[i] = _default_actions[i];
}
}
}
uint idSkill = 0;
while (true)
{
idSkill = ElementSkill.NextSkill(idSkill);
if (idSkill == 0)
break;
string skillName = ElementSkill.GetName(idSkill);
if (!string.IsNullOrEmpty(skillName))
{
var checkExist = skillActionMap.TryGetValue(skillName, out PLAYER_ACTION_INFO_CONFIG data1);
if (checkExist)
{
if(!_default_skill_actions.ContainsKey(idSkill))
{
_default_skill_actions.Add(idSkill, data1);
}
#if DEBUG_OUTPUT_ACTIONS
for (int n = 0; n < PlayerSkillAction.NUM_WEAPON_TYPE; n++)
{
var suffix = data.action_weapon_suffix[n].suffix;
if (!string.IsNullOrEmpty(suffix))
{
Debug.Log($"{data.action_prefix}_Ò÷³ª_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÆð_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÂä_{suffix}");
}
}
#endif
continue;
}
}
// ❌ not found
// Debug.LogWarning($"CECPlayer::BuildActionList() Failed to find skill action {idSkill}!");
}
}
}
public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false, 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 )
{
m_pActionController. PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime);
// if(pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, bRestart, iTransTime, true, iAction);
}
else
{
m_pActionController. 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 pAttack = CECAttacksMan.Instance.AddMeleeAttack(
GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
if (pAttack != null)
{
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
else
{
pAttack.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)
{
pAttack = attackerEvents.Find(idSkill, nSection);
if (pAttack != null)
{
// Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
pAttack.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)
{
}
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)
{
string szActRise = EC_Utility.BuildActionName(action, weapon_type, "起");
string szActFall = EC_Utility.BuildActionName(action, weapon_type, "落");
nTime1 = m_pPlayerCECModel.GetComActTimeSpanByName(szActRise);
nTime2 = m_pPlayerCECModel.GetComActTimeSpanByName(szActFall);
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (nAttackSpeed > 0)
{
float vScale = (nTime1 + nTime2) / (float)nAttackSpeed;
if (vScale > 0f)
m_pPlayerCECModel.SetPlaySpeed(vScale);
}
int iTransTime = 200;
m_pActionController.PlayNonSkillActionWithName(iAction, szActRise, true, iTransTime, bHideFX, attackEvent, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szActRise, m_iGender), 1.0f, true, iTransTime, true, iAction, bHideFX);
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundPath, Vector3.zero, iTransTime / 1000f).Forget();
m_pActionController.QueueNonSkillActionWithName(iAction, szActFall, 0, false, bHideFX);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szActFall, m_iGender), 0, iAction, false, false, bHideFX);
SFXManager.Instance.PlaySkillSfxAtPointAsync(hitSoundPath, Vector3.zero, iTransTime / 1000f + .1f).Forget();
}
// ==============================
// 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 = "空中翅膀"; // Air with wings / 空中翅膀
}
else
{
szActionMiddleName = "空中飞剑"; // Air with sword / 空中飞剑
}
string szActRiseAir = EC_Utility.BuildActionName(action, weapon_type, "起", szActionMiddleName);
string szActFallAir = EC_Utility.BuildActionName(action, weapon_type, "落", szActionMiddleName);
nTime1 = m_pPlayerCECModel.GetComActTimeSpanByName(szActRiseAir);
nTime2 = m_pPlayerCECModel.GetComActTimeSpanByName(szActFallAir);
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (nAttackSpeed > 0)
{
float vScale = (nTime1 + nTime2) / (float)nAttackSpeed;
if (vScale > 0f)
m_pPlayerCECModel.SetPlaySpeed(vScale);
}
m_pActionController.PlayNonSkillActionWithName(iAction, szActRiseAir, true, 200);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szActRiseAir, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
m_pActionController.QueueNonSkillActionWithName(iAction, szActFallAir, 0, false, false, true, false);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szActFallAir, m_iGender), 0, iAction, false, false, bHideFX);
}
// ==============================
// Queue FightStand / 结束动作
// ==============================
PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND];
szAct = EC_Utility.BuildActionName(stand_action, 0);
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 300, false, false, true, false);
// if (pRightHandWeapon != null && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true);
// 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);
}
}
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)
{
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))
{
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
{
string szAirCastMid =
((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)
? "_空中翅膀_吟唱_" // Air cast with wings / 空中翅膀吟唱
: "_空中飞剑_吟唱_"; // Air cast with flysword / 空中飞剑吟唱
szAct = EC_Utility.BuildActionName(data, weapon_type, szAirCastMid);
}
bool bHideFX = false; /*!CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());*/
if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX))
{
return false;
}
ShowWeaponByConfig(data);
//UpdateWeaponHangerPosBySkillAction(idSkill);// ¸ù¾Ý¼¼Äܲ¥·ÅµÄ¶¯×÷£¬¸ü¸ÄÎäÆ÷Ðü¹ÒλÖã¨Ö»Äܼì²é²»ÅŶӶ¯×÷£©
return true;
}
/// <summary>
/// Resolves cast (吟唱) combined-action name for anim-test / debug. Does not call or alter <see cref="PlaySkillCastAction"/>.
/// 解析吟唱组合动作名(动画测试用),不调用、不改变 PlaySkillCastAction。use for test animtion.
/// </summary>
public bool TryBuildSkillCastActionName(int idSkill, out string szAct)
{
szAct = string.Empty;
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
{
string szAirCastMid =
((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)
? "_空中翅膀_吟唱_" // Air cast with wings / 空中翅膀吟唱
: "_空中飞剑_吟唱_"; // Air cast with flysword / 空中飞剑吟唱
szAct = EC_Utility.BuildActionName(data, weapon_type, szAirCastMid);
}
return !string.IsNullOrEmpty(szAct);
}
/// <summary>
/// Combined action for skill cast GFX lookup (anim-test). / 技能吟唱组合动作(动画测试 GFX 查询)。
/// </summary>
public A3DCombinedAction GetSkillCastComAct(int idSkill)
{
if (!TryBuildSkillCastActionName(idSkill, out string szAct) || m_pPlayerCECModel == null)
return null;
return m_pPlayerCECModel.GetComActByName(szAct);
}
/// <summary>
/// Resolves skill attack (施放起/落) combined-action names for anim-test GFX lookup.
/// 解析技能施放组合动作名(动画测试 GFX 查询),不播放动作。
/// </summary>
public bool TryBuildSkillAttackActionNames(int idSkill, int nSection, out string riseName, out string fallName)
{
riseName = string.Empty;
fallName = string.Empty;
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)
{
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;
data = data2.Value;
}
else
return false;
}
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
riseName = EC_Utility.BuildActionName(data, weapon_type, "_施放起_");
fallName = EC_Utility.BuildActionName(data, weapon_type, "_施放落_");
}
else
{
string szActionMiddleName;
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 = "_空中翅膀";
}
else
{
szActionMiddleName = "_空中飞剑";
}
szActionMiddleName += "_施放起_";
riseName = EC_Utility.BuildActionName(data, weapon_type, szActionMiddleName);
fallName =
$"{data.ActionPrefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].Suffix}";
}
if (nSection != 0)
{
var pAtkMan = CECAttacksMan.Instance;
if (pAtkMan != null && pAtkMan.GetSkillSectionActionSuffix(idSkill, nSection, out string suffix))
{
riseName += "_" + suffix;
fallName += "_" + suffix;
}
}
return !string.IsNullOrEmpty(riseName);
}
/// <summary>
/// Combined action for skill attack rise (施放起) GFX lookup (anim-test).
/// 技能施放起组合动作(动画测试 GFX 查询)。
/// </summary>
public A3DCombinedAction GetSkillAttackComActRise(int idSkill, int nSection = 0)
{
if (!TryBuildSkillAttackActionNames(idSkill, nSection, out string riseName, out _) ||
m_pPlayerCECModel == null)
return null;
return m_pPlayerCECModel.GetComActByName(riseName);
}
/// <summary>
/// Combined action for skill attack fall (施放落) GFX lookup (anim-test).
/// 技能施放落组合动作(动画测试 GFX 查询)。
/// </summary>
public A3DCombinedAction GetSkillAttackComActFall(int idSkill, int nSection = 0)
{
if (!TryBuildSkillAttackActionNames(idSkill, nSection, out _, out string fallName) ||
m_pPlayerCECModel == null)
return null;
return m_pPlayerCECModel.GetComActByName(fallName);
}
public bool OnDamaged(int skill)
{
var atkMan = CECAttacksMan.Instance;
if (atkMan == null)
return false;
string name1, name2;
for (int i = 0; i < m_sciStateIDForStateAction.Length; i++)
{
if (atkMan.GetSkillStateActionName(skill, m_sciStateIDForStateAction[i], out name1, out name2))
{
m_SkillIDForStateAction = skill;
return true;
}
}
return false;
}
public CECSkill GetCurSkill() { return m_pCurSkill; }
public bool IsHangerOn() { return m_bHangerOn; }
public bool IsPlayingAction()
{
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;
// int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0); // 获取技能执行时间 / Get skill execute time
int nExecuteTime = ElementSkill.GetExecuteTime((uint)idSkill, 0); // 临时值 / Temporary value
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放起_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
nTime1 = m_pPlayerCECModel.GetComActTimeSpanByName(szAct); // 获取动作时长 / Get action time span
var pAct = m_pPlayerCECModel.GetComActByName(szAct);
if (pAct!=null) bInfinite |= pAct.IsLooping();
string szAct2 = EC_Utility.BuildActionName(data, weapon_type, "_施放落_");
GetSkillSectionActionName(ref szAct2, idSkill, nSection);
nTime2 = m_pPlayerCECModel.GetComActTimeSpanByName(szAct2);
pAct = m_pPlayerCECModel.GetComActByName(szAct2);
if (pAct!=null) bInfinite |= pAct.IsLooping();
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite && nExecuteTime > 0)
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
if (vScale > 0)
{
m_pPlayerCECModel.SetPlaySpeed(vScale * 1.2f);
}
}
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent,(uint)COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX))
{
return false;
}
QueueSkillAttackActionWithName(idSkill, szAct2, 0, bHideFX);
}
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);
nTime1 = m_pPlayerCECModel.GetComActTimeSpanByName(szAct);
var pAct = m_pPlayerCECModel.GetComActByName(szAct);
if (pAct!=null) bInfinite |= pAct.IsLooping();
string szAct2Air = $"{data.ActionPrefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].Suffix}";
GetSkillSectionActionName(ref szAct2Air, idSkill, nSection);
nTime2 = m_pPlayerCECModel.GetComActTimeSpanByName(szAct2Air);
pAct = m_pPlayerCECModel.GetComActByName(szAct2Air);
if (pAct!=null) bInfinite |= pAct.IsLooping();
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite && nExecuteTime > 0)
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
if (vScale > 0)
{
m_pPlayerCECModel.SetPlaySpeed(vScale * 1.2f);
}
}
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent, (uint)COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX))
{
return false;
}
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX);
QueueSkillAttackActionWithName(idSkill, szAct2Air, 0, bHideFX);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX);
}
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite)
{
piAttackTime = nTime1 + nTime2;
}
else
{
// 动作循环,返回技能决定的执行时间 / Action loops, return skill-determined execute time
piAttackTime = nExecuteTime;
}
ShowWeaponByConfig(data);
// UpdateWeaponHangerPosBySkillAction(idSkill); // 根据技能播放的动作,更改武器悬挂位置 / Update weapon hanger position based on skill action
return true;
}
/// <summary>Override in CECHostPlayer to return current team; base returns null.</summary>
public virtual CECTeam GetTeam() { return null; }
public bool IsTeamMember(int idPlayer)
{
var pTeam = GetTeam();
if (pTeam == null) return false;
return pTeam.GetMemberByID(idPlayer) != null;
}
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, CECAttackEvent attackEvent = null, uint dwFlagMode = 0)
{
return m_pActionController != null
&& m_pActionController.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent, dwFlagMode);
}
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<cmd_enchant_result>((byte[])msg.dwParam1);
// 初始化掩码为全1 // Initialize mask to all 1s
uint mask = 0xFFFFFFFF;
// 如果目标不是主机玩家且当前不是主机玩家,则过滤会引起气泡文本的修饰符
// We should filter out these things that will cause bubble texts
CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer();
if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer())
{
mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE |
MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED);
}
// 获取修饰符 // Get modifier
uint dwModifier = (uint)pCmd.attack_flag;
// 获取技能类型 // Get skill type
int nDamage = -2; // 默认为-2,不会引起受伤动作 // Default to -2, will not cause wounded action
if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK)
{
// 只有攻击技能会引起受伤动作,伤害值为-1 // Only attack skill will cause wounded action, when damage is -1
nDamage = -1;
}
else
{
// 其他技能不会引起受伤动作,伤害值设为-2 // Other skills will not cause wounded action, so we set damage to -2
nDamage = -2;
}
// 播放攻击效果 // Play attack effect
int attackTime = 0;
PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage,
dwModifier & mask, 0, ref attackTime, pCmd.section);
}
// 判断是否在飞行 / Check if flying
public bool IsFlying()
{
// 临时实现 / Temporary implementation
return (m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0 ? true : false;
}
public bool IsInvader()
{
return (m_dwStates & PlayerNPCState.GP_STATE_INVADER) != 0;
}
public int GetFactionID() { return m_idFaction; }
public int GetForce() { return m_idForce; }
public bool IsInDuel() { return m_pvp.iDuelState == (int)DuelState.DUEL_ST_INDUEL; }
// Duel state
public enum DuelState
{
DUEL_ST_NONE = 0,
DUEL_ST_PREPARE,
DUEL_ST_INDUEL,
DUEL_ST_STOPPING,
};
public bool IsPariah()
{
return (m_dwStates & PlayerNPCState.GP_STATE_PARIAH) != 0;
}
public virtual bool IsFighting() { return m_bFight; }
public float GetGroundSpeed()
{
// return m_bWalkRun ? g_pGame.GetConfigs().GetHostRunSpeed() : m_ExtProps.mv.walk_speed;
// return 5f;
return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed;
}
// Get move environment
public int GetMoveEnv()
{
return m_iMoveEnv;
}
public bool IsShapeChanged()
{
return m_iShape != 0;
}
// 获取职业 // Get profession
public int GetProfession()
{
return m_iProfession;
}
public int GetLevel()
{
return GetBasicProps().iLevel;
}
// 获取性别 // Get gender
public int GetGender()
{
return m_iGender;
}
// 获取变身类型 // Get shape type
// PLAYERMODEL_GETTYPE(iShape) = (iShape & 0xff) >> 6
public int GetShapeType()
{
return (m_iShape & 0xff) >> 6;
}
// 获取变身ID // Get shape ID
// PLAYERMODEL_GETID(iShape) = iShape & 0x3f
public int GetShapeID()
{
return m_iShape & 0x3f;
}
public int GetWeaponID()
{
return m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON] & 0xffff;
}
public bool IsAllResReady()
{
return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_ALL) == (uint)PlayerResourcesReadyFlag.RESFG_ALL;
}
// Get character ID
public static int GetRealmLayer(int realmLevel) { return realmLevel != 0 ? (realmLevel + 9) / 10 : 0; }
public static int GetRealmSubLevel(int realmLevel) { return realmLevel != 0 ? (realmLevel % 10 != 0 ? realmLevel % 10 : 10) : 0; }
string GetFashionActionName()
{
// ʱװװЯĶ
//
string strAction = "";
int[] local_check_order =
{
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_HEAD,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_BODY,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WRIST,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_LEG,
(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_FOOT
};
int idEquipment = 0;
for (int i = 0; i < local_check_order.Length; ++ i)
{
// ˳ָװ
idEquipment = m_aEquips[local_check_order[i]] & 0x0000ffff;
GetFashionActionNameByID(idEquipment, ref strAction);
if (!string.IsNullOrEmpty(strAction))
{
// ַǿʱװ
break;
}
}
return strAction;
}
void GetFashionActionNameByID(int idEquipment, ref string strAction)
{
if (idEquipment != 0)
{
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
object pEquip = EC_Game.GetElementDataMan().get_data_ptr(
(uint)idEquipment,
ID_SPACE.ID_SPACE_ESSENCE,
ref dt);
if (pEquip != null && dt == DATA_TYPE.DT_FASHION_ESSENCE)
{
FASHION_ESSENCE pEssence = (FASHION_ESSENCE)pEquip;
strAction = ByteToStringUtils.ByteArrayToCP936String(pEssence.wear_action);
}
}
}
protected bool PlayGfx(string szPath, string szHook, float fScale /*1.0f*/, uint iShapeTypeMask /*(1<<PLAYERMODEL_MAJOR)*/, bool bForceNoRecord = false)
{
// bool bPlayed(false);
// bool bSkipRecord = (iShapeTypeMask != PLAYERMODEL_TYPEALL) || bForceNoRecord;
// for(int i=0;i<PLAYERMODEL_MAX;i++)
// {
// if (m_pModels[i] && (iShapeTypeMask & (1<<i)))
// {
// if (IsCurrentModel(m_pModels[i])){
// m_pModels[i].PlayGfx(szPath, szHook, fScale);
// bPlayed = true;
// }
// if(bSkipRecord) continue;
// A3DGFXEx* pGfx = m_pModels[i].GetGfx(szPath, szHook);
// if (pGfx && pGfx.IsInfinite()){
// GFXRECORD rec;
// rec.strPath = szPath;
// rec.strHook = szHook;
// rec.fScale = fScale;
// AString key = rec.strPath + rec.strHook;
// m_GfxRecords[key] = rec;
// bSkipRecord = true;
// }
// }
// }
// [中文] 路由到状态 GFX 播放(支持多 GFX 同时激活)
// [English] Route to state GFX playback (supports multiple concurrent GFX)
_ = PlayStateGfxAsync(szPath, szHook, fScale);
return false;
}
// [中文] 异步加载并播放状态效果 GFX,以 (路径+挂点) 为键去重
// [English] Asynchronously load and play a state-effect GFX; keyed by (path+hook) to deduplicate
private async Task PlayStateGfxAsync(string path, string hook, float fScale)
{
if (string.IsNullOrEmpty(path)) return;
string key = path + hook;
if (_stateGfxObjects.TryGetValue(key, out GameObject gfx))
{
gfx.GetComponent<ParticleSystem>().Play();
return;
};
// path = "gfx/人物/技能/武侠/万剑诀预备.gfx";
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
if (prefab == null)
{
BMLogger.LogWarning($"[StateGFX] Failed to load prefab: {path}");
// #region agent log
LogPanelAnimeScene.AgentDebugLog("PlayStateGfxAsync:fail", "prefab load failed", "H6",
$"{{\"path\":\"{path}\",\"hook\":\"{hook ?? ""}\"}}");
// #endregion
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;
// #region agent log
LogPanelAnimeScene.AgentDebugLog("PlayStateGfxAsync:spawned", "state gfx instantiated", "H6",
$"{{\"path\":\"{path}\",\"hook\":\"{hook ?? ""}\",\"parent\":\"{parent.name}\"}}");
// #endregion
}
// [中文] 在武器 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<BaseVfxObject>();
_levelUpVfx.Play();
// vfx.transform.SetParent(transform); transform.position, prefab.transform.rotation
_levelUpVfx.transform.localPosition = Vector3.zero;
}
else
{
BMLogger.LogError($"Failed to load level up effect prefab at: {path}");
}
}
// Get booth state
public int GetBoothState() { return m_iBoothState; }
// Check whether player has effect of specified type
public bool HasEffectType(int iEffType)
{
int i;
switch (iEffType)
{
case Effect_type.EFF_FACEPILL:
{
elementdataman pDataMan = EC_Game.GetElementDataMan();
// Get item data type
for (i = 0; i < m_aCurEffects.Count; i++)
{
DATA_TYPE DataType = pDataMan.get_data_type((uint)m_aCurEffects[i], ID_SPACE.ID_SPACE_ESSENCE);
if (DataType == DATA_TYPE.DT_FACEPILL_ESSENCE)
return true;
}
break;
}
}
return false;
}
public byte GetReincarnationCount() { return m_ReincarnationCount; }
public string GetName()
{
return m_strName;
}
/// <summary>Set player display name (used when base info is received, e.g. else player).</summary>
protected void SetPlayerName(string name)
{
m_strName = name ?? "";
if (gameObject != null)
gameObject.name = m_strName;
}
public enumWingType GetWingType() { return m_wingType; }
// Set part extend properties
public void SetPartExtendProps(int iPropIdx, object pData)
{
switch (iPropIdx)
{
case (int)ExtendPropertyClass.EXTPROPIDX_BASE:
m_ExtProps.bs = (ROLEEXTPROP_BASE)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_MOVE:
m_ExtProps.mv = (ROLEEXTPROP_MOVE)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_ATTACK:
m_ExtProps.ak = (ROLEEXTPROP_ATK)pData;
break;
case (int)ExtendPropertyClass.EXTPROPIDX_DEF:
m_ExtProps.df = (ROLEEXTPROP_DEF)pData;
break;
default:
//ASSERT(0);
return;
}
}
#region Team
// Get team to which this player belongs to
// public CECTeam GetTeam() { return m_pTeam; }
#endregion
public static bool IsMoveStandAction(int action)
{
// tương đương: const static int s_MoveStandAction[]
PLAYER_ACTION_TYPE[] s_MoveStandAction =
{
PLAYER_ACTION_TYPE.ACT_RUN,
PLAYER_ACTION_TYPE.ACT_WALK,
PLAYER_ACTION_TYPE.ACT_FLY,
PLAYER_ACTION_TYPE.ACT_FLY_SWORD,
PLAYER_ACTION_TYPE.ACT_SWIM,
PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL,
PLAYER_ACTION_TYPE.ACT_STAND,
PLAYER_ACTION_TYPE.ACT_FIGHTSTAND,
PLAYER_ACTION_TYPE.ACT_HANGINAIR,
PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD,
PLAYER_ACTION_TYPE.ACT_HANGINWATER,
};
int begin = 0;
int end = s_MoveStandAction.Length - 1;
for (int i = begin; i < end; i++)
{
if ((int)s_MoveStandAction[i] == action)
return true;
}
return false;
}
public int GetLowerBodyAction()
{
return m_pActionController?.GetLowerBodyAction() ?? -1;
}
// Check water moving environment
public bool CheckWaterMoveEnv(A3DVECTOR3 vPos, float fWaterHei, float fGndHei)
{
bool bRet = false;
/* if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf - m_aabb.Extents.y)
// if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f)
/*
if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth)
bRet = true;
else if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f && fWaterHei - fGndHei > m_MoveConst.fShoreDepth)
bRet = true;
*/
//@note : modify the water test. By Kuiwu[12/10/2005]
if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf - 0.001f)
{
bRet = true;
}
//else if (vPos.y + m_aabb.Extents.y < fWaterHei- m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.2f )
else if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.01f)
{
bRet = true;
}
return bRet;
}
public bool IsAboutToDie() { return m_bAboutToDie; }
public void SetAboutToDie(bool bFlag) { m_bAboutToDie = bFlag; }
// Show / hide wing
public void ShowWing(bool bShow)
{
if (m_pPlayerModel)
{
// var pWing = FindChildRecursive(m_pPlayerModel.transform, _wing);
if (m_Wing != null)
{
m_Wing.gameObject.SetActive(bShow);
}
// var pWing2 = FindChildRecursive(m_pPlayerModel.transform, _wing2);
// m_Wing2.gameObject.SetActive(bShow);
}
}
// Get current pet id
public int GetCurPetID() { return m_idCurPet; }
// Set current pet id
public void SetCurPetID(int id) { m_idCurPet = id; }
// Get player name color
public uint GetNameColor()
{
uint dwNameCol = NameColor.NAMECOL_MAUVE;
if (IsInBattle()) // Player is in battle
{
if (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER)
dwNameCol = NameColor.NAMECOL_BC_RED;
else // (m_iBattleCamp == GP_BATTLE_CAMP_DEFENDER)
dwNameCol = NameColor.NAMECOL_BC_BLUE;
}
else if (IsPariah())
{
switch (m_byPariahLvl)
{
case 0: dwNameCol = NameColor.NAMECOL_RED0; break;
case 1: dwNameCol = NameColor.NAMECOL_RED1; break;
default: dwNameCol = NameColor.NAMECOL_RED2; break;
}
}
else if (IsInvader())
dwNameCol = NameColor.NAMECOL_PINK;
else if (m_pvp.bEnable)
dwNameCol = NameColor.NAMECOL_WHITE;
return dwNameCol;
}
// Riding pet info.
public struct RIDINGPET
{
public int id;
public ushort color;
public void Reset()
{
id = 0;
color = 0;
}
public bool GetColor(ref Color clr)
{
// Get the current pets dye/color
return id > 0 && GetColor(color, ref clr);
}
public static bool GetColor(ushort c, ref Color clr)
{
// Check whether the current pet has been dyed; if so, return the dyed color.
bool bRet = false;
if ((c & (1 << (Marshal.SizeOf(c) * 8 - 1))) != 0)
{
// unsigned short: if the highest bit is 1, it means the pet has been dyed;
// in this case, the dyed color can be retrieved.
clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3);
bRet = true;
}
return bRet;
}
public static Color GetDefaultColor()
{
return new Color(255f / 255f, 255f / 255f, 255f / 255f);
}
};
public bool IsRidingOnPet() { return m_RidingPet.id != 0; }
// Get riding pet info.
public RIDINGPET GetRidingPetInfo() { return m_RidingPet; }
public void RideOnPet(int id, ushort color)
{
m_CandPet.id = id;
m_CandPet.color = color;
m_RidingPet.id = id;
m_RidingPet.color = color;
}
public void GetOffPet(bool bResetData)
{
int iBuddyId = 0;
m_CandPet.Reset();
SetNamePos(new A3DVECTOR3(0.0f));
if (m_AttachMode != AttachMode.enumAttachNone)
{
iBuddyId = m_iBuddyId;
DetachBuddy(null, bResetData);
}
if (m_pPetModel)
{
GameObject.Destroy(m_pPetModel);
m_pPetModel = null;
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<cmd_player_mounting>((byte[])Msg.dwParam1);
if (pCmd.mount_id != 0)
RideOnPet(pCmd.mount_id, pCmd.mount_color);
else
GetOffPet(true);
}
// Build riding pet file name
string GetRidingPetFileName(int idPet)
{
string szDef = "Models/NPCs/宠物/骑宠/骑宠马/骑宠马白.ecm";
DATA_TYPE DataType = new DATA_TYPE();
var pDataPtr = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)idPet, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
if (DataType != DATA_TYPE.DT_PET_ESSENCE)
return szDef;
PET_ESSENCE pData = (PET_ESSENCE)pDataPtr;
if (pData.file_model[0] == 0)
return szDef;
return ByteToStringUtils.ByteArrayToUTF8String(pData.file_model);
}
public async void QueueLoadPetModel(string szPetPath, bool bAtOnce)
{
var modelPet = await LoadPetModel(szPetPath);
if (modelPet == null)
{
return;
}
SetPetLoadResult(modelPet);
}
public async Task<GameObject> LoadPetModel(string szPetPath)
{
var pPetModel = CECGameRun.Instance.GetPetMount();
if(pPetModel == null)
{
return null;
}
try
{
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<bool> LoadPlayerSkeleton(bool bAtOnce)
{
int[] aEnabledEquips = new int[InventoryConst.SIZE_ALL_EQUIPIVTR];
for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++)
{
// TODO: m_i64EquipDisabled — zero slot when disabled: ((1L << i) & m_i64EquipDisabled) != 0 ? 0 : m_aEquips[i]
aEnabledEquips[i] = m_aEquips[i];
}
string szPetPath = null;
if (m_RidingPet.id != 0)
szPetPath = GetRidingPetFileName(m_RidingPet.id);
int[] aEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK];
uint EquipMask = 0;
if (aEnabledEquips[InventoryConst.EQUIPIVTR_WEAPON] > 0)
EquipMask |= 1 << InventoryConst.EQUIPIVTR_WEAPON;
if (aEnabledEquips[InventoryConst.EQUIPIVTR_FASHION_WEAPON] > 0)
EquipMask |= 1 << InventoryConst.EQUIPIVTR_FASHION_WEAPON;
Array.Copy(aEnabledEquips, aEquips, InventoryConst.IVTRSIZE_EQUIPPACK);
DecideWeaponLoad(aEquips, EquipMask);
// Same pipeline as SetPlayerModel / TransformShape: NPCManager model load + optional pet + dummy shape.
int shapeSnapshot = m_iShape;
try
{
await SetPlayerModel((byte)m_iProfession, (byte)m_iGender);
// 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 float PlaySpeed;
public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false, float playSpeed = 1.0f)
{
this.ChannelAct = null;
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
Rank = 0;
PlaySpeed = playSpeed;
}
public PlayActionEvent(ref ChannelAct channelAct, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false, int rank = 0, float playSpeed = 1.0f)
{
this.ChannelAct = channelAct;
this.AnimationName = animationName;
ITransTime = iTransTime;
IsForceStopPrevious = isForceStopPrevious;
AttackEvent = attackEvent;
IsLoop = isLoop;
Rank = rank;
PlaySpeed = playSpeed;
}
}
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<bool, CECAttackEvent> SetFlag;
public CECAttackEvent AttackEvent;
public bool IsHitAnim;
public bool IsForceStopPrevious;
public bool IsLoop;
public int Rank;
public QueueActionEvent(string animationName, Action<bool, CECAttackEvent> 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<bool, CECAttackEvent> 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<bool, CECAttackEvent> 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<bool, CECAttackEvent> 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; // 扛旗者IDbFlagCarrier为false时有效)/ Carrier ID (valid when bFlagCarrier is false)
public A3DVECTOR3 posCarrier; // 扛旗者位置(bFlagCarrier为false时有效)/ Carrier position (valid when bFlagCarrier is false)
[MarshalAs(UnmanagedType.U1)]
public bool bCarrierInvader; // 扛旗者是攻击方(bFlagCarrier为false时有效)/ Carrier is invader (valid when bFlagCarrier is false)
public int iCombatTime; // 战斗时间(秒)/ Combat time (seconds)
public int iAttendTime; // 参加战场时间(秒)/ Attend time (seconds)
public int iKillCount; // 击杀次数 / Kill count
public int iDeathCount; // 死亡次数 / Death count
public int iCountryKillCount; // 同国家击杀次数 / Same country kill count
public int iCountryDeathCount;// 同国家死亡次数 / Same country death count
public int iAttackerCount; // 攻击方人数 / Attacker count
public int iDefenderCount; // 防守方人数 / Defender count
public int iStrongHoldCount; // 据点个数 / Stronghold count
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] iStrongHoldState; // 据点占领状态 8 == ARRAY_SIZE(COUNTRY_CONFIG::stronghold) / Stronghold occupation state
// Score rank containers (using List instead of std::vector) / 分数排行容器(使用List代替std::vector
public List<ScoreRankEntry> OffenseRanks; // Offense ranks / 攻击方排行
public List<ScoreRankEntry> DefenceRanks; // Defence ranks / 防守方排行
// Death containers (using List instead of std::vector) / 死亡容器(使用List代替std::vector
public List<DeathEntry> OffenseDeaths; // Offense deaths / 攻击方死亡
public List<DeathEntry> DefenceDeaths; // Defence deaths / 防守方死亡
// 战车 / Chariot
public int iChariot; // 战车id / Chariot id
public int iEnergy; // 能量 / Energy
public int iScoreSelf; // 自己成绩 / Self score
public int iMultiKill; // 连杀 / Multi kill
// Initialize arrays and lists / 初始化数组和列表
public void Initialize()
{
if (iStrongHoldState == null)
iStrongHoldState = new int[8];
if (OffenseRanks == null)
OffenseRanks = new List<ScoreRankEntry>();
if (DefenceRanks == null)
DefenceRanks = new List<ScoreRankEntry>();
if (OffenseDeaths == null)
OffenseDeaths = new List<DeathEntry>();
if (DefenceDeaths == null)
DefenceDeaths = new List<DeathEntry>();
}
// Set country battle live show info / 设置国战直播显示信息
// TODO: Implement when cmd_countrybattle_live_show_result is available
// 当cmd_countrybattle_live_show_result可用时实现
public void SetCountryBattleLiveShowInfo(/*const S2C::cmd_countrybattle_live_show_result& cmd*/)
{
// TODO: Implement SetCountryBattleLiveShowInfo
// 实现SetCountryBattleLiveShowInfo
}
// Check if in guild war / 检查是否在帮派战中
public bool IsGuildWar()
{
return nType == (int)BattleType.BT_GUILD;
}
// Check if in country war / 检查是否在国战中
public bool IsCountryWar()
{
return nType == (int)BattleType.BT_COUNTRY;
}
// Check if is flag carrier / 检查是否是旗手
public bool IsFlagCarrier()
{
return IsCountryWar() && bFlagCarrier;
}
// Check if in chariot war / 检查是否在战车战中
public bool IsChariotWar()
{
return nType == (int)BattleType.BT_CHARIOT;
}
// Reset battle info / 重置战斗信息
public void Reset()
{
nType = (int)BattleType.BT_NONE;
idBattle = 0;
iResult = 0;
iResultCnt = 0;
iMaxScore_I = 0;
iMaxScore_D = 0;
iScore_I = 0;
iScore_D = 0;
iEndTime = 0;
iOffenseCountry = 0;
iDefenceCountry = 0;
iReviveTimes = 0;
bFlagCarrier = false;
iCarrierID = 0;
posCarrier = new A3DVECTOR3(0, 0, 0);
bCarrierInvader = false;
iCombatTime = 0;
iAttendTime = 0;
iKillCount = 0;
iDeathCount = 0;
iCountryKillCount = 0;
iCountryDeathCount = 0;
iAttackerCount = 0;
iDefenderCount = 0;
iStrongHoldCount = 0;
if (iStrongHoldState != null)
{
for (int i = 0; i < iStrongHoldState.Length; i++)
iStrongHoldState[i] = 0;
}
OffenseRanks?.Clear();
DefenceRanks?.Clear();
OffenseDeaths?.Clear();
DefenceDeaths?.Clear();
iChariot = 0;
iEnergy = 0;
iScoreSelf = 0;
iMultiKill = 0;
}
};
public enum PlayerResourcesReadyFlag
{
RESFG_SKELETON = 0x01,
RESFG_SKIN = 0x02,
RESFG_CUSTOM = 0x04,
RESFG_ASSEMBLED = 0x08,
RESFG_ALL = 0x0f,
};
public static class Duel_state // Duel state
{
public const int DUEL_ST_NONE = 0,
DUEL_ST_PREPARE = 1,
DUEL_ST_INDUEL = 2,
DUEL_ST_STOPPING = 3;
}
//// Move mode
public class Move_Mode
{
public const int MOVE_STAND = 0,
MOVE_MOVE = 1, // Normal move, walk, run, swim or fly
MOVE_JUMP = 2,
MOVE_FREEFALL = 3,
MOVE_SLIDE = 4;
}
public class EC_Player_Skin_Const
{
// Skin index
public static byte SKIN_BODY_INDEX = 0;
public static byte SKIN_UPPER_BODY_INDEX = 1;
public static byte SKIN_WRIST_INDEX = 2;
public static byte SKIN_LOWER_INDEX = 3;
public static byte SKIN_FOOT_INDEX = 4;
public static byte SKIN_HEAD_INDEX = 5;
public static byte SKIN_FASHION_UPPER_BODY_INDEX = 6;
public static byte SKIN_FASHION_WRIST_INDEX = 7;
public static byte SKIN_FASHION_LOWER_INDEX = 8;
public static byte SKIN_FASHION_FOOT_INDEX = 9;
public static byte NUM_SKIN_INDEX = 10;
}
public enum enumSkinShow
{
enumSkinShowNone = 0,
enumSkinShowUpperBody,
enumSkinShowWrist,
enumSkinShowLowerBody,
enumSkinShowFoot,
enumSkinShowUpperAndLower,
enumSkinShowUpperAndWrist,
enumSkinShowLowerAndFoot,
enumSkinShowUpperLowerAndWrist,
enumSkinShowArmet,
enumSkinShowHand,
};
/// <summary>
/// Place holder for riding pet. Not test logic yet.
/// </summary>
public struct RIDINGPET
{
public int id;
public ushort color;
public RIDINGPET(bool isReset = true)
{
id = 0;
color = 0;
}
public bool GetColor(Color clr)
{
// ȡǰȾɫɫ
return id > 0 && GetColor(color, clr);
}
public static bool GetColor(ushort c, Color clr)
{
// ѯǰǷȾɫȾɫرȾ֮ɫ
bool bRet = false;
if ((c & (1 << (8 - 1))) != 0)
{
// unsigned short λΪ1ʱʾȾɫʱɻȡɫ
clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3);
bRet = true;
}
return bRet;
}
public static Color GetDefaultColor()
{
return new Color(255, 255, 255);
}
};
}