Files
test/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs
T
2025-12-13 17:49:34 +07:00

1784 lines
69 KiB
C#

using Animancer;
using BrewMonster;
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.PerfectWorld.Scripts.Vfx;
using BrewMonster.Scripts;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Skills;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using PerfectWorld.Scripts.Managers;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Xml.Linq;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
using static BrewMonster.CECPlayer;
using BrewMonster.Network;
namespace BrewMonster
{
public abstract partial class CECPlayer : CECObject
{
[SerializeField] protected Transform parentModel;
[SerializeField] protected TextMeshProUGUI txtName;
[ResetStatic]
private static PLAYER_ACTION[] _default_actions;
[ResetStatic]
private static PLAYER_ACTION[] _turning_actions;
PLAYER_ACTION[] m_PlayerActions;
[SerializeField] internal INFO m_PlayerInfo;
protected GameObject _pPlayerModel;
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 A3DAABB m_aabbServer = new A3DAABB(); // Óë·þÎñÆ÷±£³ÖÒ»ÖµÄaabb£¬ ²»ÊÜËõ·ÅÓ°Ïì
public A3DAABB m_aabb = new A3DAABB(); // Player's aabb£¬ÓÃÓÚÏÔʾµÄaabb£¬ÊÜËõ·ÅÓ°Ïì
public int m_iProfession; // Profession
public float m_fScaleBySkill;
public int m_iGender; // Gender
protected bool m_bFashionMode;
public bool m_bShowWeapon;
private QueueActionEvent queueActionEvent;
protected static PLAYER_LEVELEXP_CONFIG _player_levelup_exp;
private CECPlayerActionController m_pActionController;
private enumWingType m_wingType;
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 int NUM_WEAPON_TYPE = 15;
public static readonly int[] m_sciStateIDForStateAction = { 117 };
private static Dictionary<uint, PLAYER_ACTION_INFO_CONFIG> _default_skill_actions
= new Dictionary<uint, PLAYER_ACTION_INFO_CONFIG>();
protected int m_iBoothState = 0; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth
public int m_idFRole = GNETRoles._R_UNMEMBER; // ID of player's faction role
protected int m_idCountry = 0; // ¹úÕ½ÕóÓª id
public static int MAX_REINCARNATION = 2;
protected List<int> m_aCurEffects = new List<int>(); // Current effects
byte m_ReincarnationCount = 0;
string m_strName; // Player name
// 需要是可能 || Need is possible
protected bool m_bHangerOn = false;
protected int m_iCurAction;
public MOVECONST m_MoveConst; // Const used when moving control
public Move_Mode m_MoveMode;
public MOVECONST[] aMoveConsts = new MOVECONST[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[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 static class Effect_type
{
public const int EFF_FACEPILL = 1;
}
private BaseVfxObject _levelUpVfx;
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);
}
/// <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)
{
parentModel = transform.GetChild(0);
txtName = GetComponentInChildren<TextMeshProUGUI>();
_pPlayerModel = await NPCManager.Instance.GetModelPlayer(profession, gender);
Scene scene = SceneManager.GetActiveScene();
SceneManager.MoveGameObjectToScene(_pPlayerModel, scene);
_pPlayerModel.transform.SetParent(parentModel);
_pPlayerModel.transform.localPosition = Vector3.zero;
_pPlayerModel.SetActive(true);
}
public virtual void SetUpPlayer()
{
m_dwResFlags = 0;
m_iFashionWeaponType = -1;
m_uAttackType = DEFAULT_ACTION_TYPE;
AttachWeapon();
}
public void SetPlayerInfor(INFO playinfo)
{
m_PlayerInfo = playinfo;
}
public INFO GetPlayInfo()
{
return m_PlayerInfo;
}
public void CalcPlayerAABB()
{
int iIndex = m_iProfession * GENDER.NUM_GENDER + m_iGender;
m_aabb.Extents = aExts[iIndex] * m_fScaleBySkill;
m_aabbServer.Extents = aExts[iIndex];
m_MoveConst = aMoveConsts[iIndex];
}
public static async Task<bool> LoadPlayerSkin(GameObject aSkins, int index, string szFile)
{
// these are LOD suffix
string[] suffix1 = { "一?", "二级", "三级" };
string[] suffix2 = { "", "二级", "三级" };
string szSkinFile = "";
if (index == EC_Player_Skin_Const.SKIN_BODY_INDEX || index == EC_Player_Skin_Const.SKIN_HEAD_INDEX)
szSkinFile = $"{szFile}{suffix2[0]}";
else
szSkinFile = $"{szFile}{suffix1[0]}";
aSkins = await AddressableManager.Instance.LoadPrefabAsync(szSkinFile);
if (aSkins == null)
return false;
return true;
}
public static void InitStaticRes()
{
BuildActionList();
DATA_TYPE dt = default;
_player_levelup_exp = (PLAYER_LEVELEXP_CONFIG)ElementDataManProvider.GetElementDataMan()
.get_data_ptr(202, ID_SPACE.ID_SPACE_CONFIG, ref dt);
}
public bool IsDead()
{
return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0;
}
public bool IsValidAction(int iIndex)
{
return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false;
}
public int GetCharacterID()
{
return m_PlayerInfo.cid;
}
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) && data.ActionName[0] != '0')
{
if (!actionMap.TryAdd(data.ActionName, data))
{
}
}
if (!string.IsNullOrEmpty(data.ActionName) && data.ActionName[0] != '0')
{
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))
{
if (skillActionMap.TryGetValue(skillName, out PLAYER_ACTION_INFO_CONFIG data1))
{
// ✅ Gán dữ liệu hành động cho skill tương ứng
_default_skill_actions[idSkill] = data1;
#if DEBUG_OUTPUT_ACTIONS
for (int n = 0; n < PlayerSkillAction.NUM_WEAPON_TYPE; n++)
{
var suffix = data.action_weapon_suffix[n].suffix;
if (!string.IsNullOrEmpty(suffix))
{
Debug.Log($"{data.action_prefix}_Ò÷³ª_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÆð_{suffix}");
Debug.Log($"{data.action_prefix}_Ê©·ÅÂä_{suffix}");
}
}
#endif
continue;
}
}
// ❌ not found
// Debug.LogWarning($"CECPlayer::BuildActionList() Failed to find skill action {idSkill}!");
}
}
}
public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false)
{
return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue);
}
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);
}
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;
var szAct = EC_Utility.BuildActionName(action, 0);
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szAct));
return true;
}
public static void Dispose()
{
_default_actions = null;
_turning_actions = null;
}
public INFO GetPlayerInfo()
{
return m_PlayerInfo;
}
protected override void Update()
{
base.Update();
}
public void PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage,
uint dwModifier, int nAttackSpeed, ref int piAttackTime, int nSection = 0)
{
if (!IsAllResReady())
return;
if (idSkill == 0)
{
int idWeapon = IsShapeChanged() ? 0 : GetWeaponID();
int nTimeFly = 10;
if (idWeapon != 0)
{
// ¿´¿´ÊDz»ÊÇÔ¶³ÌÎäÆ÷
DATA_TYPE dt = default;
WEAPON_ESSENCE? pWeapon = (WEAPON_ESSENCE)ElementDataManProvider.GetElementDataMan()
.get_data_ptr((uint)idWeapon, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
if (dt == DATA_TYPE.DT_WEAPON_ESSENCE && pWeapon != null && pWeapon.Value.require_projectile != 0)
{
nTimeFly = 700;
if (m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE] != 0)
idWeapon = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE];
}
}
if (CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid))
{
ClearComActFlagAllRankNodes(true);
}
// melee attack
CECAttackEvent pAttack1 = CECAttacksMan.Instance.AddMeleeAttack(
GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
if (pAttack1 != null)
{
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack1)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
else
{
pAttack1.m_bSignaled = true;
}
}
}
else
{
if (skillLevel == 0)
{
if (m_pCurSkill != null)
skillLevel = m_pCurSkill.GetSkillLevel();
else
skillLevel = 1;
}
CECAttackEvent pAttack = null;
// first try to find if there is already a skill attack event in attackman
CECAttackerEvents attackerEvents = CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid);
if (attackerEvents)
{
CECAttackEvent pAttack1 = attackerEvents.Find(idSkill, nSection);
if (pAttack1 != null)
{
// Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
pAttack1.AddTarget(idTarget, dwModifier, nDamage);
goto EXIT;
}
else
{
attackerEvents.Signal();
}
}
if (ElementSkill.IsGoblinSkill((uint)idSkill) &&
ElementSkill.GetType((uint)idSkill) == 2)
{
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
else
{
// begin a skill attack
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
if (pAttack != null)
{
int unusedInt = 0;
pAttack.SetSkillSection(nSection);
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlaySkillAttackAction(idSkill, nAttackSpeed, ref unusedInt, nSection, pAttack)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
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)
{
BMLogger.LogError("ClearComActFlagAllRankNodes " + gameObject.name + ": " + m_PlayerInfo.cid);
EventBus.PublishChannel(m_PlayerInfo.cid, new ClearComActFlagAllRankNodesEvent(v));
}
public bool PlayAttackAction(int nAttackSpeed, ref int attackTime, CECAttackEvent attackEvent)
{
//attackTime = 0;
//if (_pPlayerModel == null)
// return false;
int nRand = UnityEngine.Random.Range(0, 4);
string szAct = string.Empty;
int weapon_type = GetShowingWeaponType();
int nTime1 = 0, nTime2 = 0;
int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand;
PLAYER_ACTION action = m_PlayerActions[iAction];
if (string.IsNullOrEmpty(action.data.ActionPrefix))
return false;
ShowWeaponByConfig(action.data);
/* var pRightHandWeapon = GetRightHandWeapon();
bool bHideFX = !CECOptimize.Instance.GFX.CanShowAttack(GetCharacterID(), GetClassID());*/
// ==============================
// Ground Attack
// ==============================
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
// “起? 动作(挥起)
szAct = EC_Utility.BuildActionName(action, weapon_type, "起");
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szAct));
szAct = EC_Utility.BuildActionName(action, weapon_type, "落");
queueActionEvent.SetData(szAct, SetApplyDamage, true, attackEvent);
EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
//PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);gagága
/*
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
nTime1 = _pPlayerModel.GetComActTimeSpanByName(szAct);
// “收” 动作(挥下)
szAct = $"{action.data.action_prefix}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä";
QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
nTime2 = _pPlayerModel.GetComActTimeSpanByName(szAct);*/
}
// ==============================
// Air Attack
// ==============================
else
{
/*string szActionMiddleName;
if ((m_wingType == WINGTYPE_WING && IsFlying()) ||
GetProfession() == PROF_ANGEL ||
GetProfession() == PROF_ARCHOR ||
GetProfession() == PROF_MONK ||
GetProfession() == PROF_GHOST)
{
szActionMiddleName = "¿ÕÖгá°ò"; // tấn công trên không
}
else
{
szActionMiddleName = "¿ÕÖзɽ£"; // rơi xuống hoặc bay
}
szAct = $"{action.data.action_prefix}_{szActionMiddleName}_{action.data.action_weapon_suffix[weapon_type].suffix}Æð";
PlayNonSkillActionWithName(iAction, szAct, true, 200, bHideFX, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX);
nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct);
szAct = $"{action.data.action_prefix}_{szActionMiddleName}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä";
QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX);
nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct);*/
}
// ==============================
// Kết thúc bằng FightStand
// ==============================
PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND];
szAct = EC_Utility.BuildActionName(stand_action, 0);
queueActionEvent.SetData(szAct, SetApplyDamage, false, attackEvent);
EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent);
/* QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true);*/
// ==============================
// Điều chỉnh tốc độ phát animation theo tốc độ tấn công
// ==============================
/* if (nAttackSpeed > 0)
{
float vScale = (nTime1 + nTime2) / (float)nAttackSpeed;
if (vScale > 0f)
{
m_pPlayerModel.SetPlaySpeed(vScale);
if (pRightHandWeapon != null && IsUsingMagicWeapon())
pRightHandWeapon.SetPlaySpeed(vScale);
}
}
attackTime = nTime1 + nTime2;*/
// ==============================
// Cập nhật vị trí weapon hanger (vũ khí)
// ==============================
//UpdateWeaponHangerPosByAction(iAction);
return true;
}
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()
{
//todo: mr Hoang should double check it
return 10;
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 (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;
}*/
m_bWeaponAttached = true;
result = true;
return result;
}
public bool InFashionMode()
{
return m_bFashionMode;
}
public bool CanShowFashionWeapon(int weapon_type, int fashion_weapon_type)
{
return IsFashionWeaponTypeFit(weapon_type, fashion_weapon_type) && InFashionMode();
}
public bool IsFashionWeaponTypeFit(int weapon_type, int fashion_weapon_type)
{
if (fashion_weapon_type < 0 || fashion_weapon_type >= NUM_WEAPON_TYPE) return false;
FASHION_WEAPON_CONFIG? pConfig = GetFashionConfig();
if (null == pConfig)
{
BMLogger.LogError("CECPlayer::GetFashionConfig, Failed to load fashion weapon config");
return false;
}
int fashion_weapon_mask = (int)pConfig.Value.action_mask[fashion_weapon_type];
return (fashion_weapon_mask & (1 << GetWeaponType(weapon_type))) != 0;
}
public FASHION_WEAPON_CONFIG GetFashionConfig()
{
FASHION_WEAPON_CONFIG? pFashionConfig = null;
if (null == pFashionConfig)
{
elementdataman pDataMan = ElementDataManProvider.GetElementDataMan();
DATA_TYPE DataType = DATA_TYPE.DT_FASHION_WEAPON_CONFIG;
uint tid = pDataMan.get_id_with_data_type(ID_SPACE.ID_SPACE_CONFIG, DataType);
if (tid != 0)
{
pFashionConfig =
(FASHION_WEAPON_CONFIG)pDataMan.get_data_ptr(tid, ID_SPACE.ID_SPACE_CONFIG, ref DataType);
BMLogger.LogError($"HoangDev : get_data_ptr {pFashionConfig.GetType()}");
}
}
return pFashionConfig == null ? default : pFashionConfig.Value;
}
public int GetSelectedTarget()
{
return m_idSelTarget;
}
public float GetTouchRadius()
{
return m_fTouchRad;
}
// Is player in battle
public bool IsInBattle()
{
return m_iBattleCamp != Player_camp_in_battle.GP_BATTLE_CAMP_NONE;
}
// Check whether specified npc in a same battle camp
public bool InSameBattleCamp(CECNPC pNPC)
{
if (!pNPC || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE ||
(m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER && !pNPC.IsInBattleInvaderCamp()) ||
(m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_DEFENDER && !pNPC.IsInBattleDefenderCamp()))
return false;
return true;
}
public int GetBattleCamp() { return m_iBattleCamp; }
public bool InSameBattleCamp(CECPlayer pPlayer)
{
if (!pPlayer || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE ||
m_iBattleCamp != pPlayer.GetBattleCamp())
return false;
return true;
}
public const uint DEFAULT_ACTION_TYPE = 0xFFFFFFFF;
public static int GetWeaponType(int iWeaponType)
{
return iWeaponType == DEFAULT_ACTION_TYPE ? 10 : iWeaponType;
}
public bool IsInFactionPVP() => (m_factionPVPMask & 0x01) != 0;
public bool CanAttackFactionPVPMineCar() => (m_factionPVPMask & 0x02) != 0;
public bool CanAttackFactionPVPMineBase() => (m_factionPVPMask & 0x04) != 0;
public int GetLevelUpExp(int iLevel)
{
return _player_levelup_exp.exp[iLevel - 1];
//return iLevel * iLevel * 500;
}
// Get basic properties
public ROLEBASICPROP GetBasicProps()
{
return m_BasicProps;
}
public override void TurnFaceTo(int idTarget, float dwTime = 200)
{
if (idTarget != 0)
{
if (idTarget == GetCharacterID())
{
return;
}
if (IsWorkMoveRunning() /*&& !IsPlayingCastingSkillAndMoveActions()*/)
{
// ÒÆ¶¯Ê±Ò»°ãÓ¦ÃæÏòÒÆ¶¯·½Ïò¡¢Ö»ÔÚÒÆ¶¯Ê©·¨ÖвÅתÏò
return;
}
}
var target = EC_ManMessageMono.Instance?.GetObject(idTarget, 0)?.gameObject.transform;
if (target == null)
{
BMLogger.LogError("HoangDev: ko có transform ");
return;
}
Vector3 direction = (target.position - transform.position).normalized;
direction.y = 0f;
int turnSpeed = 5;
if (direction.sqrMagnitude > 0.001f)
{
// T?o rotation mới hướng tới target
Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up);
// Xoay mư?t t? rotation hiện t?i sang rotation m?c tiêu
//transform.rotation = Quaternion.Slerp(
// transform.rotation,
// targetRotation,
// Time.deltaTime * turnSpeed
//);
transform.rotation = targetRotation;
}
}
public virtual bool IsWorkMoveRunning()
{
return false;
}
/* public bool IsPlayingCastingSkillAndMoveActions()
{
return IsPlayingCastingSkillAction() && IsPlayingMoveAction();
}
public bool IsPlayingCastingSkillAction()
{
return m_pActionController ? m_pActionController.IsPlayingCastingSkillAction() : false;
}
bool IsPlayingMoveAction()
{
return m_pActionController ? m_pActionController.IsPlayingMoveAction() : false;
}*/
public int GetMoveStandAction(bool bMove, bool bFight = false)
{
int iMoveEnv = m_iMoveEnv;
//if (m_AttachMode != enumAttachNone)
//{
// bFight = false;
// if (m_bHangerOn)
// iMoveEnv = MOVEENV_GROUND;
//}
int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND;
if (bMove)
{
// Play appropriate actions
if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND)
{
if (m_bWalkRun)
iAction = (int)PLAYER_ACTION_TYPE.ACT_RUN;
else
iAction = (int)PLAYER_ACTION_TYPE.ACT_WALK;
}
//else if (iMoveEnv == MOVEENV_AIR)
//{
// //if (/*UsingWing()*/ m_wingType == WINGTYPE_WING)
// // iAction = ACT_FLY;
// //else
// // iAction = ACT_FLY_SWORD;
//}
//else if (iMoveEnv == MOVEENV_WATER)
//{
// //if (CanCombineWithMoveForSkill())
// //{
// // iAction = ACT_SWIM_FOR_MOVESKILL;
// //}
// //else
// //{
// // iAction = 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 == MOVEENV_AIR)
//{
// if (/*UsingWing()*/ m_wingType == WINGTYPE_WING)
// iAction = ACT_HANGINAIR;
// else
// iAction = ACT_HANGINAIR_SWORD;
//}
//else if (iMoveEnv == MOVEENV_WATER)
// iAction = ACT_HANGINWATER;
}
return iAction;
}
public A3DVECTOR3 GetModelMoveDir()
{ // ÒÆ¶¯Ê±¡¢·µ»ØÒƶ¯³¯Ïò£¬¾²Ö¹Ê±¡¢·µ»ØÄ£Ðͳ¯Ïò
return EC_Utility.ToA3DVECTOR3(transform.forward);
}
public void Damaged(int nDamage, uint dwModifier = 0, int skill = 0)
{
if (nDamage == -2)
{
// this message is caused by a help skill, so don't use a wounded action here
/* if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);*/
}
else if (nDamage == -1)
{
// when else player hit this player iDamage is -1,
// Just play a wounded action
if (!OnDamaged(skill))
{
// PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
}
/*if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF)
BubbleText(BUBBLE_DODGE_DEBUFF, 0);*/
}
else
{
// Popup a damage decal
if (nDamage > 0)
{
int p1 = 0;
/*if (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE)
p1 |= 0x0001;
if (dwModifier & CECAttackEvent::MOD_RETORT)
p1 |= 0x0002;*/
if (!OnDamaged(skill))
// PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED);
DamageTextManager.Instance.ShowDamageText(
transform.position, nDamage, Color.yellow, 1.0f);
/* if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_REBOUND)
BubbleText(BUBBLE_REBOUND, nDamage);
else if (dwModifier & CECAttackEvent::MOD_BEAT_BACK)
BubbleText(BUBBLE_BEAT_BACK, nDamage);
else
BubbleText(BUBBLE_DAMAGE, nDamage, p1);*/
}
/* else if (dwModifier & CECAttackEvent::MOD_IMMUNE)
BubbleText(BUBBLE_IMMUNE, 0);
else if (dwModifier & CECAttackEvent::MOD_NULLITY)
BubbleText(BUBBLE_INVALIDHIT, 0);
else
BubbleText(BUBBLE_HITMISSED, 0);*/
}
}
public void StopSkillAttackAction()
{
if (m_pActionController != null)
{
m_pActionController.StopSkillAttackAction();
}
}
public void StopSkillCastAction()
{
if (m_pActionController != null)
{
m_pActionController.StopSkillCastAction();
}
}
public bool PlaySkillCastAction(int idSkill)
{
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)
{
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 (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_Ò÷³ª_");
BMLogger.LogError($"HoangDev: PlaySkillCastAction szAct={szAct} ");
}
else
{
/* if ((*//*UsingWing()*//*m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST))
sprintf(szAct, "%s_¿ÕÖгá°ò_Ò÷³ª_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);
else
sprintf(szAct, "%s_¿ÕÖзɽ£_Ò÷³ª_%s", data->action_prefix, data->action_weapon_suffix[weapon_type].suffix);*/
}
bool bHideFX = false; /*!CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());*/
if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX))
{
return false;
}
ShowWeaponByConfig(data);
//UpdateWeaponHangerPosBySkillAction(idSkill);// ¸ù¾Ý¼¼Äܲ¥·ÅµÄ¶¯×÷£¬¸ü¸ÄÎäÆ÷Ðü¹ÒλÖã¨Ö»Äܼì²é²»ÅŶӶ¯×÷£©
return true;
}
public bool OnDamaged(int skill)
{
var atkMan = CECAttacksMan.Instance;
if (atkMan == null)
return false;
string name1, name2;
for (int i = 0; i < m_sciStateIDForStateAction.Length; i++)
{
/* if (atkMan.GetSkillStateActionName(skill, m_sciStateIDForStateAction[i], out name1, out name2))
{
m_SkillIDForStateAction = skill;
return true;
}*/
}
return false;
}
public 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 (_pPlayerModel == null)
return false;
string szAct = "";
int weapon_type = GetShowingWeaponType();
if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) ||
data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
// Check if it's a target item skill / 检查是否为目标道具技能
if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4)
{
PLAYER_ACTION_INFO_CONFIG? data2 = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data;
if (data2 == null || data2.Value.action_prefix == null || data2.Value.action_prefix.Length == 0 || data2.Value.action_prefix[0] == 0)
return false;
}
else
return false;
}
int nTime1, nTime2;
bool bInfinite = false;
// CECModel pRightHandWeapon = GetRightHandWeapon(); // 获取右手武器 / Get right hand weapon
bool bHideFX = false; // !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
var atkMan = CECAttacksMan.Instance;
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放起_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct); // 获取动作时长 / Get action time span
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放落_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
else
{
// 空中动作 / Air action
string szActionMiddleName = null;
if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) ||
(m_iProfession == PROFESSION.PROF_ANGEL) ||
(m_iProfession == PROFESSION.PROF_ARCHOR) ||
(m_iProfession == PROFESSION.PROF_MONK) ||
(m_iProfession == PROFESSION.PROF_GHOST))
{
szActionMiddleName = "_空中翅膀"; // Air with wings / 空中翅膀
}
else
{
szActionMiddleName = "_空中飞剑"; // Air with sword / 空中飞剑
}
szActionMiddleName += "_施放起_";
szAct = EC_Utility.BuildActionName(data, weapon_type, szActionMiddleName);
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX);
// nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = $"{data.action_prefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].suffix}";
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX);
// nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
// int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0); // 获取技能执行时间 / Get skill execute time
int nExecuteTime = 2000; // 临时值 / Temporary value
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite)
{
if (nExecuteTime > 0)
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
// m_pPlayerModel->SetPlaySpeed(vScale * 1.2f);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->SetPlaySpeed(vScale * 1.2f);
}
piAttackTime = nTime1 + nTime2;
}
else
{
// 动作循环,返回技能决定的执行时间 / Action loops, return skill-determined execute time
piAttackTime = nExecuteTime;
}
ShowWeaponByConfig(data);
// UpdateWeaponHangerPosBySkillAction(idSkill); // 根据技能播放的动作,更改武器悬挂位置 / Update weapon hanger position based on skill action
return true;
}
public bool IsTeamMember(int idPlayer)
{
//TODO: HoangDev implement later
return false;
/* if (!m_pTeam)
return false;
return m_pTeam->GetMemberByID(idPlayer) ? true : false;*/
}
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, CECAttackEvent attackEvent = null)
{
return m_pActionController != null
&& m_pActionController.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent != null ? new bool[] { attackEvent.m_bSignaled } : null, 0);
}
public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0)
{
return m_pActionController != null
&& m_pActionController.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
private void GetSkillSectionActionName(ref string szAct, int idSkill, int nSection)
{
if (nSection != 0)
{
var pAtkMan = CECAttacksMan.Instance;
if (pAtkMan != null && pAtkMan.GetSkillSectionActionSuffix(idSkill, nSection, out string suffix))
{
szAct += "_" + suffix;
}
}
}
// 判断是否在飞行 / Check if flying
public bool IsFlying()
{
// 临时实现 / Temporary implementation
return m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR;
}
public bool IsInvader()
{
return (m_dwStates & PlayerNPCState.GP_STATE_INVADER) != 0;
}
public int GetFactionID() { return m_idFaction; }
public int GetForce() { return m_idForce; }
public bool IsInDuel() { return m_pvp.iDuelState == (int)DuelState.DUEL_ST_INDUEL; }
// Duel state
public enum DuelState
{
DUEL_ST_NONE = 0,
DUEL_ST_PREPARE,
DUEL_ST_INDUEL,
DUEL_ST_STOPPING,
};
public bool IsPariah()
{
return (m_dwStates & PlayerNPCState.GP_STATE_PARIAH) != 0;
}
bool GetSkillStateActionName(int skill, int state, string name1, string name2)
{
/* for (int i = 0; i < (int)m_SkillStateActionVec.size(); i++)
{
if (m_SkillStateActionVec[i].skill == skill && m_SkillStateActionVec[i].state == state)
{
name1 = m_SkillStateActionVec[i].beHitAction;
name2 = m_SkillStateActionVec[i].stayDownAction;
return true;
}
}*/
return false;
}
public virtual bool IsFighting() { return m_bFight; }
public float GetGroundSpeed()
{
// return m_bWalkRun ? g_pGame.GetConfigs().GetHostRunSpeed() : m_ExtProps.mv.walk_speed;
// return 5f;
return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed;
}
// Get move environment
public int GetMoveEnv()
{
return m_iMoveEnv;
}
public bool IsShapeChanged()
{
return m_iShape != 0;
}
// 获取职业 // Get profession
public int GetProfession()
{
return m_iProfession;
}
// 获取性别 // 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
// Play Gfx on Models
protected bool PlayGfx(string szPath, string szHook, float fScale /*1.0f*/, uint iShapeTypeMask /*(1<<PLAYERMODEL_MAJOR)*/, bool bForceNoRecord = false)
{
// bool bPlayed(false);
// bool bSkipRecord = (iShapeTypeMask != PLAYERMODEL_TYPEALL) || bForceNoRecord;
// for(int i=0;i<PLAYERMODEL_MAX;i++)
// {
// if (m_pModels[i] && (iShapeTypeMask & (1<<i)))
// {
// if (IsCurrentModel(m_pModels[i])){
// m_pModels[i]->PlayGfx(szPath, szHook, fScale);
// bPlayed = true;
// }
// if(bSkipRecord) continue;
// A3DGFXEx* pGfx = m_pModels[i]->GetGfx(szPath, szHook);
// if (pGfx && pGfx->IsInfinite()){
// GFXRECORD rec;
// rec.strPath = szPath;
// rec.strHook = szHook;
// rec.fScale = fScale;
// AString key = rec.strPath + rec.strHook;
// m_GfxRecords[key] = rec;
// bSkipRecord = true;
// }
// }
// }
PlayLevelUpGfx(szPath);
return false;
}
private async void PlayLevelUpGfx(string path)
{
// Usage: Load the prefab asynchronously using AddressableManager
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
if (prefab != null)
{
if (_levelUpVfx != null)
{
if (_levelUpVfx.IsPlaying())
return;
_levelUpVfx.Play();
return;
}
// Instantiate at player's current position and rotation
_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;
}
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;
}
}
}
public struct PlayActionEvent
{
public string AnimationName;
public PlayActionEvent(string animationName)
{
this.AnimationName = animationName;
}
}
public struct PLAYER_ACTION
{
public PLAYER_ACTION_TYPE type;
public PLAYER_ACTION_INFO_CONFIG data;
};
public class QueueActionEvent
{
public string AnimationName;
public Action<bool, CECAttackEvent> SetFlag;
public CECAttackEvent AttackEvent;
public bool IsHitAnim;
public QueueActionEvent(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent)
{
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
}
public void SetData(string animationName, Action<bool, CECAttackEvent> setFlag, bool isHitAnim,
CECAttackEvent attackEvent)
{
this.AnimationName = animationName;
SetFlag = setFlag;
IsHitAnim = isHitAnim;
AttackEvent = attackEvent;
}
}
public enum PLAYER_ACTION_TYPE
{
// 0
ACT_STAND = 0, // Đứng
ACT_FIGHTSTAND, // Đứng chiến đ?u
ACT_WALK, // Đi b?
ACT_RUN, // Ch?y
ACT_JUMP_START, // Bắt đ?u nh?y
// 5
ACT_JUMP_LOOP, // Nh?y trên không lặp l?i
ACT_JUMP_LAND, // Nh?y tiếp đ?t
ACT_SWIM, // Bơi
ACT_HANGINWATER, // Lơ lửng trong nước
ACT_TAKEOFF, // C?t cánh (should be ACT_TAKEOFF_WING)
// 10
ACT_HANGINAIR, // Treo trên không (should be ACT_HANGINAIR_WING)
ACT_FLY, // Bay (should be ACT_FLY_WING)
ACT_FLYDOWN, // Bay xuống cao (should be ACT_FLYDOWN_WING_HIGH)
ACT_FLYDOWN_WING_LOW, // Bay xuống th?p (should be ACT_FLYDOWN_WING_LOW)
ACT_LANDON, // H? cánh (should be ACT_LAND_WING)
// 15
ACT_TAKEOFF_SWORD, // Kiếm bay - c?t cánh
ACT_HANGINAIR_SWORD, // Kiếm bay - treo không trung
ACT_FLY_SWORD, // Kiếm bay - tiến tới
ACT_FLYDOWN_SWORD_HIGH, // Kiếm bay - rơi cao
ACT_FLYDOWN_SWORD_LOW, // Kiếm bay - rơi th?p
// 20
ACT_LANDON_SWORD, // Kiếm bay - h? cánh
ACT_SITDOWN, // Ngồi
ACT_SITDOWN_LOOP, // Ngồi lặp l?i
ACT_STANDUP, // Đứng dậy
ACT_WOUNDED, // B? thương
// 25
ACT_GROUNDDIE, // Chết trên mặt đ?t
ACT_GROUNDDIE_LOOP, // Chết trên đ?t (loop)
ACT_WATERDIE, // Chết trong nước
ACT_WATERDIE_LOOP, // Chết trong nước (loop)
ACT_AIRDIE_ST, // Chết trên không (bắt đ?u)
// 30
ACT_AIRDIE, // Chết trên không (loop rơi)
ACT_AIRDIE_ED, // Chết trên không (ch?m đ?t)
ACT_AIRDIE_LAND_LOOP, // Chết rơi đ?t (loop)
ACT_REVIVE, // Hồi sinh
ACT_CUSTOMIZE, // Động tác tùy chỉnh
// 35
ACT_STRIKEBACK, // B? đánh lùi
ACT_STRIKEDOWN, // B? đánh ngã
ACT_STRIKEDOWN_LOOP, // B? đánh ngã (loop)
ACT_STRIKEDOWN_STANDUP, // B? đánh ngã rồi đứng dậy
ACT_PICKUP, // Nhặt đ?
// 40
ACT_PICKUP_LOOP, // Nhặt đ? (loop)
ACT_PICKUP_STANDUP, // Nhặt đ? đứng dậy
ACT_PICKUP_MATTER, // Nhặt vật th?
ACT_GAPE, // Há miệng
ACT_LOOKAROUND, // Nhìn quanh
// 45
ACT_PLAYWEAPON, // Vung vũ khí
ACT_EXP_WAVE, // Vẫy tay
ACT_EXP_NOD, // Gật đ?u
ACT_EXP_SHAKEHEAD, // Lắc đ?u
ACT_EXP_SHRUG, // Nhún vai
// 50
ACT_EXP_LAUGH, // Cười lớn
ACT_EXP_ANGRY, // Tức giận
ACT_EXP_STUN, // Choáng
ACT_EXP_DEPRESSED, // Buồn bã
ACT_EXP_KISSHAND, // Hôn tay
// 55
ACT_EXP_SHY, // Ng?i ngùng
ACT_EXP_SALUTE, // Chào
ACT_EXP_SITDOWN, // Ngồi xuống
ACT_EXP_SITDOWN_LOOP, // Ngồi xuống (loop)
ACT_EXP_SITDOWN_STANDUP, // Ngồi xuống rồi đứng dậy
// 60
ACT_EXP_ASSAULT, // T?n công
ACT_EXP_THINK, // Suy nghĩ
ACT_EXP_DEFIANCE, // Thách thức
ACT_EXP_VICTORY, // Chiến thắng
ACT_EXP_KISS, // Hôn
// 65
ACT_EXP_KISS_LOOP, // Hôn (loop)
ACT_EXP_KISS_END, // Kết thúc hôn
ACT_ATTACK_1, // T?n công 1
ACT_ATTACK_2, // T?n công 2
ACT_ATTACK_3, // T?n công 3
// 70
ACT_ATTACK_4, // T?n công 4
ACT_ATTACK_TOSS, // Ném vũ khí
ACT_TRICK_RUN, // Chiêu khi ch?y
ACT_TRICK_JUMP, // Chiêu khi nh?y
ACT_FLY_GLIDE, // Lư?n
// 75
ACT_FLY_GLIDE_SWORD, // Kiếm bay - lư?n
ACT_EXP_FIGHT, // Tư th? chiến đ?u
ACT_EXP_ATTACK1, // T?n công diễn xu?t 1
ACT_EXP_ATTACK2, // T?n công diễn xu?t 2
ACT_EXP_ATTACK3, // T?n công diễn xu?t 3
// 80
ACT_EXP_ATTACK4, // T?n công diễn xu?t 4
ACT_EXP_DEFENCE, // Phòng th?
ACT_EXP_FALL, // Té ngã
ACT_EXP_FALLONGROUND, // Ngã xuống đ?t
ACT_EXP_LOOKAROUND, // Nhìn quanh
// 85
ACT_EXP_DANCE, // Nh?y múa
ACT_EXP_FASHIONWEAPON, // Động tác vũ khí thời trang
ACT_USEITEM, // Dùng item
ACT_USEITMELOOP, // Dùng item (loop)
ACT_TWO_KISS, // Hôn đôi
// 90
ACT_USING_TARGET_ITEM, // Dùng đ?o c?
ACT_SWIM_FOR_MOVESKILL, // Bơi trong lúc dùng skill di chuyển
ACT_MAX,
ACT_CASTSKILL // Ch? là placeholder cho skill actions
}
public struct ClearComActFlagAllRankNodesEvent
{
public bool v;
public ClearComActFlagAllRankNodesEvent(bool value)
{
v = value;
}
}
[Serializable]
public struct INFO
{
public int cid; // Character ID
public int crc_c; // customized data crc
public int crc_e; // Equipment data crc
public INFO(int cid, int crc_c, int crc_)
{
this.cid = cid;
this.crc_c = crc_c;
this.crc_e = crc_;
}
}
public
enum enumWingType
{
WINGTYPE_WING, // ·ÉÐÐÆ÷ÀàÐÍ£º³á°ò
WINGTYPE_FLYSWORD, // ·ÉÐÐÆ÷ÀàÐÍ£º·É½£
WINGTYPE_DOUBLEWHEEL, // ·ÉÐÐÆ÷ÀàÐÍ£ºË«½Å·ÉÐÐÆ÷
};
public struct PVPINFO
{
public bool bEnable; // PVP switch
public uint dwCoolTime;
public uint dwMaxCoolTime;
public bool bFreePVP; // Free PVP flag, ignore bEnable flag
public bool bInPVPCombat; // true, in PVP combat
public int iDuelState; // Duel state
public int idDuelOpp; // Duel opponent
public int iDuelTimeCnt; // Duel time counter
public int iDuelRlt; // Duel result. 0, no defined; 1-win; 2-lose; 3-draw
};
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;
}
}