using System; using System.Collections.Generic; using System.Text; using CommonAI.RTS; using CommonLang.Vector; using CommonAI.Zone; using CommonAI.Zone.Instance; using CommonAI.RTS.Manhattan; using CommonLang; using CommonLang.Log; using CommonAI.Zone.Formula; using CommonAI.ZoneClient; using CommonAI.Zone.Helper; using CommonAI.Zone.Attributes; using CommonLang.Property; using static CommonAI.Zone.AttackProp; using CommonAI.Data; namespace CommonAI.Zone.Instance { partial class InstanceUnit { //-----------------------------------------------------------------------------------------------------// #region SEND_EVENT private UnitForceSyncPosEvent mForceSync = new UnitForceSyncPosEvent(); private UnitActionStatus mCurrentActionMainState = UnitActionStatus.Idle; //子状态状态 private int mCurrentActionSubState = 0; //子状态扩展信息 private short mSubStateExt = 0; private UnitActionStatus mLastActionStatus = 0; private int mLastActionSubstate = 0; //蓄力状态 private byte chargeAtkStatus = 0; /// /// 当前动做主状态 /// public UnitActionStatus CurrentActionStatus { get { return mCurrentActionMainState; } } /// /// 当前动做子状态, 0-正常,1-隐身 /// public int CurrentActionSubstate { get { return mCurrentActionSubState; } } //蓄力状态 public byte ChargeAtkStatus { get; set; } public bool IsActionStatusChanged { get; private set; } public void SetActionStatus(UnitActionStatus st) { if (st == UnitActionStatus.Move && !this.Moveable) { // nothing // } else { this.mCurrentActionMainState = st; } } public void AddActionSubState(UnitActionSubStatus substate, short ext = 0) { this.mCurrentActionSubState = this.mCurrentActionSubState | (int)substate; this.mSubStateExt = ext; // 特殊状态额外信息通知 if (this.IsPlayer && substate == UnitActionSubStatus.Stealth) { UnitStealthInfo stealInfo = new UnitStealthInfo(this.ID, 1, (short)ext); this.queueEvent(stealInfo); } //Console.WriteLine("add - sub - " + this.mCurrentActionSubState); } public void RemoveActionSubState(UnitActionSubStatus substate) { //有这个状态,才能进行移除 if (this.IsHasSubState(substate)) { this.mCurrentActionSubState = this.mCurrentActionSubState ^ (int)substate; // 特殊状态额外信息通知 if (this.IsPlayer && substate == UnitActionSubStatus.Stealth) { UnitStealthInfo stealInfo = new UnitStealthInfo(this.ID, 0, 0); this.queueEvent(stealInfo); } } //Console.WriteLine("remove - sub - " + this.mCurrentActionSubState); } //是否拥有该子状态 public bool IsHasSubState(UnitActionSubStatus state) { return ((this.mCurrentActionSubState & (int)state) > 0); } public void queueEvent(ObjectEvent evt, bool force = false) { Parent.queueObjectEvent(this, evt, force); } public void queueEvent(Event evt) { Parent.queueEventInternal(evt); } public virtual bool DoAutoPick(bool ignoreInterval = false) { return false; } //通知拾取消息 public virtual void NotifyRemoveDropItemB2C(InstanceItem item) { } public override void SendForceSync() { mForceSync.object_id = this.ID; mForceSync.X = this.X; mForceSync.Y = this.Y; mForceSync.Direction = this.Direction; mForceSync.UnitMainState = (byte)mCurrentActionMainState; this.mLastActionStatus = mCurrentActionMainState; mForceSync.UnitSubState = (byte)mCurrentActionSubState; Parent.queueObjectEvent(this, mForceSync); //Console.WriteLine("--------SendForceSync x:" + mForceSync.X + ", y : " + mForceSync.Y); } internal override bool updatePos(InstanceZone zone) { this.IsActionStatusChanged = (mLastActionStatus != mCurrentActionMainState) || (mLastActionSubstate != mCurrentActionSubState); this.mLastActionStatus = mCurrentActionMainState; this.mLastActionSubstate = mCurrentActionSubState; if (base.updatePos(zone) || IsActionStatusChanged) { return true; } return false; } protected internal virtual bool GenSyncState(ref SyncPosEvent.UnitState ret) { if (IsActionStatusChanged) { ret.SetObject(this); return true; } return false; } public SyncPosEvent.UnitState GetSyncState() { SyncPosEvent.UnitState ret = new SyncPosEvent.UnitState(); ret.SetObject(this); return ret; } //------------------------------------------------------------------------------------- #endregion //-----------------------------------------------------------------------------------------------------// public abstract class State : IDisposable { private bool m_started = false; public InstanceUnit unit { get; private set; } public InstanceZone zone { get { return unit.Parent; } } public bool IsStarted { get { return m_started; } } public State(InstanceUnit unit) { this.unit = unit; } internal void start() { if (!m_started) { m_started = true; onStart(); if (this.mOnStart != null) { this.mOnStart(unit, this); } } } internal void update() { onUpdate(); } internal void stop() { if (m_started) { m_started = false; onStop(); if (this.mStopOnce != null) { var invoke = mStopOnce; this.mStopOnce = null; invoke.Invoke(unit, this); } if (this.mOnStop != null) { this.mOnStop.Invoke(unit, this); } } } public virtual void MarkRemove() { } /// 当前状态是否可以被新状态打断 public abstract bool onBlock(State new_state); protected abstract void onStart(); protected abstract void onUpdate(); protected abstract void onStop(); public virtual void Dispose() { mOnStart = null; mOnStop = null; mStopOnce = null; } public delegate void StateStartHandler(InstanceUnit obj, State state); public delegate void StateStopHandler(InstanceUnit obj, State state); private StateStartHandler mOnStart; private StateStopHandler mOnStop; private StateStopHandler mStopOnce; [EventTriggerDescAttribute("状态机每次开始时触发")] public event StateStartHandler OnStart { add { mOnStart += value; } remove { mOnStart -= value; } } [EventTriggerDescAttribute("状态机每次结束时触发")] public event StateStopHandler OnStop { add { mOnStop += value; } remove { mOnStop -= value; } } [DescAttribute("状态机结束时触发,停止后自动清理所有监听")] public void AddStopOnce(StateStopHandler stop) { mStopOnce += stop; } } //-----------------------------------------------------------------------------------------------------// public class StateSpawn : State { private TimeExpire timer; public StateSpawn(InstanceUnit unit, int timeMS) : base(unit) { timer = new TimeExpire(timeMS); } override public bool onBlock(State new_state) { if(new_state is StateDuJie) { return true; } return timer.IsEnd; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Spawn); } override protected void onUpdate() { if (timer.Update(zone.UpdateIntervalMS)) { unit.doSomething(); } } override protected void onStop() { unit.doActivated(); } } //-----------------------------------------------------------------------------------------------------// /// /// 待机状态 /// public class StateIdle : State { public StateIdle(InstanceUnit unit) : base(unit) { } override public bool onBlock(State new_state) { if (new_state is StateIdle) { return false; } return true; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Idle); } override protected void onUpdate() { unit.doSomething(); //unit.SetActionStatus(UnitActionStatus.Idle); } override protected void onStop() { } } /// /// 浪 /// public class StateIdleMove : State { private readonly TimeExpire mExpire; private readonly MoveAI mMoveAI; private readonly Vector2 mOrginPos; private readonly float mRange; private MoveBlockResult mLastResult; public MoveBlockResult LastMoveResult { get { return mLastResult; } } public StateIdleMove(InstanceUnit unit, Vector2 orginPos, int timeMS, float range) : base(unit) { this.mExpire = new TimeExpire(timeMS); this.mMoveAI = new MoveAI(unit, false); this.mRange = Math.Abs(range); this.mOrginPos = orginPos; } public override bool onBlock(State new_state) { return true; } protected override void onStart() { Vector2 target = this.FindTargetPos(); this.mMoveAI.FindPath(target.X, target.Y); unit.SetActionStatus(UnitActionStatus.Move); } protected override void onStop() { } protected override void onUpdate() { if (mExpire.Update(zone.UpdateIntervalMS)) { unit.doSomething(); } else { mLastResult = mMoveAI.Update(); if ((mLastResult.result & MoveResult.RESULTS_MOVE_END) != 0) { Vector2 target = this.FindTargetPos(); this.mMoveAI.FindPath(target.X, target.Y); } } } /// /// 搜索要去的地方 /// /// protected virtual Vector2 FindTargetPos() { var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, mOrginPos.X, mOrginPos.Y, mRange); if (node != null) { return new Vector2(node.PosX, node.PosY); } return new Vector2(mOrginPos.X, mOrginPos.Y); } } /// /// 移动状态 /// public class StateMove : State { private Vector2 target; private int minStepTime; private bool moveEnd = false; private MoveBlockResult mLastMoveResult; public Vector2 Target { get { return target; } } public bool IsMoveEnd { get { return moveEnd; } } public MoveBlockResult LastMoveResult { get { return mLastMoveResult; } } public int MinStepCheckCount { get; set; } public bool StopOnTouchMap { get; set; } public Predicate EndMoveAction { get; set; } public StateMove(InstanceUnit unit, float x, float y) : base(unit) { this.StopOnTouchMap = false; this.MinStepCheckCount = 10; this.target = new Vector2(x, y); } override public bool onBlock(State new_state) { return true; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Move); } override protected void onUpdate() { unit.SetActionStatus(UnitActionStatus.Move); unit.faceTo(target.X, target.Y); mLastMoveResult = unit.moveBlockTo(target.X, target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS); if ((mLastMoveResult.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0 && StopOnTouchMap) { moveEnd = true; if (EndMoveAction == null || !EndMoveAction(this)) { unit.doSomething(); } } else if ((mLastMoveResult.result & MoveResult.RESULTS_MOVE_END) != 0) { moveEnd = true; if (EndMoveAction == null || !EndMoveAction(this)) { unit.doSomething(); } } else if ((mLastMoveResult.result & MoveResult.MOVE_RESULT_MIN_STEP) != 0) { moveEnd = true; minStepTime++; if (minStepTime > MinStepCheckCount) { if (EndMoveAction == null || !EndMoveAction(this)) { unit.doSomething(); } } } else { minStepTime = 0; } } override protected void onStop() { } } /// /// 释放技能状态 /// public class StateSkill : State { readonly private InstanceUnit.SkillState skill; readonly private SkillLaunched launched; readonly private AttackRangeHelper attack_range; private Queue action_queue; private LaunchSkillParam param; private InstanceUnit targetUnit; private bool is_done = false; private UnitActionData current_action = null; private int curActionTotalTimes = 0; private PopupKeyFrames current_frames = new PopupKeyFrames(); private BitSet8 current_action_status = new BitSet8(); private int current_pass_time = 0; private Vector2 move_to; private HitMoveSpeed start_move; private Vector2 body_hited_last_pos = new Vector2(); private HashMap body_hited = new HashMap(); private TimeExpire chantExpire; private AstarManhattan.MWayPoint move_to_target_path; private float jump_to_target_speed_sec; private TVector2 jump_to_target_pos; // 技能加速,攻速 private float mSkillSpeed = 0.0f; public InstanceUnit.SkillState Skill { get { return skill; } } public SkillTemplate SkillData { get { return skill.Data; } } public InstanceUnit TargetUnit { get { return targetUnit; } } public Queue ActionQqueue { get { return action_queue; } } public bool IsControlMoveable { get { return current_action_status.Get(0); } private set { current_action_status.Set(0, value); } } public bool IsControlFaceable { get { return current_action_status.Get(1); } private set { current_action_status.Set(1, value); } } public bool IsCancelableBySkill { get { return current_action_status.Get(2); } private set { current_action_status.Set(2, value); } } public bool IsCancelableByMove { get { return current_action_status.Get(3); } private set { current_action_status.Set(3, value); } } public bool IsNoneBlock { get { return current_action_status.Get(4); } private set { current_action_status.Set(4, value); } } public bool IsNoneTouch { get { return current_action_status.Get(5); } private set { current_action_status.Set(5, value); } } public bool IsFaceToTarget { get { return current_action_status.Get(6); } private set { current_action_status.Set(6, value); } } public Vector2 GetMoveToPos() { return this.move_to; } // public bool IsCancelableBySkill { get; private set; } // public bool IsCancelableByMove { get; private set; } // public bool IsNoneBlock { get; private set; } // public bool IsNoneTouch { get; private set; } // public bool IsFaceToTarget { get; private set; } // public bool IsControlMoveable { get; private set; } // public bool IsControlFaceable { get; private set; } /// /// 技能是否完结 /// public bool IsDone { get { return is_done; } } /// /// 是否在吟唱中 /// public bool IsChanting { get { return chantExpire != null; } } /// /// 动作加速因子 /// public float ActionSpeed { get; private set; } /// /// 技能释放结束后的朝向 /// public Vector2 StopFaceTo { set; get; } /// /// 动作总时间 /// public int ActionTotalTimeMS { get; private set; } public int CurrentActionIndex { get { if (current_action != null) { return SkillData.ActionQueue.IndexOf(current_action); } return 0; } } public StateSkill(InstanceUnit unit, InstanceUnit.SkillState skill, LaunchSkillParam param, float actionSpeed, SkillLaunched skillLaunched) : base(unit) { this.skill = skill; this.param = param; this.ActionSpeed = actionSpeed; this.ActionTotalTimeMS = skill.Data.ActionQueueTimeMS; this.launched = skillLaunched; this.targetUnit = zone.getUnit(param.TargetUnitID); this.attack_range = new AttackRangeHelper(unit); //if (SkillData.ChantTimeMS > 0) //{ // this.chantExpire = new TimeExpire(SkillData.ChantTimeMS); // this.IsCancelableByMove = true; //} //this.beginLaunch(); } /// /// 释放前判断 /// /// public bool tryLaunch() { if (SkillData.ActionQueue.Count > 0) { if (!checkTargetRange()) { return false; } if (!checkMoveToTarget(SkillData.ActionQueue[0])) { return false; } return true; } return false; } public bool CanBlockByNewSkill(SkillTemplate sk) { // 反击 if (sk.IsCounter) { return true; } // 高优先级技能打断老技能, 0普通,-1标识位移技能 if (sk.ActionPriority > 0 && sk.ActionPriority > this.SkillData.ActionPriority) { return true; } // 当前动作是否可被打断 if (this.IsCancelableBySkill) { return true; } return false; } override public bool onBlock(State new_state) { // 吟唱中 // if (IsChanting) { return true; } // 技能完结 // if (is_done) { return true; } // 被死亡或控制类技能中断 // if (new_state is StateDead || new_state is StateStun) { skill.Reset(); return true; } // 如果死亡则受击 // else if (new_state is StateDamage) { if (IsNoneBlock) { return false; } skill.ForceIntoCD(); return true; } else if (new_state is StateSkill) { StateSkill ns = new_state as StateSkill; if (CanBlockByNewSkill(ns.SkillData)) { return true; } else if (SkillData.ID == ns.SkillData.ID && SkillData.ActionQueue.Count > CurrentActionIndex) { if (SkillData.ActionQueue[this.CurrentActionIndex].IsCancelBySkillNext) { return true; } } } else { // 当前动作是否可被打断 // if (this.IsCancelableByMove) { return true; } } return false; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Skill); if (IsChanting) { unit.queueEvent(new UnitChantSkillEvent(unit.ID, SkillData)); } else { beginLaunch(); } } override protected void onStop() { move_to_target_path = null; if (start_move != null) { start_move.Stop(); start_move = null; } unit.Z = 0; is_done = true; if (!IsChanting) { if (skill != null) { skill.Stop(this); } if (unit.IsSkillControllableByServer) { if (StopFaceTo != null) { //unit.Direction = MathVector.getDegree(StopFaceTo); unit.faceTo(StopFaceTo.X, StopFaceTo.Y); } } } PlayerSkillStopEvent evt = new PlayerSkillStopEvent(unit.ID, skill.ID); unit.queueEvent(evt); unit.Virtual.DispatchSkillBlockEvent(this, null); } override protected void onUpdate() { if (chantExpire != null) { if (!checkTargetRange()) { is_done = true; unit.doSomething(); return; } if (chantExpire.Update(zone.UpdateIntervalMS)) { beginLaunch(); chantExpire = null; } } if (IsChanting) return; if (is_done) return; this.current_pass_time += (int)(zone.UpdateIntervalMS * ActionSpeed); if (current_action == null) { nextAction(); } if (current_action == null) { is_done = true; unit.doSomething(); } else { body_hited_last_pos.SetX(unit.X); body_hited_last_pos.SetY(unit.Y); if (IsFaceToTarget) { float tx = 0; float ty = 0; if (getTargetPos(out tx, out ty)) { unit.faceTo(tx, ty); unit.SendForceSync(); } } // 关键帧 // List kfs = new List(); // 技能加速 int timePassVirtual = current_pass_time; if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk && this.mSkillSpeed != 0) { timePassVirtual = (int)(timePassVirtual * this.mSkillSpeed); } if (current_frames.PopKeyFrames(timePassVirtual, kfs) > 0) { for (int i = 0; i < kfs.Count; i++) { doKeyFrame(kfs[i]); } } if (current_action != null) { var action = current_action; // 技能位移 // // 移动到目标时,不切换动作 // if (action.IsMoveToTarget) { // 冲到目标,立即下段 // doMoveToTarget(action); } else if (action.IsJumpToTarget) { doJumpToTarget(action); } else { if (unit.IsSkillControllableByServer) { if (start_move != null) { doMove(); } if (move_to != null) { if (IsControlMoveable && !unit.IsCannotMove) { unit.moveImpactTo(move_to.X, move_to.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS); } else { move_to = null; } } } // 身体攻击 // if (action.BodyHit != null) { doBodyHit(action); } // 防止技能位移导致单位重合 // if (action.BodyBlockOnAttackRange) { doBodyBlock(action); } if (IsFaceToTarget) { float tx = 0; float ty = 0; if (getTargetPos(out tx, out ty)) { unit.faceTo(tx, ty); unit.SendForceSync(); } } } } //ADD 6/21 By Zou 加入自动战斗取消后摇 if (current_action != null) { var isFinish = current_pass_time >= this.curActionTotalTimes; if (!isFinish && (IsCancelableBySkill) && unit is InstancePlayer) { isFinish = (unit as InstancePlayer).IsGuard; } if (isFinish && !nextAction()) { is_done = true; unit.doSomething(); } } } } private void beginLaunch() { //是否使用多段中字段时间作为cd bool isUseActionQueuetime = false; int launchIndex = 0; skill.setTriggerDecreaseTime(0); skill.Launch(this, param); { launchIndex = skill.ActionIndex; int maxCount = skill.GetMaxSteps();// skill.Data.ActionQueue.Count; if (skill.Data.IsSingleAction) { if (launchIndex > 0 && launchIndex < skill.Data.ActionQueue.Count //&& skill.Data.ActionQueue[actionIndex].SigleActionType == ActionEnum.forbidNext_lock) && !skill.IsCanLaunchNextStepByPlayer(skill.Data.ActionQueue[launchIndex])) { skill.Reset(); } this.action_queue = new Queue(1); if (0 <= skill.LockActionStep && skill.LockActionStep <= maxCount) { this.action_queue = new Queue(1); launchIndex = skill.LockActionStep; skill.Reset(); this.action_queue.Enqueue(skill.Data.ActionQueue[skill.LockActionStep]); } else { skill.LockActionStep = -1; for (int i = launchIndex; i <= maxCount; i++) { UnitActionData data = skill.Data.ActionQueue[i]; this.action_queue.Enqueue(data); if (data.SigleActionType == ActionEnum.chargeAtk || data.SigleActionType == ActionEnum.showLeftTime) { isUseActionQueuetime = true; } else if (data.SigleActionType == ActionEnum.forbidNext_showTime) { isUseActionQueuetime = true; break; } else if (data.SigleActionType == ActionEnum.IsAutoNext) { continue; } else { break; } } } } else { //if (skill.OveryLayer > 0 && maxCount > 1) if(skill.CanStoreTimes) { int maxIndex = Math.Min(skill.OveryLayer, maxCount); this.action_queue = new Queue(maxIndex); for (int i = 0; i < maxIndex; i++) { UnitActionData temp = skill.Data.ActionQueue[i]; this.action_queue.Enqueue(temp); if (temp.SigleActionType == ActionEnum.forbidNext || temp.SigleActionType == ActionEnum.forbidNext_lock || temp.SigleActionType == ActionEnum.forbidNext_showTime) { break; } } //技能释放 if (skill.CanStoreTimes) { skill.updateOverLayer(0); } } else { this.action_queue = new Queue(skill.Data.ActionQueue); } } launched.Invoke(this); if (mSkillLaunched != null) { mSkillLaunched.Invoke(this); mSkillLaunched = null; } } if (unit.IsSkillControllableByServer && param.AutoFocusNearTarget && (targetUnit == null || !targetUnit.IsActive)) { //自动锁定目标// bool directionChange = false; this.targetUnit = unit.getSkillAttackableFirstTarget(this.SkillData, AttackReason.Look, ref directionChange); if (targetUnit != null && targetUnit != unit && directionChange) { unit.faceTo(targetUnit.X, targetUnit.Y); } } else { if (param.SpellTargetPos != null) { unit.faceTo(param.SpellTargetPos.X, param.SpellTargetPos.Y); unit.SendForceSync(); } } { if (skill.IsMutilAction()) { //最后一段取消连招标记 if (launchIndex + 1 == skill.Data.ActionQueue.Count && skill.Data.ActionQueue[launchIndex].SigleActionType != ActionEnum.showLeftTime) { skill.Reset(); skill.ResetTotalTime(); } else if(!skill.IsCodeConttrolCD()) { if (isUseActionQueuetime) { skill.TotalCDTime = skill.Data.ActionQueue[launchIndex].TotalTimeMS; } else if (launchIndex + 1 != skill.Data.ActionQueue.Count && skill.IsCanLaunchNextStepByPlayer(skill.Data.ActionQueue[launchIndex]))//非最后一段才用这个时间 { skill.TotalCDTime = skill.Data.SingleActionCoolDownMS; } } } //Console.WriteLine("skill.TotalCDTime - " + launchIndex); PushLaunchSkillEvent(launchIndex); } nextAction(); beginMoveToTarget(); } private void PushLaunchSkillEvent(int launchIndex) { float speed = ActionSpeed; if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk) { speed = speed * this.unit.GetAttackSpeed() / 10000; } UnitLaunchSkillEvent evt = new UnitLaunchSkillEvent( unit.ID, skill.Data, (byte)launchIndex, speed, skill.TotalCDTime, param.AutoFocusNearTarget, targetUnit != unit ? param.SpellTargetPos : null, targetUnit != null ? targetUnit.ID : 0, skill.LockActionStep); unit.queueEvent(evt); } private bool beginMoveToTarget() { if (current_action != null && current_action.IsMoveToTarget) { if (targetUnit != null && zone.TouchObject2(unit, targetUnit)) { if (nextAction()) { unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex)); } return true; } } return false; } private bool nextAction() { move_to_target_path = null; if (start_move != null) { start_move.Stop(); start_move = null; } if (action_queue != null && action_queue.Count > 0) { bool isNeedNotifyClient = (this.current_action != null && (this.current_action.SigleActionType == ActionEnum.IsAutoNext || this.current_action.SigleActionType == ActionEnum.chargeAtk)); //bool perChargeAtk = (this.current_action != null && this.current_action.SigleActionType == ActionEnum.chargeAtk); this.current_action = action_queue.Dequeue(); if (this.Skill.GetSkillType() == XmdsSkillType.normalAtk && this.unit.GetAttackSpeed() != 0) { this.mSkillSpeed = this.unit.GetAttackSpeed() * 0.0001f; this.curActionTotalTimes = (int)(this.current_action.TotalTimeMS / this.mSkillSpeed); } else { this.mSkillSpeed = 0; this.curActionTotalTimes = this.current_action.TotalTimeMS; } //如果为蓄力技能,通知客户端状态 if (this.current_action.SigleActionType == ActionEnum.chargeAtk) { this.skill.Owner.AddActionSubState(UnitActionSubStatus.ChargeAtkIdle); } else { this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle); this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkMove); } this.current_frames.AddRange(current_action.KeyFrames); this.current_pass_time = 0; this.IsCancelableByMove = current_action.IsCancelable; this.IsCancelableBySkill = current_action.IsCancelableBySkill; this.IsNoneBlock = current_action.IsNoneBlock; this.IsNoneTouch = current_action.IsNoneTouch; this.IsFaceToTarget = current_action.IsFaceToTarget; this.IsControlFaceable = current_action.IsControlFaceable; this.IsControlMoveable = current_action.IsControlMoveable; if (isNeedNotifyClient) { skill.ResetPassTime(); skill.NextAction(); //程序自动连接每一段动作,时间默认为totalMS UnitActionData actionData = skill.Data.ActionQueue[skill.ActionIndex]; if(!skill.IsCodeConttrolCD()) { if (skill.Data.IsSingleAction && actionData.SigleActionType == ActionEnum.None) { skill.TotalCDTime = skill.Data.SingleActionCoolDownMS; } else { skill.TotalCDTime = actionData.TotalTimeMS; } } this.PushLaunchSkillEvent(skill.ActionIndex); } if (IsNoneBlock) { unit.SetNoneBlockTimeMS(this.curActionTotalTimes); } if (current_action.IsMoveToTarget) { //先寻路// checkMoveToTarget(current_action); } else if (current_action.IsJumpToTarget) { //计算跳跃距离// checkJumpToTarget(current_action); } else { if (unit.IsSkillControllableByServer) { if (param.AutoFocusNearTarget && (targetUnit == null || !targetUnit.IsActive)) { //自动锁定目标// bool directionChange = false; targetUnit = unit.getSkillAttackableFirstTarget(this.SkillData, AttackReason.Look, ref directionChange); if (targetUnit != null && targetUnit != unit && directionChange) { unit.faceTo(targetUnit.X, targetUnit.Y); } } } } return true; } //如果为蓄力技能,通知客户端状态 if (this.current_action != null && this.current_action.SigleActionType == ActionEnum.chargeAtk) { this.skill.Owner.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle); } current_action = null; return false; } public void doKeyFrame(UnitActionData.KeyFrame kf) { // 关键帧改变状态 if (kf.ChangeStatus != null) { this.IsNoneBlock = kf.ChangeStatus.IsNoneBlock; this.IsNoneTouch = kf.ChangeStatus.IsNoneTouch; this.IsFaceToTarget = kf.ChangeStatus.IsFaceToTarget; this.IsCancelableByMove = kf.ChangeStatus.IsCancelable; this.IsCancelableBySkill = kf.ChangeStatus.IsCancelableBySkill; this.IsControlFaceable = kf.ChangeStatus.IsControlFaceable; this.IsControlMoveable = kf.ChangeStatus.IsControlMoveable; } // 如果关键帧绑定特效 if (kf.Effect != null) { unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Effect)); } // 如果关键帧绑定近战攻击 if (kf.Attack != null) { doHitAttack(kf.Attack); } // 如果关键帧绑定释放法术 if (kf.Spell != null) { float tx = unit.X; float ty = unit.Y; if (param.SpellTargetPos != null) { float td = MathVector.getDistance(unit.X, unit.Y, param.SpellTargetPos.X, param.SpellTargetPos.Y); // TargetPos超出技能范围 // if (td > SkillData.AttackRange) { // 把TargetPos拉回 // MathVector.movePolar(param.SpellTargetPos, MathVector.getDegree(unit.X, unit.Y, param.SpellTargetPos.X, param.SpellTargetPos.Y), SkillData.AttackRange - td); } // 设置法术出生点 (非自身坐标发射,比如Cannon) // if (!SkillData.IsLaunchBody) { tx = param.SpellTargetPos.X; ty = param.SpellTargetPos.Y; } } //else if(this.targetUnit != null) //{ // tx = this.targetUnit.X; // ty = this.targetUnit.Y; //} zone.unitLaunchSpell(this.skill == null ?XmdsSkillType.none : this.skill.GetSkillType(), unit, kf.Spell, tx, ty, param.TargetUnitID, param.SpellTargetPos, this.CurrentActionIndex); } // 如果关键帧绑定自己释放BUFF if (kf.SelfBuff != null) { unit.AddBuff(kf.SelfBuff, unit); } // 如果关键帧绑定单位位移 if (kf.Move != null && (targetUnit == null || kf.hitTargetMoveEnable)) { StartMove action_move = kf.Move; //if (unit.IsSkillControllableByServer) { this.start_move = unit.StartHitMove(this, unit.Direction + action_move.Direction, action_move.RotateSpeedSEC, action_move.KeepTimeMS, action_move.SpeedSEC, action_move.SpeedAdd, action_move.SpeedAcc, action_move.IsNoneTouch); this.start_move.SetFly(this, action_move.ZSpeedSEC, action_move.ZLimit, 0); } if (action_move.HasFly && !zone.IsSyncZ) { unit.queueEvent(new UnitJumpEvent(unit.ID, action_move.ZSpeedSEC, action_move.OverrideGravity, action_move.ZLimit)); } } if (kf.Blink != null) { if (kf.Blink.BeginEffect != null) { unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Blink.BeginEffect)); } unit.moveBlink(kf.Blink, param.SpellTargetPos, targetUnit); unit.SendForceSync(); if (kf.Blink.TargetEffect != null) { unit.queueEvent(new UnitEffectEvent(unit.ID, kf.Blink.TargetEffect)); } } } /// /// 近战攻击 /// /// private void doHitAttack(AttackProp attack) { float rg = unit.GetSkillAttackRange(skill.Data); if (current_action.OverrideAttackShape != null) { attack_range.Shape = (AttackShape)current_action.OverrideAttackShape.AShape; attack_range.Direction = unit.Direction; attack_range.ExpectTarget = SkillData.ExpectTarget; attack_range.BodySize = current_action.OverrideAttackShape.AttackRange; attack_range.Distance = current_action.OverrideAttackShape.AttackRange; attack_range.FanAngle = current_action.OverrideAttackShape.AttackAngle; attack_range.StripWide = current_action.OverrideAttackShape.StripWide; float dx = unit.X; float dy = unit.Y; if (current_action.OverrideAttackShape.OffsetRadius != 0) { MathVector.movePolar(ref dx, ref dy, unit.Direction, current_action.OverrideAttackShape.OffsetRadius); } using (var list = ListObjectPool.AllocAutoRelease()) { attack_range.GetShapeAttackable(list, AttackReason.Attack, SkillData, dx, dy, dx, dy, 0, unit.AoiStatus); if (list.Count > 0) { zone.unitAttackDirect(unit, new AttackSource(skill, attack), list); } } } else if (skill.Data.AttackAngle == 0) { if (targetUnit != null) { if (checkTargetRange()) { zone.unitAttackSingle( unit, new AttackSource(skill, attack), targetUnit, SkillData.ExpectTarget); } } } else { int hitcount = zone.unitAttackFan( unit, new AttackSource(skill, attack), unit.Direction, rg, skill.Data.AttackAngle, SkillData.ExpectTarget); } } /// /// 身体攻击 /// private void doBodyHit(UnitActionData current_action) { using (var list = ListObjectPool.AllocAutoRelease()) { float line_r = (current_action.BodyHitSize > 0) ? current_action.BodyHitSize : unit.BodyHitSize; zone.getObjectsRoundLineRange( Collider.Object_HitBody_TouchRoundLine, body_hited_last_pos.X, body_hited_last_pos.Y, unit.X, unit.Y, line_r, list, unit.AoiStatus); if (list.Count > 0) { CUtils.RemoveAll(list, body_hited.Values); zone.unitAttack(unit, new AttackSource(skill, current_action.BodyHit), list, SkillData.ExpectTarget); if (list.Count > 0) { for (int i = 0; i < list.Count; i++) { InstanceUnit o = list[i]; body_hited.Put(o.ID, o); } if (current_action.BodyHitNextAction) { if (nextAction()) { unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex)); } unit.SendForceSync(); } } } } } private void doMove() { start_move.IsNoneTouch = IsNoneTouch; if (start_move.IsEnd) { start_move = null; } } /// /// 防止技能位移导致单位重合 /// private void doBodyBlock(UnitActionData current_action) { if (start_move != null || move_to != null) { if (unit.ElasticOtherObjects()) { unit.SendForceSync(); } } } /// /// 移动到目标面前 /// private bool doMoveToTarget(UnitActionData current_action) { if (this.move_to_target_path == null) { if (nextAction()) { unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex)); } return true; } else if (targetUnit != null && zone.TouchObject2(unit, targetUnit)) { this.move_to_target_path = null; unit.ElasticOtherObjects(); if (nextAction()) { unit.queueEvent(new UnitSkillActionChangeEvent(unit.ID, (byte)CurrentActionIndex)); } return true; } else { float tx, ty; tx = move_to_target_path.PosX; ty = move_to_target_path.PosY; unit.faceTo(tx, ty);// = MathVector.getDegree(tx - unit.X, ty - unit.Y); if (unit.jumpToTarget(tx, ty, current_action.MoveToTargetSpeedSEC, zone.UpdateIntervalMS)) { move_to_target_path = move_to_target_path.Next; } unit.SendForceSync(); return false; } } private bool doJumpToTarget(UnitActionData action) { unit.Z = MoveHelper.CalulateParabolicHeight(action.JumpToTargetHeightZ, action.TotalTimeMS, this.current_pass_time); unit.jumpToTarget(jump_to_target_pos.X, jump_to_target_pos.Y, jump_to_target_speed_sec, zone.UpdateIntervalMS); unit.SendForceSync(); return false; } public bool setMoveTo(float x, float y) { //if(Math.Abs(this.unit.X - x) < 0.5 && Math.Abs(this.unit.Y - y) < 0.5) //{ // return true; //} if (unit.IsSkillControllableByServer) { if (IsControlMoveable && !unit.IsCannotMove) { if (move_to == null) { move_to = new Vector2(x, y); } else { move_to.SetX(x); move_to.SetY(y); } } if (IsControlFaceable) { unit.faceTo(x, y); } this.StopFaceTo = new Vector2(x - unit.X, y - unit.Y); } return false; } public void setMoveTo(Vector2 pos) { if (unit.IsSkillControllableByServer) { if (pos == null) { this.move_to = null; return; } if (IsControlMoveable && !unit.IsCannotMove) { move_to = pos; } if (IsControlFaceable) { unit.faceTo(pos.X, pos.Y); } this.StopFaceTo = new Vector2(pos.X - unit.X, pos.Y - unit.Y); } } public void block(State newState = null) { bool old_done = is_done; is_done = true; if (newState != null) { unit.changeState(newState); } else if (!old_done) { unit.doSomething(); } } /// /// 检测目标距离 /// /// private bool checkTargetRange() { return skill.checkTargetRange(targetUnit); } /// /// 检测冲锋距离 /// /// private bool checkMoveToTarget(UnitActionData action) { if (action.IsMoveToTarget) { float tx; float ty; if (getTargetPos(out tx, out ty)) { this.move_to_target_path = zone.findPath(unit.X, unit.Y, tx, ty); if (this.move_to_target_path != null) { float max = MoveHelper.GetDistance(action.TotalTimeMS, action.MoveToTargetSpeedSEC); float total = this.move_to_target_path.GetTotalDistance(); if (total > max) { move_to_target_path = null; return false; } return true; } } return false; } return true; } /// /// 检测跳跃速度 /// /// /// private bool checkJumpToTarget(UnitActionData action) { if (action.IsJumpToTarget) { float tx; float ty; if (getTargetPos(out tx, out ty)) { float distance = CMath.getDistance(unit.X, unit.Y, tx, ty); this.jump_to_target_pos = new TVector2(tx, ty); this.jump_to_target_speed_sec = distance / (action.TotalTimeMS * 0.001f); } } return true; } private bool getTargetPos(out float x, out float y) { x = unit.X; y = unit.Y; if (param.SpellTargetPos != null) { x = param.SpellTargetPos.X; y = param.SpellTargetPos.Y; return true; } else if (targetUnit != null && targetUnit != unit) { x = targetUnit.X; y = targetUnit.Y; return true; } else return false; } public void doUpdatePosByClient(UnitUpdatePosAction act) { if (!unit.IsSkillControllableByServer) { if(this.skill.GetSkillType() == XmdsSkillType.petGiveAcitve) { unit.setPos(act.x, act.y, unit.IntersectMap); unit.faceTo(act.d); } else { //暂时只管方向,不管pos if (this.IsControlMoveable && !unit.IsCannotMove) { unit.setPos(act.x, act.y, unit.IntersectMap); } if (this.IsControlFaceable) { unit.faceTo(act.d); } else { unit.SendForceSync(); } } } } public delegate void SkillLaunched(StateSkill state); private SkillLaunched mSkillLaunched; public event SkillLaunched OnSkillLaunched { add { mSkillLaunched += value; } remove { mSkillLaunched -= value; } } } internal void SetActionSubState(UnitActionStatus unitSubState) { throw new NotImplementedException(); } //-------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------- public class StatePickObject : State { readonly private TimeExpire mTimer; readonly private int mTotalTimeMS; readonly private InstanceZoneObject mPickable; private bool mIsDone = false; private string mStopReason; private string mStatus; private OnPickDone mOnDone; private OnCheckPickable mCheckTargetActive; public string StopReason { get { return mStopReason; } } /// /// 设置目标检测状态方法 /// /// check返回True,终止状态机。 public void SetCheckTargetAcvite(OnCheckPickable check) { this.mCheckTargetActive = check; } public StatePickObject(InstanceUnit unit, InstanceZoneObject pickable, int timeMS, string status, OnPickDone done) : base(unit) { this.mStatus = status; this.mTimer = new TimeExpire(timeMS); this.mPickable = pickable; this.mTotalTimeMS = timeMS; this.mOnDone = done; } public override bool onBlock(State new_state) { if (new_state is StateIdle) return mIsDone; //block by anything// return true; } protected override void onStart() { unit.SetActionStatus(UnitActionStatus.Pick); unit.queueEvent(new UnitStartPickObjectEvent(unit.ID, mTotalTimeMS, mPickable.ID, mStatus)); } protected override void onStop() { unit.queueEvent(new UnitStopPickObjectEvent(unit.ID, mStopReason)); this.mOnDone = null; mCheckTargetActive = null; } protected override void onUpdate() { if (!mPickable.Enable) { mIsDone = true; unit.doSomething(); return; } if (mCheckTargetActive != null && mCheckTargetActive(unit, mPickable, ref mStopReason)) { mIsDone = true; unit.doSomething(); return; } if (mTimer.Update(zone.UpdateIntervalMS)) { mIsDone = true; unit.doSomething(); if (mOnDone != null) { mOnDone.Invoke(unit, mPickable); } } } public delegate void OnPickDone(InstanceUnit unit, InstanceZoneObject pickable); public delegate bool OnCheckPickable(InstanceUnit unit, InstanceZoneObject pickable, ref string reason); } //--------------------------------------------------------------------------------------- #region __状态限制__ //--------------------------------------------------------------------------------------- public interface IStateNoneControllable { State AsState(); } /// /// 被击中受击过程 /// public class StateDamage : State, IStateNoneControllable { private readonly AttackSource source; private readonly InstanceUnit attacker; private float startDirection; private float rotateSpeedSEC; private bool isEnd = false; private HitMoveSpeed hitMoveSpeed; private TimeExpire damageExpire; private HashMap body_hited = new HashMap(); private IStateNoneControllable nextState; public void SetNextNoneControllable(IStateNoneControllable state) { nextState = state; } public State AsState() { return this; } public bool IsFallingDown { get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); } } public bool IsKnockDown { get { return source.OutHasKnockDown; } } public bool IsDamageProtect { get { return source.Attack.IsDamageProtect; } } public int DamageTimeMS { get { return damageExpire.TotalTimeMS; } } public bool IsHitMove { get { return hitMoveSpeed != null; } } public StateDamage(InstanceUnit unit, AttackSource source, InstanceUnit attacker) : base(unit) { this.source = source; this.attacker = attacker; this.body_hited.Put(unit.ID, unit); AttackProp.HitMoveType mtype = source.Attack.HitMoveMType; if (source.FromSpell != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype); } else if (source.FromSkill != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype); } else { this.startDirection = unit.Direction + CMath.PI_F; } if (source.OutHitMove != null) { this.startDirection += source.OutHitMove.Direction; this.rotateSpeedSEC = source.OutHitMove.RotateSpeedSEC * ((unit.RandomN.Next() % 2) == 0 ? -1 : 1); } // 计算受击时间 // int damageTime = unit.Info.DamageTimeMS; if (source.OutKnockDownTimeMS > 0) { damageTime = source.OutKnockDownTimeMS; } else if (unit.mInfo.DamageTimeMS > 0) { damageTime = unit.mInfo.DamageTimeMS; } else { damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS; } this.damageExpire = new TimeExpire(damageTime); } override public bool onBlock(State new_state) { if (isEnd) { return true; } if (new_state is StateDead) { return true; } if (new_state is StateDamage) { return onBlockNewDamage(new_state as StateDamage); } if (new_state is IStateNoneControllable) { this.SetNextNoneControllable(new_state as IStateNoneControllable); } if (unit.IsDead()) { return false; } if (new_state is StateSkill) { StateSkill ss = new_state as StateSkill; // 反击或者状态解除// if (ss.SkillData.IsCounter) { return true; } } return isEnd; } private bool onBlockNewDamage(StateDamage new_damage) { //击飞只能被击飞中断// if (this.IsFallingDown) { if (!new_damage.source.OutHasFly) { return false; } } //击倒只能被击飞或击倒中断// if (this.IsKnockDown) { if (!new_damage.source.OutHasFly) { return false; } if (!new_damage.source.OutHasKnockDown) { return false; } } //如果正在位移,需要更高优先级// if (hitMoveSpeed != null) { if (new_damage.source.OutHasFly || new_damage.source.OutHasKnockDown || new_damage.source.OutHitMove != null) { //带位移的受击,相等优先级也可以打断当前位移// if (new_damage.source.OutWeight >= this.source.OutWeight) { return true; } } else { //普通受击,更高优先级才能打断当前位移// if (new_damage.source.OutWeight > this.source.OutWeight) { return true; } } return false; } return true; } override protected void onStart() { float zgravity = 0; float zlimit = 0; bool hasHitMove = false; if (source.OutHitMove != null) { int keepTimeMs = source.OutHitMove.KeepTimeMS; float speedSEC = source.OutHitMove.SpeedSEC; if (source.Attack.HitMoveMType == AttackProp.HitMoveType.BySenderRange) { float distance = CMath.getDistance(attacker.X, attacker.Y, unit.X, unit.Y); if (distance > source.FromSpell.BodySize) { keepTimeMs = 0; speedSEC = 0; } else { float moveDistance = source.FromSpell.BodySize - distance; keepTimeMs = (int)(moveDistance * 1000 / source.OutHitMove.SpeedSEC); } } hasHitMove = true; this.hitMoveSpeed = unit.StartHitMove(this, startDirection, source.OutHitMove.RotateSpeedSEC, keepTimeMs, speedSEC, source.OutHitMove.SpeedAdd, source.OutHitMove.SpeedAcc, source.OutHitMove.IsNoneTouch); if (source.OutHasFly) { this.hitMoveSpeed.SetFly(this, source.OutHitMove.ZSpeedSEC, source.OutHitMove.OverrideGravity, source.OutHitMove.ZLimit); zgravity = source.OutHitMove.OverrideGravity; zlimit = source.OutHitMove.ZLimit; } } else if (source.OutHasFly) { hasHitMove = true; this.hitMoveSpeed = unit.StartHitMove(this, startDirection, 0, 0, // 如果击飞,则计算按落地时间 // zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_SEC, zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_ADD, zone.Templates.CFG.OBJECT_DAMAGE_FLY_SPEED_ACC, false); this.hitMoveSpeed.SetFly(this, zone.Templates.CFG.OBJECT_DAMAGE_FLY_ZSPEED_SEC, 0, 0); } int moveTime = 0; float zspeed = 0; if (hitMoveSpeed != null) { moveTime = hitMoveSpeed.TotalTimeMS; zspeed = hitMoveSpeed.ZSpeedSEC; if (source.Attack.HitMoveMType == AttackProp.HitMoveType.ToSenderCenter) { if (source.FromSpellUnit != null) { this.hitMoveSpeed.SetMoveTarget(source.FromSpellUnit, false); } else if (source.FromSkill != null) { this.hitMoveSpeed.SetMoveTarget(this.attacker, false); } } else if (source.Attack.HitMoveMType == AttackProp.HitMoveType.ToSenderBodySize) { if (source.FromSpellUnit != null) { this.hitMoveSpeed.SetMoveTarget(source.FromSpellUnit, true); } else if (source.FromSkill != null) { this.hitMoveSpeed.SetMoveTarget(this.attacker, true); } } } unit.queueEvent(new UnitDamageEvent( unit.ID, DamageTimeMS, moveTime, zspeed, zgravity, zlimit, source.OutHasKnockDown, source.Attack)); if (hasHitMove) { unit.SetActionStatus(UnitActionStatus.HitMove); } else { unit.SetActionStatus(UnitActionStatus.Damage); } } override protected void onUpdate() { if (hitMoveSpeed != null) { if (hitMoveSpeed.IsEnd) { hitMoveSpeed = null; if (source.Attack.FlyFallenDownAttack != null) { doFlyDownAttack(); } } else if (source.Attack.HitMoveBodyAttack != null) { doBodyAttack(); } } else if (damageExpire != null) { if (damageExpire.Update(zone.UpdateIntervalMS)) { damageExpire = null; } } else { end(); } } override protected void onStop() { if (unit.IsStun) { unit.changeState(new StateStun(unit)); } else if (nextState != null) { unit.changeState(nextState.AsState()); } } private void end() { if (unit.IsDead()) { isEnd = true; unit.changeState(new StateDead(unit, attacker)); } else if (unit.IsStun) { unit.SetActionStatus(UnitActionStatus.Stun); } else { isEnd = true; unit.doSomething(); } } /// /// 自己落地摔一下 /// private void doFlyDownAttack() { unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack)); } /// /// 飞行过程中打别人 /// private void doBodyAttack() { using (var list = ListObjectPool.AllocAutoRelease()) { zone.getObjectsRoundLineRange( Collider.Object_HitBody_TouchRoundLine, hitMoveSpeed.PrevX, hitMoveSpeed.PrevY, unit.X, unit.Y, unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize, list, unit.AoiStatus); if (list.Count > 0) { CUtils.RemoveAll(list, body_hited.Values); zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget); if (list.Count > 0) { for (int i = 0; i < list.Count; i++) { InstanceUnit o = list[i]; body_hited.Put(o.ID, o); } } } } } } /// /// 死了,而且是被艹翻的,暴击打死然后击退 /// public class StateDeadFuckFuck : State, IStateNoneControllable { private readonly AttackSource source; private readonly InstanceUnit attacker; private float startDirection; private bool isEnd = false; private HitMoveSpeed hitMoveSpeed; private TimeExpire damageExpire; private HashMap body_hited = new HashMap(); private IStateNoneControllable nextState; public void SetNextNoneControllable(IStateNoneControllable state) { nextState = state; } public State AsState() { return this; } public bool IsFallingDown { get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); } } public bool IsKnockDown { get { return source.OutHasKnockDown; } } public bool IsDamageProtect { get { return source.Attack.IsDamageProtect; } } public int DamageTimeMS { get { return damageExpire.TotalTimeMS; } } public bool IsHitMove { get { return hitMoveSpeed != null; } } public StateDeadFuckFuck(InstanceUnit unit, AttackSource source, InstanceUnit attacker, HitMoveType movetype) : base(unit) { this.source = source; this.attacker = attacker; this.body_hited.Put(unit.ID, unit); HitMoveType mtype = movetype; if (source.FromSpell != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype); } else if (source.FromSkill != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype); } else { this.startDirection = unit.Direction + CMath.PI_F; } // 计算受击时间 // int damageTime = unit.Info.DamageTimeMS; if (source.OutKnockDownTimeMS > 0) { damageTime = source.OutKnockDownTimeMS; } else if (unit.mInfo.DamageTimeMS > 0) { damageTime = unit.mInfo.DamageTimeMS; } else { damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS; } this.damageExpire = new TimeExpire(damageTime); } override public bool onBlock(State new_state) { if (isEnd) { return true; } if (new_state is StateDead) { return true; } if (new_state is IStateNoneControllable) { this.SetNextNoneControllable(new_state as IStateNoneControllable); } if (unit.IsDead()) { return false; } if (new_state is StateDamage) { return unit.CanWhiplashDeadBody; } if (new_state is StateRebirth) { return true; } return isEnd; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Dead); float zgravity = 0; float zlimit = 0; if (true) { int keepTimeMs = 0; int moveDistance = new Random().Next(2, 12); float speedSEC = 15; keepTimeMs = (int)(moveDistance * 1000 / speedSEC); //speedSEC = new Random().Next(0, 11); this.hitMoveSpeed = unit.StartHitMove(this, startDirection, 0, keepTimeMs, speedSEC, 0, 0, false); } int moveTime = 0; float zspeed = 0; if (hitMoveSpeed != null) { moveTime = hitMoveSpeed.TotalTimeMS; zspeed = hitMoveSpeed.ZSpeedSEC; } unit.queueEvent(new UnitDamageEvent( unit.ID, DamageTimeMS, moveTime, zspeed, zgravity, zlimit, source.OutHasKnockDown, source.Attack)); //unit.SetActionStatus(UnitActionStatus.Dead); } override protected void onUpdate() { if (hitMoveSpeed != null) { if (hitMoveSpeed.IsEnd) { hitMoveSpeed = null; if (source.Attack.FlyFallenDownAttack != null) { doFlyDownAttack(); } } else if (source.Attack.HitMoveBodyAttack != null) { doBodyAttack(); } } else if (damageExpire != null) { if (damageExpire.Update(zone.UpdateIntervalMS)) { damageExpire = null; } } else { end(); } } override protected void onStop() { if (unit.IsStun) { unit.changeState(new StateStun(unit)); } else if (nextState != null) { unit.changeState(nextState.AsState()); } } private void end() { isEnd = true; unit.changeState(new StateDead(unit, attacker)); } /// /// 自己落地摔一下 /// private void doFlyDownAttack() { unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack)); } /// /// 飞行过程中打别人 /// private void doBodyAttack() { using (var list = ListObjectPool.AllocAutoRelease()) { zone.getObjectsRoundLineRange( Collider.Object_HitBody_TouchRoundLine, hitMoveSpeed.PrevX, hitMoveSpeed.PrevY, unit.X, unit.Y, unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize, list, unit.AoiStatus); if (list.Count > 0) { CUtils.RemoveAll(list, body_hited.Values); zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget); if (list.Count > 0) { for (int i = 0; i < list.Count; i++) { InstanceUnit o = list[i]; body_hited.Put(o.ID, o); } } } } } } /// /// 死了,而且是被艹翻的,暴击打死然后击退 /// public class StateDeadFuck : State, IStateNoneControllable { private readonly AttackSource source; private readonly InstanceUnit attacker; private float startDirection; private bool isEnd = false; private HitMoveSpeed hitMoveSpeed; private TimeExpire damageExpire; private HashMap body_hited = new HashMap(); private IStateNoneControllable nextState; public void SetNextNoneControllable(IStateNoneControllable state) { nextState = state; } public State AsState() { return this; } public bool IsFallingDown { get { return (hitMoveSpeed != null && hitMoveSpeed.IsFly && unit.Z > 0); } } public bool IsKnockDown { get { return source.OutHasKnockDown; } } public bool IsDamageProtect { get { return source.Attack.IsDamageProtect; } } public int DamageTimeMS { get { return damageExpire.TotalTimeMS; } } public bool IsHitMove { get { return hitMoveSpeed != null; } } public StateDeadFuck(InstanceUnit unit, AttackSource source, InstanceUnit attacker) : base(unit) { this.source = source; this.attacker = attacker; this.body_hited.Put(unit.ID, unit); AttackProp.HitMoveType mtype = AttackProp.HitMoveType.BySenderPosition; if (source.FromSpell != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, source.FromSpellUnit, mtype); } else if (source.FromSkill != null) { this.startDirection = MoveHelper.CalculateHitMoveDirection(unit, attacker, mtype); } else { this.startDirection = unit.Direction + CMath.PI_F; } // 计算受击时间 // int damageTime = unit.Info.DamageTimeMS; if (source.OutKnockDownTimeMS > 0) { damageTime = source.OutKnockDownTimeMS; } else if (unit.mInfo.DamageTimeMS > 0) { damageTime = unit.mInfo.DamageTimeMS; } else { damageTime = zone.Templates.CFG.OBJECT_DAMAGE_TIME_MS; } this.damageExpire = new TimeExpire(damageTime); } override public bool onBlock(State new_state) { if (isEnd) { return true; } if (new_state is StateDead) { return true; } if (new_state is IStateNoneControllable) { this.SetNextNoneControllable(new_state as IStateNoneControllable); } if (unit.IsDead()) { return false; } if (new_state is StateDamage) { return unit.CanWhiplashDeadBody; } if (new_state is StateRebirth) { return true; } return isEnd; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Dead); float zgravity = 0; float zlimit = 0; if (true) { int keepTimeMs = 0; float speedSEC = 3;//这个数字要随机1-10 speedSEC = new Random().Next(0, 11); this.hitMoveSpeed = unit.StartHitMove(this, startDirection, 0, keepTimeMs, speedSEC, 0, 0, false); if (true) { this.hitMoveSpeed.SetFly(this, 15,//source.OutHitMove.ZSpeedSEC 0, 0); zgravity = 0; zlimit = 0; } } int moveTime = 0; float zspeed = 0; if (hitMoveSpeed != null) { moveTime = hitMoveSpeed.TotalTimeMS; zspeed = hitMoveSpeed.ZSpeedSEC; } unit.queueEvent(new UnitDamageEvent( unit.ID, DamageTimeMS, moveTime, zspeed, zgravity, zlimit, source.OutHasKnockDown, source.Attack)); unit.SetActionStatus(UnitActionStatus.Dead); } override protected void onUpdate() { if (hitMoveSpeed != null) { if (hitMoveSpeed.IsEnd) { hitMoveSpeed = null; if (source.Attack.FlyFallenDownAttack != null) { doFlyDownAttack(); } } else if (source.Attack.HitMoveBodyAttack != null) { doBodyAttack(); } } else if (damageExpire != null) { if (damageExpire.Update(zone.UpdateIntervalMS)) { damageExpire = null; } } else { end(); } } override protected void onStop() { if (unit.IsStun) { unit.changeState(new StateStun(unit)); } else if (nextState != null) { unit.changeState(nextState.AsState()); } } private void end() { isEnd = true; unit.changeState(new StateDead(unit, attacker)); } /// /// 自己落地摔一下 /// private void doFlyDownAttack() { unit.doHitAttack(attacker, source.GenAttackSource(source.Attack.FlyFallenDownAttack)); } /// /// 飞行过程中打别人 /// private void doBodyAttack() { using (var list = ListObjectPool.AllocAutoRelease()) { zone.getObjectsRoundLineRange( Collider.Object_HitBody_TouchRoundLine, hitMoveSpeed.PrevX, hitMoveSpeed.PrevY, unit.X, unit.Y, unit.BodyBlockSize + source.Attack.HitMoveBodyAttackSize, list, unit.AoiStatus); if (list.Count > 0) { CUtils.RemoveAll(list, body_hited.Values); zone.unitAttack(attacker, source.GenAttackSource(source.Attack.HitMoveBodyAttack), list, source.FromExpectTarget); if (list.Count > 0) { for (int i = 0; i < list.Count; i++) { InstanceUnit o = list[i]; body_hited.Put(o.ID, o); } } } } } } /// /// 死亡状态 /// public class StateDead : State, IStateNoneControllable { private TimeExpire dead_time; private TimeExpire rebirth_time; private InstanceUnit attacker; private bool crushed; private List> dead_delayTimes = new List>(); public StateDead(InstanceUnit unit, InstanceUnit attacker, bool crush = false) : base(unit) { this.attacker = attacker; this.crushed = crush; } public State AsState() { return this; } override public bool onBlock(State new_state) { if (new_state is StateDamage) { return unit.CanWhiplashDeadBody; } if (new_state is StateRebirth) { return true; } return !unit.IsDead(); } override protected void onStart() { //某些状态帧下死亡调用漏掉了 if (unit.IsNeedProcessDead()) { unit.Parent.cb_unitDeadCallBack(unit, this.attacker); } unit.SetActionStatus(UnitActionStatus.Dead); this.rebirth_time = new TimeExpire(unit.mInfo.RebirthTimeMS); this.dead_time = new TimeExpire(unit.mInfo.DeadTimeMS); if (unit.Info.DeadLaunchSpell != null) { // 自爆法术 zone.unitLaunchSpell(XmdsSkillType.none, unit, unit.Info.DeadLaunchSpell, unit.X, unit.Y); } // Boss 死亡之后灵魂飘到击杀者身上 if (unit.mInfo.DeadDelayTimeMS > 0) { dead_delayTimes.Clear(); for (var i = 0; i < unit.Info.DeadDelaySpellNumber; i++) { this.dead_delayTimes.Add(new TimeExpire( unit.mInfo.DeadDelayTimeMS + i * unit.Info.DeadDelaySpellIntervalMS)); } } } override protected void onUpdate() { if (dead_time.Update(zone.UpdateIntervalMS)) { if (unit.mInfo.RebirthTimeMS <= 0) { zone.RemoveObject(unit); } //跨服场景中,单位死亡,需要移除单位,然后才能复活 if (unit.IsDead() && unit.IsPlayer && unit.GetSceneType() >= CommonAI.Data.SceneType.CROSS_SERVER_NEW) { // zone.RemoveObject(unit); unit.DeadHide = true; } } if (rebirth_time.Update(zone.UpdateIntervalMS)) { if (unit.mInfo.RebirthTimeMS > 0) { unit.startRebirth(); } } for (var i = 0; i < this.dead_delayTimes.Count; i++) { if (dead_delayTimes[i] != null && dead_delayTimes[i].Update(zone.UpdateIntervalMS)) { zone.unitLaunchSpell(XmdsSkillType.none, unit, unit.Info.DeadDelayLaunchSpell, unit.X, unit.Y, attacker == null ? 0 : ((InstanceUnit)attacker).mSyncInfo.ObjectID); dead_delayTimes[i] = null; } } } override protected void onStop() { //unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 复活 /// public class StateRebirth : State, IStateNoneControllable { private bool is_done = false; private int max_hp = 0; private int max_mp = 0; public StateRebirth(InstanceUnit unit, int max_hp, int max_mp) : base(unit) { this.max_hp = max_hp; this.max_mp = max_mp; } public State AsState() { return this; } override public bool onBlock(State new_state) { return is_done; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Rebirth); } override protected void onUpdate() { this.is_done = true; unit.doRebirth(max_hp, max_mp); unit.doSomething(); } override protected void onStop() { } } //--------------------------------------------------------------------------------------- /// /// 眩晕状态 /// public class StateStun : State, IStateNoneControllable { public StateStun(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { if (new_state is StateDamage) { return true; } if (unit.IsDead() && new_state is StateDead) { return true; } if (new_state is StateSkill) { StateSkill ss = new_state as StateSkill; // 反击或者状态解除// if (ss.SkillData.IsCounter) { return true; } } return !unit.IsStun; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Stun); } override protected void onUpdate() { if (!unit.IsStun) { unit.doSomething(); } } override protected void onStop() { //unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 不可移动状态 /// public class StateChuanGongA : State, IStateNoneControllable { private bool markRemove; public StateChuanGongA(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { if (this.markRemove) { return true; } return unit.chuangongTime < CommonLang.CUtils.localTimeMS; } public override void MarkRemove() { this.markRemove = true; } override protected void onStart() { this.markRemove = false; unit.chuangongTime = CommonLang.CUtils.localTimeMS + 60000; unit.SetActionStatus(UnitActionStatus.ChuanGongA); } override protected void onUpdate() { if (this.markRemove) { unit.startIdle(); } else if (unit.chuangongTime < CommonLang.CUtils.localTimeMS) { unit.doSomething(); } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 不可移动状态 /// public class StateChuanGongB : State, IStateNoneControllable { private bool markRemove; public StateChuanGongB(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { if (this.markRemove) { return true; } return unit.chuangongTime < CommonLang.CUtils.localTimeMS; } public override void MarkRemove() { this.markRemove = true; } override protected void onStart() { this.markRemove = false; unit.chuangongTime = CommonLang.CUtils.localTimeMS + 60000; unit.SetActionStatus(UnitActionStatus.ChuanGongB); } override protected void onUpdate() { if (this.markRemove) { unit.startIdle(); } else if (unit.chuangongTime < CommonLang.CUtils.localTimeMS) { unit.doSomething(); } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 不可移动状态 净妖,和传功一样锁定4秒,时间变量用传功的 /// public class StateClearYaoQi : State, IStateNoneControllable { public StateClearYaoQi(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { return unit.chuangongTime < CommonLang.CUtils.localTimeMS; } override protected void onStart() { unit.chuangongTime = CommonLang.CUtils.localTimeMS + 4000; unit.SetActionStatus(UnitActionStatus.ClearYaoQi); } override protected void onUpdate() { if (unit.chuangongTime < CommonLang.CUtils.localTimeMS) { unit.doSomething(); } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 打坐 /// public class StateDaZuo : State { private float startX; private float startY; private long lockEndTime; private bool markRemove; public StateDaZuo(InstanceUnit unit, int time) : base(unit) { int lockTime = Math.Max(1, time); //锁定短暂时间,避免一打坐就被客户端取消了。 lockEndTime = 0;// CommonLang.CUtils.localTimeMS + lockTime * 1000; } public override void MarkRemove() { this.markRemove = true; } override public bool onBlock(State new_state) { if (this.markRemove) { return true; } if (CommonLang.CUtils.localTimeMS < lockEndTime) { return false; } if (new_state is StateIdle) { return false; } return true; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.DaZuo); } override protected void onUpdate() { if(this.markRemove) { unit.startIdle(); } else if(lockEndTime > CommonLang.CUtils.localTimeMS) { startX = unit.X; startY = unit.Y; } else if (unit.X != startX || unit.Y != startY) { unit.doSomething(); } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 打坐恢复血量 /// public class StateDaZuoRecoveryAttr : State { private long endTime;//回血结束时间 private bool markRemove; private int sustainTime; //持续时间 private long nextRecoveryTime; //下一次恢复时间 public StateDaZuoRecoveryAttr(InstanceUnit unit, int time) : base(unit) { endTime = CommonLang.CUtils.CurrentTimeMS + time*1000; sustainTime = time-3; //减去3是因为等待坐下去后才开始回血 nextRecoveryTime = CommonLang.CUtils.CurrentTimeMS+2350; //2350是客户端坐下去整个动作的时间,等待动作播放完成,开始回血 } public override void MarkRemove() { this.markRemove = true; } override public bool onBlock(State new_state) { return true; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.DaZuoRecoveryAttr); } override protected void onUpdate() { if(this.markRemove) { unit.startIdle(); } else { if (unit.Virtual.GetBattleStatus() != BattleStatus.None) { unit.startIdle(); return; } if (CommonLang.CUtils.CurrentTimeMS > endTime) { unit.startIdle(); return; } if (nextRecoveryTime < CommonLang.CUtils.CurrentTimeMS) { int Recover = 0; //恢复主角血量 // if (unit.CurrentHP < unit.MaxHP) //{ Recover = (int)(unit.MaxHP / sustainTime); /*if (unit.CurrentHP + Recover > unit.MaxHP) { Recover = unit.MaxHP - unit.CurrentHP; }*/ unit.add_hp(Recover); // } //恢复宠物血量 InstanceUnit petUnit = unit.Virtual.GetPetUnit(); if (petUnit != null) { if (petUnit.CurrentHP < petUnit.MaxHP && petUnit.Virtual.GetBattleStatus() == BattleStatus.None) { Recover = (int)(petUnit.MaxHP / sustainTime); if (petUnit.CurrentHP + Recover > petUnit.MaxHP) { Recover = petUnit.MaxHP - petUnit.CurrentHP; } petUnit.add_hp(Recover); } } nextRecoveryTime = CommonLang.CUtils.CurrentTimeMS + 1 * 1000; } } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 随从向玩家瞬移 /// public class PetLockState : State { private long endTime;//瞬移后定住时间 private bool markRemove; public PetLockState(InstanceUnit unit) : base(unit) { endTime = CommonLang.CUtils.CurrentTimeMS + 1*1000; //持续时间1秒 } public override void MarkRemove() { this.markRemove = true; } override public bool onBlock(State new_state) { return true; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.PetLock); } override protected void onUpdate() { if(this.markRemove) { unit.startIdle(); } else { if (CommonLang.CUtils.CurrentTimeMS > endTime) { unit.startIdle(); return; } } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 渡劫场景,不能移动 /// public class StateDuJie : State, IStateNoneControllable { public StateDuJie(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { return unit.chuangongTime < CommonLang.CUtils.localTimeMS; } override protected void onStart() { // 管他多长时间,锁一个小时再说 unit.chuangongTime = CommonLang.CUtils.localTimeMS + 3600000; unit.SetActionStatus(UnitActionStatus.CrossRobbery); } override protected void onUpdate() { //if (unit.chuangongTime < CommonLang.CUtils.localTimeMS) //{ // unit.doSomething(); //} } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } /// /// 渡劫场景,不能移动 /// public class StateTransport : State, IStateNoneControllable { private long mLockEndTime = 0; public StateTransport(InstanceUnit unit) : base(unit) { } public State AsState() { return this; } override public bool onBlock(State new_state) { if(new_state is StateSkill) { return true; } return unit.chuangongTime < CommonLang.CUtils.localTimeMS; } override protected void onStart() { // 管他多长时间,锁定300ms this.mLockEndTime = CommonLang.CUtils.localTimeMS + 250; unit.SetActionStatus(UnitActionStatus.Transport); //System.Console.WriteLine("开始传送状态:" + CommonLang.CUtils.localTimeMS); } override protected void onUpdate() { if (this.mLockEndTime <= CommonLang.CUtils.localTimeMS) { unit.doSomething(); } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); //System.Console.WriteLine("end传送状态:" + CommonLang.CUtils.localTimeMS); } } //--------------------------------------------------------------------------------------- /// /// 状态限制移动 /// abstract public class StateMoveNoneControllable : State, IStateNoneControllable { private TimeExpire mExpire; private MoveAI mMoveAI; private MoveBlockResult mLastResult; public MoveBlockResult LastMoveResult { get { return mLastResult; } } public State AsState() { return this; } public StateMoveNoneControllable(InstanceUnit unit, int timeMS) : base(unit) { this.mExpire = new TimeExpire(timeMS); this.mMoveAI = new MoveAI(unit, false); } /// /// 搜索要去的地方 /// /// protected abstract Vector2 FindTargetPos(); public override bool onBlock(State new_state) { if (new_state is StateDead) { return true; } if (new_state is StateDamage) { (new_state as StateDamage).SetNextNoneControllable(this); return true; } if (new_state is StateSkill) { StateSkill ss = new_state as StateSkill; // 反击或者状态解除// if (ss.SkillData.IsCounter) { return true; } } return mExpire.IsEnd; } protected override void onStart() { Vector2 target = this.FindTargetPos(); this.mMoveAI.FindPath(target.X, target.Y); } protected override void onUpdate() { if (mExpire.Update(zone.UpdateIntervalMS)) { unit.doSomething(); } else { mLastResult = mMoveAI.Update(); if ((mLastResult.result & MoveResult.RESULTS_MOVE_END) != 0) { Vector2 target = this.FindTargetPos(); this.mMoveAI.FindPath(target.X, target.Y); } } } protected override void onStop() { } } /// /// 拾取状态 /// public class StateAutoPick : State { private InstanceItem mPickItem; //要自动拾取的物品 private MoveAI mMoveAi; bool mIsEnd; public StateAutoPick(InstanceUnit unit, InstanceItem item) : base(unit) { this.mPickItem = item; this.mMoveAi = new MoveAI(unit); this.mMoveAi.FindPath(item.X, item.Y); } override public bool onBlock(State new_state) { if (unit.IsDead()) { return true; } return true; } override protected void onStart() { //unit.SetActionStatus(UnitActionStatus.AutoPick); } override protected void onUpdate() { if (mIsEnd || this.mPickItem.IsDead() || !this.mPickItem.Enable || this.unit.Virtual.GetBattleStatus() != BattleStatus.None) { unit.doSomething(); } else { MoveBlockResult result = mMoveAi.Update(); if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0) { mIsEnd = true; unit.doSomething(); } else { float r = Math.Max(zone.MinStep, unit.BodyBlockSize); if (CMath.includeRoundPoint(unit.X, unit.Y, r, mPickItem.X, mPickItem.Y)) { mIsEnd = true; unit.doSomething(); } } } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } //--------------------------------------------------------------------------------------- /// /// 逃跑状态 /// public class StateEscape : StateMoveNoneControllable { private float mDistance; public StateEscape(InstanceUnit unit, int timeMS, float distance = 0) : base(unit, timeMS) { if (distance > 0) { this.mDistance = distance; } else { this.mDistance = unit.Info.GuardRange; } } protected override void onStart() { base.onStart(); unit.SetActionStatus(UnitActionStatus.Escape); } protected override Vector2 FindTargetPos() { var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, unit.X, unit.Y, mDistance); return new Vector2(node.BX, node.BY); } } //--------------------------------------------------------------------------------------- /// /// 混乱状态 /// public class StateChaos : StateMoveNoneControllable { public StateChaos(InstanceUnit unit, int timeMS) : base(unit, timeMS) { } protected override void onStart() { base.onStart(); unit.SetActionStatus(UnitActionStatus.Chaos); } protected override void onStop() { base.onStop(); } protected override Vector2 FindTargetPos() { var node = zone.PathFinder.FindNearRandomMoveableNode(zone.RandomN, unit.X, unit.Y, unit.Info.GuardRange); return new Vector2(node.BX, node.BY); } } //--------------------------------------------------------------------------------------- /// /// 破定 /// public class StateBreakShield : State { private long mStateEndTime; public StateBreakShield(InstanceUnit unit) : base(unit) { this.mStateEndTime = CommonLang.CUtils.localTimeMS + GlobalData.SHIELD_BREAK_HOLDTIME; } protected override void onStart() { unit.SetActionStatus(UnitActionStatus.BreakShield); unit.AddBuff(GlobalData.SHIELD_BREAK_BUFF, 0, true); } protected override void onUpdate() { if(CommonLang.CUtils.localTimeMS > this.mStateEndTime) { unit.startIdle(); } } public override bool onBlock(State new_state) { if (CommonLang.CUtils.localTimeMS > this.mStateEndTime) { return true; } else if (new_state is StateDead) { return true; } return false; } protected override void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); //unit.removeBuff(GlobalData.SHIELD_BREAK_BUFF); unit.Virtual.StartRecoverMP(); } } //--------------------------------------------------------------------------------------- #endregion #region __AI行为__ //--------------------------------------------------------------------------------------- /// /// 移动状态 /// abstract public class StateFollow : State { public enum MoveState { Hold, Move, } // 被追目标 protected IPositionObject target; // 如果被单位碰撞,则向左或右挪动// readonly private MoveAI moveAI; // 检测切换走停的间隔时间 // readonly private State state = new State(MoveState.Move); readonly private bool begin_in_min_range; // 检测切换走停的间隔时间 // private TimeInterval start_move_hold_time; public abstract bool IsActive { get; } public MoveAI MoveAI { get { return moveAI; } private set { } } public bool IsNoWay { get { if (moveAI != null) { return moveAI.IsNoWay; } return false; } } public IPositionObject Target { get { return target; } } public MoveState FollowState { get { return state.Value; } } /// /// Hold到Move之间的检测间隔 /// public int StartMoveHoldTimeMS { get { return (start_move_hold_time != null) ? start_move_hold_time.IntervalTimeMS : 0; } set { if (value > 0 && value != StartMoveHoldTimeMS) { start_move_hold_time = new TimeInterval(value); } } } public StateFollow(InstanceUnit unit, InstanceZoneObject target, bool beginInMinRange = true, int holdTime = 0) : base(unit) { this.begin_in_min_range = beginInMinRange; this.target = target; this.moveAI = new MoveAI(unit, true, holdTime); } public override bool onBlock(State new_state) { return true; } protected override void onStart() { if (this.unit.Info.SumType == SummonType.AwaitMaster || cheekBeginInRange()) { state.ChangeState(MoveState.Hold); unit.SetActionStatus(UnitActionStatus.Idle); } else { state.ChangeState(MoveState.Move); unit.SetActionStatus(UnitActionStatus.Move); moveAI.FindPath(target); } } protected virtual void OnMoveAiNoWay() { } protected override void onUpdate() { if (!IsActive) { unit.doSomething(); } else if ((unit.CurrentActionSubstate & (int)UnitActionSubStatus.CanNotMove) > 0) { //不能移动,啥事也不干 } else { switch (FollowState) { case MoveState.Move: // 进入最小追踪距离 // if (CheckTargetInMinRange() == true) { changeToHold(); } else { if (moveAI.Target == null) { moveAI.FindPath(target); } moveAI.Update(); if (moveAI.IsNoWay) { this.OnMoveAiNoWay(); if (CheckTargetInMaxRange() == true) { changeToHold(); } else { unit.doSomething(); } } } break; case MoveState.Hold: // 超过最大追踪范围 // if ((start_move_hold_time == null || start_move_hold_time.Update(zone.UpdateIntervalMS)) && (CheckTargetInMaxRange() == false)) { changeToMove(); } else { if (unit.CurrentActionStatus != UnitActionStatus.Idle) { unit.SetActionStatus(UnitActionStatus.Idle); } } onUpdateFollowed(target); break; } } } protected override void onStop() { } private bool cheekBeginInRange() { if (begin_in_min_range) { return CheckTargetInMinRange(); } else { return CheckTargetInMaxRange(); } } private void changeToMove() { state.ChangeState(MoveState.Move); unit.SetActionStatus(UnitActionStatus.Move); moveAI.FindPath(target); onInRangeChanged(); onChangedToMove(target); } private void changeToHold() { state.ChangeState(MoveState.Hold); unit.SetActionStatus(UnitActionStatus.Idle); moveAI.Pause(); onInRangeChanged(); onChangedToHold(target); } /// /// 检查目标是否在跟随范围内。 /// 检测为True,停止移动。 /// protected abstract bool CheckTargetInMinRange(); /// /// 检查目标是否在跟随范围内。 /// 检测为False,开始移动。 /// protected abstract bool CheckTargetInMaxRange(); /// /// 行为改变 /// protected virtual void onInRangeChanged() { } /// /// 目标已经被追踪到 /// /// protected virtual void onUpdateFollowed(IPositionObject target) { } /// /// 开始移动 /// /// protected virtual void onChangedToMove(IPositionObject target) { } /// /// changeToHold /// /// protected virtual void onChangedToHold(IPositionObject target) { } } /// /// /// public class StateFollowObject : StateFollow { protected float distance; //protected InstanceZoneObject target; public override bool IsActive { get { var t = target as InstanceZoneObject; if (t != null) { return t.Enable; } return false; } } public float Distance { set { this.distance = value; } get { return this.distance; } } public StateFollowObject(InstanceUnit unit, InstanceZoneObject target, int holdTime = 0) : base(unit, target, true, holdTime) { //this.target = target; this.distance = Target.RadiusSize + unit.BodyBlockSize * 2; } protected override bool CheckTargetInMaxRange() { return CMath.includeRoundPoint( unit.X, unit.Y, distance * 2, Target.X, Target.Y); } protected override bool CheckTargetInMinRange() { return CMath.includeRoundPoint( unit.X, unit.Y, distance, Target.X, Target.Y); } } public class VStateFollowLeader : StateFollowObject { public VStateFollowLeader(InstanceUnit unit, InstanceZoneObject target, int holdTime = 0) : base(unit, target, holdTime) { } } /// /// /// public class StateFollowAndGuard : StateFollow { private readonly float distance_min; private readonly float distance_max; private readonly InstanceUnit targetUnit; public InstanceUnit TargetUnit { get { return targetUnit; } } public override bool IsActive { get { return targetUnit.Enable; } } public StateFollowAndGuard(InstanceUnit unit, InstanceUnit target, float minDistance, float maxDistance) : base(unit, target) { this.targetUnit = target; this.distance_min = Math.Max(minDistance, target.BodyBlockSize + unit.BodyBlockSize * 2); this.distance_max = Math.Max(maxDistance, distance_min); } protected override bool CheckTargetInMinRange() { return CMath.includeRoundPoint( unit.X, unit.Y, distance_min, Target.X, Target.Y); } protected override bool CheckTargetInMaxRange() { return CMath.includeRoundPoint( unit.X, unit.Y, distance_max, Target.X, Target.Y); } } /// /// /// public class StateFollowAndAttack : StateFollow { /*readonly private*/ InstanceUnit targetUnit; private SkillTemplate.CastTarget expectTarget; private TimeInterval checkAdjustLaunchSkillTime; private SkillState launchSkill; private bool can_auto_focus_near_target; private bool can_random_skill = true; private bool can_attack = true; private float min_distance; private float max_distance; /// /// 是否追踪 /// /// override public bool IsActive { get { return can_attack && targetUnit.IsActive; } } public SkillState ExpectSkillState { get { return launchSkill; } set { launchSkill = value; expectTarget = value.Data.ExpectTarget; } } public SkillTemplate ExpectSkill { get { return (launchSkill != null) ? launchSkill.Data : unit.DefaultSkill; } } public InstanceUnit TargetUnit { get { return targetUnit; } set { targetUnit = value; } } public SkillTemplate.CastTarget ExpectTarget { get { return expectTarget; } } public bool IsLaunchRandomSkill { get { return can_random_skill; } set { can_random_skill = value; } } public bool IsAutoFocusNearTarget { get { return can_auto_focus_near_target; } set { can_auto_focus_near_target = value; } } public StateFollowAndAttack( InstanceUnit unit, InstanceUnit target, SkillTemplate.CastTarget expectTarget = SkillTemplate.CastTarget.Enemy, bool autoFocusNearTarget = false) : base(unit, target, false) { this.targetUnit = target; // Console.WriteLine(" - - - - StateFollowAndAttack - - - - " + this.TargetUnit.Name); this.expectTarget = expectTarget; this.can_auto_focus_near_target = autoFocusNearTarget; this.StartMoveHoldTimeMS = zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_HOLD_TIME_MS; } protected override void onStart() { this.checkAdjustLaunchSkillTime = new TimeInterval(zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_HOLD_TIME_MS); this.launchSkill = unit.getRandomLaunchableExpectSkill(expectTarget); base.onStart(); } protected override void onUpdateFollowed(IPositionObject target) { this.can_attack = zone.IsAttackable(unit, targetUnit, expectTarget, AttackReason.Tracing, this.ExpectSkill); if (can_attack) { unit.faceTo(target.X, target.Y); if (TryLaunchSkill() == null) { SkillTemplate expect_skill = ExpectSkill; if (expect_skill != null && expect_skill.AttackKeepRange > 0) { if (checkAdjustLaunchSkillTime.IntervalTimeMS == 0 || checkAdjustLaunchSkillTime.Update(zone.UpdateIntervalMS)) { if (CUtils.RandomPercent(zone.RandomN, zone.Templates.CFG.AI_FOLLOW_AND_ATTACK_ADJUST_ESCAPE_PCT)) { unit.startAdjustLaunchSkill(expect_skill, targetUnit, this.OnEndAdjustKeepRange); } } } } } } protected override void onUpdate() { if (IsActive) { resetMaxMinRange(); } base.onUpdate(); } private void resetMaxMinRange() { var expect_skill = ExpectSkillState; min_distance = unit.BodyBlockSize + targetUnit.BodyBlockSize; max_distance = Math.Max(min_distance, unit.BodyBlockSize + targetUnit.BodyHitSize); bool needCheck = true; if (expect_skill == null) { var new_skill = unit.getRandomLaunchableExpectSkill(targetUnit, expectTarget, AttackReason.Tracing, true); if (new_skill != null) { ExpectSkillState = new_skill; expect_skill = new_skill; needCheck = false; } } if (expect_skill != null) { if (can_random_skill) { if (needCheck == true && !expect_skill.checkTargetRange(targetUnit)) { var new_skill = unit.getRandomLaunchableExpectSkill(targetUnit, expectTarget, AttackReason.Tracing, true); if (new_skill != null) { ExpectSkillState = new_skill; expect_skill = new_skill; } } } float skill_distance = unit.GetSkillAttackRange(expect_skill.Data); float half = (skill_distance - min_distance) / 2; if (expect_skill.Data.AttackKeepRange > 0 && expect_skill.Data.AttackRange > expect_skill.Data.AttackKeepRange) { min_distance = Math.Max(min_distance, unit.GetSkillAttackRange(expect_skill.Data.AttackKeepRange) + targetUnit.BodyBlockSize); max_distance = Math.Max(max_distance, min_distance); } else if (half > 0) { min_distance = min_distance + half; max_distance = Math.Max(max_distance, min_distance); } else { min_distance = Math.Max(min_distance, skill_distance + targetUnit.BodyBlockSize); max_distance = Math.Max(max_distance, min_distance); } max_distance = Math.Max(max_distance, skill_distance + targetUnit.BodyHitSize); } } protected override bool CheckTargetInMaxRange() { return CMath.includeRoundPoint(unit.X, unit.Y, max_distance, targetUnit.X, targetUnit.Y); } protected override bool CheckTargetInMinRange() { return CMath.includeRoundPoint(unit.X, unit.Y, min_distance, targetUnit.X, targetUnit.Y); } protected virtual bool OnEndAdjustKeepRange(StateMove m) { unit.faceTo(Target.X, Target.Y); unit.changeState(this); return true; } protected virtual SkillTemplate TryLaunchSkill() { if (launchSkill == null) { this.launchSkill = unit.getRandomLaunchableExpectSkill(expectTarget); } StateSkill ret = null; Vector2 targetPos = null; if (launchSkill != null) { ret = unit.launchSkill(launchSkill, new InstanceUnit.LaunchSkillParam(targetUnit.ID, targetPos, can_auto_focus_near_target)); if (ret != null) { return ret.SkillData; } } if (can_random_skill) { ret = unit.launchRandomSkill(expectTarget, new InstanceUnit.LaunchSkillParam(targetUnit.ID, targetPos, can_auto_focus_near_target)); if (ret != null) { return ret.SkillData; } } return null; } } /// /// /// public class StateFollowAndPickObject : StateFollow { private readonly InstanceZoneObject targetObject; private readonly int pickTimeMS; private readonly StatePickObject.OnPickDone doneEvent; private readonly string status; public StateFollowAndPickObject(InstanceUnit unit, InstanceZoneObject target, int timeMS, StatePickObject.OnPickDone done, string status = null) : base(unit, target, false) { this.targetObject = target; this.pickTimeMS = timeMS; this.doneEvent = done; this.status = status; } public override bool IsActive { get { return targetObject.Enable; } } protected override bool CheckTargetInMinRange() { return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, targetObject.X, targetObject.Y); } protected override bool CheckTargetInMaxRange() { return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize + targetObject.BodyBlockSize, targetObject.X, targetObject.Y); } protected override void onUpdateFollowed(IPositionObject target) { unit.startPickProgressObject(targetObject, pickTimeMS, doneEvent, status); } } /// /// /// public class StateFollowAndPickItem : StateFollow { public readonly InstanceItem targetObject; private long mLockEndTime; private bool mDoPick; public StateFollowAndPickItem(InstanceUnit unit, InstanceItem target, bool doPick) : base(unit, target, false) { this.targetObject = target; this.mDoPick = doPick; } public override bool IsActive { get { return (targetObject.Enable && targetObject.IsPosValid()) || mLockEndTime > CommonLang.CUtils.localTimeMS; } } protected override bool CheckTargetInMinRange() { return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, targetObject.X, targetObject.Y); } protected override bool CheckTargetInMaxRange() { return CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize + targetObject.BodyBlockSize, targetObject.X, targetObject.Y); } protected override void onUpdateFollowed(IPositionObject target) { if (this.mDoPick && this.targetObject.Enable) { targetObject.PickItem(unit); } } public void CheckAndLockPickTime() { if(!this.targetObject.Enable && mLockEndTime == 0) { mLockEndTime = CommonLang.CUtils.localTimeMS + 350; } } protected override void onUpdate() { this.CheckAndLockPickTime(); if (!this.IsActive && unit.IsPlayer) { if (unit.DoAutoPick(true)) { return; } } base.onUpdate(); } protected override void OnMoveAiNoWay() { this.mLockEndTime = 0; targetObject.setPosNotValid(); } public override bool onBlock(State new_state) { if(/*!(new_state is StateFollowAndPickItem) && */mLockEndTime > CommonLang.CUtils.localTimeMS) { return false; } //把当前拾取弄完,再去跟随 if (new_state is VStateFollowLeader && unit.DoAutoPick(true)) { return false; } return true; } } /// /// /// public abstract class StateAttackTo : State { public IPositionObject Target { get { return target; } } public MoveBlockResult LastMovingResult { get; private set; } public MoveAI UnitMoveAI { get { return moveAI; } } // 如果被地图碰撞,则寻路 private IPositionObject target; // 如果被单位碰撞,则向左或右挪动 private MoveAI moveAI; private int holdTimeMS; private long mPeaceEndTime; public StateAttackTo(InstanceUnit unit, int move_ai_hold_time_ms = -1, int peaceTime = 0) : base(unit) { this.holdTimeMS = move_ai_hold_time_ms; this.mPeaceEndTime = CommonLang.CUtils.CurrentTimeMS + peaceTime; } override public bool onBlock(State new_state) { if(this.mPeaceEndTime > CommonLang.CUtils.CurrentTimeMS) { return false; } return true; } override protected void onStart() { if (target == null) { target = PopNextPos(); } this.moveAI = new MoveAI(unit, true, holdTimeMS); if (target != null) { this.moveAI.FindPath(target); unit.SetActionStatus(UnitActionStatus.Move); } else { unit.SetActionStatus(UnitActionStatus.Idle); } } override protected void onUpdate() { if (target == null) { unit.doSomething(); } else { LastMovingResult = this.moveAI.Update(); if (TestPopNext()) { this.target = PopNextPos(); if (target != null) { this.moveAI.FindPath(target); } } } } override protected void onStop() { } abstract protected bool HasNextPos(); abstract protected IPositionObject PopNextPos(); protected virtual bool TestPopNext() { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y)) { return true; } return false; } public virtual bool IsDone { get { if (IsStarted) { if (target == null) { return true; } if (HasNextPos()) { return false; } return TestPopNext(); } return false; } } } public class StateAttackToZoneWayPoint : StateAttackTo { // 如果被地图碰撞,则寻路 private ZoneWayPoint paths; private ZoneWayPoint prev; protected ZoneWayPoint Paths { get { return paths; } } public StateAttackToZoneWayPoint(InstanceUnit unit, ZoneWayPoint wps, int peaceTime) : base(unit, -1, peaceTime) { this.paths = wps; } protected override bool HasNextPos() { return paths != null; } protected override IPositionObject PopNextPos() { if (paths != null) { ZoneWayPoint ret = paths; ZoneWayPoint prv = prev; prev = paths; paths = paths.GetRandomNext(prv); return ret; } return null; } protected override bool TestPopNext() { if (LastMovingResult.obj != null) { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, Target.X, Target.Y)) { return true; } } else { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, Target.X, Target.Y)) { return true; } } return false; } } public class StatePatrolWayPoint : StateAttackTo { // 如果被地图碰撞,则寻路 private ZoneWayPoint paths; private ZoneWayPoint prev; private TimeExpire hold_time; private int hold_max_time_ms, hold_min_time_ms; protected ZoneWayPoint Paths { get { return paths; } } public StatePatrolWayPoint(InstanceUnit unit, ZoneWayPoint wps, int hold_max_time_ms, int hold_min_time_ms, int peaceTime) : base(unit, -1, peaceTime) { this.paths = wps; this.hold_max_time_ms = Math.Max(hold_max_time_ms, hold_min_time_ms); this.hold_min_time_ms = Math.Min(hold_max_time_ms, hold_min_time_ms); } protected override void onUpdate() { if (this.hold_time != null) { if (this.hold_time.Update(zone.UpdateIntervalMS)) { this.hold_time = null; } } else { base.onUpdate(); } } protected override bool HasNextPos() { return paths != null; } private void Hold() { if (hold_max_time_ms > 0) { unit.SetActionStatus(UnitActionStatus.Idle); this.hold_time = new TimeExpire(unit.RandomN.Next(hold_min_time_ms, hold_max_time_ms)); } } protected override IPositionObject PopNextPos() { if (paths != null) { ZoneWayPoint ret = paths; ZoneWayPoint prv = prev; prev = paths; paths = paths.GetRandomNext(prv); Hold(); return ret; } return null; } protected override bool TestPopNext() { if (LastMovingResult.obj != null) { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, Target.X, Target.Y)) { return true; } } else { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, Target.X, Target.Y)) { return true; } } return false; } } /// /// /// public class StateGuardInPosition : State { public Vector2 Target { get { return target; } } public MoveBlockResult LastMovingResult { get; private set; } // 如果被地图碰撞,则寻路 private Vector2 target; // 如果被单位碰撞,则向左或右挪动 private MoveAI moveAI; public StateGuardInPosition(InstanceUnit unit, Vector2 target) : base(unit) { this.target = target; this.moveAI = new MoveAI(unit); } override public bool onBlock(State new_state) { return true; } override protected void onStart() { this.moveAI.FindPath(target.X, target.Y); if (moveAI.IsNoWay) { unit.SetActionStatus(UnitActionStatus.Idle); } else { unit.SetActionStatus(UnitActionStatus.Move); } } override protected void onUpdate() { this.LastMovingResult = this.moveAI.Update(); if ((LastMovingResult.result & MoveResult.RESULTS_MOVE_END) != 0) { if ((LastMovingResult.result & MoveResult.MOVE_RESULT_BLOCK_MAP) != 0) { moveAI.Pause(); unit.SetActionStatus(UnitActionStatus.Idle); } else if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y)) { moveAI.Pause(); unit.SetActionStatus(UnitActionStatus.Idle); } } } override protected void onStop() { } } /// /// /// public class StateBackToPosition : State { public Vector2 Target { get { return target; } } public MoveBlockResult LastMovingResult { get; private set; } public bool IsDone { get { return isDone; } } // 如果被地图碰撞,则寻路 private Vector2 target; // 如果被单位碰撞,则向左或右挪动 private MoveAI moveAI; private bool isDone = false; public StateBackToPosition(InstanceUnit unit, Vector2 target) : base(unit) { this.target = target; this.moveAI = new MoveAI(unit); } override public bool onBlock(State new_state) { if (new_state is StateDamage) { return true; } if (new_state is StateDead) { return true; } return isDone; } override protected void onStart() { this.unit.onBack2PositionStart(); this.moveAI.FindPath(target.X, target.Y); if (moveAI.IsNoWay) { unit.SetActionStatus(UnitActionStatus.Idle); } else { unit.SetActionStatus(UnitActionStatus.Move); } } override protected void onUpdate() { this.LastMovingResult = this.moveAI.Update(); if ((LastMovingResult.result & MoveResult.RESULTS_MOVE_END) != 0) { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.Info.GuardRange, target.X, target.Y)) { isDone = true; unit.doSomething(); } else { moveAI.FindPath(target.X, target.Y); } } } override protected void onStop() { this.unit.onBack2PositionEnd(); } } protected virtual void onBack2PositionEnd() { } protected virtual void onBack2PositionStart() { } #endregion //--------------------------------------------------------------------------------------- #region __强制剧情播放__ public abstract class ForceState : State { public ForceState(InstanceUnit unit) : base(unit) { } override public bool onBlock(State new_state) { if (new_state is StateDead) return true; if (new_state is StateRebirth) return true; if (new_state is StateStun) return true; return unit.IsDead(); } } /// /// 强制移动到目标点,一般用于剧情动画 /// public class ForceStateMoveTo : ForceState { private readonly float targetX; private readonly float targetY; private bool isEnd = false; private MoveAI moveAI; public ForceStateMoveTo(InstanceUnit unit, float x, float y) : base(unit) { this.targetX = x; this.targetY = y; } override public bool onBlock(State new_state) { if (base.onBlock(new_state)) return true; return isEnd; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Move); this.moveAI = new MoveAI(unit); this.moveAI.FindPath(targetX, targetY); } override protected void onUpdate() { if (!isEnd) { unit.faceTo(targetX, targetY); MoveBlockResult result = moveAI.Update(); if ((result.result & MoveResult.MOVE_RESULT_NO_WAY) != 0) { isEnd = true; unit.doSomething(); } else if ((result.result & MoveResult.RESULTS_MOVE_END) != 0) { float r = Math.Max(zone.MinStep, unit.BodyBlockSize); if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY)) { isEnd = true; unit.doSomething(); } } else { float r = Math.Max(zone.MinStep, unit.BodyBlockSize); if (CMath.includeRoundPoint(unit.X, unit.Y, r, targetX, targetY)) { isEnd = true; unit.doSomething(); } } } } override protected void onStop() { } } public class ForceStateLaunchSkill : ForceState { private readonly int SkillID; private readonly bool IsRandom; private readonly StateStopHandler SkillOver; private StateSkill mSkillState; public ForceStateLaunchSkill(InstanceUnit unit, int skillID, bool random, StateStopHandler over = null) : base(unit) { this.SkillID = skillID; this.IsRandom = random; this.SkillOver = over; } public override bool onBlock(State new_state) { if (base.onBlock(new_state)) return true; if (new_state is StateSkill) { return true; } return mSkillState != null; } protected override void onStart() { } protected override void onUpdate() { if (IsRandom) { mSkillState = unit.launchRandomSkillForAll(new InstanceUnit.LaunchSkillParam()); } else { mSkillState = unit.launchSkill(SkillID, new InstanceUnit.LaunchSkillParam()); } if (mSkillState == null) { mSkillState = unit.launchRandomSkillForAll(new InstanceUnit.LaunchSkillParam()); } if (mSkillState != null && SkillOver != null) { mSkillState.AddStopOnce(SkillOver); } } protected override void onStop() { if (mSkillState == null && SkillOver != null) { SkillOver.Invoke(unit, this); } } } public class ForceStateIdleTime : ForceState { private readonly TimeExpire mIdleTime; public ForceStateIdleTime(InstanceUnit unit, float timeSEC) : base(unit) { mIdleTime = new TimeExpire((int)(timeSEC * 1000)); } override public bool onBlock(State new_state) { if (base.onBlock(new_state)) return true; return mIdleTime.IsEnd; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Idle); } override protected void onUpdate() { if (mIdleTime.Update(zone.UpdateIntervalMS)) { unit.doSomething(); } } override protected void onStop() { } } public class ForceStateActionTime : ForceStateIdleTime { private readonly string ActionName; public ForceStateActionTime(InstanceUnit unit, float timeSEC, string actionName) : base(unit, timeSEC) { this.ActionName = actionName; } override protected void onStart() { unit.queueEvent(new UnitDoActionEvent(unit.ID, ActionName)); } } #endregion } }