Files
test/Assets/PerfectWorld/Scripts/Players/CECPlayerWrapper.cs
2026-01-23 18:01:15 +07:00

1336 lines
37 KiB
C#

using BrewMonster;
using BrewMonster.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using CSNetwork;
using CSNetwork.GPDataType;
using PerfectWorld.Scripts;
using PerfectWorld.Scripts.Managers;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class AP
{
// AP events (from EC_PlayerWrapper.h anonymous enum)
public const int AP_EVENT_CANNOTMOVE = 0;
public const int AP_EVENT_MOVEFINISHED = 1;
public const int AP_EVENT_TRACEOK = 2;
public const int AP_EVENT_STARTSKILL = 3;
public const int AP_EVENT_STOPSKILL = 4;
public const int AP_EVENT_STARTUSEITEM = 5;
public const int AP_EVENT_STOPUSEITEM = 6;
public const int AP_EVENT_PICKUPOK = 7;
public const int AP_EVENT_CANNOTPICKUP = 8;
public const int AP_EVENT_STARTMELEE = 9;
public const int AP_EVENT_STOPMELEE = 10;
public const int AP_EVENT_COMBOCONTINUE = 11;
public const int AP_EVENT_COMBOFINISH = 12;
public const int AP_EVENT_MELEEOUTOFRANGE = 13;
// NOTE: C# doesn't have free functions; keep names, put into static class.
public static void AP_ActionEvent(int iEvent, int iParam = 0)
{
if (!CECAutoPolicy.GetInstance().IsAutoPolicyEnabled())
return;
var pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
pWrapper?.OnActionEvent(iEvent, iParam);
}
public static string AP_GetActionName(int iAction)
{
return iAction switch
{
CECPlayerWrapper.ACTION_IDLE => "ACTION_IDLE",
CECPlayerWrapper.ACTION_MOVE => "ACTION_MOVE",
CECPlayerWrapper.ACTION_CASTSKILL => "ACTION_CASTSKILL",
CECPlayerWrapper.ACTION_USEITEM => "ACTION_USEITEM",
CECPlayerWrapper.ACTION_PICKUP => "ACTION_PICKUP",
CECPlayerWrapper.ACTION_COMBOSKILL => "ACTION_COMBOSKILL",
CECPlayerWrapper.ACTION_MELEE => "ACTION_MELEE",
_ => "Unknown",
};
}
public static string AP_GetEventName(int iEvent)
{
return iEvent switch
{
AP_EVENT_CANNOTMOVE => "AP_EVENT_CANNOTMOVE",
AP_EVENT_MOVEFINISHED => "AP_EVENT_MOVEFINISHED",
AP_EVENT_TRACEOK => "AP_EVENT_TRACEOK",
AP_EVENT_STARTSKILL => "AP_EVENT_STARTSKILL",
AP_EVENT_STOPSKILL => "AP_EVENT_STOPSKILL",
AP_EVENT_STARTUSEITEM => "AP_EVENT_STARTUSEITEM",
AP_EVENT_STOPUSEITEM => "AP_EVENT_STOPUSEITEM",
AP_EVENT_PICKUPOK => "AP_EVENT_PICKUPOK",
AP_EVENT_CANNOTPICKUP => "AP_EVENT_CANNOTPICKUP",
AP_EVENT_STARTMELEE => "AP_EVENT_STARTMELEE",
AP_EVENT_STOPMELEE => "AP_EVENT_STOPMELEE",
AP_EVENT_COMBOCONTINUE => "AP_EVENT_COMBOCONTINUE",
AP_EVENT_COMBOFINISH => "AP_EVENT_COMBOFINISH",
AP_EVENT_MELEEOUTOFRANGE => "AP_EVENT_MELEEOUTOFRANGE",
_ => "Unknown",
};
}
}
public class CECPlayerWrapper
{
// Actions (from EC_PlayerWrapper.h enum)
public const int ACTION_IDLE = 0;
public const int ACTION_MOVE = 1;
public const int ACTION_CASTSKILL = 2;
public const int ACTION_USEITEM = 3;
public const int ACTION_PICKUP = 4;
public const int ACTION_COMBOSKILL = 5;
public const int ACTION_MELEE = 6;
private const int MAX_ATTACK_ERROR = 3;
private const int INVALIDOBJ_TIMEOUT = 30000;
private const float MATTER_SEARCH_RANGE = 60.0f;
public struct DelayTask
{
public int iType;
public int iParam1;
public int iParam2;
public DelayTask(int _)
{
iType = ACTION_IDLE;
iParam1 = 0;
iParam2 = 0;
}
}
// ===== Base Action =====
public abstract class Action
{
protected readonly int type;
protected readonly CECPlayerWrapper host;
protected Action(CECPlayerWrapper pHost, int t)
{
host = pHost;
type = t;
}
public virtual bool StartAction() => true;
public virtual void EndAction() { }
// return true => action finished
public virtual bool Tick(uint dwDeltaTime) => false;
public virtual void OnEvent(int iEvent, int iParam) { }
public virtual bool CanBreak() => true;
public bool HaveNextAction() => host.m_Actions.Count > 0;
public int GetType() => type;
}
public delegate void ActionEventDelegate(int iEvent, int iParam);
// ===== Dependencies (keep original names/types; implement in your project) =====
protected CECHostPlayer m_pHost;
// ===== Runtime state =====
protected readonly LinkedList<Action> m_Actions = new();
protected Action m_pCurAction;
protected A3DVECTOR3 m_vOrigPos;
protected bool m_bForceAttack;
protected int m_iAttackErrCnt;
protected int m_iPickupErrCnt;
// invalid objects timeout map
protected readonly Dictionary<int, int> m_InvalidObj = new();
// monsters attacking me
protected readonly HashSet<int> m_MonsterAttackMe = new();
protected DelayTask m_DelayTask = new DelayTask(0);
// Keep accessors like C++ (AutoPolicy.Render reads these directly in C++)
public CECHostPlayer GetHostPlayer() => m_pHost;
public CECPlayerWrapper(CECHostPlayer pHost)
{
m_pHost = pHost;
m_pCurAction = null;
m_iAttackErrCnt = 0;
m_iPickupErrCnt = 0;
m_bForceAttack = false;
m_vOrigPos = m_pHost.GetPos();
}
public virtual void Tick(uint dwDeltaTime)
{
if (m_pCurAction != null)
{
if (m_pCurAction.Tick(dwDeltaTime))
{
EndCurAction();
StartAction();
}
}
if (m_DelayTask.iType != ACTION_IDLE)
ProcessDelayTask();
// decrement invalid timeouts
if (m_InvalidObj.Count > 0)
{
var toRemove = new List<int>();
foreach (var kv in m_InvalidObj)
{
int t = kv.Value - (int)dwDeltaTime;
if (t <= 0) toRemove.Add(kv.Key);
else m_InvalidObj[kv.Key] = t;
}
for (int i = 0; i < toRemove.Count; i++)
m_InvalidObj.Remove(toRemove[i]);
}
}
public void StopPolicy()
{
CECAutoPolicy.GetInstance().StopPolicy();
}
public void OnStopPolicy()
{
ClearAction();
m_bForceAttack = false;
m_iAttackErrCnt = 0;
m_iPickupErrCnt = 0;
m_InvalidObj.Clear();
m_MonsterAttackMe.Clear();
}
public bool HaveAction()
{
return m_pCurAction != null || m_Actions.Count > 0;
}
public bool AddIdleAction(int iTime)
{
AddAction(new IdleAction(this, iTime));
return StartAction();
}
protected bool AddAction(Action pAction)
{
if (pAction == null) return false;
if (m_pCurAction != null && m_pCurAction.GetType() == pAction.GetType())
return false;
for (var node = m_Actions.First; node != null; node = node.Next)
{
if (node.Value.GetType() == pAction.GetType())
return false;
}
m_Actions.AddLast(pAction);
return true;
}
protected bool StartAction()
{
if (m_pCurAction != null)
return true;
bool ret = false;
while (m_Actions.Count > 0)
{
m_pCurAction = m_Actions.First.Value;
m_Actions.RemoveFirst();
ret = m_pCurAction.StartAction();
if (ret) break;
EndCurAction(); // if StartAction failed, kill and try next
}
return ret;
}
protected bool EndCurAction()
{
if (m_pCurAction == null)
return false;
m_pCurAction.EndAction();
m_pCurAction = null;
return true;
}
public void ClearAction()
{
if (m_pCurAction != null)
EndCurAction();
m_Actions.Clear();
}
private bool AddOneAction(int iActionType, int iParam = 0)
{
switch (iActionType)
{
case ACTION_MOVE: AddAction(new MoveAction(this)); break;
case ACTION_CASTSKILL: AddAction(new CastSkillAction(this)); break;
case ACTION_USEITEM: AddAction(new UseItemAction(this)); break;
case ACTION_PICKUP: AddAction(new PickupAction(this, iParam)); break;
case ACTION_COMBOSKILL: AddAction(new ComboSkillAction(this)); break;
case ACTION_MELEE: AddAction(new MeleeAction(this)); break;
default: throw new ArgumentOutOfRangeException(nameof(iActionType));
}
return StartAction();
}
// ===== Inventory helpers =====
public int GetItemIndex(int iPack, int tid)
{
if (iPack >= (int)InventoryType.IVTRTYPE_PACK && iPack <= (int)InventoryType.IVTRTYPE_TASKPACK)
{
var pPack = m_pHost.GetPack(iPack);
return pPack.FindItem(tid);
}
return -1;
}
public int GetItemCount(int iPack, int tid)
{
if (iPack >= (int)InventoryType.IVTRTYPE_PACK && iPack <= (int)InventoryType.IVTRTYPE_TASKPACK)
{
var pPack = m_pHost.GetPack(iPack);
return pPack.GetItemTotalNum(tid);
}
return 0;
}
public A3DVECTOR3 GetPos()
{
return m_pHost.GetPos();
}
public void MoveTo(float x, float z)
{
var pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan();
//pGameUI?.AutoMoveStart((int)x, (int)z, false);
AddOneAction(ACTION_MOVE);
}
public void CancelAction()
{
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_PRESSCANCEL, MANAGER_INDEX.MAN_PLAYER, 0);
}
public A3DVECTOR3 GetOrigPos()
{
return m_vOrigPos;
}
public void SetOrigPos(A3DVECTOR3 vPos)
{
m_vOrigPos = vPos;
}
// ===== Target search =====
private sealed class ObjectSorter : IComparer<CECObject>
{
private readonly CECPlayerWrapper _host;
public ObjectSorter(CECPlayerWrapper host)
{
_host = host;
}
public int Compare(CECObject p1, CECObject p2)
{
float f1 = GetDistToHost(p1);
float f2 = GetDistToHost(p2);
float df = Math.Abs(f1 - f2);
if (df > 0.00001f)
return f1 < f2 ? -1 : 1;
if (p1.GetClassID() == p2.GetClassID())
{
// pointer compare equivalent
int h1 = RuntimeHelpers.GetHashCode(p1);
int h2 = RuntimeHelpers.GetHashCode(p2);
return h1.CompareTo(h2);
}
// C++: return p1->IsMatter(); => matter first if same dist but different class
return p1.IsMatter() ? -1 : 1;
}
private float GetDistToHost(CECObject p)
{
if (p == null) return 0.0f;
if (p.IsMonsterNPC())
{
var pNPC = p as CECNPC;
return pNPC != null ? pNPC.GetDistToHost() : 0.0f;
}
/* else if (p.IsMatter())
{
var pMatter = p as CECMatter;
return pMatter != null ? pMatter.GetDistToHost() : 0.0f;
}*/
else
{
return 0.0f;
}
}
}
public bool SearchTarget(ref int id, ref int tid)
{
int iTarget = 0;
int iTargetTempl = 0;
var pNPCMan = EC_ManMessageMono.Instance.CECNPCMan;
var pMatterMan = EC_ManMessageMono.Instance.EC_ManMatter;
m_iAttackErrCnt = 0;
// Prefer monsters attacking me
if (m_MonsterAttackMe.Count > 0)
{
float fMinDist = 999999.0f;
int chosen = 0;
foreach (var mid in m_MonsterAttackMe)
{
var pNPC = pNPCMan.GetNPC(mid);
if (pNPC == null)
continue;
#if UNITY_5_3_OR_NEWER
float fDist = (m_pHost.GetPos() - pNPC.GetPos()).Magnitude();
#else
float fDist = A3DVECTOR3.Magnitude(m_pHost.GetPos() - pNPC.GetPos());
#endif
if (fDist < fMinDist)
{
fMinDist = fDist;
iTarget = mid;
iTargetTempl = pNPC.GetTemplateID();
chosen = mid;
}
}
if (iTarget != 0)
{
m_MonsterAttackMe.Remove(chosen);
id = iTarget;
tid = iTargetTempl;
return true;
}
}
// Collect candidates (monsters + matters)
var targets = new List<CECObject>();
var monsters = new List<CECNPC>();
pNPCMan.TabSelectCandidates(0, monsters);
for (int i = 0; i < monsters.Count; i++)
targets.Add(monsters[i]);
var matters = new List<CECMatter>();
//pMatterMan.FindMattersInRange(MATTER_SEARCH_RANGE, true, matters);
for (int i = 0; i < matters.Count; i++)
targets.Add(matters[i]);
if (targets.Count > 0)
{
targets.Sort(new ObjectSorter(this));
for (int i = 0; i < targets.Count; i++)
{
var obj = targets[i];
if (obj.IsMonsterNPC())
{
var pNPC = obj as CECNPC;
if (pNPC != null && NpcCanAttack(pNPC.GetNPCID()))
{
iTarget = pNPC.GetNPCID();
iTargetTempl = pNPC.GetTemplateID();
break;
}
}
else if (obj.IsMatter())
{
var pMatter = obj as CECMatter;
if (pMatter != null && MatterCanPickup(pMatter.GetMatterID(), pMatter.GetTemplateID()))
{
iTarget = pMatter.GetMatterID();
iTargetTempl = pMatter.GetTemplateID();
break;
}
}
}
if (iTarget != 0 && iTargetTempl != 0)
{
id = iTarget;
tid = iTargetTempl;
return true;
}
}
id = 0;
tid = 0;
return false;
}
public int GetSelectedTarget()
{
return m_pHost.GetSelectedTarget();
}
public void SelectTarget(int iTarget)
{
m_iAttackErrCnt = 0;
m_pHost.SelectTarget(iTarget);
}
public void Unselect()
{
m_iAttackErrCnt = 0;
m_pHost.SelectTarget(0);
}
public bool NpcCanAttack(int nid)
{
if (m_pHost.AttackableJudge(nid, false) != 1)
return false;
if (m_InvalidObj.ContainsKey(nid))
return false;
return true;
}
public bool NormalAttack()
{
bool bRet = m_pHost.CmdNormalAttack(false, false, 0, m_bForceAttack ? 1 : -1);
if (bRet)
{
AddAttackError();
AddOneAction(ACTION_MELEE);
}
return bRet;
}
// NOTE: header calls this bQueue; cpp uses bDelay. Here keep signature like header.
public bool CastComboSkill(int group_id, bool bIgnoreAtkLoop, bool bQueue = false)
{
if (bQueue)
{
DoDelayTask(ACTION_COMBOSKILL, group_id, bIgnoreAtkLoop ? 1 : 0);
return true;
}
AddOneAction(ACTION_COMBOSKILL, group_id);
bool bRet = m_pHost.ApplyComboSkill(group_id, bIgnoreAtkLoop, m_bForceAttack ? 1 : -1);
if (!bRet && m_iAttackErrCnt++ >= 3)
{
m_iAttackErrCnt = 0;
m_pHost.ClearComboSkill();
}
return true;
}
public bool CastSkill(int skill_id, bool bQueue = false)
{
if (bQueue)
{
DoDelayTask(ACTION_CASTSKILL, skill_id);
return true;
}
bool bRet = m_pHost.ApplySkillShortcut(skill_id, false, 0, m_bForceAttack ? 1 : -1);
if (bRet)
{
AddAttackError();
AddOneAction(ACTION_CASTSKILL);
// self-cast: no trace needed
if (m_pHost.GetPrepSkill() != null)
AP.AP_ActionEvent(AP.AP_EVENT_TRACEOK);
}
return bRet;
}
/* public void UseItem(int iSlot)
{
bool bRet = m_pHost.UseItemInPack(EC_GPDataType.IVTRTYPE_PACK, iSlot);
if (bRet) AddOneAction(ACTION_USEITEM);
}*/
public bool MatterCanPickup(int mid, int tid)
{
int iPickMode = CECAutoPolicy.GetInstance().GetConfigData().iAutoPickMode;
if (iPickMode == 0 || (iPickMode == 2 && !GPDataTypeHelper.ISMONEYTID(tid)))
return false;
if (!m_pHost.CanTakeItem(tid, 1))
return false;
if (m_InvalidObj.ContainsKey(mid))
return false;
return true;
}
public void Pickup(int mid)
{
bool bRet = m_pHost.PickupObject(mid, false);
if (m_iPickupErrCnt++ >= 3)
{
m_iPickupErrCnt = 0;
m_InvalidObj[mid] = INVALIDOBJ_TIMEOUT;
}
if (bRet)
AddOneAction(ACTION_PICKUP, mid);
}
public bool IsPlayerInSlice(int idPlayer)
{
var pPlayerMan = EC_ManMessageMono.Instance.EC_ManPlayer;
var pPlayer = pPlayerMan.GetPlayer(idPlayer);
return pPlayer != null && !pPlayer.IsDead();
}
/* public int GetWeaponEndurance()
{
var pWeapon = m_pHost.GetEquipment().GetItem((int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON) as CECIvtrWeapon;
if (pWeapon != null)
{
if (pWeapon.IsRangeWeapon())
{
var pArrow = m_pHost.GetEquipment().GetItem(EC_GPDataType.EQUIPIVTR_PROJECTILE) as CECIvtrArrow;
if (pArrow == null || pArrow.GetCount() == 0)
return 0;
}
return pWeapon.GetCurEndurance();
}
return 0;
}*/
public bool IsDead() => m_pHost.IsDead();
/* public bool IsRevivedByOther()
{
return m_pHost.GetReviveLostExp() >= 0.0f;
}
public void AcceptRevive()
{
UnityGameSession.c2s_CmdRevivalAgree();
}*/
/* public bool ReviveByItem()
{
if (m_pHost.GetCoolTime((int)CoolTimeIndex.GP_CT_SOUL_STONE) == 0)
{
UnityGameSession.c2s_CmdReviveItem();
return true;
}
return false;
}*/
public void ReviveInTown()
{
UnityGameSession.c2s_CmdReviveVillage();
}
public void SetForceAttack(bool bFlag)
{
m_bForceAttack = bFlag;
}
/* public bool IsInSanctuary()
{
return m_pHost.IsInSanctuary();
}*/
public bool IsMonsterAttackMe()
{
return m_MonsterAttackMe.Count > 0;
}
public A3DVECTOR3 GetObjectPos(int object_id)
{
if (GPDataTypeHelper.ISPLAYERID(object_id))
{
var pMan = EC_ManMessageMono.Instance.EC_ManPlayer;
var pPlayer = pMan.GetElsePlayer(object_id);
return pPlayer != null ? pPlayer.GetPos() : new A3DVECTOR3(0, 0, 0);
}
else if (GPDataTypeHelper.ISNPCID(object_id))
{
var pMan = EC_ManMessageMono.Instance.CECNPCMan;
var pNPC = pMan.GetNPC(object_id);
return pNPC != null ? pNPC.GetPos() : new A3DVECTOR3(0, 0, 0);
}
else if (GPDataTypeHelper.ISMATTERID(object_id))
{
var pMan = EC_ManMessageMono.Instance.EC_ManMatter;
var pMatter = pMan.GetMatter(object_id);
return pMatter != null ? pMatter.GetPos() : new A3DVECTOR3(0, 0, 0);
}
return new A3DVECTOR3(0, 0, 0);
}
public void SetInvalidObject(int object_id)
{
m_InvalidObj[object_id] = INVALIDOBJ_TIMEOUT;
}
public void OnObjectDisappear(int object_id)
{
m_InvalidObj.Remove(object_id);
m_MonsterAttackMe.Remove(object_id);
}
public void OnMonsterAttackMe(int monster_id)
{
if (GetSelectedTarget() != monster_id)
{
m_MonsterAttackMe.Add(monster_id);
m_InvalidObj.Remove(monster_id);
}
}
public void AddAttackError()
{
if (m_iAttackErrCnt++ >= MAX_ATTACK_ERROR)
{
m_iAttackErrCnt = 0;
m_InvalidObj[GetSelectedTarget()] = INVALIDOBJ_TIMEOUT;
}
}
public void ResetAttackError()
{
m_iAttackErrCnt = 0;
}
public void ResetPickupError()
{
m_iPickupErrCnt = 0;
}
public int GetAttackError() => m_iAttackErrCnt;
public int GetPickupError() => m_iPickupErrCnt;
public void OnActionEvent(int iEvent, int iParam)
{
m_pCurAction?.OnEvent(iEvent, iParam);
}
private void DoDelayTask(int iType, int iParam1 = 0, int iParam2 = 0)
{
m_DelayTask.iType = iType;
m_DelayTask.iParam1 = iParam1;
m_DelayTask.iParam2 = iParam2;
if (m_pHost.IsMeleeing() || m_pHost.IsPlayerMoving())
CancelAction();
}
private void ProcessDelayTask()
{
if (m_pCurAction != null && !m_pCurAction.CanBreak())
return;
ClearAction();
m_iAttackErrCnt = 0;
m_iPickupErrCnt = 0;
switch (m_DelayTask.iType)
{
case ACTION_CASTSKILL:
CastSkill(m_DelayTask.iParam1);
break;
case ACTION_COMBOSKILL:
CastComboSkill(m_DelayTask.iParam1, m_DelayTask.iParam2 == 1);
break;
default:
throw new InvalidOperationException("Unknown delay task type");
}
m_DelayTask.iType = ACTION_IDLE;
m_DelayTask.iParam1 = 0;
m_DelayTask.iParam2 = 0;
}
// =========================================================
// Action implementations (converted 1:1)
// =========================================================
private sealed class IdleAction : Action
{
private int m_iTime;
public IdleAction(CECPlayerWrapper pPlayer, int iTime)
: base(pPlayer, ACTION_IDLE)
{
m_iTime = iTime;
}
public override bool Tick(uint dwDeltaTime)
{
if (HaveNextAction())
return true;
if (m_iTime > 0)
{
m_iTime -= (int)dwDeltaTime;
return m_iTime <= 0;
}
return true;
}
}
private sealed class MoveAction : Action
{
private bool m_bFinish;
private int m_iTimeOut;
public MoveAction(CECPlayerWrapper pPlayer)
: base(pPlayer, ACTION_MOVE)
{
m_bFinish = false;
m_iTimeOut = 30000;
}
public override bool CanBreak() => false;
public override bool Tick(uint dwDeltaTime)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
public override void OnEvent(int iEvent, int iParam)
{
if (iEvent == AP.AP_EVENT_CANNOTMOVE || iEvent == AP.AP_EVENT_MOVEFINISHED)
m_bFinish = true;
}
}
private sealed class CastSkillAction : Action
{
private const int TRACE = 0;
private const int SPELL = 1;
private int m_iStep;
private bool m_bFinish;
private int m_iTimeOut;
private bool m_bSuccess;
public CastSkillAction(CECPlayerWrapper pPlayer)
: base(pPlayer, ACTION_CASTSKILL)
{
m_iStep = TRACE;
m_iTimeOut = 30000;
m_bSuccess = false;
m_bFinish = false;
}
public override void EndAction()
{
if (m_bSuccess)
host.ResetAttackError();
}
public override bool CanBreak()
{
return m_iStep == TRACE && !host.GetHostPlayer().IsPlayerMoving();
}
public override bool Tick(uint dwDeltaTime)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
public override void OnEvent(int iEvent, int iParam)
{
if (m_iStep == TRACE)
{
if (iEvent == AP.AP_EVENT_TRACEOK)
{
m_iStep = SPELL;
m_iTimeOut = 2000;
}
else if (iEvent == AP.AP_EVENT_MOVEFINISHED)
{
m_bFinish = true;
}
}
else if (m_iStep == SPELL)
{
if (iEvent == AP.AP_EVENT_STARTSKILL)
{
m_iTimeOut = iParam * 2;
m_bSuccess = true;
}
else if (iEvent == AP.AP_EVENT_STOPSKILL)
{
m_bFinish = true;
}
}
}
}
private sealed class UseItemAction : Action
{
private bool m_bFinish;
private int m_iTimeOut;
public UseItemAction(CECPlayerWrapper pPlayer)
: base(pPlayer, ACTION_USEITEM)
{
m_bFinish = false;
m_iTimeOut = 2000;
}
public override bool CanBreak() => false;
public override bool Tick(uint dwDeltaTime)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
public override void OnEvent(int iEvent, int iParam)
{
if (iEvent == AP.AP_EVENT_STARTUSEITEM)
{
m_iTimeOut = iParam * 2;
}
else if (iEvent == AP.AP_EVENT_STOPUSEITEM)
{
m_bFinish = true;
}
}
}
private sealed class PickupAction : Action
{
private const int TRACE = 0;
private const int PICKUP = 1;
private int m_iStep;
private bool m_bFinish;
private int m_iTimeOut;
private bool m_bSuccess;
private readonly int m_iMatterID;
public PickupAction(CECPlayerWrapper pPlayer, int iMatterID)
: base(pPlayer, ACTION_PICKUP)
{
m_iMatterID = iMatterID;
m_iTimeOut = 30000;
m_iStep = TRACE;
m_bSuccess = false;
m_bFinish = false;
}
public override void EndAction()
{
if (m_bSuccess)
host.ResetPickupError();
}
public override bool CanBreak()
{
return m_iStep == TRACE && !host.GetHostPlayer().IsPlayerMoving();
}
public override bool Tick(uint dwDeltaTime)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
public override void OnEvent(int iEvent, int iParam)
{
if (m_iStep == TRACE)
{
if (iEvent == AP.AP_EVENT_TRACEOK)
{
m_iStep = PICKUP;
m_iTimeOut = 2000;
}
else if (iEvent == AP.AP_EVENT_MOVEFINISHED)
{
m_bFinish = true;
}
}
else if (m_iStep == PICKUP)
{
if (iEvent == AP.AP_EVENT_PICKUPOK)
{
m_bFinish = true;
m_bSuccess = true;
}
else if (iEvent == AP.AP_EVENT_CANNOTPICKUP)
{
m_bFinish = true;
host.SetInvalidObject(m_iMatterID);
host.ResetPickupError();
}
}
}
}
private sealed class MeleeAction : Action
{
private const int TRACE = 0;
private const int MELEE = 1;
private bool m_bFinish;
private int m_iStep;
private int m_iTimeOut;
private bool m_bMeleeing;
private bool m_bLastMeleeStopped;
public MeleeAction(CECPlayerWrapper pPlayer)
: base(pPlayer, ACTION_MELEE)
{
m_iStep = TRACE;
m_iTimeOut = 30000;
m_bMeleeing = false;
m_bFinish = false;
m_bLastMeleeStopped = true;
}
public override bool CanBreak()
{
return m_iStep == TRACE && !host.GetHostPlayer().IsPlayerMoving();
}
public override bool Tick(uint dwDeltaTime)
{
if (!m_bMeleeing)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
return false;
}
public override void OnEvent(int iEvent, int iParam)
{
if (iEvent == AP.AP_EVENT_TRACEOK)
{
if (m_iStep == TRACE)
{
m_iStep = MELEE;
m_iTimeOut = 2000;
}
}
else if (iEvent == AP.AP_EVENT_MOVEFINISHED)
{
if (m_iStep == TRACE)
m_bFinish = true;
}
else if (iEvent == AP.AP_EVENT_STARTMELEE)
{
if (m_iStep == MELEE)
{
m_bMeleeing = true;
m_iTimeOut = 10000;
host.ResetAttackError();
}
}
else if (iEvent == AP.AP_EVENT_STOPMELEE)
{
if (!m_bLastMeleeStopped)
{
m_bMeleeing = false;
m_bLastMeleeStopped = true;
return;
}
if (m_iStep == MELEE && m_bMeleeing)
{
m_bMeleeing = false;
m_bFinish = true;
host.ResetAttackError();
}
}
else if (iEvent == AP.AP_EVENT_MELEEOUTOFRANGE)
{
if (!m_bLastMeleeStopped)
{
m_bLastMeleeStopped = true;
return;
}
if (m_iStep == MELEE)
{
m_iStep = TRACE;
m_iTimeOut = 30000;
m_bLastMeleeStopped = (iParam == 1);
}
}
}
}
private sealed class ComboSkillAction : Action
{
private const int TRACE = 0;
private const int SPELL = 1;
private const int MELEE = 2;
private int m_iState;
private int m_iTimeOut;
private bool m_bFinish;
private bool m_bMeleeing;
private bool m_bCasting;
private bool m_bDelayContinue;
private bool m_bSelfSkillFlag;
private bool m_bSending;
private bool m_bLastMeleeStopped;
public ComboSkillAction(CECPlayerWrapper pPlayer)
: base(pPlayer, ACTION_COMBOSKILL)
{
m_iState = TRACE;
m_iTimeOut = 30000;
m_bMeleeing = false;
m_bDelayContinue = false;
m_bCasting = false;
m_bSelfSkillFlag = false;
m_bSending = false;
m_bFinish = false;
m_bLastMeleeStopped = true;
}
public override bool CanBreak()
{
return !m_bSending && !m_bCasting && !m_bMeleeing && !host.GetHostPlayer().IsPlayerMoving();
}
public override bool Tick(uint dwDeltaTime)
{
var pCombo = host.GetHostPlayer().GetComboSkill();
if (pCombo == null && !m_bMeleeing)
return true;
if (pCombo != null && !pCombo.IsIgnoreAtkLoop() &&
pCombo.GetTarget() != host.GetSelectedTarget() &&
!m_bCasting && !m_bMeleeing)
return true;
if (!m_bMeleeing)
{
m_iTimeOut -= (int)dwDeltaTime;
if (m_iTimeOut <= 0)
return true;
return m_bFinish;
}
return false;
}
public override void OnEvent(int iEvent, int iParam)
{
if (iEvent == AP.AP_EVENT_COMBOCONTINUE)
{
if (m_iState == MELEE)
{
m_bDelayContinue = true;
m_bSelfSkillFlag = (iParam == 1);
}
else
{
if (iParam == 1)
{
m_iState = SPELL;
m_iTimeOut = 2000;
m_bSending = true;
}
else
{
m_iState = TRACE;
m_iTimeOut = 30000;
}
}
}
else if (iEvent == AP.AP_EVENT_TRACEOK)
{
if (m_iState == TRACE)
{
m_iState = (iParam == 0) ? MELEE : SPELL;
m_iTimeOut = 2000;
m_bSending = true;
}
}
else if (iEvent == AP.AP_EVENT_MOVEFINISHED)
{
if (m_iState == TRACE)
m_bFinish = true;
}
else if (iEvent == AP.AP_EVENT_STARTMELEE)
{
if (m_iState == MELEE)
{
m_iTimeOut = 10000;
m_bMeleeing = true;
m_bSending = false;
host.ResetAttackError();
}
}
else if (iEvent == AP.AP_EVENT_STOPMELEE)
{
if (!m_bLastMeleeStopped)
{
m_bMeleeing = false;
m_bLastMeleeStopped = true;
return;
}
if (m_iState == MELEE && m_bMeleeing)
{
m_bMeleeing = false;
host.ResetAttackError();
var pCombo = host.GetHostPlayer().GetComboSkill();
if (pCombo != null && pCombo.IsStop())
{
m_bFinish = true;
}
else
{
m_iTimeOut = 10000;
if (m_bDelayContinue)
{
m_bDelayContinue = false;
if (m_bSelfSkillFlag)
{
m_iState = SPELL;
m_iTimeOut = 2000;
m_bSending = true;
}
else
{
m_iState = TRACE;
m_iTimeOut = 30000;
}
}
}
}
}
else if (iEvent == AP.AP_EVENT_MELEEOUTOFRANGE)
{
if (!m_bLastMeleeStopped)
{
m_bLastMeleeStopped = true;
return;
}
if (m_iState == MELEE)
{
m_iState = TRACE;
m_iTimeOut = 30000;
m_bLastMeleeStopped = (iParam == 1);
}
}
else if (iEvent == AP.AP_EVENT_STARTSKILL)
{
if (m_iState == SPELL)
{
m_iTimeOut = iParam * 2;
m_bCasting = true;
m_bSending = false;
host.ResetAttackError();
}
}
else if (iEvent == AP.AP_EVENT_STOPSKILL)
{
if (m_iState == SPELL && m_bCasting)
{
m_bCasting = false;
host.ResetAttackError();
var pCombo = host.GetHostPlayer().GetComboSkill();
if (pCombo != null && pCombo.IsStop())
m_bFinish = true;
else
m_iTimeOut = 10000;
}
}
else if (iEvent == AP.AP_EVENT_COMBOFINISH)
{
m_bFinish = true;
}
}
}
public enum AP_EVENT
{
AP_EVENT_CANNOTMOVE, // ²»ÄÜÒÆ¶¯
AP_EVENT_MOVEFINISHED, // ÒÆ¶¯½áÊø
AP_EVENT_TRACEOK, // ×·×ٳɹ¦
AP_EVENT_STARTSKILL, // ¼¼ÄÜ¿ªÊ¼
AP_EVENT_STOPSKILL, // ¼¼ÄÜÍ£Ö¹
AP_EVENT_STARTUSEITEM, // ʹÓÃÎïÆ·¿ªÊ¼
AP_EVENT_STOPUSEITEM, // ʹÓÃÎïÆ·½áÊø
AP_EVENT_PICKUPOK, // ³É¹¦¼ñÈ¡ÎïÆ·
AP_EVENT_CANNOTPICKUP, // ËûÈËÎïÆ·£¬²»ÄܼñÈ¡
AP_EVENT_STARTMELEE, // ¿ªÊ¼ÆÕ¹¥
AP_EVENT_STOPMELEE, // ½áÊøÆÕ¹¥
AP_EVENT_COMBOCONTINUE, // ×éºÏ¼¼Íƽø
AP_EVENT_COMBOFINISH, // ×éºÏ¼¼ÖÕÖ¹£¬Ó¦¶Ô×îºóÒ»¸ö¼¼ÄÜûÓзųöµÄÇé¿ö
AP_EVENT_MELEEOUTOFRANGE, // ÆÕ¹¥³¬³ö¾àÀë
};
}