diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab old mode 100755 new mode 100644 similarity index 100% rename from Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab rename to Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab.meta b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab.meta old mode 100755 new mode 100644 similarity index 100% rename from Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab.meta rename to Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab.meta diff --git a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs index 801ecc0fd6..cce14ba1ff 100644 --- a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs +++ b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs @@ -78,7 +78,7 @@ namespace BrewMonster.Network // return m_dwRealTickTime; // return Time.realtimeSinceStartup; // 0.018f is value to make mining process run fit with player animation. if have any issue => discussing with Mr. Drimdar - return (Time.unscaledDeltaTime - 0.018f) * 1000f;//-0.001f + return Mathf.Abs(Time.unscaledDeltaTime - 0.018f) * 1000f;//-0.001f } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs b/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs index c4356919e9..c4354e57c3 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using BrewMonster.Network; using BrewMonster.Utils; using Random = UnityEngine.Random; - +using UnityEngine; namespace BrewMonster.Scripts { using WorkList = System.Collections.Generic.List; @@ -279,61 +279,56 @@ namespace BrewMonster.Scripts // class CECEPWorkSpell public class CECEPWorkSpell : CECEPWork { - CECCounter m_SkillCnt; - CECSkill m_pCurSkill; - int m_idCurSkillTarget; - - public CECEPWorkSpell(CECEPWorkMan pWorkMan, uint dwPeriod, CECSkill pSkill, int target) : base(CECEPWork.EP_work_ID.WORK_SPELL, pWorkMan) + CECCounter m_SkillCnt; + CECSkill m_pCurSkill; + int m_idCurSkillTarget; + public CECEPWorkSpell(CECEPWorkMan pWorkMan, uint dwPeriod, CECSkill pSkill, int target) : base(EP_work_ID.WORK_SPELL, pWorkMan) { m_pCurSkill = pSkill; m_idCurSkillTarget = target; + if (m_SkillCnt == null){ + m_SkillCnt = new CECCounter(); + } m_SkillCnt.SetPeriod(dwPeriod); m_SkillCnt.Reset(); } + // public CECEWorkSpell(){ + // if (m_pCurSkill != null){ + // m_pCurSkill = null; + // } + // } public override void Start() { - GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_STAND; + GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_STAND; } - public override void Tick(float dwDeltaTime) - { - //TO DO: fix later - //GetPlayer().m_FightCnt.IncCounter(dwDeltaTime); - //int iRealTime = g_pGame.GetRealTickTime(); - //if (m_SkillCnt.IncCounter(iRealTime)) - //{ - // Finish(); - //} - //else - //{ - // if (m_idCurSkillTarget != 0) - // { - // GetPlayer().TurnFaceTo(m_idCurSkillTarget); - // } - // if (GetPlayer().IsPlayingMoveAction() && !GetPlayer().IsWorkMoveRunning()) - // { // ���ƶ�ʩ����ֹͣ�ƶ�����һֱ�ڳ��������ƶ��������˴���ͣ - // GetPlayer().PlayAction(CECPlayer::ACT_FIGHTSTAND); - // } - // if (!GetPlayer().IsPlayingAction()) - // { - // GetPlayer().PlayAction((int)CECPlayer.PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); // ���ܶ���������ɺ󡢲���ս��վ������ - // } - //} + public override void Tick(float dwDeltaTime){ + GetPlayer().m_FightCnt.IncCounter(dwDeltaTime *1000); + float iRealTime = EC_Game.GetRealTickTime(); + if (m_SkillCnt.IncCounter(Time.unscaledDeltaTime * 1000f, out float fCounter, out float fPeriod)){ + Finish(); + }else{ + if (m_idCurSkillTarget != 0){ + GetPlayer().TurnFaceTo(m_idCurSkillTarget); + } + if (GetPlayer().IsPlayingMoveAction() && !GetPlayer().IsWorkMoveRunning()){ // ´ÓÒÆ¶¯Ê©·¨µ½Í£Ö¹Òƶ¯¡¢»áÒ»Ö±ÔÚ³ÖÐø²¥·ÅÒÆ¶¯¶¯×÷£¬´Ë´¦ÔÝÍ£ + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); + } + if (!GetPlayer().IsPlayingAction()){ + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); // ¼¼Äܶ¯×÷²¥·ÅÍê³Éºó¡¢²¥·ÅÕ½¶·Õ¾Á¢¶¯×÷ + } + } } - public override void Cancel() - { - //TO DO: fix later - //if (m_pCurSkill != null) - //{ - // m_pCurSkill = null; - //} - //m_idCurSkillTarget = 0; - //GetPlayer().StopSkillAttackAction(); - //GetPlayer().TurnFaceTo(0); + public override void Cancel(){ + if (m_pCurSkill != null){ + m_pCurSkill = null; + } + m_idCurSkillTarget = 0; + GetPlayer().StopSkillAttackAction(); + GetPlayer().TurnFaceTo(0); } - public CECSkill GetSkill() - { + public CECSkill GetSkill(){ return m_pCurSkill; - } + } } public class CECEPWorkMan @@ -898,4 +893,43 @@ namespace BrewMonster.Scripts //GetPlayer().StopModelMove(GetPlayer().m_vStopDir, g_vAxisY, 150); } }; + public class CECEPWorkFlashMove : CECEPWork + { + private A3DVECTOR3 m_vServerPos; + private float m_fMoveSpeed; + public CECEPWorkFlashMove(CECEPWorkMan pWorkMan, A3DVECTOR3 vServerPos, float fMoveSpeed) + : base(CECEPWork.EP_work_ID.WORK_FLASHMOVE, pWorkMan) + { + m_vServerPos = vServerPos; + m_fMoveSpeed = fMoveSpeed; + } + public override void Start() + { + GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_MOVE; + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_START, true, 0); + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 0, true); + } + public override void Tick(float dwDeltaTime) + { + base.Tick(dwDeltaTime); + A3DVECTOR3 vCurPos = GetPlayer().GetPos(); + A3DVECTOR3 vDir = m_vServerPos - vCurPos; + float fDist = vDir.Normalize(); + float fMoveDelta = m_fMoveSpeed * dwDeltaTime * 0.001f; + if (fMoveDelta >= fDist) + { + GetPlayer().SetPos(m_vServerPos); + Finish(); + } + else + { + vCurPos = vCurPos + vDir * fMoveDelta; + GetPlayer().SetPos(vCurPos); + } + } + public override void Cancel() + { + GetPlayer().SetPos(m_vServerPos); + } + } } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs index 8857340faa..896e06d6de 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs @@ -111,6 +111,7 @@ namespace BrewMonster private bool m_bCooling; private int m_iChargeCnt; private int m_iChargeMax; + public int ChargeMax => m_iChargeMax; private bool m_bCharging; private static CECSkillStr l_SkillStr = new CECSkillStr(); diff --git a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs index 2dfd24dfcd..e10c5f4601 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs @@ -40,6 +40,13 @@ public class CECCounter m_dwCounter += dwCounter; return (m_dwCounter >= m_dwPeriod) ? true : false; } + public bool IncCounter(float dwCounter, out float fCounter, out float fPeriod) + { + m_dwCounter += dwCounter; + fCounter = m_dwCounter; + fPeriod = m_dwPeriod; + return (m_dwCounter >= m_dwPeriod) ? true : false; + } // Decrease counter public void DecCounter(float dwCounter) diff --git a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs index ef3b988eba..181c2f5356 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs @@ -2491,7 +2491,6 @@ namespace BrewMonster 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)) { @@ -2525,7 +2524,8 @@ namespace BrewMonster public bool IsHangerOn() { return m_bHangerOn; } public bool IsPlayingAction() { - return true /*GetLowerBodyAction() != -1*/ ; + var check = GetLowerBodyAction() != -1 ; + return check; } public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX/* =false */) { @@ -4052,26 +4052,32 @@ namespace BrewMonster public struct PlayActionEvent { + public ChannelAct ChannelAct; public string AnimationName; public int ITransTime; public bool IsForceStopPrevious; public bool IsLoop; public CECAttackEvent AttackEvent; - public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false) - { - this.AnimationName = shapeName + animationName; - ITransTime = iTransTime; - IsForceStopPrevious = isForceStopPrevious; - AttackEvent = attackEvent; - IsLoop = isLoop; - } + public int Rank; public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false) { + this.ChannelAct = null; this.AnimationName = animationName; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; AttackEvent = attackEvent; IsLoop = isLoop; + Rank = 0; + } + public PlayActionEvent(ref ChannelAct channelAct, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false, int rank = 0) + { + this.ChannelAct = channelAct; + this.AnimationName = animationName; + ITransTime = iTransTime; + IsForceStopPrevious = isForceStopPrevious; + AttackEvent = attackEvent; + IsLoop = isLoop; + Rank = rank; } } public struct PLAYER_ACTION @@ -4081,6 +4087,7 @@ namespace BrewMonster }; public class QueueActionEvent { + public ChannelAct ChannelAct; public string AnimationName; public int ITransTime; public Action SetFlag; @@ -4088,9 +4095,11 @@ namespace BrewMonster public bool IsHitAnim; public bool IsForceStopPrevious; public bool IsLoop; + public int Rank; public QueueActionEvent(string animationName, Action setFlag, bool isHitAnim, CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false) { + this.ChannelAct = null; this.AnimationName = animationName; SetFlag = setFlag; IsHitAnim = isHitAnim; @@ -4098,6 +4107,20 @@ namespace BrewMonster ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; IsLoop = isLoop; + Rank = 0; + } + public QueueActionEvent(ref ChannelAct channelAct, string animationName, Action setFlag, bool isHitAnim, + CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false, int rank = 0) + { + this.ChannelAct = channelAct; + this.AnimationName = animationName; + SetFlag = setFlag; + IsHitAnim = isHitAnim; + AttackEvent = attackEvent; + ITransTime = iTransTime; + IsForceStopPrevious = isForceStopPrevious; + IsLoop = isLoop; + Rank = rank; } public void SetData(string shapeName, string animationName, Action setFlag, bool isHitAnim, diff --git a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs index cce383018f..f3db65e1b6 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs @@ -10,6 +10,7 @@ using CombinedActMap = System.Collections.Generic.Dictionary; using CoGfxMap = System.Collections.Generic.Dictionary; using ConvexHullDataArray = System.Collections.Generic.List; using ECModelHookMap = System.Collections.Generic.Dictionary; +using ActQueue = System.Collections.Generic.List; using BrewMonster; using BrewMonster.Scripts.ECModel; using Unity.VisualScripting.FullSerializer; @@ -45,7 +46,110 @@ public enum ECMScriptVar enumECMVarSelf, enumECMVarCount } +public enum ActionChannel +{ + ACTCHA_DEFAULT = 0, + ACTCHA_WOUND = 1, + ACTCHA_MAX = 16, // Keep this value same with A3DSkinModelActionCore::ACTCHA_MAX +}; +public class A3DCombActDynData +{ + public A3DCombinedAction combinedAction; + public int nChannel; + public int m_dwUserData; + public bool IsAllActionFinished => m_EventNames.Count == 0; + public List m_EventNames = new List(); + public void SetUserData(int dwUserData) { m_dwUserData = dwUserData; } + public int GetUserData() { return m_dwUserData; } +} +public class ChannelActNode +{ + public byte m_Rank; + public A3DCombActDynData m_pActive; + public bool m_pActFlag; + public int m_dwFlagMode; + public ActQueue m_ActQueue; + public ChannelActNode() + { + m_Rank = 0; + m_pActive = null; + m_pActFlag = false; + m_dwFlagMode = 0; + if(m_ActQueue == null) + { + m_ActQueue = new ActQueue(); + } + m_ActQueue.Clear(); + } + public void RemoveQueuedActs() + { + m_ActQueue.Clear(); + } +} +public class ChannelAct +{ + public List m_RankNodes; + public ChannelAct() + { + Release(); + } + + public void Release() + { + if(m_RankNodes == null) + { + m_RankNodes = new List(); + } + m_RankNodes.Clear(); + } + + public ChannelActNode GetNodeByRank(byte rank) + { + if(m_RankNodes == null || m_RankNodes.Count == 0) + { + return null; + } + foreach(var node in m_RankNodes) + { + if(node.m_Rank == rank) + { + return node; + } + } + return null; + } + + public ChannelActNode GetHighestRankNode() + { + if(m_RankNodes == null || m_RankNodes.Count == 0) + { + return null; + } + ChannelActNode highestNode = m_RankNodes[0]; + foreach(var node in m_RankNodes) + { + if(node.m_Rank > highestNode.m_Rank) + { + highestNode = node; + } + } + return highestNode; + } + + public ChannelActNode RemoveNodeByRank(byte rank) + { + foreach(var node in m_RankNodes) + { + if(node.m_Rank == rank) + { + m_RankNodes.Remove(node); + return node; + } + } + return null; + } +}; public static class CECModelConstants { public const int ECM_SCRIPT_MAX_VAR_COUNT = 8; @@ -382,6 +486,15 @@ public class CECModel private Transform m_transform; public bool InheritParentId() => m_bInheritParentId; public void SetId(int nId) => m_nId = nId; + //16 is + ChannelAct[] m_ChannelActs = InitChannelActs(); + private static ChannelAct[] InitChannelActs() + { + var acts = new ChannelAct[(int)ActionChannel.ACTCHA_MAX]; + for (int i = 0; i < acts.Length; i++) + acts[i] = new ChannelAct(); + return acts; + } public void ClearComActFlag(bool bSignalCurrent) { ClearComActFlag(0, bSignalCurrent); } public void ClearComActFlag(int nChannel, bool bSignalCurrent) { @@ -672,11 +785,30 @@ public class CECModel } var actionInfos = combinedAction.m_ActLst; var isLoop = combinedAction.m_nLoops == 1; - EventBus.PublishChannel(m_nId, new PlayActionEvent(actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop)); + var node = m_ChannelActs[nChannel].GetNodeByRank(0); + if (node == null) + { + node = new ChannelActNode { m_Rank = 0 }; + m_ChannelActs[nChannel].m_RankNodes.Add(node); + } + var actData = new A3DCombActDynData + { + combinedAction = combinedAction, + nChannel = nChannel, + m_dwUserData = (int)dwUserData + }; + EventBus.PublishChannel(m_nId, new PlayActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[0].m_strName); + for(int i = 1; i < actionInfos.Count; i++) { - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop)); + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[i].m_strName); } + + node.m_pActive = actData; + + //Todo: should move those event logic to channel act because their control the animation life span. var eventInfoList = combinedAction.m_EventInfoLst; if(eventInfoList != null && eventInfoList.Count > 0) { @@ -716,25 +848,44 @@ public class CECModel return false; } A3DCombinedAction combinedAction = GetComActByName(szActName); - if(combinedAction == null) + if(combinedAction == null) { return false; } var actionInfos = combinedAction.m_ActLst; var isLoop = combinedAction.m_nLoops == 1; - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop)); + var node = new ChannelActNode { m_Rank = (byte)m_ChannelActs[nChannel].m_RankNodes.Count}; + m_ChannelActs[nChannel].m_RankNodes.Add(node); + var actData = new A3DCombActDynData + { + // combinedAction = combinedAction, // not needed now + nChannel = nChannel, + m_dwUserData = (int)dwUserData + }; + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop, node.m_Rank)); for(int i = 1; i < actionInfos.Count; i++) { - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop)); + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[i].m_strName); } + node.m_pActive = actData; + //todo: should add sfx and gfx logic to channel act. currently we dont have logic for queue action. only available for play action. return true; } - public bool ClearComActFlagAllRankNodes(bool bSignalCurrent){ - EventBus.PublishChannel(m_nId, new ClearComActFlagAllRankNodesEvent(bSignalCurrent)); + public bool ClearComActFlagAllRankNodes(bool bSignalCurrent) + { + foreach (var ca in m_ChannelActs) + ca?.Release(); + //EventBus.PublishChannel(m_nId, new ClearComActFlagAllRankNodesEvent(bSignalCurrent)); return false; } - public uint GetCurActionUserData(){ - return 0; + + public int GetCurActionUserData() + { + var returnValue = -1; + if (m_ChannelActs[0].GetHighestRankNode() != null) + returnValue = m_ChannelActs[0].GetHighestRankNode().m_pActive.GetUserData(); + return returnValue; } public bool QueueAction(CECNPC.INFO iNFO, string szActName, ref bool pNewActFlag, int nTransTime = 200, uint dwUserData = 0, bool bForceStopPrevAct = false, bool bCheckTailDup = false, bool bNoFx = false, bool bResetSpeed = false /*joslian*/, bool bResetActFlag = false, uint dwNewFlagMode = COMACT_FLAG_MODE_NONE) @@ -846,8 +997,3 @@ public class CECModel // m_CoGfxMap[strKey] = pInfo; } } -// Action channel -public enum ActionChannel -{ - ACTCHA_WOUND = 1, -}; diff --git a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs index 4a4dd77b79..1a65390cb9 100644 --- a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs +++ b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs @@ -450,13 +450,14 @@ namespace BrewMonster } public override bool IsPlayingMoveAction(){ if (GetModel()!=null){ - return IsMoveAction((int)GetModel().GetCurActionUserData()); + var userData = GetModel().GetCurActionUserData(); + return IsMoveAction((int)userData); } return false; } public override int GetLowerBodyAction(){ if (GetModel()!=null){ - return (int)GetModel().GetCurActionUserData(); + return GetModel().GetCurActionUserData(); } return -1; } diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index 390cd62ac3..c4eafb0a73 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -672,80 +672,70 @@ namespace BrewMonster // Get skill object (else players don't have skill lists, so we create a temporary skill reference) // For else players, we mainly need the skill ID for animation purposes int skillID = pCmd.skill; - + if ((m_pCurSkill = new CECSkill(pCmd.skill, pCmd.level)) == null) + { + BMLogger.LogError($"OnMsgPlayerCastSkill: Failed to create CECSkill for skillID={pCmd.skill}, level={pCmd.level}"); + return; + } // Store current skill target m_idCurSkillTarget = pCmd.target; - // Face the target - TurnFaceTo(pCmd.target); + uint dwPeriod = (uint)(pCmd.time + m_pCurSkill.GetExecuteTime()) * 10; + m_pEPWorkMan.StartNormalWork(new CECEPWorkSpell(m_pEPWorkMan, dwPeriod, new CECSkill(pCmd.skill, pCmd.level), pCmd.target)); + PlaySkillCastAction(m_pCurSkill.GetSkillID()); + // // Face the target + // TurnFaceTo(pCmd.target); - // Play skill cast animation - PlaySkillCastAction(skillID); + // // Play skill cast animation + // PlaySkillCastAction(skillID); - // Create a temporary skill object for tracking (if needed) - // Note: Else players don't maintain skill lists like host player does - // We create a minimal skill object just for the current cast - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) - { - // Create a temporary skill object with level 1 (we don't know the actual level) - m_pCurSkill = new CECSkill(skillID, 1); - } + // // Create a temporary skill object for tracking (if needed) + // // Note: Else players don't maintain skill lists like host player does + // // We create a minimal skill object just for the current cast + // if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + // { + // // Create a temporary skill object with level 1 (we don't know the actual level) + // m_pCurSkill = new CECSkill(skillID, 1); + // } - // Enter fight state - EnterFightState(); + // // Enter fight state + // EnterFightState(); break; } case CommandID.OBJECT_CAST_INSTANT_SKILL: { + StopCurPosWork(); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); cmd_object_cast_instant_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - int skillID = pCmd.skill; - - m_idCurSkillTarget = pCmd.target; - - TurnFaceTo(pCmd.target); - PlaySkillCastAction(skillID); - - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) - { - m_pCurSkill = new CECSkill(skillID, 1); - } - - EnterFightState(); + PlaySkillCastAction(pCmd.skill); break; } case CommandID.OBJECT_CAST_POS_SKILL: { + StopCurPosWork(); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); + + cmd_object_cast_pos_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int skillID = pCmd.skill; + SetServerPos(pCmd.pos); - // For position-based skills, target is the position, not an object - // We still play the cast animation - PlaySkillCastAction(skillID); - - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + float fDist = A3d_Magnitude(pCmd.pos - GetPos()); + if (fDist <= 0.0001f) { - m_pCurSkill = new CECSkill(skillID, 1); - } - - EnterFightState(); - break; - } - case CommandID.SKILL_PERFORM: - { - // Skill perform - the skill has finished casting and is being executed - // For else players, we keep m_pCurSkill until attack result is received - // This allows PlayAttackEffect to use the skill information - // Durative skills (channeling) will continue until interrupted - if (m_pCurSkill != null && m_pCurSkill.IsDurative()) - { - // For durative skills, we keep the skill active - // It will be cleared when SKILL_INTERRUPTED is received + SetPos(pCmd.pos); + return; } + int nExecuteTime = ElementSkill.GetExecuteTime((uint)pCmd.skill, pCmd.level); + nExecuteTime = Mathf.Max(nExecuteTime, 50); + + m_fMoveSpeed = 1.3f * fDist * 1000.0f / nExecuteTime; + m_pEPWorkMan.StartNormalWork(new CECEPWorkFlashMove(m_pEPWorkMan, pCmd.pos, m_fMoveSpeed)); break; } case CommandID.SKILL_INTERRUPTED: @@ -753,13 +743,10 @@ namespace BrewMonster // Skill was interrupted, clear current skill cmd_skill_interrupted pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (m_pCurSkill != null) - { - StopSkillCastAction(); - m_pCurSkill = null; - } - m_idCurSkillTarget = 0; + ClearComActFlagAllRankNodes(false); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); + StopSkillCastAction(); break; } default: @@ -768,7 +755,25 @@ namespace BrewMonster } } } - + private void ClearCastingSkill(){ + if (m_pCurSkill != null){ + m_pCurSkill = null; + } + m_idCurSkillTarget = 0; + } + private void StopCurPosWork() + { + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_MOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_MOVE); + } + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_PASSIVEMOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_PASSIVEMOVE); + } + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_FLASHMOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_FLASHMOVE); + } + } + private async void LoadAppearGfx() { if (!m_pAppearGFX && m_iAppearFlag == (int)PlayerAppearFlag.APPEAR_ENTERWORLD) diff --git a/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs b/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs index 75c6b42e6b..606fe6d192 100644 --- a/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs +++ b/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs @@ -196,6 +196,15 @@ namespace BrewMonster.Scripts.Skills // ������ȴʱ�䣬��λ���� public virtual int GetCoolingTime() { return 5000; } // ����ִ��ʱ�䣬��λ���� + public static int GetExecuteTime(uint id, int level) + { + Skill s = Skill.Create(id, level); + if (s == null) + return 0; + + int ret = s.GetExecuteTime(); + return ret; + } public virtual int GetExecuteTime() { return 1000; } // Ŀ����������, 0:����Ŀ�꣬1:��ҪĿ�꣬2:Ŀ��������?��, 3:Ŀ������?����, 4:Ŀ������?���� public virtual int GetTargetType() { return 0; } diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs index 57940f9f58..e79b9b083e 100644 --- a/Assets/Scripts/PlayerVisual.cs +++ b/Assets/Scripts/PlayerVisual.cs @@ -14,6 +14,8 @@ namespace BrewMonster public int ITransTime; public CECAttackEvent AttackEvent; public bool IsLoop; + public ChannelAct ChannelAct; + public int Rank; } public class PlayerVisual : MonoBehaviour { @@ -48,14 +50,16 @@ namespace BrewMonster { AnimationName = @event.AnimationName, IsForceStopPrevious = @event.IsForceStopPrevious, - AttackEvent = @event.AttackEvent + AttackEvent = @event.AttackEvent, + ChannelAct = @event.ChannelAct, + Rank = @event.Rank }); _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); return; } previousAnimationName = @event.AnimationName; InternalPlayAnimation(@event.AnimationName, @event.ITransTime, FadeMode, @event.IsLoop); - ApplyAttackSignalOnAnimationEnd(@event.AttackEvent); + ApplyAnimationEndCallbacks(@event.AttackEvent, @event.ChannelAct, @event.Rank); } public void InitPlayerEventDoneHandler() { @@ -156,7 +160,9 @@ namespace BrewMonster IsForceStopPrevious = @event.IsForceStopPrevious, ITransTime = @event.ITransTime, AttackEvent = @event.AttackEvent, - IsLoop = @event.IsLoop + IsLoop = @event.IsLoop, + ChannelAct = @event.ChannelAct, + Rank = @event.Rank }); _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); if (!isHit) @@ -222,18 +228,21 @@ namespace BrewMonster _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); previousAnimationName = animationQueue.AnimationName; InternalPlayAnimation(animationQueue.AnimationName, animationQueue.ITransTime, FadeMode, animationQueue.IsLoop); - ApplyAttackSignalOnAnimationEnd(animationQueue.AttackEvent); + ApplyAnimationEndCallbacks(animationQueue.AttackEvent, animationQueue.ChannelAct, animationQueue.Rank); } - private void ApplyAttackSignalOnAnimationEnd(CECAttackEvent attackEvent) - { - if (attackEvent == null || _currentState == null) - { - return; - } + private void ApplyAnimationEndCallbacks(CECAttackEvent attackEvent, ChannelAct channelAct, int rank) + { + if (_currentState == null) return; _currentState.Events.OnEnd = () => { - attackEvent.m_bSignaled = true; + if (attackEvent != null) + attackEvent.m_bSignaled = true; + channelAct.GetNodeByRank((byte)rank).m_pActive.m_EventNames.Remove(_currentAnimationName); + if(channelAct.GetNodeByRank((byte)rank).m_pActive.IsAllActionFinished) + { + //channelAct.RemoveNodeByRank((byte)rank); + } }; } void ApplyDamage()