Files
test/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkFly.cs
T
2026-05-31 18:01:16 +07:00

520 lines
18 KiB
C#

/*
* 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
{
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;
}
}
}