/* * FILE: EC_HPWorkFly.cs * * DESCRIPTION: Host player work classes for flying, flash move, and passive movement * * CONVERTED FROM: EC_HPWorkFly.cpp/EC_HPWorkFly.h * * CREATED BY: Duyuxin, 2004/11/23 * * Copyright (c) 2004 Archosaur Studio, All Rights Reserved. */ using UnityEngine; using CSNetwork.GPDataType; using BrewMonster.Scripts.Skills; using BrewMonster; namespace BrewMonster.Scripts { /////////////////////////////////////////////////////////////////////////// // // Class CECHPWorkFly // /////////////////////////////////////////////////////////////////////////// public class CECHPWorkFly : CECHPWork { // Constants private const uint FLY_PREPARE = 420; private const uint FLY_LAUNCH = 1400; private const float LAUNCH_HEIGHT = 2.0f; private const float LAUNCH_VELOCITY = LAUNCH_HEIGHT * 1000.0f / FLY_PREPARE; // Attributes public uint m_dwLaunchTime; public bool m_bContinueFly; protected A3DVECTOR3 m_vDestPos; // 目的地停止位置 / Destination stop position protected bool m_bAddSpeed; // 添加一个垂直速度 / Add a vertical speed // Constructor and Destructor public CECHPWorkFly(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_FLYOFF, pWorkMan) { m_dwMask = Work_mask.MASK_FLYOFF; m_dwTransMask = Work_mask.MASK_STAND | Work_mask.MASK_MOVETOPOS; Reset(); } // Reset work public override void Reset() { base.Reset(); m_dwLaunchTime = 0; m_bAddSpeed = true; m_bContinueFly = false; } // Copy work data public override bool CopyData(CECHPWork pWork) { if (!base.CopyData(pWork)) return false; CECHPWorkFly pSrc = (CECHPWorkFly)pWork; m_vDestPos = pSrc.m_vDestPos; m_dwLaunchTime = pSrc.m_dwLaunchTime; m_bContinueFly = pSrc.m_bContinueFly; m_bAddSpeed = pSrc.m_bAddSpeed; return true; } // Work is cancel public override void Cancel() { m_pHost.m_CDRInfo.vAbsVelocity.Clear(); m_pHost.m_CDRInfo.fYVel = 0.0f; base.Cancel(); } // This work is do player moving? public override bool IsMoving() { return true; } // On first tick protected override void OnFirstTick() { m_pHost.m_iMoveEnv = (int)CECPlayer.Move_environment.MOVEENV_AIR; m_pHost.m_iMoveMode = (int)MoveMode.MOVE_MOVE; m_pHost.m_vVelocity.Clear(); m_pHost.m_vAccel.Clear(); m_pHost.ResetJump(); m_vDestPos = m_pHost.GetPos(); m_vDestPos.y += LAUNCH_HEIGHT; // for test: solving the pull down problem, by sxw 2009-09-03 m_bAddSpeed = false; if (m_pHost.m_GndInfo.fGndHei > m_pHost.m_GndInfo.fWaterHei) { if (m_pHost.GetPos().y - m_pHost.m_GndInfo.fGndHei < 0.2f) m_bAddSpeed = true; } else m_bAddSpeed = true; m_pHost.ShowWing(true); if (m_pHost.GetWingType() == enumWingType.WINGTYPE_WING) m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_TAKEOFF); else { Debug.LogError("(int)PLAYER_ACTION_TYPE.ACT_TAKEOFF_SWORD"); m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_TAKEOFF_SWORD); } } // Tick routine public override bool Tick(float dwDeltaTime) { base.Tick(dwDeltaTime); m_dwLaunchTime += (uint)(dwDeltaTime * 1000.0f); if (m_dwLaunchTime < FLY_PREPARE) { if (m_bContinueFly) return true; else { float fDeltaTime = dwDeltaTime; float fVerSpeed = m_bAddSpeed ? LAUNCH_VELOCITY : 0.0f; m_bAddSpeed = false; A3DVECTOR3 vCurPos = m_pHost.m_MoveCtrl.GroundMove(new A3DVECTOR3 (0), 0.0f, fDeltaTime, fVerSpeed, 0.0f); m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); } } else if (m_dwLaunchTime < FLY_LAUNCH && !m_bContinueFly) return true; else { m_bFinished = true; A3DVECTOR3 vCurPos = m_pHost.GetPos(); m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), 0, (int)GPMoveMode.GP_MOVE_AIR | (int)GPMoveMode.GP_MOVE_RUN); // TODO: Implement GetWingType and wing action constants when wing system is ready m_pHost.PlayAction( m_pHost.GetWingType() == enumWingType.WINGTYPE_WING ? (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR : (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD, true, 300); } return true; } } /////////////////////////////////////////////////////////////////////////// // // Class CECHPWorkFMove // /////////////////////////////////////////////////////////////////////////// public class CECHPWorkFMove : CECHPWork { // Attributes protected A3DVECTOR3 m_vDestPos; // 目的地位置 / Destination position protected A3DVECTOR3 m_vMoveDir; // 移动方向 / Move direction protected float m_fSpeed; // 移动速度 / Move speed protected float m_fDist; // 距离 / Distance protected float m_fDistCnt; // 距离计数器 / Distance counter protected int m_iFMoveSkillID; // Flash move skill id // Constructor and Destructor public CECHPWorkFMove(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_FLASHMOVE, pWorkMan) { m_dwMask = Work_mask.MASK_FLYOFF; m_dwTransMask = Work_mask.MASK_STAND; Reset(); } // Reset work public override void Reset() { base.Reset(); m_fSpeed = 0.0f; m_fDist = 0.0f; m_fDistCnt = 0.0f; m_iFMoveSkillID = 0; } // Copy work data public override bool CopyData(CECHPWork pWork) { if (!base.CopyData(pWork)) return false; CECHPWorkFMove pSrc = (CECHPWorkFMove)pWork; m_vDestPos = pSrc.m_vDestPos; m_fSpeed = pSrc.m_fSpeed; m_fDist = pSrc.m_fDist; m_fDistCnt = pSrc.m_fDistCnt; m_vMoveDir = pSrc.m_vMoveDir; m_iFMoveSkillID = pSrc.m_iFMoveSkillID; return true; } // This work is do player moving? public override bool IsMoving() { return true; } // Prepare to move public void PrepareMove(A3DVECTOR3 vDestPos, float fMoveTime, int iFMoveSkillID = 0) { // ASSERT(fMoveTime > 0.0f); fMoveTime = Mathf.Max(fMoveTime, 0.001f * 50); m_vDestPos = vDestPos; m_fDistCnt = 0.0f; m_vMoveDir = vDestPos - m_pHost.GetPos(); m_fDist = m_vMoveDir.Magnitude(); m_vMoveDir.Normalize(); m_fSpeed = m_fDist / fMoveTime; m_iFMoveSkillID = iFMoveSkillID; } // On first tick protected override void OnFirstTick() { A3DVECTOR3 newPos = m_pHost.GetPos() + new A3DVECTOR3(0.0f, 0.7f, 0.0f); m_pHost.SetPos(EC_Utility.ToVector3(newPos)); m_pHost.m_MoveCtrl.SetHostLastPos(newPos); if (m_iFMoveSkillID > 0) { int reffake = 0; // TODO: Verify PlayAttackEffect signature when implemented m_pHost.PlayAttackEffect(m_pHost.GetSelectedTarget(), m_iFMoveSkillID, 0, -2, 0, 0, ref reffake ); } else { m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_START, true, 0); m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 0, true); } // Motion blur effect (if needed, can be implemented later) // CECFullGlowRender* pGlow = g_pGame->GetGameRun()->GetFullGlowRender(); // if (pGlow && pGlow->IsGlowOn()) // pGlow->SetMotionBlur(0.8f, 0.8f, 1); } // Tick routine public override bool Tick(float dwDeltaTime) { base.Tick(dwDeltaTime); float fMoveDelta = m_fSpeed * dwDeltaTime; A3DVECTOR3 vCurPos = m_pHost.GetPos(); if (m_fDistCnt + fMoveDelta >= m_fDist) { fMoveDelta = m_fDist - m_fDistCnt; m_fDistCnt = m_fDist; m_pHost.SetPos(EC_Utility.ToVector3(m_vDestPos)); m_pHost.m_MoveCtrl.Reset(); m_pHost.m_MoveCtrl.SetHostLastPos(m_vDestPos); m_pHost.m_MoveCtrl.SetLastSevPos(m_vDestPos); if (!m_pHost.m_CDRInfo.vTPNormal.IsZero()) m_pHost.SetGroundNormal(m_pHost.m_CDRInfo.vTPNormal); // Motion blur effect (if needed, can be implemented later) // CECFullGlowRender* pGlow = g_pGame->GetGameRun()->GetFullGlowRender(); // if (pGlow && pGlow->IsGlowOn()) // pGlow->SetMotionBlur(0.8f, 0.0f, 3000); // Finish work Finish(); } else { m_fDistCnt += fMoveDelta; vCurPos += m_vMoveDir * fMoveDelta; m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); m_pHost.m_MoveCtrl.SetHostLastPos(vCurPos); } return true; } // Finish work protected void Finish() { m_bFinished = true; CECComboSkill pcs = m_pHost.m_pComboSkill; if (pcs != null && !pcs.IsStop()) pcs.Continue(false); } } /////////////////////////////////////////////////////////////////////////// // // Class CECHPWorkPassiveMove // /////////////////////////////////////////////////////////////////////////// public class CECHPWorkPassiveMove : CECHPWork { // Passive move type public static class PassiveMoveType { public const int PASSIVE_DIRECT = 0; // cmd_player_teleport mode == 0 public const int PASSIVE_PULL = 1; // cmd_player_teleport mode == 1 public const int PASSIVE_KNOCKBACK = 2; // cmd_player_knockback } // Attributes protected A3DVECTOR3 m_vStartPos; // 起始位置,传送开始时起始位置 / Start position when teleport begins protected A3DVECTOR3 m_vDestPos; // 目标位置,传送后结果 / Destination position, result after teleport protected A3DVECTOR3 m_vMoveDir; // 移动方向 / Move direction protected float m_fSpeed; // 移动速度 / Move speed protected int m_nMoveTime; // 移动所需总时间(ms) / Total time required for movement (ms) protected int m_nMoveTimeCnt; // 累积的移动时间(ms) / Accumulated movement time (ms) protected int m_nWaitTime; // 移动完成后,进行服务器同步等待的时间(ms) / Wait time for server sync after movement (ms) protected int m_nWaitTimeCnt; // 累积的同步等待时间(ms) / Accumulated sync wait time (ms) // Constructor and Destructor public CECHPWorkPassiveMove(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_PASSIVEMOVE, pWorkMan) { Reset(); } // Reset work public override void Reset() { base.Reset(); m_fSpeed = 0.0f; m_nMoveTime = 0; m_nMoveTimeCnt = 0; m_nWaitTime = 0; m_nWaitTimeCnt = 0; } // Copy work data public override bool CopyData(CECHPWork pWork) { if (!base.CopyData(pWork)) return false; CECHPWorkPassiveMove pSrc = (CECHPWorkPassiveMove)pWork; m_vStartPos = pSrc.m_vStartPos; m_vDestPos = pSrc.m_vDestPos; m_vMoveDir = pSrc.m_vMoveDir; m_fSpeed = pSrc.m_fSpeed; m_nMoveTime = pSrc.m_nMoveTime; m_nMoveTimeCnt = pSrc.m_nMoveTimeCnt; m_nWaitTime = pSrc.m_nWaitTime; m_nWaitTimeCnt = pSrc.m_nWaitTimeCnt; return true; } // This work is do player moving? public override bool IsMoving() { return true; } // Prepare to move public void PrepareMove(A3DVECTOR3 vDestPos, int nMoveTime) { // ASSERT(nMoveTime > 0); nMoveTime = Mathf.Max(nMoveTime, 50); A3DVECTOR3 vCurPos = m_pHost.GetPos(); m_vStartPos = vCurPos; m_vDestPos = vDestPos; m_vMoveDir = vDestPos - vCurPos; // 移动速度保持不变(与等待时间无关),因此为等待时间长,则移动速度变大 / Movement speed remains constant (independent of wait time), so longer wait time means faster movement speed float fDist = m_vMoveDir.Magnitude(); m_vMoveDir.Normalize(); m_fSpeed = fDist / (nMoveTime * 0.001f); // 计算移动时间、等待时间、移动位置 / Calculate movement time, wait time, movement position m_nMoveTime = nMoveTime; m_nWaitTime = nMoveTime - m_nMoveTime; m_nWaitTimeCnt = 0; m_nMoveTimeCnt = 0; } // On first tick protected override void OnFirstTick() { m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_STRIKEBACK, true, 0); // Motion blur effect (if needed, can be implemented later) // CECFullGlowRender* pGlow = g_pGame->GetGameRun()->GetFullGlowRender(); // if (pGlow && pGlow->IsGlowOn()) // pGlow->SetMotionBlur(0.8f, 0.8f, 1); } // Helper function: Calculate no brush collide position // 计算非冲突位置 / Calculate non-collision position private bool CalculateNoBrushCollidePos(int nMaxTryTimes, float fStep, float fMaxMove, bool bDownward, A3DVECTOR3 vCurPos, A3DVECTOR3 vExt, out A3DVECTOR3 vPos) { // nMaxTryTimes: 尝试发出射线次数 / Max try times for raycasting // fStep: 每次尝试向垂直方向上下移动(起始为向下) / Each attempt moves vertically up or down (initially down) // fMaxMove: 尝试发出射线距离(起始为向下) / Max distance for raycasting (initially down) // bDownward: 是否向下移动 / Whether to move downward // vCurPos: 起始参考位置 / Starting reference position // vExt: 包围盒大小 / Bounding box size // vPos: 返回的非冲突位置(返回值为 true 有效) / Returned non-collision position (valid if return value is true) vPos = vCurPos; bool bOK = false; // For now, simplified collision detection // TODO: Implement proper brush collision detection with raycasting // This would require access to world terrain and collision systems return bOK; } // Tick routine public override bool Tick(float dwDeltaTime) { base.Tick(dwDeltaTime); int dwDeltaTimeMs = (int)(dwDeltaTime * 1000.0f); // 计算本次的移动时间、等待时间 / Calculate movement time and wait time for this tick int nMoveTime = dwDeltaTimeMs; int nWaitTime = 0; if (nMoveTime + m_nMoveTimeCnt > m_nMoveTime) { nMoveTime = m_nMoveTime - m_nMoveTimeCnt; nWaitTime = dwDeltaTimeMs - nMoveTime; if (nWaitTime + m_nWaitTimeCnt > m_nWaitTime) nWaitTime = m_nWaitTime - m_nWaitTimeCnt; } if (nMoveTime > 0) { // 需要移动 / Need to move // 计算移动后的距离 / Calculate distance after movement float fMoveDelta = m_fSpeed * (m_nMoveTimeCnt + nMoveTime) * 0.001f; A3DVECTOR3 vCurPos = m_vStartPos; vCurPos += m_vMoveDir * fMoveDelta; // 根据地形的高度调整高度,保证在地面之上 / Adjust height based on terrain to ensure above ground // TODO: Implement proper terrain height query // float terrainHeight = g_pGame->GetGameRun()->GetWorld()->GetTerrainHeight(vCurPos); // vCurPos.y = Mathf.Max(vCurPos.y, terrainHeight); A3DVECTOR3 vExt = m_pHost.m_CDRInfo.vExtent; A3DVECTOR3 vStart = vCurPos + new A3DVECTOR3(0,1,0) * vExt.y; // 检查当前位置是否与刷子冲突 / Check if current position collides with brush // TODO: Implement proper collision detection // For now, just set the position directly // 记录新位置 / Record new position m_pHost.SetPos(EC_Utility.ToVector3(vCurPos)); m_pHost.m_MoveCtrl.SetHostLastPos(vCurPos); // 记录时间 / Record time m_nMoveTimeCnt += nMoveTime; } if (nWaitTime > 0) { // 需要等待,与服务器同步 / Need to wait, sync with server m_nWaitTimeCnt += nWaitTime; } if (m_nMoveTimeCnt >= m_nMoveTime && m_nWaitTimeCnt >= m_nWaitTime) { // 工作完成 / Work finished A3DVECTOR3 vCurPos = m_pHost.GetPos(); m_pHost.m_MoveCtrl.Reset(); m_pHost.m_MoveCtrl.SetHostLastPos(vCurPos); m_pHost.m_MoveCtrl.SetLastSevPos(vCurPos); // Motion blur effect (if needed, can be implemented later) // CECFullGlowRender* pGlow = g_pGame->GetGameRun()->GetFullGlowRender(); // if (pGlow && pGlow->IsGlowOn()) // pGlow->SetMotionBlur(0.8f, 0.0f, 3000); Finish(); } return true; } // Finish work protected void Finish() { m_bFinished = true; } } }