server cast skill player processing

This commit is contained in:
VDH
2025-11-12 17:59:50 +07:00
parent 752d2cd69e
commit 62575718f6
8 changed files with 1081 additions and 7 deletions
+126 -7
View File
@@ -2,6 +2,7 @@ using Animancer;
using BrewMonster;
using BrewMonster.Managers;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts.Skills;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using PerfectWorld.Scripts.Managers;
@@ -13,6 +14,8 @@ using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
using static CECPlayer;
public abstract class CECPlayer : CECObject
{
@@ -51,9 +54,13 @@ public abstract class CECPlayer : CECObject
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 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>();
public MOVECONST m_MoveConst; // Const used when moving control
public Move_Mode m_MoveMode;
@@ -150,7 +157,7 @@ public abstract class CECPlayer : CECObject
m_dwResFlags = 0;
m_iFashionWeaponType = -1;
m_uAttackType = DEFAULT_ACTION_TYPE;
AttachWeapon();
}
@@ -250,6 +257,63 @@ public abstract class CECPlayer : CECObject
}
}
}
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}!");
}
}
}
@@ -606,7 +670,7 @@ public abstract class CECPlayer : CECObject
// ==============================
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
// “起” 动作(挥起)
szAct = EC_Utility.BuildActionName(action, weapon_type, "Æð");
EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szAct));
@@ -719,7 +783,7 @@ public abstract class CECPlayer : CECObject
{
//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)
@@ -740,9 +804,10 @@ public abstract class CECPlayer : CECObject
{
return m_bWeaponAttached;
}
bool AttachWeapon(){
bool AttachWeapon()
{
bool result = (false);
/*while (GetPlayerModel() && (GetLeftHandWeapon() || GetRightHandWeapon())){
A3DSkinModel *pSkinModel = GetPlayerModel()->GetA3DSkinModel();
if (!pSkinModel ||
@@ -804,7 +869,7 @@ public abstract class CECPlayer : CECObject
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;
}
@@ -1064,7 +1129,50 @@ public abstract class CECPlayer : CECObject
BubbleText(BUBBLE_HITMISSED, 0);*/
}
}
public bool PlaySkillCastAction(int idSkill)
{
string szAct = "";
int weapon_type = GetShowingWeaponType();
PLAYER_ACTION_INFO_CONFIG data = _default_skill_actions[(uint)idSkill];
if (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, "_Ò÷³ª_");
}
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;
@@ -1084,7 +1192,11 @@ public abstract class CECPlayer : CECObject
return false;
}
public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX/* =false */)
{
return m_pActionController != null
&& m_pActionController.PlaySkillCastActionWithName(idSkill, szActName, bNoFX);
}
bool GetSkillStateActionName(int skill, int state, string name1, string name2)
{
/* for (int i = 0; i < (int)m_SkillStateActionVec.size(); i++)
@@ -1179,6 +1291,13 @@ public struct INFO
this.crc_e = crc_;
}
}
public
enum enumWingType
{
WINGTYPE_WING, // ·ÉÐÐÆ÷ÀàÐÍ£º³á°ò
WINGTYPE_FLYSWORD, // ·ÉÐÐÆ÷ÀàÐÍ£º·É½£
WINGTYPE_DOUBLEWHEEL, // ·ÉÐÐÆ÷ÀàÐÍ£ºË«½Å·ÉÐÐÆ÷
};
public enum PlayerResourcesReadyFlag
@@ -0,0 +1,190 @@
using System;
// CECPlayerActionController
// 玩家动作控制器 / Player action controller
public class CECPlayerActionController
{
// Action channels for split-body animation (kept for parity with C++)
// 动作通道(保留与C++一致的接口语义) / Channels kept to mirror C++ API
public const int ACT_CHANNEL_UPPERBODY = 0;
public const int ACT_CHANNEL_LOWERBODY = 1;
public const int ACT_CHANNEL_WOUND = 2;
private CECPlayer m_pPlayer;
private CECModel m_pPlayerModel;
private bool m_bSupportCastSkillWhenMove;
private CECPlayerActionPlayPolicy m_actionPlayPolicy;
private bool m_bSkillAttackActionPlayed;
public CECPlayerActionController()
{
m_pPlayer = null;
m_pPlayerModel = null;
m_bSupportCastSkillWhenMove = false;
m_actionPlayPolicy = null;
m_bSkillAttackActionPlayed = false;
}
~CECPlayerActionController()
{
ReleaseActionPlayPolicy();
}
public void Bind(CECPlayer player, CECModel playerModel)
{
if (player == null)
{
return;
}
if (player == m_pPlayer && playerModel == m_pPlayerModel)
{
return;
}
ReleaseActionPlayPolicy();
m_pPlayer = player;
m_pPlayerModel = playerModel;
// 是否支持移动中施法(当前C#端未实现,统一设为false)
// Support cast-while-move (not implemented in C# port -> false)
m_bSupportCastSkillWhenMove = false;
if (!m_bSupportCastSkillWhenMove)
{
// 如果不支持,仍保留“受击”通道逻辑钩子(在C#里留空)
// If not supported, keep the hook for wound channel (no-op in C#)
}
InitializeActionPlayPolicy();
}
public bool SupportCastSkillWhenMove()
{
return m_bSupportCastSkillWhenMove;
}
public bool CanCombineWithMoveForSkill(int idSkill)
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.CanCombineWithMoveForSkill(idSkill);
}
private void InitializeActionPlayPolicy()
{
// 当前C#只提供默认策略(不拆分上下半身)
// Use default policy in this C# port
m_actionPlayPolicy = new CECPlayerActionPlayPolicy(m_pPlayer, m_pPlayerModel);
}
private void ReleaseActionPlayPolicy()
{
m_actionPlayPolicy = null;
}
// Build channels (C# no-op, return false to indicate not supported here)
// 构建动作通道(C#未实现,返回false)
private bool BuildChannelForCastSkillWhenMove()
{
return false;
}
public bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart = true, int nTransTime = 200, bool bNoFx = false, bool[] pActFlag = null, uint dwFlagMode = 0)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, pActFlag, dwFlagMode);
}
public bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime = 200, bool bForceStopPrevAct = false, bool bNoFx = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX = false)
{
if (m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlaySkillCastActionWithName(idSkill, szActName, bNoFX))
{
m_bSkillAttackActionPlayed = false;
return true;
}
return false;
}
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, bool[] pActFlag = null, uint dwFlagMode = 0)
{
if (m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, pActFlag, dwFlagMode))
{
m_bSkillAttackActionPlayed = true;
return true;
}
return false;
}
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_actionPlayPolicy != null
&& m_actionPlayPolicy.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
public bool PlayWoundActionWithName(string szActName)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlayWoundActionWithName(szActName);
}
public void ClearComActFlagAllRankNodes(bool bSignalCurrent)
{
if (m_actionPlayPolicy != null)
{
m_actionPlayPolicy.ClearComActFlagAllRankNodes(bSignalCurrent);
}
}
public void StopChannelAction()
{
if (m_actionPlayPolicy != null)
{
m_actionPlayPolicy.StopChannelAction();
}
}
public void StopSkillCastAction()
{
if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && !m_bSkillAttackActionPlayed)
{
m_actionPlayPolicy.StopSkillAction();
// LOG kept minimal in C#
}
}
public void StopSkillAttackAction()
{
if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && m_bSkillAttackActionPlayed)
{
m_actionPlayPolicy.StopSkillAction();
// LOG kept minimal in C#
}
}
public bool IsPlayingAction(int iAction)
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingAction(iAction);
}
public bool IsPlayingCastingSkillAction()
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction();
}
public bool IsPlayingMoveAction()
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingMoveAction();
}
public int GetLowerBodyAction()
{
return m_actionPlayPolicy != null ? m_actionPlayPolicy.GetLowerBodyAction() : -1;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a0afbacc947643442a7bb827ce5b8000
@@ -0,0 +1,340 @@
using System;
/*public class CECPlayerActionController
{
// Action channels for split-body animation (kept for parity with C++)
// 动作通道(保留与C++一致的接口语义) / Channels kept to mirror C++ API
public const int ACT_CHANNEL_UPPERBODY = 0;
public const int ACT_CHANNEL_LOWERBODY = 1;
public const int ACT_CHANNEL_WOUND = 2;
private CECPlayer m_pPlayer;
private CECModel m_pPlayerModel;
private bool m_bSupportCastSkillWhenMove;
private CECPlayerActionPlayPolicy m_actionPlayPolicy;
private bool m_bSkillAttackActionPlayed;
public CECPlayerActionController()
{
m_pPlayer = null;
m_pPlayerModel = null;
m_bSupportCastSkillWhenMove = false;
m_actionPlayPolicy = null;
m_bSkillAttackActionPlayed = false;
}
~CECPlayerActionController()
{
ReleaseActionPlayPolicy();
}
public void Bind(CECPlayer player, CECModel playerModel)
{
if (player == null)
{
return;
}
if (player == m_pPlayer && playerModel == m_pPlayerModel)
{
return;
}
ReleaseActionPlayPolicy();
m_pPlayer = player;
m_pPlayerModel = playerModel;
// 是否支持移动中施法(当前C#端未实现,统一设为false)
// Support cast-while-move (not implemented in C# port -> false)
m_bSupportCastSkillWhenMove = false;
if (!m_bSupportCastSkillWhenMove)
{
// 如果不支持,仍保留“受击”通道逻辑钩子(在C#里留空)
// If not supported, keep the hook for wound channel (no-op in C#)
}
InitializeActionPlayPolicy();
}
public bool SupportCastSkillWhenMove()
{
return m_bSupportCastSkillWhenMove;
}
public bool CanCombineWithMoveForSkill(int idSkill)
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.CanCombineWithMoveForSkill(idSkill);
}
private void InitializeActionPlayPolicy()
{
// 当前C#只提供默认策略(不拆分上下半身)
// Use default policy in this C# port
m_actionPlayPolicy = new CECPlayerActionPlayPolicy(m_pPlayer, m_pPlayerModel);
}
private void ReleaseActionPlayPolicy()
{
m_actionPlayPolicy = null;
}
// Build channels (C# no-op, return false to indicate not supported here)
// 构建动作通道(C#未实现,返回false)
private bool BuildChannelForCastSkillWhenMove()
{
return false;
}
public bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart = true, int nTransTime = 200, bool bNoFx = false, bool[] pActFlag = null, uint dwFlagMode = 0)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlayNonSkillActionWithName(iAction, szActName, bRestart, nTransTime, bNoFx, pActFlag, dwFlagMode);
}
public bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime = 200, bool bForceStopPrevAct = false, bool bNoFx = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.QueueNonSkillActionWithName(iAction, szActName, nTransTime, bForceStopPrevAct, bNoFx, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX = false)
{
if (m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlaySkillCastActionWithName(idSkill, szActName, bNoFX))
{
m_bSkillAttackActionPlayed = false;
return true;
}
return false;
}
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, bool[] pActFlag = null, uint dwFlagMode = 0)
{
if (m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, pActFlag, dwFlagMode))
{
m_bSkillAttackActionPlayed = true;
return true;
}
return false;
}
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_actionPlayPolicy != null
&& m_actionPlayPolicy.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
public bool PlayWoundActionWithName(string szActName)
{
return m_actionPlayPolicy != null
&& m_actionPlayPolicy.PlayWoundActionWithName(szActName);
}
public void ClearComActFlagAllRankNodes(bool bSignalCurrent)
{
if (m_actionPlayPolicy != null)
{
m_actionPlayPolicy.ClearComActFlagAllRankNodes(bSignalCurrent);
}
}
public void StopChannelAction()
{
if (m_actionPlayPolicy != null)
{
m_actionPlayPolicy.StopChannelAction();
}
}
public void StopSkillCastAction()
{
if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && !m_bSkillAttackActionPlayed)
{
m_actionPlayPolicy.StopSkillAction();
// LOG kept minimal in C#
}
}
public void StopSkillAttackAction()
{
if (m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction() && m_bSkillAttackActionPlayed)
{
m_actionPlayPolicy.StopSkillAction();
// LOG kept minimal in C#
}
}
public bool IsPlayingAction(int iAction)
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingAction(iAction);
}
public bool IsPlayingCastingSkillAction()
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingCastingSkillAction();
}
public bool IsPlayingMoveAction()
{
return m_actionPlayPolicy != null && m_actionPlayPolicy.IsPlayingMoveAction();
}
public int GetLowerBodyAction()
{
return m_actionPlayPolicy != null ? m_actionPlayPolicy.GetLowerBodyAction() : -1;
}
}*/
public class CECPlayerActionPlayPolicy
{
protected readonly CECPlayer m_pPlayer;
protected readonly CECModel m_pPlayerModel;
// 简单状态记录以支持“是否在施法中”的判断
// Simple state to support IsPlayingCastingSkillAction
private bool m_isCastingSkill;
public CECPlayerActionPlayPolicy(CECPlayer pPlayer, CECModel pPlayerModel)
{
m_pPlayer = pPlayer;
m_pPlayerModel = pPlayerModel;
m_isCastingSkill = false;
}
public virtual bool CanCombineWithMoveForSkill(int idSkill)
{
return false;
}
public CECPlayer GetPlayer()
{
return m_pPlayer;
}
public CECModel GetModel()
{
return m_pPlayerModel;
}
public bool IsMoving()
{
return IsPlayingMoveAction() && (m_pPlayer != null && m_pPlayer.IsWorkMoveRunning());
}
public static bool IsMoveAction(int action)
{
return action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_RUN
|| action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_WALK
|| action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_FLY
|| action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_FLY_SWORD
|| action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_SWIM
|| action == (int)CECPlayer.PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL;
}
public bool IsPlayingCastingSkillAction()
{
return m_isCastingSkill;
}
// Non-skill action
public virtual bool PlayNonSkillActionWithName(int iAction, string szActName, bool bRestart, int nTransTime, bool bNoFx, bool[] pActFlag, uint dwFlagMode)
{
if (m_pPlayer == null || string.IsNullOrEmpty(szActName))
{
return false;
}
EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName));
return true;
}
public virtual bool QueueNonSkillActionWithName(int iAction, string szActName, int nTransTime, bool bForceStopPrevAct, bool bNoFx, bool bResetSpeed, bool bResetActFlag, bool[] pNewActFlag, uint dwNewFlagMode)
{
// 当前实现:直接播放(队列行为由上层系统处理)
// Current: just play, queue behavior handled by upper systems
return PlayNonSkillActionWithName(iAction, szActName, false, nTransTime, bNoFx, pNewActFlag, dwNewFlagMode);
}
// Skill actions
public virtual bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX)
{
if (m_pPlayer == null || string.IsNullOrEmpty(szActName))
{
return false;
}
if (IsMoving())
{
return false;
}
m_isCastingSkill = true;
EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName));
return true;
}
public virtual bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX, bool[] pActFlag, uint dwFlagMode)
{
if (m_pPlayer == null || string.IsNullOrEmpty(szActName))
{
return false;
}
if (IsMoving())
{
return false;
}
m_isCastingSkill = true;
EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName));
return true;
}
public virtual bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime, bool bNoFX, bool bResetSpeed, bool bResetActFlag, bool[] pNewActFlag, uint dwNewFlagMode)
{
return PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, pNewActFlag, dwNewFlagMode);
}
public virtual bool PlayWoundActionWithName(string szActName)
{
if (m_pPlayer == null || string.IsNullOrEmpty(szActName))
{
return false;
}
EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new PlayActionEvent(szActName));
return true;
}
public virtual void ClearComActFlagAllRankNodes(bool bSignalCurrent)
{
if (m_pPlayer != null)
{
EventBus.PublishChannel(m_pPlayer.GetPlayerInfo().cid, new CECPlayer.CleearComActFlagAllRankNodesEvent(bSignalCurrent));
}
}
public virtual void StopChannelAction()
{
// 在C#端没有底层通道概念,做成清旗标即可
// No channel concept here; clear act flags as a substitute
ClearComActFlagAllRankNodes(true);
}
public virtual void StopSkillAction()
{
m_isCastingSkill = false;
StopChannelAction();
}
public virtual bool IsPlayingAction(int iAction)
{
// C#动画系统由上层驱动,这里不跟踪具体动作,统一返回false
// Not tracked here; return false by default
return false;
}
public virtual bool IsPlayingMoveAction()
{
return false;
}
public virtual int GetLowerBodyAction()
{
return -1;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2f3e916f6bf57b24db022c97379fffca
@@ -151,6 +151,13 @@ namespace BrewMonster.Scripts.Skills
return new Dictionary<uint, int>();
}
public virtual string GetName() { return null; }
public static string GetName(uint id)
{
SkillStub s = SkillStub.GetStub(id);
if (s != null)
return s.GetName();
return "";
}
public virtual byte[] GetNativeName() { return null; }
// ?,skill_type
public virtual byte GetType() { return 1; }
@@ -225,6 +232,13 @@ namespace BrewMonster.Scripts.Skills
// ֧
public virtual int GetArrowCost() { return 0; }
public static int GetCommonCoolDown(uint id)
{
SkillStub s = SkillStub.GetStub(id);
if (s != null)
return s.commoncooldown;
return 0;
}
// ж
public virtual bool ValidWeapon(int w) { return true; }
// 0, ɹ1ƥ䣻2, mp㣻3λ㣻4?5ID, 6δѡĿ
+393
View File
@@ -61,6 +61,7 @@ public partial class CECHostPlayer : CECPlayer
private int m_iRoleCreateTime;
private int m_iRoleLastLoginTime; // Role last login time
private int m_iAccountTotalCash;
private int m_idCurSkillTarget;
private List<CECObject> m_aTabSels = new List<CECObject>();
private List<CECSkill> m_aPtSkills = new List<CECSkill>();
@@ -68,8 +69,11 @@ public partial class CECHostPlayer : CECPlayer
private List<CECSkill> m_aEquipSkills = new List<CECSkill>();
private List<CECSkill> m_aGoblinSkills = new List<CECSkill>();
private bool m_bSpellDSkill;
private bool m_bEnterGame;
public CECSkill m_pPrepSkill;
private CECSkill m_pCurSkill;
private CECCounter m_IncantCnt;
private float playerSpeed = 5.0f;
private float jumpHeight = 1.5f;
private float gravityValue = -9.81f;
@@ -404,9 +408,398 @@ public partial class CECHostPlayer : CECPlayer
case int value when value == EC_MsgDef.MSG_HST_SKILLDATA: OnMsgHstSkillData(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_DIED: OnMsgHstDied(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break;
case int value when value == EC_MsgDef.MSG_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break;
}
}
private void OnMsgPlayerCastSkill(ECMSG Msg)
{
// using namespace S2C;
bool bDoOtherThing = false;
int idTarget = 0;
bool bActionStartSkill = false;
int iActionTime = 1000;
//CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
BMLogger.LogError("HoangDev OnMsgPlayerCastSkill Msg.dwParam2 " + (int)Msg.dwParam2);
switch ((int)Msg.dwParam2)
{
case CommandID.OBJECT_CAST_SKILL:
{
var pCmd = GPDataTypeHelper.FromBytes<cmd_object_cast_skill>((byte[])Msg.dwParam1);
if (m_pCurSkill != null)
{
m_pCurSkill.EndCharging();
}
m_pCurSkill = GetPositiveSkillByID(pCmd.skill);
if (m_pCurSkill == null) m_pCurSkill = GetEquipSkillByID(pCmd.skill);
if (m_pCurSkill == null) m_pCurSkill = CECComboSkillState.Instance.GetInherentSkillByID((uint)pCmd.skill);
if (m_pCurSkill == null)
{
System.Diagnostics.Debug.Assert(m_pCurSkill != null);
return;
}
if (m_pCurSkill.IsChargeable())
m_pCurSkill.StartCharging(pCmd.time);
int iWaitTime = -1;
if (m_pCurSkill.GetExecuteTime() >= 0)
iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime();
var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.Host_work_ID.WORK_SPELLOBJECT);
pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime);
m_pWorkMan.StartWork_p1(pWork);
if (!m_pCurSkill.IsChargeable())
{
int iTime = pCmd.time;
iTime = Math.Max(iTime, 10);
m_IncantCnt.SetPeriod(iTime);
m_IncantCnt.Reset();
}
else
{
m_IncantCnt.Reset(true);
}
m_bSpellDSkill = false;
TurnFaceTo(pCmd.target);
m_idCurSkillTarget = pCmd.target;
PlaySkillCastAction(m_pCurSkill.GetSkillID());
bActionStartSkill = true;
iActionTime = iWaitTime;
break;
}
/* case CommandID.SKILL_PERFORM:
{
m_pPrepSkill = null;
if (m_pCurSkill != null && m_pCurSkill.IsDurative())
m_bSpellDSkill = true;
break;
}
case CommandID.HOST_STOP_SKILL:
{
m_pPrepSkill = null;
CECSkill pSkillToMatch = m_pCurSkill;
if (m_pCurSkill != null)
{
ClearComActFlagAllRankNodes(true);
if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) ||
m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork())
{
bDoOtherThing = true;
idTarget = m_idCurSkillTarget;
}
m_pCurSkill.EndCharging();
m_pCurSkill = null;
}
AP_ActionEvent(AP_EVENT_STOPSKILL);
if (pSkillToMatch != null)
{
m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch));
}
StopSkillAttackAction();
m_idCurSkillTarget = 0;
break;
}
case CommandID.SELF_SKILL_INTERRUPTED:
{
int skill_id = 0;
m_pPrepSkill = null;
CECSkill pSkillToMatch = m_pCurSkill;
if (m_pCurSkill != null)
{
skill_id = m_pCurSkill.GetSkillID();
ClearComActFlagAllRankNodes(false);
if (((m_pComboSkill != null && !m_pComboSkill.IsStop()) ||
m_pCurSkill.ChangeToMelee()) && !m_pWorkMan.HasDelayedWork())
{
bDoOtherThing = true;
idTarget = m_idCurSkillTarget;
}
m_pCurSkill.EndCharging();
m_pCurSkill = null;
}
m_idCurSkillTarget = 0;
if (pSkillToMatch != null)
{
m_pWorkMan.FinishWork(new CECHPWorkSpellMatcher(pSkillToMatch));
}
StopSkillCastAction();
g_pGame.GetGameRun().AddFixedMessage(FIXMSG_SKILLINTERRUPT);
AP_ActionEvent(AP_EVENT_STOPSKILL);
CECAutoPolicy.GetInstance().SendEvent_SkillInterrupt(skill_id);
break;
}
case CommandID.OBJECT_CAST_INSTANT_SKILL:
{
var pCmd = (S2C.cmd_object_cast_instant_skill)Msg.Param1;
System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
CECSkill pSkill = GetPositiveSkillByID(pCmd.skill);
if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill);
if (pSkill == null)
{
System.Diagnostics.Debug.Assert(pSkill != null);
return;
}
if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid)
TurnFaceTo(pCmd.target);
PlaySkillCastAction(pSkill.GetSkillID());
bActionStartSkill = true;
break;
}
case CommandID.OBJECT_CAST_POS_SKILL:
{
var pCmd = (S2C.cmd_object_cast_pos_skill)Msg.Param1;
System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
CECSkill pSkill = GetNormalSkill(pCmd.skill);
if (pSkill == null) pSkill = GetEquipSkillByID(pCmd.skill);
if (pSkill == null)
{
System.Diagnostics.Debug.Assert(pSkill != null);
break;
}
TurnFaceTo(pCmd.target);
if (pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SLEF &&
pSkill.GetRangeType() != CECSkill.RangeType.RANGE_SELFSPHERE &&
(pSkill.GetSkillID() == 1095 ||
pSkill.GetSkillID() == 1278 ||
pSkill.GetSkillID() == 1279 ||
pSkill.GetSkillID() == 2313))
{
// Teleport-style placement
A3DVECTOR3 vPos = pCmd.pos;
if (!IsPosCollideFree(vPos))
{
vPos += g_vAxisY * 0.1f;
}
A3DVECTOR3 vNormal;
float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal);
if (vPos.y < vTerrainHeight)
vPos.y = vTerrainHeight;
SetPos(vPos);
m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin;
m_CDRInfo.fYVel = 0.0f;
m_CDRInfo.vAbsVelocity.Clear();
ResetJump();
m_MoveCtrl.SetHostLastPos(vPos);
m_MoveCtrl.SetLastSevPos(vPos);
UpdateFollowCamera(false, 10);
}
else
{
var pWork = (CECHPWorkFMove)m_pWorkMan.CreateWork(CECHPWork.WORK_FLASHMOVE);
int nExecuteTime = pSkill.GetExecuteTime();
nExecuteTime = Math.Max(nExecuteTime, 50);
if (pSkill.GetSkillID() == 1145 ||
pSkill.GetSkillID() == 1314 ||
pSkill.GetSkillID() == 1315 ||
pSkill.GetSkillID() == 1362 ||
pSkill.GetSkillID() == 1690 ||
pSkill.GetSkillID() == 1691 ||
pSkill.GetSkillID() == 1845 ||
pSkill.GetSkillID() == 1844 ||
pSkill.GetSkillID() == 1815 ||
pSkill.GetSkillID() == 2272 ||
pSkill.GetSkillID() == 2315 ||
pSkill.GetSkillID() == 2285 ||
pSkill.GetSkillID() == 2340 ||
pSkill.GetSkillID() == 2341 ||
pSkill.GetSkillID() == 2342 ||
pSkill.GetSkillID() == 2553 ||
pSkill.GetSkillID() == 2740 ||
pSkill.GetSkillID() == 2741 ||
pSkill.GetSkillID() == 2559 ||
pSkill.GetSkillID() == 2752 ||
pSkill.GetSkillID() == 2753)
{
A3DVECTOR3 vPos = pCmd.pos;
if (!IsPosCollideFree(vPos))
{
vPos += g_vAxisY * 0.1f;
}
A3DVECTOR3 vNormal;
float vTerrainHeight = g_pGame.GetGameRun().GetWorld().GetTerrainHeight(vPos, out vNormal);
if (vPos.y < vTerrainHeight)
vPos.y = vTerrainHeight;
m_CDRInfo.vTPNormal = (vPos.y <= vTerrainHeight + 0.1f) ? vNormal : g_vOrigin;
m_CDRInfo.fYVel = 0.0f;
m_CDRInfo.vAbsVelocity.Clear();
ResetJump();
pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, pSkill.GetSkillID());
}
else
{
if (pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SLEF ||
pSkill.GetRangeType() == CECSkill.RangeType.RANGE_SELFSPHERE)
{
m_CDRInfo.vTPNormal = m_MoveCtrl.m_vFlashTPNormal;
}
pWork.PrepareMove(pCmd.pos, nExecuteTime * 0.001f, 0);
}
m_pWorkMan.StartWork_p2(pWork);
iActionTime = nExecuteTime;
}
bActionStartSkill = true;
break;
}
case CommandID.PLAYER_CAST_RUNE_SKILL:
{
var pCmd = (S2C.cmd_player_cast_rune_skill)Msg.Param1;
System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
if (m_pTargetItemSkill != null)
{
m_pTargetItemSkill = null;
}
m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level);
if (m_pTargetItemSkill == null)
{
System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null);
return;
}
m_pCurSkill = m_pTargetItemSkill;
if (m_pCurSkill.IsChargeable())
m_pCurSkill.StartCharging(pCmd.time);
int iWaitTime = -1;
if (m_pCurSkill.GetExecuteTime() >= 0)
iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime();
var pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(CECHPWork.WORK_SPELLOBJECT);
pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime);
m_pWorkMan.StartWork_p1(pWork);
if (!m_pCurSkill.IsChargeable())
{
int iTime = pCmd.time;
iTime = Math.Max(iTime, 10);
m_IncantCnt.SetPeriod(iTime);
m_IncantCnt.Reset();
}
else
{
m_IncantCnt.Reset(true);
}
m_bSpellDSkill = false;
TurnFaceTo(pCmd.target);
m_idCurSkillTarget = pCmd.target;
PlaySkillCastAction(m_pCurSkill.GetSkillID());
bActionStartSkill = true;
iActionTime = iWaitTime;
g_pGame.RuntimeDebugInfo(0xffffffff, $"Cast skill({m_pCurSkill.GetSkillID()}): {g_pGame.GetSkillDesc().GetWideString(m_pCurSkill.GetSkillID() * 10)}");
break;
}
case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL:
{
var pCmd = (S2C.cmd_player_cast_rune_instant_skill)Msg.Param1;
System.Diagnostics.Debug.Assert(pCmd.caster == m_PlayerInfo.cid);
if (m_pTargetItemSkill != null)
{
m_pTargetItemSkill = null;
}
m_pTargetItemSkill = new CECSkill(pCmd.skill, pCmd.level);
if (m_pTargetItemSkill == null)
{
System.Diagnostics.Debug.Assert(m_pTargetItemSkill != null);
return;
}
if (pCmd.target != 0 && pCmd.target != m_PlayerInfo.cid)
TurnFaceTo(pCmd.target);
PlaySkillCastAction(m_pTargetItemSkill.GetSkillID());
bActionStartSkill = true;
break;
}
case CommandID.ERROR_MESSAGE:
bDoOtherThing = true;
// m_pPrepSkill = null;
break;
default:
System.Diagnostics.Debug.Assert(false);
break;*/
}
if (bActionStartSkill)
AP_ActionEvent(AP_EVENT_STARTSKILL, iActionTime);
if (bDoOtherThing)
{
if (m_pComboSkill != null && !m_pComboSkill.IsStop())
{
if (CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
g_pGame.GetGameRun().PostMessage(MSG_HST_CONTINUECOMBOSKILL, MAN_PLAYER, 0, 0, m_pComboSkill.GetGroupIndex());
else
m_pComboSkill.Continue(false);
}
else
{
if (idTarget != 0 && idTarget != m_PlayerInfo.cid)
NormalAttackObject(idTarget, true);
}
}
}
private void OnMsgHstSkillData(ECMSG Msg)
{
cmd_skill_data pCmd = default;
+14
View File
@@ -116,6 +116,20 @@ public static class EC_Utility
var tailFixed = FixGBKString(tail);
return $"{prefix}_{suffix}{tailFixed}";
}
public static string BuildActionName(PLAYER_ACTION_INFO_CONFIG data, int weaponType, string midBody = "")
{
string prefix = data.ActionPrefix ?? string.Empty;
string suffix = string.Empty;
if (data.action_weapon_suffix != null
&& weaponType >= 0
&& weaponType < data.action_weapon_suffix.Length)
{
suffix = data.action_weapon_suffix[weaponType].Suffix ?? string.Empty;
}
var midBodyFixed = FixGBKString(midBody);
return $"{prefix}{midBodyFixed}{suffix}";
}
// Build pvp mask
public static byte glb_BuildPVPMask(bool bForceAttack)