// Enable IntelligentRoute AutoPF integration (ported from original PW client).
// 启用智能寻路 AutoPF 集成(从原版完美客户端移植)。
#define ENABLE_CEC_INTELLIGENT_ROUTE
using CSNetwork.GPDataType;
using System;
using System.Collections.Generic;
using UnityEngine;
using BrewMonster.Managers;
using Types = BrewMonster.Scripts.CECHPWorkMove.DestTypes;
using BrewMonster.Network;
namespace BrewMonster.Scripts
{
public class CECHPWorkMove : CECHPWork
{
public static class DestTypes
{
public const int DEST_2D = 0,
DEST_3D = 1,
DEST_DIR = 2,
DEST_PUSH = 3,
DEST_STANDJUMP = 4,
DEST_AUTOPF = 5; // Movement type
}
const float A3D_PI = 3.1415926535f;
static float DEG2RAD(float deg) => ((deg) * A3D_PI / 180.0f);
static float pitch_ang_wing => DEG2RAD(45.0f);
static float pitch_ang_fly_sword => DEG2RAD(25.0f);
static float lean_max_ang => DEG2RAD(45.0f);
static float ang_vel_fly => 1.0f / DEG2RAD(60.0f);
static float ang_vel_swim => 1.0f / DEG2RAD(180.0f);
static float pitch_co_wing => pitch_ang_wing / A3D_PI;
static float pitch_co_fly_sword => pitch_ang_fly_sword / A3D_PI;
const float sidle_co = .5f;
static float sidle_co_r => 1.0f - sidle_co;
static float push_pitch_vel_wing => pitch_ang_wing / 0.5f;
static float push_pitch_vel_fly_sword => pitch_ang_fly_sword / 0.5f;
private const uint MoveInputMask = 0x0F; // MD_FORWARD | MD_RIGHT | MD_BACK | MD_LEFT
protected A3DVECTOR3 m_vMoveDest; // Move destination position or direction
protected int m_iDestType; // Destination type
protected bool m_bHaveDest; // true, have destination
protected bool m_bMeetSlide; // true, meet slide
protected A3DVECTOR3 m_vCurDir; // Current move direction
protected bool m_bReadyCancel; // true, ready to cancel
protected bool m_bGliding; // glide
protected float m_fGlideTime;
protected float m_fGlideSpan;
protected float m_fGlideAng;
protected float m_fGlideVel; // glide angular vel
protected float m_fGlidePitch; // glide pitch angle
protected float m_fCurPitch;
protected float m_fPushPitch;
protected float m_fPushLean;
protected A3DVECTOR3 vDir = new A3DVECTOR3();
protected bool m_bUseAutoMoveDialog; // Auto move
protected float m_fAutoHeight; // Height of auto moving destination
protected bool m_bAutoLand; // Auto land when arrive at destination
protected bool m_bAutoFly; // Auto fly
protected bool m_bReachedHeight;// Player reached specified height
protected bool m_bAutoFlyPending; // Mark whether a fly command had been executed
protected int m_iNPCTempleId;
protected int m_iTaskId;
protected bool m_bSwitchTo2D;
protected bool m_bResetAutoPF;
///
/// RMap marks deep water as blocked; AutoPF snaps goals to nearest land. If the real mission point
/// (m_vMoveDest) is still farther horizontally (e.g. in water), continue with DEST_2D after AutoPF ends.
///
const float AutoPF_WorldDestContinueDistH = 0.1f;
/// Horizontal radius to treat DEST_2D as arrived (swim/fly overshoot logic often never fires).
const float Dest2D_ArrivalDistH = 0.1f;
public CECHPWorkMove(CECHPWorkMan pWorkMan) : base(Host_work_ID.WORK_MOVETOPOS, pWorkMan)
{
m_dwMask = Work_mask.MASK_MOVETOPOS;
m_dwTransMask = Work_mask.MASK_STAND | Work_mask.MASK_TRACEOBJECT | Work_mask.MASK_FOLLOW;
Reset();
}
public CECHPWorkMove(int iWorkID, CECHPWorkMan pWorkMan) : base(iWorkID, pWorkMan)
{
}
// Set destination position or direction
public void SetDestination(int iDestType, A3DVECTOR3 vMoveDest)
{
m_iDestType = iDestType;
m_vMoveDest = vMoveDest;
m_bHaveDest = true;
m_bGliding = false;
//m_pHost.SetAdjustOrient(false); // 2014-9-10 ���ı��� CECHPWorkMove ������ʱ����ô˺������ᵼ������ʱ��ͨ�� SetDestDirAndUp ���ö�����ij������ʧЧ��
// ���ַ���Ϊ�����ɡ�����ӽ�������ͷź����ϰ�ס'A'��'D'���ƶ�������ס���ţ�����������ʩ������ƫ��Ŀ��������ƶ��������γ��ԣ�
//���������Ϣ
m_iTaskId = 0;
m_iNPCTempleId = 0;
ResetUseAutoPF();
if (iDestType == Types.DEST_DIR)
{
m_vCurDir = vMoveDest;
if (m_bUseAutoMoveDialog)
{
m_bUseAutoMoveDialog = false;
m_bAutoLand = false;
m_fAutoHeight = -1.0f;
m_bAutoFly = false;
m_bReachedHeight = true;
m_bAutoFlyPending = false;
}
}
else if (iDestType == Types.DEST_2D || iDestType == Types.DEST_3D)
{
m_vCurDir = vMoveDest - m_pHost.GetPos();
m_vCurDir.y = 0.0f;
if (m_vCurDir.Normalize() > 1e-4f)
OrientHostHorizontal(m_vCurDir);
}
else if (IsAutoPF())
{
// Search() has not run yet — GetCurDest() is wrong here; use goal direction until first waypoint.
// Search() 尚未执行时 GetCurDest() 不可靠;先用目标方向,寻路成功后再对准第一个节点。
m_vCurDir = vMoveDest - m_pHost.GetPos();
m_vCurDir.y = 0.0f;
if (m_vCurDir.Normalize() > 1e-4f)
OrientHostHorizontal(m_vCurDir);
if (m_bUseAutoMoveDialog)
{
// �˴����� m_bUseAutoMoveDialog���� SetUseAutoMoveDialog ��˵��
m_bUseAutoMoveDialog = false;
m_bAutoLand = false;
m_fAutoHeight = -1.0f;
m_bAutoFly = false;
m_bReachedHeight = true;
m_bAutoFlyPending = false;
}
}
// Swim/fly velocity carry-over skews the first AirWaterMove/GroundMove frame on new click.
if (iDestType == Types.DEST_2D || iDestType == Types.DEST_3D || iDestType == Types.DEST_AUTOPF)
{
m_pHost.m_vVelocity.x = 0f;
m_pHost.m_vVelocity.z = 0f;
}
// TO DO: fix later
//if (m_pHost.m_pMoveTargetGFX)
//{
// if (iDestType != DEST_PUSH)
// m_pHost.m_pMoveTargetGFX.Stop();
//}
}
void ResetUseAutoPF()
{
m_bResetAutoPF = true;
}
// Tick routine
public override bool Tick(float dwDeltaTime)
{
UpdateResetUseAutoPF();
if (m_bSwitchTo2D)
{
SwitchToDest2D();
m_bSwitchTo2D = false;
return true;
}
#if ENABLE_CEC_INTELLIGENT_ROUTE
if (IsAutoPF())
{
if (global::BrewMonster.Scripts.CECIntelligentRoute.Instance().IsIdle())
{
// C++: AutoPF not ready yet, wait next tick for SwitchTo2D (EC_HPWorkMove.cpp).
// C++:智能寻路模式未成功时,等待下个 Tick 切换到 DEST_2D 模式。
return true;
}
// EC_HPWorkMove.cpp: mid-air AutoPF → reset route and switch to DEST_2D next tick.
if (m_pHost.IsFlying())
{
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().ResetSearch();
m_bSwitchTo2D = true;
return true;
}
}
#endif
base.Tick(dwDeltaTime);
// Draw red line showing the path the player has to move
// 绘制红色线条显示玩家需要移动的路径
if (m_bHaveDest)
{
A3DVECTOR3 curPos = m_pHost.GetPos();
Vector3 vCurPos = new Vector3(curPos.x, curPos.y, curPos.z);
#if ENABLE_CEC_INTELLIGENT_ROUTE
if (IsAutoPF() && global::BrewMonster.Scripts.CECIntelligentRoute.Instance().IsMoveOn())
{
// Draw AutoPF path in red
// 绘制 AutoPF 路径(红色)
List path = global::BrewMonster.Scripts.CECIntelligentRoute.Instance().GetFullPath();
if (path != null && path.Count > 1)
{
// Draw lines connecting all path nodes (red)
// 绘制连接所有路径节点的线(红色)
for (int i = 0; i < path.Count - 1; i++)
{
Vector3 from = path[i];
Vector3 to = path[i + 1];
Debug.DrawLine(from, to, Color.red, 0.1f, false);
}
// Draw line from current position to first path node (red)
// 绘制从当前位置到第一个路径节点的线(红色)
if (path.Count > 0)
{
Debug.DrawLine(vCurPos, path[0], Color.red, 0.1f, false);
}
}
}
else
#endif
{
// Draw straight line to destination (red)
// 绘制到目的地的直线(红色)
Vector3 vDest = new Vector3(m_vMoveDest.x, m_vMoveDest.y, m_vMoveDest.z);
Debug.DrawLine(vCurPos, vDest, Color.red, 0.1f, false);
}
}
if (m_pHost.IsRooting())
return true;
if (m_pHost.IsDead())
{
Finish();
return true;
}
if (m_bUseAutoMoveDialog)
{
if (m_pHost.IsFlying())
{
m_bAutoFly = false;
m_bAutoFlyPending = false;
}
if (m_bAutoFly && !m_bAutoFlyPending && !m_pHost.IsFlying())
{
if (m_pHost.CmdFly(true))
{
m_bAutoFly = false;
m_bAutoFlyPending = true;
}
}
}
else
{
// Make sure 'Win_AutoPlay' dialog doesn't show up
/* CECGameUIMan pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
pGameUI.AutoMoveShowDialog(false);*/
}
// 如果目标是任务 NPC(模板ID),当接近时切换到 WorkTrace(对话/交互)。
// English: If destination is a task NPC (template id), handoff to WorkTrace (talk/interact) when close.
if ((m_vMoveDest - m_pHost.GetPos()).MagnitudeH() <= 5.0f)
{
if (m_iNPCTempleId != 0)
{
// Find live NPC in scene by template id.
// 按模板ID在场景中查找活体 NPC。
CECNPC pNPC = EC_ManMessageMono.Instance != null
? EC_ManMessageMono.Instance.CECNPCMan.FindNPCByTemplateID(m_iNPCTempleId)
: null;
if (pNPC != null && m_pHost.SelectTarget(pNPC.GetNPCID()))
{
CECHPWorkTrace pWork = m_pWorkMan.CreateNPCTraceWork(pNPC, m_iTaskId);
if (pWork != null)
{
// Prevent auto land before switching.
// 防止在切换前自动降落。
m_bAutoLand = false;
Finish();
m_pWorkMan.SetPostTickCommand(new CECHPWorkPostTickRunWorkCommand(pWork, true));
return true;
}
}
}
}
//m_pHost.SetGroundInfoClient();
float fDeltaTime = dwDeltaTime;
if (m_pHost.m_iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND ||
m_pHost.m_iMoveEnv == (int)MoveEnvironment.MOVEENV_WATER && m_pHost.IsJumping() && (m_pHost.m_CDRInfo.vAbsVelocity.y > 0 || m_pHost.m_CDRInfo.fYVel > 0))
{
// Play appropriate actions
if (!m_pHost.IsJumping() && !m_pHost.IsPlayingAction((int)PLAYER_ACTION_TYPE.ACT_TRICK_RUN) &&
m_pHost.m_iMoveMode != (int)MoveMode.MOVE_SLIDE && !m_bMeetSlide)
{
int iAction = m_pHost.GetMoveStandAction(true);
m_pHost.PlayAction(iAction, false);
}
Tick_Walk(fDeltaTime);
}
else // (m_pHost.m_iMoveEnv == CECPlayer::MOVEENV_AIR || m_pHost.m_iMoveEnv == CECPlayer::MOVEENV_WATER)
{
m_pHost.ResetJump();
// Play appropriate actions
if (!m_bGliding)
{
int iAction = m_pHost.GetMoveStandAction(true);
m_pHost.PlayAction(iAction, false);
}
Tick_FlySwim(fDeltaTime);
}
return true;
}
// Reset work
public override void Reset()
{
base.Reset();
m_iDestType = DestTypes.DEST_2D;
m_bHaveDest = false;
m_bMeetSlide = false;
m_bReadyCancel = false;
m_bGliding = false;
m_fGlideTime = 0;
m_fCurPitch = 0;
m_fPushPitch = 0;
m_fPushLean = 0;
m_bUseAutoMoveDialog = false;
m_fAutoHeight = -1.0f;
m_bAutoLand = false;
m_bAutoFly = false;
m_bReachedHeight = true;
m_bAutoFlyPending = false;
m_iNPCTempleId = 0;
m_iTaskId = 0;
m_bSwitchTo2D = false;
m_bResetAutoPF = false;
}
// Work is cancel
public override void Cancel()
{
//if (m_pHost.m_pMoveTargetGFX)
// m_pHost.m_pMoveTargetGFX.Stop();
//A3DVECTOR3 vDir = m_pHost.GetDir();
//vDir.y = 0;
//vDir.Normalize();
//if (!vDir.IsZero())
//{
// m_pHost.StopModelMove(vDir, g_vAxisY, 0);
//}
ClearResetUseAutoPF();
//if (CECIntelligentRoute::Instance().IsUsageMove())
//{
// if (!CECIntelligentRoute::Instance().IsIdle())
// {
// CECIntelligentRoute::Instance().ResetSearch();
// m_bSwitchTo2D = true; // Æô¶¯·ÉÐÐÖжϺó»Ö¸´Ê±¡¢ÐèÒªÇл»µ½ DEST_2D ģʽ
// }
//}
base.Cancel();
//AP_ActionEvent(AP_EVENT_MOVEFINISHED);
}
// This work is do player moving ?
public override bool IsMoving() { return true; }
// Copy work data
public override bool CopyData(CECHPWork pWork)
{
if (!base.CopyData(pWork))
return false;
CECHPWorkMove pSrc = pWork as CECHPWorkMove;
m_iDestType = pSrc.m_iDestType;
m_bHaveDest = pSrc.m_bHaveDest;
m_bMeetSlide = pSrc.m_bMeetSlide;
m_bReadyCancel = pSrc.m_bReadyCancel;
m_bGliding = pSrc.m_bGliding;
m_fGlideTime = pSrc.m_fGlideTime;
m_fGlideSpan = pSrc.m_fGlideSpan;
m_fGlideAng = pSrc.m_fGlideAng;
m_fGlideVel = pSrc.m_fGlideVel;
m_fGlidePitch = pSrc.m_fGlidePitch;
m_fCurPitch = pSrc.m_fCurPitch;
m_fPushPitch = pSrc.m_fPushPitch;
m_fPushLean = pSrc.m_fPushLean;
m_iDestType = pSrc.m_iDestType;
m_vMoveDest = pSrc.m_vMoveDest;
m_vCurDir = pSrc.m_vCurDir;
m_bUseAutoMoveDialog = pSrc.m_bUseAutoMoveDialog;
m_fAutoHeight = pSrc.m_fAutoHeight;
m_bAutoLand = pSrc.m_bAutoLand;
m_bAutoFly = pSrc.m_bAutoFly;
m_bReachedHeight = pSrc.m_bReachedHeight;
m_bAutoFlyPending = pSrc.m_bAutoFlyPending;
m_iNPCTempleId = pSrc.m_iNPCTempleId;
m_iTaskId = pSrc.m_iTaskId;
m_bSwitchTo2D = pSrc.m_bSwitchTo2D;
m_bResetAutoPF = pSrc.m_bResetAutoPF;
return true;
}
// Play move target effect
public void PlayMoveTargetGFX(A3DVECTOR3 vPos, A3DVECTOR3 vNormal)
{
}
// User press cancel button
public void PressCancel() { m_bReadyCancel = true; }
public void SetUseAutoMoveDialog(bool bUseAutoMoveDialog)
{
m_bUseAutoMoveDialog = bUseAutoMoveDialog;
}
public bool GetUseAutoMoveDialog() { return m_bUseAutoMoveDialog; }
/// Matches C++ CECHPWorkMove::GetAutoMove — must not always return true or input stays "auto" forever.
public bool GetAutoMove()
{
if (m_bUseAutoMoveDialog)
return true;
#if ENABLE_CEC_INTELLIGENT_ROUTE
if (IsAutoPF())
{
var r = global::BrewMonster.Scripts.CECIntelligentRoute.Instance();
return r.IsUsageMove() && !r.IsIdle();
}
#endif
return false;
}
void SetAutoLand(bool bAutoLand) { m_bAutoLand = bAutoLand; }
bool GetAutoLand() { return m_bAutoLand; }
void SetAutoHeight(float fHeight) { m_fAutoHeight = fHeight; m_bAutoFly = true; m_bReachedHeight = false; }
float GetAutoHeight() { return m_fAutoHeight; }
bool IsAutoFly() { return m_bAutoFly; }
bool IsAutoPF() { return m_iDestType == Types.DEST_AUTOPF; }
// Finish work
public void Finish()
{
m_bFinished = true;
Cancel();
// Close 'Win_AutoPlay' dialog if it exists
//CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
//pGameUI.AutoMoveShowDialog(false);
if (m_bUseAutoMoveDialog)
{
if (m_bAutoLand)
{
m_bAutoLand = false;
if (EC_Game.GetGameRun().GetHostPlayer().IsFlying())
EC_Game.GetGameRun().GetHostPlayer().CmdFly(false);
}
m_bUseAutoMoveDialog = false;
m_fAutoHeight = -1.0f;
m_bAutoFly = false;
m_bReachedHeight = true;
}
//�������������
m_iNPCTempleId = 0;
m_iTaskId = 0;
}
public void SetTaskNPCInfo(int tid, int taskid)
{
m_iNPCTempleId = tid;
m_iTaskId = taskid;
}
void SwitchToDest2D()
{
int tid, taskid;
tid = m_iNPCTempleId;
taskid = m_iTaskId;
//CECGameUIMan* pGameUI = g_pGame.GetGameRun().GetUIManager().GetInGameUIMan();
//pGameUI.SetAutoMoveShowDialogTarget((int)m_vMoveDest.x, (int)m_vMoveDest.z);
SetDestination(CECHPWorkMove.DestTypes.DEST_2D, m_vMoveDest);
SetTaskNPCInfo(tid, taskid);
SetUseAutoMoveDialog(true);
}
#if ENABLE_CEC_INTELLIGENT_ROUTE
/// True if switched to direct 2D leg — caller must not Finish() this frame.
bool TryContinueAutoPFToWorldDestDirect()
{
A3DVECTOR3 p = m_pHost.GetPos();
float dx = m_vMoveDest.x - p.x;
float dz = m_vMoveDest.z - p.z;
if (dx * dx + dz * dz <= AutoPF_WorldDestContinueDistH * AutoPF_WorldDestContinueDistH)
return false;
int tid = m_iNPCTempleId;
int taskid = m_iTaskId;
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().ResetSearch();
SetDestination(DestTypes.DEST_2D, m_vMoveDest);
SetTaskNPCInfo(tid, taskid);
SetUseAutoMoveDialog(true);
return true;
}
#endif
///
/// Swim/fly DEST_2D often never satisfies the overshoot branch; ground can miss when vTPNormal is zero.
/// Finishes the move work so GetAutoMove() goes false and the player can steer again.
///
bool TryFinishDest2DIfArrived(A3DVECTOR3 vCurPos, float stopSpeed, int iMoveMode, bool flySwimAddRun)
{
if (m_iDestType != DestTypes.DEST_2D)
return false;
float dx = m_vMoveDest.x - vCurPos.x;
float dz = m_vMoveDest.z - vCurPos.z;
if (dx * dx + dz * dz > Dest2D_ArrivalDistH * Dest2D_ArrivalDistH)
return false;
Finish();
int mode = flySwimAddRun ? (iMoveMode | (int)GPMoveMode.GP_MOVE_RUN) : iMoveMode;
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), stopSpeed, mode);
return true;
}
void OrientHostHorizontal(A3DVECTOR3 dirHorizontal)
{
if (dirHorizontal.IsZero())
return;
Vector3 d = EC_Utility.ToVector3(dirHorizontal);
d.y = 0f;
if (d.sqrMagnitude < 1e-8f)
return;
d.Normalize();
m_pHost.SetDirAndUp(d, Vector3.up);
}
#if ENABLE_CEC_INTELLIGENT_ROUTE
/// After Search(), face the first path node so swim/air/walk doesn't use previous heading.
void OrientHostToFirstAutoPFWaypoint()
{
var route = global::BrewMonster.Scripts.CECIntelligentRoute.Instance();
if (!route.IsMoveOn())
return;
A3DVECTOR3 d = route.GetCurDest() - m_pHost.GetPos();
d.y = 0f;
if (d.Normalize() < 1e-4f)
return;
m_vCurDir = d;
OrientHostHorizontal(d);
}
#endif
// On first tick
protected override void OnFirstTick()
{
m_pHost.m_iMoveMode = Move_Mode.MOVE_MOVE;
//PlayMoveTargetGFX();
if (m_pHost.m_iMoveEnv != CECPlayer.Move_environment.MOVEENV_AIR)
m_pHost.ShowWing(false);
if (!m_pHost.IsJumping())
{
int iAction = m_pHost.GetMoveStandAction(true);
m_pHost.PlayAction(iAction, false);
}
}
// Tick routine of walking on ground
protected bool Tick_Walk(float fDeltaTime)
{
A3DVECTOR3 vCurPos = m_pHost.GetPos();
ref CDR_INFO cdr = ref m_pHost.m_CDRInfo;
if (m_pHost.m_iMoveMode == (int)MoveMode.MOVE_SLIDE)
{
m_pHost.PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false);
A3DVECTOR3 vDir;
if (m_iDestType == DestTypes.DEST_DIR)
{
vDir = m_vCurDir;
}
else if (m_iDestType == DestTypes.DEST_PUSH)
{
vDir = GetCurrentModelDir();
}
#if ENABLE_CEC_INTELLIGENT_ROUTE
else if (IsAutoPF())
{
vDir = global::BrewMonster.Scripts.CECIntelligentRoute.Instance().GetCurDest() - vCurPos;
vDir.y = 0.0f;
vDir.Normalize();
}
#endif
else
{
vDir = m_vMoveDest - vCurPos;
vDir.y = 0.0f;
vDir.Normalize();
}
float fMaxSpeedV = 0.0f;
m_bMeetSlide = m_pHost.m_MoveCtrl.MeetSlope(vDir, fMaxSpeedV);
cdr.fYVel = EC_Utility.a_ClampFloor(cdr.fYVel, -fMaxSpeedV);
if (m_pHost.m_GndInfo.bOnGround)
m_vCurDir = vDir;
vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDir, m_pHost.GetGroundSpeed(), fDeltaTime);
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
m_pHost.m_MoveCtrl.SetSlideLock(true);
cdr.fYVel = 0.0f;
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), m_pHost.GetGroundSpeed(), (int)GPMoveMode.GP_MOVE_SLIDE);
}
else
{
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
#if ENABLE_CEC_INTELLIGENT_ROUTE
if (IsAutoPF() && global::BrewMonster.Scripts.CECIntelligentRoute.Instance().IsMoveOn())
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().OnPlayerPosChange(vCurPos);
#endif
#if SHOW_AUTOMOVE_FOOTPRINTS
if (IsAutoPF() || m_iDestType == DestTypes.DEST_2D)
g_AutoPFFollowPoints.Add(vCurPos);
#endif
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
2,
GPDataTypeHelper.g_vOrigin,
(cdr.vAbsVelocity),
(int)GPMoveMode.GP_MOVE_SLIDE);
}
}
else if (!m_bMeetSlide)
{
float fSpeed = m_pHost.GetGroundSpeed();
int iMoveMode = m_pHost.m_bWalkRun ? (int)GPMoveMode.GP_MOVE_RUN : (int)GPMoveMode.GP_MOVE_WALK;
if (m_pHost.IsJumping())
iMoveMode = (int)GPMoveMode.GP_MOVE_JUMP;
else if (!m_pHost.m_GndInfo.bOnGround)
iMoveMode = (int)GPMoveMode.GP_MOVE_FALL;
if (m_bReadyCancel && m_pHost.m_GndInfo.bOnGround)
{
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
return true;
}
if ((GetMoveRelDirMask() & (uint)((CECHostPlayer.MOVE_DIR.MD_LEFT | CECHostPlayer.MOVE_DIR.MD_RIGHT | CECHostPlayer.MOVE_DIR.MD_FORWARD | CECHostPlayer.MOVE_DIR.MD_BACK))) != 0)
m_iDestType = DestTypes.DEST_PUSH;
if (m_iDestType == DestTypes.DEST_2D)
{
if (TryFinishDest2DIfArrived(vCurPos, fSpeed, iMoveMode, false))
return true;
float fDist;
if (m_pHost.m_GndInfo.bOnGround)
{
m_vCurDir = m_vMoveDest - vCurPos;
m_vCurDir.y = 0.0f;
fDist = m_vCurDir.Normalize();
}
else
{
fDist = (m_vMoveDest - vCurPos).MagnitudeH();
}
vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDir, fSpeed, fDeltaTime, m_pHost.m_fVertSpeed);
UpdateFacingFromDelta(vCurPos);
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
cdr.fYVel = 0.0f;
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else if (cdr.vTPNormal != new A3DVECTOR3(0))
{
A3DVECTOR3 vMoveDelta = vCurPos - m_pHost.GetPos();
vMoveDelta.y = 0.0f;
float fMoveDist = vMoveDelta.Normalize();
if (fMoveDist >= fDist)
{
Finish();
m_bUseAutoMoveDialog = false;
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
0,
m_vMoveDest,
(cdr.vAbsVelocity),
iMoveMode);
}
#if SHOW_AUTOMOVE_FOOTPRINTS
g_AutoPFFollowPoints.Add(vCurPos);
#endif
}
else
{
#if SHOW_AUTOMOVE_FOOTPRINTS
g_AutoPFFollowPoints.Add(vCurPos);
#endif
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
1,
m_vMoveDest,
(cdr.vAbsVelocity),
iMoveMode);
}
}
else if (m_iDestType == DestTypes.DEST_DIR)
{
vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDir, fSpeed -0.5f, fDeltaTime, m_pHost.m_fVertSpeed);
UpdateFacingFromDelta(vCurPos);
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
cdr.fYVel = 0.0f;
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else if (m_pHost.m_GndInfo.bOnGround)
{
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
2,
GPDataTypeHelper.g_vOrigin,
(cdr.vAbsVelocity),
iMoveMode);
}
else
{
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
1,
m_vMoveDest,
(cdr.vAbsVelocity),
iMoveMode);
}
}
else if (m_iDestType == DestTypes.DEST_STANDJUMP)
{
if (!m_pHost.IsJumping())
{
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
vCurPos = m_pHost.m_MoveCtrl.GroundMove(GPDataTypeHelper.g_vOrigin, 0.0f, fDeltaTime, m_pHost.m_fVertSpeed);
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
m_pHost.ResetJump();
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
0,
m_vMoveDest,
(cdr.vAbsVelocity),
iMoveMode);
}
}
}
else if (m_iDestType == DestTypes.DEST_PUSH)
{
Vector3 vMoveDir = Vector3.zero;//EC_Utility.ToVector3(GPDataTypeHelper.g_vOrigin);
fSpeed = m_pHost.GetGroundSpeed();
bool bFinish = false;
if (m_pHost.GetPushDir(ref vMoveDir, (uint)(CECHostPlayer.MOVE_DIR.MD_FORWARD | CECHostPlayer.MOVE_DIR.MD_BACK | CECHostPlayer.MOVE_DIR.MD_LEFT | CECHostPlayer.MOVE_DIR.MD_RIGHT), fDeltaTime))
{
if (vMoveDir != Vector3.zero)
{
m_pHost.SetRotationHP(vMoveDir);
}
vCurPos = m_pHost.m_MoveCtrl.GroundMove(EC_Utility.ToA3DVECTOR3(vMoveDir), fSpeed, fDeltaTime, m_pHost.m_fVertSpeed);
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
}
else
{
if (!m_bUseAutoMoveDialog)
bFinish = true;
else
m_iDestType = DestTypes.DEST_2D;
}
if (bFinish || m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
cdr.fYVel = 0.0f;
}
Finish();
m_pHost.m_vVelocity.Clear();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
m_pHost.m_vVelocity = EC_Utility.ToA3DVECTOR3(vMoveDir) * fSpeed;
m_pHost.m_MoveCtrl.SendMoveCmd(
vCurPos,
2,
GPDataTypeHelper.g_vOrigin,
m_pHost.m_vVelocity,
iMoveMode);
}
}
//else if (m_iDestType == DestTypes.DEST_PUSH)
//{
// m_iDestType = DestTypes.DEST_2D;
//}
#if ENABLE_CEC_INTELLIGENT_ROUTE
else if (IsAutoPF())
{
float fDist = 0.0f;
A3DVECTOR3 vCurDest = global::BrewMonster.Scripts.CECIntelligentRoute.Instance().GetCurDest();
if (m_pHost.m_GndInfo.bOnGround)
{
m_vCurDir = vCurDest - vCurPos;
m_vCurDir.y = 0.0f;
fDist = m_vCurDir.Normalize();
}
else
{
fDist = (vCurDest - vCurPos).MagnitudeH();
}
vCurPos = m_pHost.m_MoveCtrl.GroundMove(m_vCurDir, fSpeed, fDeltaTime, m_pHost.m_fVertSpeed);
if (!m_vCurDir.IsZero())
{
//m_pHost.StartModelMove(m_vCurDir, GPDataTypeHelper.g_vAxisY, 100);
//m_pHost.ChangeModelTargetDirAndUp(m_vCurDir, GPDataTypeHelper.g_vAxisY);
UpdateFacingFromDelta(vCurPos);
}
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
cdr.fYVel = 0.0f;
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().OnPlayerPosChange(vCurPos);
if (global::BrewMonster.Scripts.CECIntelligentRoute.Instance().IsPathFinished())
{
if (TryContinueAutoPFToWorldDestDirect())
return true;
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fSpeed, iMoveMode);
}
else
{
// C++: SendMoveCmd(vCurPos, 1, vCurDest, cdr.vAbsVelocity, iMoveMode)
m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 1, vCurDest, cdr.vAbsVelocity, iMoveMode);
}
}
}
#else
else if (IsAutoPF())
{
m_bSwitchTo2D = true;
}
#endif
}
else
{
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), m_pHost.GetGroundSpeed(), (int)GPMoveMode.GP_MOVE_SLIDE);
Finish();
}
return true;
}
// Tick routine of flying or swimming
protected bool Tick_FlySwim(float fDeltaTime)
{
A3DVECTOR3 vCurPos = m_pHost.GetPos();
int iMoveMode = (m_pHost.m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR) ? (int)GPMoveMode.GP_MOVE_AIR : (int)GPMoveMode.GP_MOVE_WATER;
float na, fMaxSpeed;
bool bInAir;
//Debug.LogError("Tick_FlySwim m_pHost.m_dwMoveRelDir = " + m_pHost.m_dwMoveRelDir);
if (m_pHost.m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR)
{
bInAir = true;
na = CECHostMove.EC_NACCE_AIR;
fMaxSpeed = m_pHost.GetFlySpeed();
}
else
{
bInAir = false;
na = CECHostMove.EC_NACCE_WATER;
fMaxSpeed = m_pHost.GetSwimSpeedSev();
}
if (m_bReadyCancel || m_bMeetSlide)
{
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fMaxSpeed, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
Finish();
return true;
}
// for auto move
if (m_bUseAutoMoveDialog && m_fAutoHeight > 0.0f && m_iDestType != DestTypes.DEST_PUSH)
{
if (m_pHost.m_dwMoveRelDir == 0)
{
if ((int)(vCurPos.y / 10.0f) == (int)m_fAutoHeight)
{
if (!m_bReachedHeight)
{
m_pHost.m_vVelocity.y = 0.0f;
m_pHost.m_dwMoveRelDir &= ~((uint)(CECHostPlayer.MOVE_DIR.MD_ABSUP | CECHostPlayer.MOVE_DIR.MD_ABSDOWN));
m_bReachedHeight = true;
}
}
else
{
if (!m_bReachedHeight)
{
if (vCurPos.y < m_fAutoHeight * 10.0f)
{
m_pHost.m_dwMoveRelDir &= ~((uint)(CECHostPlayer.MOVE_DIR.MD_ABSDOWN));
m_pHost.m_dwMoveRelDir |= ((uint)CECHostPlayer.MOVE_DIR.MD_ABSUP);
}
else if (vCurPos.y > m_fAutoHeight * 10.0f)
{
m_pHost.m_dwMoveRelDir &= ~((uint)(CECHostPlayer.MOVE_DIR.MD_ABSUP));
m_pHost.m_dwMoveRelDir |= (uint)CECHostPlayer.MOVE_DIR.MD_ABSDOWN;
}
}
else // Auto adjust height, so we should refresh move height
{
m_fAutoHeight = vCurPos.y / 10.0f;
}
}
}
else // Player manually set auto move height
{
m_bReachedHeight = true;
m_fAutoHeight = vCurPos.y / 10.0f;
}
}
if ((m_pHost.m_dwMoveRelDir & (uint)(CECHostPlayer.MOVE_DIR.MD_LEFT | CECHostPlayer.MOVE_DIR.MD_RIGHT | CECHostPlayer.MOVE_DIR.MD_FORWARD | CECHostPlayer.MOVE_DIR.MD_BACK)) != 0)
m_iDestType = DestTypes.DEST_PUSH;
ON_AIR_CDR_INFO cdr = m_pHost.m_AirCDRInfo;
if (m_iDestType == DestTypes.DEST_DIR)
{
Vector3 vPushDir = Vector3.zero;
m_pHost.GetPushDir(ref vPushDir, (uint)CECHostPlayer.MOVE_DIR.MD_ALL, 0);
vPushDir.x = vPushDir.z = 0.0f;
float fSpeed1H = m_pHost.m_vVelocity.MagnitudeH();
float fSpeed1V = m_pHost.m_vVelocity.y;
A3DVECTOR3 vMoveDirH = m_vMoveDest;
float pa = CECHostMove.EC_PUSH_ACCE;
float fSpeed2H = fSpeed1H + (pa + na) * fDeltaTime;
if (Math.Abs(pa - 0) < float.Epsilon && fSpeed2H < 0.0f)
fSpeed2H = 0.0f; // Only resistance couldn't generate negative speed
else if (fSpeed2H > fMaxSpeed)
fSpeed2H = fMaxSpeed;
Glide(5.0f, vMoveDirH, fDeltaTime, bInAir);
vMoveDirH = m_pHost.GetModelMoveDir();
vMoveDirH.y = 0;
vMoveDirH.Normalize();
// Vertical speed
float fSpeed2V = CalcFlySwimVertSpeed(fSpeed1V, vPushDir.y, CECHostMove.EC_PUSH_ACCE, fDeltaTime);
A3DVECTOR3 vVel2 = vMoveDirH * fSpeed2H + GPDataTypeHelper.g_vAxisY * fSpeed2V;
// Air/water move
vCurPos = m_pHost.m_MoveCtrl.AirWaterMove(vVel2, fDeltaTime, bInAir);
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_vVelocity = vVel2;
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
Finish();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fMaxSpeed, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
else
m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 0, m_vMoveDest, vVel2, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
else if (m_iDestType == DestTypes.DEST_2D)
{
if (TryFinishDest2DIfArrived(vCurPos, fMaxSpeed, iMoveMode, true))
return true;
Vector3 vPushDir = Vector3.zero;
m_pHost.GetPushDir(ref vPushDir, (uint)CECHostPlayer.MOVE_DIR.MD_ALL, 0f);
vPushDir.x = vPushDir.z = 0.0f;
float fSpeed1H = m_pHost.m_vVelocity.MagnitudeH();
float fSpeed1V = m_pHost.m_vVelocity.y;
A3DVECTOR3 vMoveDirH = m_vMoveDest - vCurPos;
vMoveDirH.y = 0.0f;
float fDistH = vMoveDirH.Normalize();
float pa = 0.0f;
// Calculate the distance to reduce velocity to 0
float s = -0.5f * fSpeed1H * fSpeed1H / na;
if (fDistH > s - 0.01f)
pa = CECHostMove.EC_PUSH_ACCE;
float fSpeed2H = fSpeed1H + (pa + na) * fDeltaTime;
if (Math.Abs(pa - 0f) < float.Epsilon && fSpeed2H < 0.0f)
fSpeed2H = 0.0f; // Only resistance couldn't generate negative speed
else if (fSpeed2H > fMaxSpeed)
fSpeed2H = fMaxSpeed;
Glide(fDistH / fMaxSpeed, vMoveDirH, fDeltaTime, bInAir);
vMoveDirH = m_pHost.GetModelMoveDir();
vMoveDirH.y = 0;
vMoveDirH.Normalize();
// Vertical speed
float fSpeed2V = CalcFlySwimVertSpeed(fSpeed1V, vPushDir.y, CECHostMove.EC_PUSH_ACCE, fDeltaTime);
A3DVECTOR3 vVel2 = vMoveDirH * fSpeed2H + GPDataTypeHelper.g_vAxisY * fSpeed2V;
// Air/water move
vCurPos = m_pHost.m_MoveCtrl.AirWaterMove(vVel2, fDeltaTime, bInAir);
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
vVel2.Clear();
Finish();
}
else
{
// Reached destination ?
A3DVECTOR3 vMoveDelta = vCurPos - m_pHost.GetPos();
vMoveDelta.y = 0.0f;
float fMoveDistH = vMoveDelta.Normalize();
if (fMoveDistH >= fDistH)
{
vVel2.x = vVel2.z = 0.0f;
if (Math.Abs(vVel2.y - 0f) < float.Epsilon)
{
Finish();
}
else
{
if (m_bUseAutoMoveDialog)
{
Finish();
vVel2.y = 0.0f;
}
m_iDestType = DestTypes.DEST_PUSH;
}
}
}
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_vVelocity = vVel2;
if (m_bFinished)
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), vVel2.Magnitude(), iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
else
m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 0, m_vMoveDest, vVel2, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
else if (m_iDestType == DestTypes.DEST_3D)
{
float fSpeed1 = m_pHost.m_vVelocity.Magnitude();
A3DVECTOR3 vMoveDir = m_vMoveDest - vCurPos;
float fDist = vMoveDir.Normalize();
float pa = 0.0f;
// Calculate the distance to reduce velocity to 0
float s = -0.5f * fSpeed1 * fSpeed1 / na;
if (fDist > s - 0.01f)
pa = CECHostMove.EC_PUSH_ACCE;
float fSpeed2 = fSpeed1 + (pa + na) * fDeltaTime;
if (Math.Abs(pa - 0f) < float.Epsilon && fSpeed2 < 0.0f)
fSpeed2 = 0.0f; // Only resistance couldn't generate negative speed
AAssist.a_Clamp(ref fSpeed2, -fMaxSpeed, fMaxSpeed);
Vector3 vMoveDirH = new Vector3(vMoveDir.x, 0.0f, vMoveDir.z);
if (vMoveDirH != Vector3.zero)
{
//m_pHost.StartModelMove(vMoveDirH, g_vAxisY, 100);
//m_pHost.ChangeModelTargetDirAndUp(vMoveDirH, g_vAxisY);
m_pHost.SetRotationHP(vMoveDirH);
}
// Air/water move
// A3DVECTOR3 vVel1 = vMoveDir * fSpeed1;
A3DVECTOR3 vVel2 = vMoveDir * fSpeed2;
vCurPos = m_pHost.m_MoveCtrl.AirWaterMove(vMoveDir, fSpeed2, fDeltaTime, bInAir, false);
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
vVel2.Clear();
Finish();
}
else
{
// Reached destination ?
A3DVECTOR3 vMoveDelta = vCurPos - m_pHost.GetPos();
float fMoveDist = vMoveDelta.Normalize();
if (fMoveDist >= fDist)
{
vVel2.Clear();
Finish();
m_bUseAutoMoveDialog = false;
}
}
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
m_pHost.m_vVelocity = vVel2;
if (m_bFinished)
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fMaxSpeed, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
else
m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 1, m_vMoveDest, vVel2, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
else if (m_iDestType == DestTypes.DEST_PUSH)
{
Vector3 vPushDir = Vector3.zero;
bool bPush = m_pHost.GetPushDir(ref vPushDir, (uint)(CECHostPlayer.MOVE_DIR.MD_FORWARD | CECHostPlayer.MOVE_DIR.MD_BACK | CECHostPlayer.MOVE_DIR.MD_LEFT | CECHostPlayer.MOVE_DIR.MD_RIGHT), fDeltaTime);
if (!bPush)
{
//vPushDir = m_pHost.GetCameraCoord().GetDir();
vPushDir.y = 0;
vPushDir.Normalize();
}
int nPitchDir = 0;
if ((m_pHost.m_dwMoveRelDir & (int)(CECHostPlayer.MOVE_DIR.MD_LEFT | CECHostPlayer.MOVE_DIR.MD_RIGHT)) == 0)
{
A3DVECTOR3 vOldDir = m_pHost.GetModelMoveDir();
vOldDir.y = 0;
vOldDir.Normalize();
A3DVECTOR3 vNewDir = EC_Utility.ToA3DVECTOR3(vPushDir);
vNewDir.y = 0;
vNewDir.Normalize();
float fAngle = A3DVECTOR3.DotProduct(vOldDir, vNewDir);
if (fAngle < 1.0f - 1e-4)
{
A3DVECTOR3 vUp_fAngle = A3DVECTOR3.CrossProduct(vOldDir, vNewDir);
if (vUp_fAngle.y > 0) nPitchDir = 1;
else nPitchDir = -1;
if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_BACK) != 0)
nPitchDir = -nPitchDir;
}
}
if (m_pHost.m_dwMoveRelDir != 0)
{
if ((m_pHost.m_dwMoveRelDir & ~(uint)(CECHostPlayer.MOVE_DIR.MD_ABSDOWN | CECHostPlayer.MOVE_DIR.MD_ABSUP)) != 0)
{
float fPitchDelta = (/*m_pHost.UsingWing()*/m_pHost.GetWingType() == enumWingType.WINGTYPE_WING ? push_pitch_vel_wing : push_pitch_vel_fly_sword) * fDeltaTime;
if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_LEFT) != 0 || nPitchDir == -1)
{
if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_BACK) != 0)
m_fPushPitch -= fPitchDelta;
else
m_fPushPitch += fPitchDelta;
}
else if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_RIGHT) != 0 || nPitchDir == 1)
{
if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_BACK) != 0)
m_fPushPitch += fPitchDelta;
else
m_fPushPitch -= fPitchDelta;
}
else if (m_fPushPitch > fPitchDelta)
m_fPushPitch -= fPitchDelta;
else if (m_fPushPitch < -fPitchDelta)
m_fPushPitch += fPitchDelta;
else
m_fPushPitch = 0;
// TO DO: fix after
//A3DVECTOR3 vRight = m_pHost.GetCameraCoord().GetRight();
//float fLean = -Math.Asin(m_pHost.GetCameraCoord().GetDir().y);
//AAssist.a_Clamp(ref fLean, -lean_max_ang, lean_max_ang);
//if (Math.Abs(fLean) > DEG2RAD(3.0f))
//{
// vPushDir = a3d_RotatePosAroundAxis(vPushDir, vRight, fLean);
// vUp = a3d_RotatePosAroundAxis(g_vAxisY, vRight, fLean);
//}
//else
// vUp = EC_Utility.ToVector3(GPDataTypeHelper.g_vAxisY);
//float pitch_ang = /*m_pHost.UsingWing()*/ m_pHost.GetWingType() == enumWingType.WINGTYPE_WING ? pitch_ang_wing : pitch_ang_fly_sword;
//AAssist.a_Clamp(ref m_fPushPitch, -pitch_ang, pitch_ang);
//if (Math.Abs(m_fPushPitch) > DEG2RAD(4.0f))
// vUp = a3d_RotatePosAroundAxis(vUp, vPushDir, m_fPushPitch);
//m_pHost.StartModelMove(vPushDir, vUp, 0);
if (vPushDir != Vector3.zero)
{
m_pHost.SetRotationHPWithTime(vPushDir, 0.1f);
}
}
// if (bPush)
if (bPush || (m_pHost.m_dwMoveRelDir & (uint)(CECHostPlayer.MOVE_DIR.MD_ABSDOWN | CECHostPlayer.MOVE_DIR.MD_ABSUP)) != 0)
{
// float pa = bPush ? EC_PUSH_ACCE : 0.0f;
float pa = CECHostMove.EC_PUSH_ACCE;
float na1 = m_pHost.m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR ? CECHostMove.EC_NACCE_AIR : CECHostMove.EC_NACCE_WATER;
float fAccel = pa + na1;
float fSpeed1 = m_pHost.m_vVelocity.Magnitude();
float fSpeed2 = fSpeed1 + fAccel * fDeltaTime;
AAssist.a_Clamp(ref fSpeed2, 0.0f, fMaxSpeed);
// Air/water move
Vector3 vVelDir = Vector3.zero;
if (bPush)
vVelDir = vPushDir;
if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_ABSDOWN) != 0)
{
vVelDir += -EC_Utility.ToVector3(GPDataTypeHelper.g_vAxisY);
vVelDir.Normalize();
}
else if ((m_pHost.m_dwMoveRelDir & (uint)CECHostPlayer.MOVE_DIR.MD_ABSUP) != 0)
{
vVelDir += EC_Utility.ToVector3(GPDataTypeHelper.g_vAxisY);
vVelDir.Normalize();
}
// A3DVECTOR3 vVel = vPushDir * fSpeed2;
Vector3 vVel = vVelDir * fSpeed2;
vCurPos = m_pHost.m_MoveCtrl.AirWaterMove(EC_Utility.ToA3DVECTOR3(vVel), fDeltaTime, bInAir);
if (m_pHost.m_MoveCtrl.MoveBlocked() >= 3)
{
Finish();
m_pHost.m_vVelocity.Clear();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fMaxSpeed, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
else
{
m_pHost.SetPos(EC_Utility.ToVector3(vCurPos));
if (m_bUseAutoMoveDialog)
{
m_fAutoHeight = vCurPos.y / 10.0f;
}
m_pHost.m_vVelocity = EC_Utility.ToA3DVECTOR3(vVel);
m_pHost.m_MoveCtrl.SendMoveCmd(vCurPos, 2, GPDataTypeHelper.g_vOrigin, EC_Utility.ToA3DVECTOR3(vVel), iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
}
}
else
{
if (!m_bUseAutoMoveDialog)
Finish();
else
m_iDestType = DestTypes.DEST_2D;
m_fPushPitch = 0;
m_pHost.m_vVelocity.Clear();
m_pHost.m_MoveCtrl.SendStopMoveCmd(EC_Utility.ToVector3(vCurPos), fMaxSpeed, iMoveMode | (int)GPMoveMode.GP_MOVE_RUN);
}
}
else if (m_iDestType == DestTypes.DEST_STANDJUMP)
{
// If host player fly off when jumping up, code will go here. In the
// case, just stop move work is well.
Finish();
}
else if (IsAutoPF())
{
// EC_HPWorkMove.cpp Tick_FlySwim: AutoPF in air/water does not walk waypoints — drop path and use DEST_2D.
#if ENABLE_CEC_INTELLIGENT_ROUTE
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().ResetSearch();
#endif
m_bSwitchTo2D = true;
}
return true;
}
// Start gliding
protected void Glide(float fMoveTime, A3DVECTOR3 vMoveDirH, float fDeltaTime, bool bFly)
{
}
// Calculate vertical speed when fly or swim
protected float CalcFlySwimVertSpeed(float fSpeed1, float fPushDir, float fPushAccel, float fDeltaTime)
{
float pa = Math.Abs(fPushDir - 0.0f) > float.Epsilon ? fPushAccel : 0.0f;
float na = 0.0f, fMaxSpeed;
if (m_pHost.m_iMoveEnv == CECPlayer.Move_environment.MOVEENV_AIR)
{
na = CECHostMove.EC_NACCE_AIR;
fMaxSpeed = m_pHost.GetFlySpeed();
}
else
{
na = CECHostMove.EC_NACCE_WATER;
fMaxSpeed = m_pHost.GetSwimSpeedSev();
}
// When player free fall into water, fSpeed1 may be >= fMaxSpeed
if (Math.Abs(fSpeed1) > fMaxSpeed)
{
na *= 2.0f;
if (fPushDir * fSpeed1 > 0.0f)
pa = 0.0f;
}
// Vertical accelerate
float fAccel = 0.0f;
if (fPushDir > 0.0f)
fAccel = pa + na;
else if (fPushDir < 0.0f)
fAccel = -(pa + na);
else if (fSpeed1 > 0.0f)
fAccel = na;
else if (fSpeed1 < 0.0f)
fAccel = -na;
// Vertical speed
float fSpeed2 = fSpeed1 + fAccel * fDeltaTime;
if (Math.Abs(pa - 0.0f) < float.Epsilon && fSpeed2 * fSpeed1 < 0.0f)
fSpeed2 = 0.0f;
// If accelerate and speed on same direction, limit speed
if (fAccel * fSpeed2 > 0.0f)
AAssist.a_Clamp(ref fSpeed2, -fMaxSpeed, fMaxSpeed);
return fSpeed2;
}
protected void ClearResetUseAutoPF()
{
m_bResetAutoPF = false;
}
protected void UpdateResetUseAutoPF()
{
if (!m_bResetAutoPF)
{
return;
}
#if ENABLE_CEC_INTELLIGENT_ROUTE
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().SetUsage(global::BrewMonster.Scripts.CECIntelligentRoute.Usage.enumUsageWorkMove);
global::BrewMonster.Scripts.CECIntelligentRoute.Instance().ResetSearch();
if (IsAutoPF())
{
bool bSwitchTo2D = true;
while (true)
{
// EC_HPWorkMove.cpp UpdateResetUseAutoPF: skip Search while flying (bSwitchTo2D stays true).
if (m_pHost.IsFlying())
break;
// Brush test is not fully ported yet; pass null for now (static movemap only).
// BrushTest 暂未完整移植;当前先传 null(仅静态 movemap)。
var ret = global::BrewMonster.Scripts.CECIntelligentRoute.Instance().Search(
m_pHost.GetPos(),
m_vMoveDest,
null);
if (ret == CECIntelligentRoute.SearchResult.enumSearchNoPath)
{
// C++ UpdateResetUseAutoPF: Search != success → break; bSwitchTo2D stays true (fallback straight line).
// Do not Finish() — same as EC_HPWorkMove.cpp (no path still switches to DEST_2D).
int mapX = Mathf.RoundToInt(m_vMoveDest.x / 10.0f) + 400;
int mapY = Mathf.RoundToInt(m_vMoveDest.y / 10.0f);
int mapZ = Mathf.RoundToInt(m_vMoveDest.z / 10.0f) + 550;
Debug.LogWarning(
$"[CECIntelligentRoute] No path; switching to DEST_2D. Map coords: ({mapX}, {mapZ}, ↑{mapY}).");
break;
}
else if (ret != CECIntelligentRoute.SearchResult.enumSearchSuccess)
{
break;
}
bSwitchTo2D = false;
OrientHostToFirstAutoPFWaypoint();
break;
}
if (bSwitchTo2D)
{
m_bSwitchTo2D = true;
}
}
#endif
ClearResetUseAutoPF();
}
protected virtual uint GetMoveRelDirMask()
{
// TODO: hook up CECHostPlayer move-direction flags when available.
return m_pHost.m_dwMoveRelDir;
}
private void UpdateFacingFromDelta(A3DVECTOR3 nextPos)
{
A3DVECTOR3 prevPos = m_pHost.GetPos();
Vector3 delta = EC_Utility.ToVector3(nextPos - prevPos);
delta.y = 0.0f;
if (delta.sqrMagnitude > 1e-6f)
{
delta.Normalize();
m_pHost.SetDirAndUp(delta, Vector3.up);
}
}
private A3DVECTOR3 GetCurrentModelDir()
{
Vector3 forward = m_pHost != null ? m_pHost.transform.forward : Vector3.forward;
return new A3DVECTOR3(forward.x, forward.y, forward.z);
}
}
}