InstanceNpcs.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using CommonAI.RTS.Manhattan;
  5. using CommonAI.RTS;
  6. using CommonLang.Vector;
  7. using CommonLang;
  8. using CommonAI.ZoneClient;
  9. using CommonAI.Zone.Helper;
  10. using CommonAI.Zone.Formula;
  11. using CommonAI.Zone.Attributes;
  12. namespace CommonAI.Zone.Instance
  13. {
  14. //--------------------------------------------------------------------------------------------------------
  15. /// <summary>
  16. /// 所有自动电脑AI
  17. /// </summary>
  18. public class InstanceGuard : InstanceUnit, IGuardUnit, ViewTrigger.ViewTriggerListener
  19. {
  20. protected ViewTrigger mViewTrigger;
  21. protected HateSystem mHateSystem;
  22. protected StateAttackTo mRunningPath;
  23. protected StateFollowAndAttack mTracingTarget;
  24. protected StateFollowAndGuard mGuardTarget;
  25. protected StateBackToPosition mBackToPosition;
  26. protected Vector2 mOrginPosition;
  27. //protected TimeInterval<int> mCheckInGuardLimit;
  28. protected SimpleTrigger mNextCheckGuardLimit;
  29. public InstanceUnit TracingTarget
  30. {
  31. get
  32. {
  33. if (mTracingTarget != null) return mTracingTarget.TargetUnit;
  34. return null;
  35. }
  36. }
  37. public InstanceGuard(InstanceZone zone, UnitInfo info, string name, int force, int level)
  38. : base(zone, info, name, force, level)
  39. {
  40. //this.mCheckInGuardLimit = new TimeInterval<int>(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);
  41. this.mNextCheckGuardLimit = new SimpleTrigger(Templates.CFG.AI_NPC_CHECK_IN_GUARD_LIMIT_TIME_MS);
  42. this.OnActivated += this.onUnitActivated;
  43. }
  44. protected override void onAdded(bool pointLv)
  45. {
  46. base.onAdded(pointLv);
  47. this.mHateSystem = TemplateManager.Factory.CreateHateSystem(this);
  48. this.mOrginPosition = new Vector2(X, Y);
  49. }
  50. protected override void Disposing()
  51. {
  52. base.Disposing();
  53. if (mViewTrigger != null) mViewTrigger.Dispose();
  54. mHateSystem.Clear();
  55. mRunningPath = null;
  56. mTracingTarget = null;
  57. mGuardTarget = null;
  58. mBackToPosition = null;
  59. mOrginPosition = null;
  60. this.mNextCheckGuardLimit = null;
  61. this.OnActivated -= this.onUnitActivated;
  62. }
  63. override protected void onResetAI()
  64. {
  65. mTracingTarget = null;
  66. mHateSystem.Clear();
  67. doSomething();
  68. }
  69. protected override void onDead(InstanceUnit killer)
  70. {
  71. base.onDead(killer);
  72. SetEnableView(false);
  73. }
  74. //--------------------------------------------------------------------------------------------------------
  75. #region View
  76. public void SetEnableView(bool view)
  77. {
  78. if (mViewTrigger != null)
  79. {
  80. this.mViewTrigger.Enable = view && !IsNature && !IsNoneSkill;
  81. }
  82. }
  83. private void initViewTrigger()
  84. {
  85. this.mViewTrigger = CreateViewTrigger(Parent);
  86. if (mViewTrigger != null)
  87. {
  88. this.mViewTrigger.setListener(this);
  89. }
  90. }
  91. protected virtual ViewTrigger CreateViewTrigger(InstanceZone zone)
  92. {
  93. if (Info.GuardRange > 0)
  94. {
  95. return new ViewTriggerRoundBody(zone, Info.GuardRange);
  96. }
  97. else
  98. {
  99. return new ViewTriggerBlind(zone);
  100. }
  101. }
  102. void ViewTrigger.ViewTriggerListener.onObjectEnterView(ViewTrigger src, InstanceZoneObject obj)
  103. {
  104. onAddEnemy(obj as InstanceUnit, true, AttackReason.Look);
  105. }
  106. void ViewTrigger.ViewTriggerListener.onObjectLeaveView(ViewTrigger src, InstanceZoneObject obj)
  107. {
  108. }
  109. bool ViewTrigger.ViewTriggerListener.select(ViewTrigger src, InstanceZoneObject obj)
  110. {
  111. if (obj == this)
  112. {
  113. return false;
  114. }
  115. else if ((obj is InstanceUnit))
  116. {
  117. InstanceUnit u = obj as InstanceUnit;
  118. if (!u.IsNature && !this.IsNature && Parent.IsAttackable(this, u, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
  119. {
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. #endregion
  126. //--------------------------------------------------------------------------------------------------------
  127. #region Action
  128. void IGuardUnit.AttackTo(ZoneWayPoint start, int peaceTime)
  129. {
  130. this.attackTo(start, peaceTime);
  131. }
  132. void IGuardUnit.SetOrginPosition(float x, float y)
  133. {
  134. this.setOrginPosition(x, y);
  135. }
  136. void IGuardUnit.PatrolWith(ZoneWayPoint start, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime)
  137. {
  138. this.patrolWith(start, holdMinTimeMS, holdMaxTimeMS, peaceTime);
  139. }
  140. bool IGuardUnit.FollowAndAttack(InstanceUnit target, AttackReason reason)
  141. {
  142. return this.followAndAttack(target, reason);
  143. }
  144. void IGuardUnit.GuardUnit(InstanceUnit vip)
  145. {
  146. this.guardUnit(vip);
  147. }
  148. public override void doSomething()
  149. {
  150. if (CurrentState is StateSkill)
  151. {
  152. var target = TracingTarget;
  153. if (target != null)
  154. {
  155. if (tryMoveScatterTarget(target)) { return; }
  156. }
  157. }
  158. guard();
  159. }
  160. /// <summary>
  161. /// 设置警戒地点,如果在寻路或保护单位,则无效
  162. /// </summary>
  163. /// <param name="x"></param>
  164. /// <param name="y"></param>
  165. public virtual void setOrginPosition(float x, float y)
  166. {
  167. this.mOrginPosition.SetX(x);
  168. this.mOrginPosition.SetY(y);
  169. }
  170. public virtual Vector2 GetOrginPosition()
  171. {
  172. return mOrginPosition;
  173. }
  174. /// <summary>
  175. /// 寻路攻击目标
  176. /// </summary>
  177. /// <param name="src"></param>
  178. /// <param name="reason"></param>
  179. public virtual bool followAndAttack(InstanceUnit src, AttackReason reason)
  180. {
  181. if (IsNoneSkill) return false;
  182. if ((src != null))
  183. {
  184. if (Parent.IsAttackable(this, src, SkillTemplate.CastTarget.Enemy, reason, Info))
  185. {
  186. this.SetEnableView(false);
  187. mHateSystem.Add(src);
  188. if (TracingTarget != src)
  189. {
  190. //Console.WriteLine(" - - BBBBBB - - " + ((TracingTarget == null) ? "null" : TracingTarget.Name) + ", " + src.Name);
  191. mTracingTarget = new StateFollowAndAttack(this, src);
  192. }
  193. changeState(mTracingTarget);
  194. return true;
  195. }
  196. else
  197. {
  198. mHateSystem.Remove(src);
  199. }
  200. }
  201. return false;
  202. }
  203. /// <summary>
  204. /// 寻路并一路警戒
  205. /// </summary>
  206. /// <param name="path"></param>
  207. public virtual void attackTo(ZoneWayPoint path, int peaceTime = 0)
  208. {
  209. this.mRunningPath = new StateAttackToZoneWayPoint(this, path, peaceTime);
  210. changeState(this.mRunningPath);
  211. }
  212. /// <summary>
  213. /// 在路点范围内警戒
  214. /// </summary>
  215. /// <param name="wp"></param>
  216. /// <param name="holdMinTimeMS"></param>
  217. /// <param name="holdMaxTimeMS"></param>
  218. public virtual void patrolWith(ZoneWayPoint wp, int holdMinTimeMS, int holdMaxTimeMS, int peaceTime = 0)
  219. {
  220. this.mRunningPath = new StatePatrolWayPoint(this, wp, holdMinTimeMS, holdMaxTimeMS, peaceTime);
  221. changeState(this.mRunningPath);
  222. }
  223. /// <summary>
  224. /// 保护单位
  225. /// </summary>
  226. /// <param name="vip"></param>
  227. public virtual void guardUnit(InstanceUnit vip)
  228. {
  229. if (mGuardTarget == null || !mGuardTarget.IsActive || mGuardTarget.TargetUnit != vip)
  230. {
  231. mGuardTarget = new StateFollowAndGuard(this, vip, this.BodyBlockSize * 2 + vip.BodyBlockSize, Info.GuardRange);
  232. }
  233. changeState(mGuardTarget);
  234. }
  235. /// <summary>
  236. /// 待机
  237. /// </summary>
  238. public virtual void guard()
  239. {
  240. if(mHateSystem != null && mHateSystem.Count > 0)
  241. {
  242. if (followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing))
  243. {
  244. return;
  245. }
  246. }
  247. mTracingTarget = null;
  248. SetEnableView(true);
  249. if (mGuardTarget != null && mGuardTarget.IsActive)
  250. {
  251. changeState(this.mGuardTarget);
  252. return;
  253. }
  254. if (mRunningPath != null && !mRunningPath.IsDone)
  255. {
  256. changeState(this.mRunningPath);
  257. return;
  258. }
  259. if (Moveable && MoveSpeedSEC > 0)
  260. {
  261. guardInPosition(mOrginPosition);
  262. return;
  263. }
  264. base.startIdle();
  265. }
  266. public virtual void guardInPosition(Vector2 pos)
  267. {
  268. changeState(new StateGuardInPosition(this, pos));
  269. }
  270. /// <summary>
  271. /// 立刻开始返回原点
  272. /// </summary>
  273. public virtual void backToOrgin()
  274. {
  275. mHateSystem.Clear();
  276. mTracingTarget = null;
  277. if (mGuardTarget != null && mGuardTarget.IsActive)
  278. {
  279. changeState(this.mGuardTarget);
  280. }
  281. else
  282. {
  283. mBackToPosition = new StateBackToPosition(this, mOrginPosition);
  284. changeState(mBackToPosition);
  285. }
  286. OnBackToOrgin();
  287. }
  288. /// <summary>
  289. /// 在一定范围内浪
  290. /// </summary>
  291. /// <param name="timeMS">浪多久</param>
  292. /// <param name="range">浪多远</param>
  293. public virtual void idleMove(int timeMS, int range)
  294. {
  295. changeState(new StateIdleMove(this, mOrginPosition, timeMS, range));
  296. }
  297. #endregion
  298. //--------------------------------------------------------------------------------------------------------
  299. #region Update
  300. protected override void onUpdateRecover()
  301. {
  302. if (mTracingTarget == null)
  303. {
  304. base.onUpdateRecover();
  305. }
  306. }
  307. override protected void onUpdate(bool slowRefresh)
  308. {
  309. base.onUpdate(slowRefresh);
  310. updateTracingTarget();
  311. updateRunningPath();
  312. updateGuardTarget();
  313. updateBackToOrgin();
  314. //updateHate();
  315. updateView();
  316. }
  317. protected virtual void updateTracingTarget()
  318. {
  319. if (mTracingTarget != null)
  320. {
  321. if (Parent.IsAttackable(this, mTracingTarget.TargetUnit, SkillTemplate.CastTarget.Enemy, AttackReason.Tracing, Info))
  322. {
  323. //有攻击目标//
  324. if ((CurrentState is StateSkill))
  325. {
  326. tryLaunchRandomSkillAndCancelCurrentSkill(TracingTarget, false);
  327. }
  328. else if (CurrentState is StateIdle)
  329. {
  330. tryMoveScatterTarget(TracingTarget);
  331. }
  332. }
  333. else
  334. {
  335. mHateSystem.Remove(mTracingTarget.TargetUnit);
  336. if (mTracingTarget == CurrentState)
  337. {
  338. doSomething();
  339. }
  340. mTracingTarget = null;
  341. }
  342. }
  343. }
  344. protected virtual void updateRunningPath()
  345. {
  346. if (mRunningPath != null)
  347. {
  348. if (CurrentState == mRunningPath)
  349. {
  350. if (mRunningPath.IsDone)
  351. {
  352. mRunningPath = null;
  353. }
  354. else if (mRunningPath.Target != null)
  355. {
  356. mOrginPosition.SetX(this.X);
  357. mOrginPosition.SetY(this.Y);
  358. }
  359. }
  360. else if (CurrentState is StateIdle)
  361. {
  362. changeState(this.mRunningPath);
  363. }
  364. }
  365. }
  366. protected virtual void updateGuardTarget()
  367. {
  368. //如果在寻路或保护,则实时更新OrginPosition//
  369. if (mGuardTarget != null)
  370. {
  371. if (!mGuardTarget.IsActive)
  372. {
  373. mGuardTarget = null;
  374. }
  375. else
  376. {
  377. mOrginPosition.SetX(mGuardTarget.TargetUnit.X);
  378. mOrginPosition.SetY(mGuardTarget.TargetUnit.Y);
  379. }
  380. }
  381. }
  382. protected virtual void updateBackToOrgin()
  383. {
  384. if (mBackToPosition != null)
  385. {
  386. if (mBackToPosition.IsDone)
  387. {
  388. mBackToPosition = null;
  389. }
  390. }
  391. if (Info.GuardRangeLimit > Info.GuardRange)
  392. {
  393. //if (mCheckInGuardLimit.Update(Parent.UpdateIntervalMS))
  394. if(mNextCheckGuardLimit != null && mNextCheckGuardLimit.IsTrigger())
  395. {
  396. if (!CMath.includeRoundPoint(X, Y, Info.GuardRangeLimit, mOrginPosition.X, mOrginPosition.Y))
  397. {
  398. backToOrgin();
  399. }
  400. else if (mTracingTarget != null)
  401. {
  402. if (!mTracingTarget.IsActive || !CMath.intersectRound(
  403. X, Y, Info.GuardRangeLimit,
  404. mTracingTarget.TargetUnit.X,
  405. mTracingTarget.TargetUnit.Y,
  406. mTracingTarget.TargetUnit.BodyHitSize))
  407. {
  408. backToOrgin();
  409. return;
  410. }
  411. }
  412. }
  413. }
  414. }
  415. protected virtual void updateView()
  416. {
  417. if (mViewTrigger != null)
  418. {
  419. mViewTrigger.onLookUpdate(X, Y);
  420. }
  421. }
  422. //protected virtual void updateHate(bool slowRefresh, int intervalMS)
  423. //{
  424. // if(slowRefresh && mHateSystem != null)
  425. // {
  426. // mHateSystem.Update(intervalMS);
  427. // }
  428. //}
  429. /// <summary>
  430. /// 攻击间歇,尝试换个位置,避免怪物堆在一个点
  431. /// </summary>
  432. protected virtual bool tryMoveScatterTarget(InstanceUnit target)
  433. {
  434. //只有单位为非碰撞时,才有这个需求//
  435. if (!this.IntersectObj)
  436. {
  437. if (CommonLang.CUtils.localTimeMS > mCheckAttackSpread && CUtils.RandomPercent(Parent.RandomN, Templates.CFG.AI_NPC_ATTACK_IDLE_SCATTER_PCT))
  438. {
  439. mCheckAttackSpread = CommonLang.CUtils.localTimeMS + Templates.CFG.AI_NPC_ATTACK_IDLE_INTERVAL;
  440. InstanceUnit block = null;
  441. Parent.ForEachNearObjects(X, Y, (InstanceZoneObject o, ref bool cancel) =>
  442. {
  443. if ((o != this) && (o is InstanceUnit) && Parent.TouchObject2(this, o))
  444. {
  445. block = o as InstanceUnit;
  446. cancel = true;
  447. }
  448. });
  449. if (block != null)
  450. {
  451. float degree = MathVector.getDegree(X, Y, target.X, target.Y);
  452. float distance = this.BodyBlockSize + block.BodyBlockSize;
  453. Vector2 turnL = new Vector2(X, Y);
  454. Vector2 turnR = new Vector2(X, Y);
  455. MathVector.movePolar(turnL, degree + CMath.PI_DIV_2, distance);
  456. MathVector.movePolar(turnR, degree - CMath.PI_DIV_2, distance);
  457. float dl = MathVector.getDistanceSquare(turnL.X, turnL.Y, target.X, target.Y);
  458. float dr = MathVector.getDistanceSquare(turnR.X, turnR.Y, target.X, target.Y);
  459. if (dl < dr)
  460. {
  461. this.startMoveTo(turnL.X, turnL.Y);
  462. }
  463. else
  464. {
  465. this.startMoveTo(turnR.X, turnR.Y);
  466. }
  467. return true;
  468. }
  469. }
  470. }
  471. return false;
  472. }
  473. #endregion
  474. //--------------------------------------------------------------------------------------------------------
  475. #region InternalEvents
  476. protected virtual void onUnitActivated(InstanceUnit unit)
  477. {
  478. initViewTrigger();
  479. }
  480. protected override void onStateChanged(State old_state, State state)
  481. {
  482. if (state is StateIdle)
  483. {
  484. followAndAttack(mHateSystem.GetHated(), AttackReason.Tracing);
  485. }
  486. if (old_state != null)
  487. {
  488. if (old_state == mBackToPosition)
  489. {
  490. mBackToPosition = null;
  491. }
  492. if (old_state == mTracingTarget)
  493. {
  494. if (mTracingTarget.IsNoWay)
  495. {
  496. mHateSystem.Remove(mTracingTarget.TargetUnit);
  497. mTracingTarget = null;
  498. }
  499. }
  500. }
  501. }
  502. protected override void onMoveBlockWithObject(InstanceZoneObject obj)
  503. {
  504. if (IsNoneSkill)
  505. {
  506. return;
  507. }
  508. if (obj is InstanceUnit)
  509. {
  510. followAndAttack(obj as InstanceUnit, AttackReason.MoveBlocked);
  511. }
  512. }
  513. protected override bool onBlockOther(InstanceZoneObject obj)
  514. {
  515. if (CurrentActionStatus == UnitActionStatus.Move)
  516. {
  517. return true;
  518. }
  519. if (CurrentActionStatus == UnitActionStatus.Idle)
  520. {
  521. //给自己友军让路//
  522. if (obj is InstanceUnit)
  523. {
  524. InstanceUnit u = obj as InstanceUnit;
  525. if (u.Force == this.Force)
  526. {
  527. return changeState(new StateMoveAway(this, u));
  528. }
  529. }
  530. }
  531. return false;
  532. }
  533. protected override void onDamaged(InstanceUnit attacker, AttackSource attack, int reduceHP)
  534. {
  535. if (IsNoneSkill)
  536. {
  537. return;
  538. }
  539. if(attacker.IsPet)
  540. {
  541. InstanceUnit master = attacker.Virtual.GetMasterUnit();
  542. if(master == null)
  543. {
  544. log.Warn("onDamaged: 找不到宠物主人:" + attacker.Info.ID + ", " + attacker.Parent.GetSceneID());
  545. }
  546. else
  547. {
  548. attacker = master;
  549. }
  550. }
  551. // 被攻击转火
  552. mHateSystem.OnHitted(attacker, attack, reduceHP);
  553. onAddEnemy(attacker, true, AttackReason.Damaged);
  554. }
  555. protected virtual void onAddEnemy(InstanceUnit target, bool group, AttackReason reason)
  556. {
  557. if (onAddEnemyInternal(target, group, reason))
  558. {
  559. if (group && Info.GuardRangeGroup > 0)
  560. {
  561. Parent.ForEachNearObjects(X, Y, Info.GuardRangeGroup, (InstanceZoneObject o, ref bool cancel) =>
  562. {
  563. if ((o != this) && (o is InstanceGuard))
  564. {
  565. InstanceGuard g = o as InstanceGuard;
  566. if (g.Force == this.Force && Parent.IsAttackable(g, target, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info))
  567. {
  568. if (CMath.includeRoundPoint(g.X, g.Y, g.Info.GuardRangeLimit, target.X, target.Y))
  569. {
  570. g.onAddEnemyInternal(target, true, reason);
  571. }
  572. }
  573. }
  574. });
  575. }
  576. }
  577. }
  578. protected bool onAddEnemyInternal(InstanceUnit target, bool group, AttackReason reason)
  579. {
  580. bool attack = true;
  581. if (mOnEnemyAdded != null)
  582. {
  583. mOnEnemyAdded.Invoke(this, target, ref attack);
  584. }
  585. if (attack)
  586. {
  587. if (!mHateSystem.Contains(target))
  588. {
  589. mHateSystem.Add(target);
  590. }
  591. followAndAttack(mHateSystem.GetHated(), reason);
  592. }
  593. return attack;
  594. }
  595. protected virtual void OnBackToOrgin()
  596. {
  597. }
  598. #endregion
  599. //--------------------------------------------------------------------------------------------------------
  600. #region Events
  601. protected override void clearEvents()
  602. {
  603. base.clearEvents();
  604. mOnEnemyAdded = null;
  605. }
  606. public delegate void EnemyAdded(InstanceUnit unit, InstanceUnit enemy, ref bool attack);
  607. private EnemyAdded mOnEnemyAdded;
  608. [EventTriggerDescAttribute("Add敌人")]
  609. public event EnemyAdded OnEnemyAdded { add { mOnEnemyAdded += value; } remove { mOnEnemyAdded -= value; } }
  610. #endregion
  611. //--------------------------------------------------------------------------------------------------------
  612. /// <summary>
  613. /// 移动状态
  614. /// </summary>
  615. public class StateMoveAway : State
  616. {
  617. private Vector2 target;
  618. private InstanceUnit other;
  619. public StateMoveAway(InstanceGuard unit, InstanceUnit other)
  620. : base(unit)
  621. {
  622. this.other = other;
  623. this.target = new Vector2(unit.X, unit.Y);
  624. float angle = MathVector.getDegree(other.X, other.Y, unit.X, unit.Y);
  625. angle = (float)(-CMath.PI_DIV_2 + unit.RandomN.NextDouble() * CMath.PI_F);
  626. MathVector.movePolar(target, angle, (unit.BodyBlockSize));
  627. }
  628. override public bool onBlock(State new_state)
  629. {
  630. return true;
  631. }
  632. override protected void onStart()
  633. {
  634. unit.SetActionStatus(UnitActionStatus.Move);
  635. }
  636. override protected void onUpdate()
  637. {
  638. unit.SetActionStatus(UnitActionStatus.Move);
  639. unit.faceTo(target.X, target.Y);
  640. MoveBlockResult result = unit.moveBlockTo(target.X, target.Y, unit.MoveSpeedSEC, zone.UpdateIntervalMS);
  641. if ((result.result & MoveResult.RESULTS_MOVE_END) != 0)
  642. {
  643. InstanceGuard guard = (unit as InstanceGuard);
  644. guard.doSomething();
  645. }
  646. }
  647. override protected void onStop()
  648. {
  649. }
  650. }
  651. //----------------------------------------------------------------------------------------------------------
  652. }
  653. //--------------------------------------------------------------------------------------------------------
  654. public class InstanceSummon : InstanceGuard, ISummonedUnit
  655. {
  656. public InstanceUnit SummonerUnit { get; set; }
  657. public InstanceSummon(InstanceZone zone, UnitInfo info, string name, int force, int level)
  658. : base(zone, info, name, force, level)
  659. {
  660. }
  661. override protected void onUpdate(bool slowRefresh)
  662. {
  663. base.onUpdate(slowRefresh);
  664. if ((PassTimeMS >= Info.LifeTimeMS) || (SummonerUnit != null && SummonerUnit.IsDead()))
  665. {
  666. kill();
  667. }
  668. }
  669. }
  670. //--------------------------------------------------------------------------------------------------------
  671. }