using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.RTS.Manhattan;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonLang;
using CommonAI.ZoneClient;
using CommonAI.Zone.Helper;
using CommonAI.Zone.Formula;
using CommonAI.Zone.Attributes;
namespace CommonAI.Zone.Instance
{
//--------------------------------------------------------------------------------------------------------
///
/// 所有自动电脑AI
///
public class InstanceGuard : InstanceUnit, IGuardUnit, ViewTrigger.ViewTriggerListener
{
protected ViewTrigger mViewTrigger;
protected HateSystem mHateSystem;
protected StateAttackTo mRunningPath;
protected StateFollowAndAttack mTracingTarget;
protected StateFollowAndGuard mGuardTarget;
protected StateBackToPosition mBackToPosition;
protected Vector2 mOrginPosition;
//protected TimeInterval mCheckInGuardLimit;
protected SimpleTrigger mNextCheckGuardLimit;
public InstanceUnit TracingTarget
{
get
{
if (mTracingTarget != null) return mTracingTarget.TargetUnit;
return null;
}
}
public InstanceGuard(InstanceZone zone, UnitInfo info, string name, int force, int level)
: base(zone, info, name, force, level)
{
//this.mCheckInGuardLimit = new TimeInterval(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);
this.mNextCheckGuardLimit = new SimpleTrigger(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);
this.OnActivated += this.onUnitActivated;
}
protected override void onAdded(bool pointLv)
{
base.onAdded(pointLv);
this.mHateSystem = TemplateManager.Factory.CreateHateSystem(this);
this.mOrginPosition = new Vector2(X, Y);
}
protected override void Disposing()
{
base.Disposing();
if (mViewTrigger != null) mViewTrigger.Dispose();
mHateSystem.Clear();
mRunningPath = null;
mTracingTarget = null;
mGuardTarget = null;
mBackToPosition = null;
mOrginPosition = null;
this.mNextCheckGuardLimit = null;
this.OnActivated -= this.onUnitActivated;
}
override protected void onResetAI()
{
mTracingTarget = null;
mHateSystem.Clear();
doSomething();
}
protected override void onDead(InstanceUnit killer)
{
base.onDead(killer);
SetEnableView(false);
}
//--------------------------------------------------------------------------------------------------------
#region View
public void SetEnableView(bool view)
{
if (mViewTrigger != null)
{
this.mViewTrigger.Enable = view && !IsNature && !IsNoneSkill;
}
}
private void initViewTrigger()
{
this.mViewTrigger = CreateViewTrigger(Parent);
if (mViewTrigger != null)
{
this.mViewTrigger.setListener(this);
}
}
protected virtual ViewTrigger CreateViewTrigger(InstanceZone zone)
{
if (Info.GuardRange > 0)
{
return new ViewTriggerRoundBody(zone, Info.GuardRange);
}
else
{
return new ViewTriggerBlind(zone);
}
}
void ViewTrigger.ViewTriggerListener.onObjectEnterView(ViewTrigger src, InstanceZoneObject obj)
{
onAddEnemy(obj as InstanceUnit, true, AttackReason.Look);
}
void ViewTrigger.ViewTriggerListener.onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj)
{
}
bool ViewTrigger.ViewTriggerListener.select(ViewTrigger src, InstanceZoneObject obj)
{
if (obj == this)
{
return false;
}
else if ((obj is InstanceUnit))
{
InstanceUnit u = obj as InstanceUnit;
if (!u.IsNature && !this.IsNature && Parent.IsAttackable(this, u, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
{
return true;
}
}
return false;
}
#endregion
//--------------------------------------------------------------------------------------------------------
#region Action
void IGuardUnit.AttackTo(ZoneWayPoint start, int peaceTime)
{
this.attackTo(start, peaceTime);
}
void IGuardUnit.SetOrginPosition(float x, float y)
{
this.setOrginPosition(x, y);
}
void IGuardUnit.PatrolWith(ZoneWayPoint start, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime)
{
this.patrolWith(start, holdMinTimeMS, holdMaxTimeMS, peaceTime);
}
bool IGuardUnit.FollowAndAttack(InstanceUnit target, AttackReason reason)
{
return this.followAndAttack(target, reason);
}
void IGuardUnit.GuardUnit(InstanceUnit vip)
{
this.guardUnit(vip);
}
public override void doSomething()
{
if (CurrentState is StateSkill)
{
var target = TracingTarget;
if (target != null)
{
if (tryMoveScatterTarget(target)) { return; }
}
}
guard();
}
///
/// 设置警戒地点,如果在寻路或保护单位,则无效
///
///
///
public virtual void setOrginPosition(float x, float y)
{
this.mOrginPosition.SetX(x);
this.mOrginPosition.SetY(y);
}
public virtual Vector2 GetOrginPosition()
{
return mOrginPosition;
}
///
/// 寻路攻击目标
///
///
///
public virtual bool followAndAttack(InstanceUnit src, AttackReason reason)
{
if (IsNoneSkill) return false;
if ((src != null))
{
if (Parent.IsAttackable(this, src, SkillTemplate.CastTarget.Enemy, reason, Info))
{
this.SetEnableView(false);
mHateSystem.Add(src);
if (TracingTarget != src)
{
//Console.WriteLine(" - - BBBBBB - - " + ((TracingTarget == null) ? "null" : TracingTarget.Name) + ", " + src.Name);
mTracingTarget = new StateFollowAndAttack(this, src);
}
changeState(mTracingTarget);
return true;
}
else
{
mHateSystem.Remove(src);
}
}
return false;
}
///
/// 寻路并一路警戒
///
///
public virtual void attackTo(ZoneWayPoint path, int peaceTime = 0)
{
this.mRunningPath = new StateAttackToZoneWayPoint(this, path, peaceTime);
changeState(this.mRunningPath);
}
///
/// 在路点范围内警戒
///
///
///
///
public virtual void patrolWith(ZoneWayPoint wp, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime = 0)
{
this.mRunningPath = new StatePatrolWayPoint(this, wp, holdMinTimeMS, holdMaxTimeMS, peaceTime);
changeState(this.mRunningPath);
}
///
/// 保护单位
///
///
public virtual void guardUnit(InstanceUnit vip)
{
if (mGuardTarget == null || !mGuardTarget.IsActive || mGuardTarget.TargetUnit != vip)
{
mGuardTarget = new StateFollowAndGuard(this, vip, this.BodyBlockSize * 2 + vip.BodyBlockSize, Info.GuardRange);
}
changeState(mGuardTarget);
}
///
/// 待机
///
public virtual void guard()
{
if(mHateSystem != null && mHateSystem.Count > 0)
{
if (followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing))
{
return;
}
}
mTracingTarget = null;
SetEnableView(true);
if (mGuardTarget != null && mGuardTarget.IsActive)
{
changeState(this.mGuardTarget);
return;
}
if (mRunningPath != null && !mRunningPath.IsDone)
{
changeState(this.mRunningPath);
return;
}
if (Moveable && MoveSpeedSEC > 0)
{
guardInPosition(mOrginPosition);
return;
}
base.startIdle();
}
public virtual void guardInPosition(Vector2 pos)
{
changeState(new StateGuardInPosition(this, pos));
}
///
/// 立刻开始返回原点
///
public virtual void backToOrgin()
{
mHateSystem.Clear();
mTracingTarget = null;
if (mGuardTarget != null && mGuardTarget.IsActive)
{
changeState(this.mGuardTarget);
}
else
{
mBackToPosition = new StateBackToPosition(this, mOrginPosition);
changeState(mBackToPosition);
}
OnBackToOrgin();
}
///
/// 在一定范围内浪
///
/// 浪多久
/// 浪多远
public virtual void idleMove(int timeMS, int range)
{
changeState(new StateIdleMove(this, mOrginPosition, timeMS, range));
}
#endregion
//--------------------------------------------------------------------------------------------------------
#region Update
protected override void onUpdateRecover()
{
if (mTracingTarget == null)
{
base.onUpdateRecover();
}
}
override protected void onUpdate(bool slowRefresh)
{
base.onUpdate(slowRefresh);
updateTracingTarget();
updateRunningPath();
updateGuardTarget();
updateBackToOrgin();
//updateHate();
updateView();
}
protected virtual void updateTracingTarget()
{
if (mTracingTarget != null)
{
if (Parent.IsAttackable(this, mTracingTarget.TargetUnit, SkillTemplate.CastTarget.Enemy, AttackReason.Tracing, Info))
{
//有攻击目标//
if ((CurrentState is StateSkill))
{
tryLaunchRandomSkillAndCancelCurrentSkill(TracingTarget, false);
}
else if (CurrentState is StateIdle)
{
tryMoveScatterTarget(TracingTarget);
}
}
else
{
mHateSystem.Remove(mTracingTarget.TargetUnit);
if (mTracingTarget == CurrentState)
{
doSomething();
}
mTracingTarget = null;
}
}
}
protected virtual void updateRunningPath()
{
if (mRunningPath != null)
{
if (CurrentState == mRunningPath)
{
if (mRunningPath.IsDone)
{
mRunningPath = null;
}
else if (mRunningPath.Target != null)
{
mOrginPosition.SetX(this.X);
mOrginPosition.SetY(this.Y);
}
}
else if (CurrentState is StateIdle)
{
changeState(this.mRunningPath);
}
}
}
protected virtual void updateGuardTarget()
{
//如果在寻路或保护,则实时更新OrginPosition//
if (mGuardTarget != null)
{
if (!mGuardTarget.IsActive)
{
mGuardTarget = null;
}
else
{
mOrginPosition.SetX(mGuardTarget.TargetUnit.X);
mOrginPosition.SetY(mGuardTarget.TargetUnit.Y);
}
}
}
protected virtual void updateBackToOrgin()
{
if (mBackToPosition != null)
{
if (mBackToPosition.IsDone)
{
mBackToPosition = null;
}
}
if (Info.GuardRangeLimit > Info.GuardRange)
{
//if (mCheckInGuardLimit.Update(Parent.UpdateIntervalMS))
if(mNextCheckGuardLimit != null && mNextCheckGuardLimit.IsTrigger())
{
if (!CMath.includeRoundPoint(X, Y, Info.GuardRangeLimit, mOrginPosition.X, mOrginPosition.Y))
{
backToOrgin();
}
else if (mTracingTarget != null)
{
if (!mTracingTarget.IsActive || !CMath.intersectRound(
X, Y, Info.GuardRangeLimit,
mTracingTarget.TargetUnit.X,
mTracingTarget.TargetUnit.Y,
mTracingTarget.TargetUnit.BodyHitSize))
{
backToOrgin();
return;
}
}
}
}
}
protected virtual void updateView()
{
if (mViewTrigger != null)
{
mViewTrigger.onLookUpdate(X, Y);
}
}
//protected virtual void updateHate(bool slowRefresh, int intervalMS)
//{
// if(slowRefresh && mHateSystem != null)
// {
// mHateSystem.Update(intervalMS);
// }
//}
///
/// 攻击间歇,尝试换个位置,避免怪物堆在一个点
///
protected virtual bool tryMoveScatterTarget(InstanceUnit target)
{
//只有单位为非碰撞时,才有这个需求//
if (!this.IntersectObj)
{
if (CommonLang.CUtils.localTimeMS > mCheckAttackSpread && CUtils.RandomPercent(Parent.RandomN, Templates.CFG.AI_NPC_ATTACK_IDLE_SCATTER_PCT))
{
mCheckAttackSpread = CommonLang.CUtils.localTimeMS + Templates.CFG.AI_NPC_ATTACK_IDLE_INTERVAL;
InstanceUnit block = null;
Parent.ForEachNearObjects(X, Y, (InstanceZoneObject o, ref bool cancel) =>
{
if ((o != this) && (o is InstanceUnit) && Parent.TouchObject2(this, o))
{
block = o as InstanceUnit;
cancel = true;
}
});
if (block != null)
{
float degree = MathVector.getDegree(X, Y, target.X, target.Y);
float distance = this.BodyBlockSize + block.BodyBlockSize;
Vector2 turnL = new Vector2(X, Y);
Vector2 turnR = new Vector2(X, Y);
MathVector.movePolar(turnL, degree + CMath.PI_DIV_2, distance);
MathVector.movePolar(turnR, degree - CMath.PI_DIV_2, distance);
float dl = MathVector.getDistanceSquare(turnL.X, turnL.Y, target.X, target.Y);
float dr = MathVector.getDistanceSquare(turnR.X, turnR.Y, target.X, target.Y);
if (dl < dr)
{
this.startMoveTo(turnL.X, turnL.Y);
}
else
{
this.startMoveTo(turnR.X, turnR.Y);
}
return true;
}
}
}
return false;
}
#endregion
//--------------------------------------------------------------------------------------------------------
#region InternalEvents
protected virtual void onUnitActivated(InstanceUnit unit)
{
initViewTrigger();
}
protected override void onStateChanged(State old_state, State state)
{
if (state is StateIdle)
{
followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing);
}
if (old_state != null)
{
if (old_state == mBackToPosition)
{
mBackToPosition = null;
}
if (old_state == mTracingTarget)
{
if (mTracingTarget.IsNoWay)
{
mHateSystem.Remove(mTracingTarget.TargetUnit);
mTracingTarget = null;
}
}
}
}
protected override void onMoveBlockWithObject(InstanceZoneObject obj)
{
if (IsNoneSkill)
{
return;
}
if (obj is InstanceUnit)
{
followAndAttack(obj as InstanceUnit, AttackReason.MoveBlocked);
}
}
protected override bool onBlockOther(InstanceZoneObject obj)
{
if (CurrentActionStatus == UnitActionStatus.Move)
{
return true;
}
if (CurrentActionStatus == UnitActionStatus.Idle)
{
//给自己友军让路//
if (obj is InstanceUnit)
{
InstanceUnit u = obj as InstanceUnit;
if (u.Force == this.Force)
{
return changeState(new StateMoveAway(this, u));
}
}
}
return false;
}
protected override void onDamaged(InstanceUnit attacker, AttackSource attack, int reduceHP)
{
if (IsNoneSkill)
{
return;
}
if(attacker.IsPet)
{
InstanceUnit master = attacker.Virtual.GetMasterUnit();
if(master == null)
{
log.Warn("onDamaged: 找不到宠物主人:" + attacker.Info.ID + ", " + attacker.Parent.GetSceneID());
}
else
{
attacker = master;
}
}
// 被攻击转火
mHateSystem.OnHitted(attacker, attack, reduceHP);
onAddEnemy(attacker, true, AttackReason.Damaged);
}
protected virtual void onAddEnemy(InstanceUnit target, bool group, AttackReason reason)
{
if (onAddEnemyInternal(target, group, reason))
{
if (group && Info.GuardRangeGroup > 0)
{
Parent.ForEachNearObjects(X, Y, Info.GuardRangeGroup, (InstanceZoneObject o, ref bool cancel) =>
{
if ((o != this) && (o is InstanceGuard))
{
InstanceGuard g = o as InstanceGuard;
if (g.Force == this.Force && Parent.IsAttackable(g, target, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
{
if (CMath.includeRoundPoint(g.X, g.Y, g.Info.GuardRangeLimit, target.X, target.Y))
{
g.onAddEnemyInternal(target, true, reason);
}
}
}
});
}
}
}
protected bool onAddEnemyInternal(InstanceUnit target, bool group, AttackReason reason)
{
bool attack = true;
if (mOnEnemyAdded != null)
{
mOnEnemyAdded.Invoke(this, target, ref attack);
}
if (attack)
{
if (!mHateSystem.Contains(target))
{
mHateSystem.Add(target);
}
followAndAttack(mHateSystem.GetHated(), reason);
}
return attack;
}
protected virtual void OnBackToOrgin()
{
}
#endregion
//--------------------------------------------------------------------------------------------------------
#region Events
protected override void clearEvents()
{
base.clearEvents();
mOnEnemyAdded = null;
}
public delegate void EnemyAdded(InstanceUnit unit, InstanceUnit enemy, ref bool attack);
private EnemyAdded mOnEnemyAdded;
[EventTriggerDescAttribute("Add敌人")]
public event EnemyAdded OnEnemyAdded { add { mOnEnemyAdded += value; } remove { mOnEnemyAdded -= value; } }
#endregion
//--------------------------------------------------------------------------------------------------------
///
/// 移动状态
///
public class StateMoveAway : State
{
private Vector2 target;
private InstanceUnit other;
public StateMoveAway(InstanceGuard unit, InstanceUnit other)
: base(unit)
{
this.other = other;
this.target = new Vector2(unit.X, unit.Y);
float angle = MathVector.getDegree(other.X, other.Y, unit.X, unit.Y);
angle = (float)(-CMath.PI_DIV_2 + unit.RandomN.NextDouble() * CMath.PI_F);
MathVector.movePolar(target, angle, (unit.BodyBlockSize));
}
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);
MoveBlockResult result = unit.moveBlockTo(target.X, target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
{
InstanceGuard guard = (unit as InstanceGuard);
guard.doSomething();
}
}
override protected void onStop()
{
}
}
//----------------------------------------------------------------------------------------------------------
}
//--------------------------------------------------------------------------------------------------------
public class InstanceSummon : InstanceGuard, ISummonedUnit
{
public InstanceUnit SummonerUnit { get; set; }
public InstanceSummon(InstanceZone zone, UnitInfo info, string name, int force, int level)
: base(zone, info, name, force, level)
{
}
override protected void onUpdate(bool slowRefresh)
{
base.onUpdate(slowRefresh);
if ((PassTimeMS >= Info.LifeTimeMS) || (SummonerUnit != null && SummonerUnit.IsDead()))
{
kill();
}
}
}
//--------------------------------------------------------------------------------------------------------
}