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