XmdsServerScene.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. using CommonAI.Zone.Instance;
  2. using CommonAI.Zone.ZoneEditor;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using XmdsCommon.Plugin;
  8. using CommonAI.Zone;
  9. using CommonAI.Zone.Attributes;
  10. using CommonAI.Zone.Helper;
  11. using XmdsCommonServer.Plugin.Units;
  12. using XmdsCommonServer.Plugin.Quest;
  13. using XmdsCommon.EditorData;
  14. using CommonLang;
  15. using CommonLang.Vector;
  16. using CommonAI.RTS.Manhattan;
  17. using XmdsCommon.Message;
  18. using CommonAI.Data;
  19. using CommonAI.ZoneServer.JSGModule;
  20. namespace XmdsCommonServer.Plugin.Scene
  21. {
  22. /// <summary>
  23. /// Xmds场景
  24. /// </summary>
  25. public class XmdsServerScene : EditorScene
  26. {
  27. /// <summary>
  28. /// 遍历单位
  29. /// </summary>
  30. /// <param name="obj"></param>
  31. /// <param name="cancel">设置为True,立即停止遍历</param>
  32. public delegate void ObjectForEachAction<T>(T obj, ref bool cancel) where T : class;
  33. private HashMap<int, List<ZoneRegion>> mRebirthRegionMap = new HashMap<int, List<ZoneRegion>>();
  34. public XmdsServerScene(TemplateManager templates, InstanceZoneListener listener, SceneData data, GSCreateAreaData gsData, string bindGameSrvId, int spaceDiv = 11)
  35. : this(templates, listener, data, gsData, spaceDiv, DateTime.Now.Millisecond, bindGameSrvId)
  36. { }
  37. protected XmdsServerScene(TemplateManager templates, InstanceZoneListener listener, SceneData data, GSCreateAreaData gsData, int spaceDiv, int rarndomSeed, string bindGameSrvId)
  38. : base(templates, listener, data, gsData, spaceDiv, rarndomSeed)
  39. {
  40. this.OnQuestAccepted += XmdsServerScene_OnQuestAccepted;
  41. this.OnQuestDropped += XmdsServerScene_OnQuestDropped;
  42. this.OnQuestCommitted += XmdsServerScene_OnQuestCommitted;
  43. this.OnQuestStatusChanged += XmdsServerScene_OnQuestStatusChanged;
  44. this.OnPlayerReady += XmdsServerScene_OnPlayerReady;
  45. //设置山大王信息
  46. this.mKingID = XmdsDataMgr.GetInstance().GetMapKingID(this.GetSceneID());
  47. this.mBindGameSrvId = bindGameSrvId;
  48. }
  49. protected override void InitTerrain(SceneData data, int spaceDiv, out ZoneManhattanMap terrain_data, out AstarManhattan path_finder, out ManhattanMapAreaGenerator area_gen)
  50. {
  51. if ((data.Properties as XmdsSceneProperties).ServerSceneData.UsespaceDiv) { spaceDiv = 11; }
  52. else { spaceDiv = 0; }
  53. base.InitTerrain(data, spaceDiv, out terrain_data, out path_finder, out area_gen);
  54. }
  55. // private static int GetSpaceDiv(SceneData data)
  56. // {
  57. // if ((data.Properties as XmdsSceneProperties).ServerSceneData.UsespaceDiv) { return 11; }
  58. // else { return 0; }
  59. // }
  60. //---------------------------------------------------------------------------------------------------------------------
  61. #region _任务相关_
  62. private void XmdsServerScene_OnPlayerReady(InstancePlayer player)
  63. {
  64. XmdsInstancePlayer p = player as XmdsInstancePlayer;
  65. var list = p.GetQuests();
  66. foreach (var q in list)
  67. {
  68. QuestScriptManager.CreateQuestScript(q.QuestID, p);
  69. }
  70. }
  71. private void XmdsServerScene_OnQuestStatusChanged(InstancePlayer player, string quest, string key, string value)
  72. {
  73. if (key == XmdsQuestData.Attribute_InitOK)
  74. {
  75. QuestScriptManager.CreateQuestScript(quest, player as XmdsInstancePlayer);
  76. }
  77. else
  78. {
  79. QuestScriptManager.QuestStatusChanged(quest, player as XmdsInstancePlayer, key, value);
  80. }
  81. }
  82. private void XmdsServerScene_OnQuestAccepted(InstancePlayer player, string quest)
  83. {
  84. //此时没有属性,CreateQuestScript放在INIT_OK
  85. //QuestScriptManager.CreateQuestScript(quest, player as XmdsInstancePlayer);
  86. }
  87. private void XmdsServerScene_OnQuestCommitted(InstancePlayer player, string quest)
  88. {
  89. QuestScriptManager.ClearQuestScript(quest, player as XmdsInstancePlayer);
  90. }
  91. private void XmdsServerScene_OnQuestDropped(InstancePlayer player, string quest)
  92. {
  93. QuestScriptManager.ClearQuestScript(quest, player as XmdsInstancePlayer);
  94. }
  95. #endregion
  96. //---------------------------------------------------------------------------------------------------------------------
  97. #region _AOI_相关_
  98. public override bool IsTeammates(InstanceUnit src, InstanceUnit dst)
  99. {
  100. if (src != null && dst != null)
  101. {
  102. var s_v = src.Virtual as XmdsVirtual;
  103. var d_v = dst.Virtual as XmdsVirtual;
  104. return d_v.IsTeamMember(s_v.GetPlayerUUID());
  105. }
  106. return false;
  107. }
  108. public override bool IsVisibleAOI(InstanceZoneObject src, InstanceZoneObject dst)
  109. {
  110. if (src is XmdsInstancePlayer)
  111. {
  112. XmdsInstancePlayer player = src as XmdsInstancePlayer;
  113. if (!player.IsPlayerReady())
  114. {
  115. return false;
  116. }
  117. String bindPlayerId = dst.GetBindPlayerId();
  118. if(bindPlayerId != null && bindPlayerId != player.PlayerUUID)
  119. {
  120. return false;
  121. }
  122. }
  123. if (src.AoiStatus == dst.AoiStatus)
  124. {
  125. var dstUnit = dst as InstanceUnit;
  126. if (dstUnit == null)
  127. {
  128. return true;
  129. }
  130. //if(dstUnit.IsPet)
  131. //{
  132. // InstancePet dstPet = dst as InstancePet;
  133. // if(dstPet != null && dstPet.Master != null && dstPet.Master.AoiStatus != src.AoiStatus)
  134. // {
  135. // return false;
  136. // }
  137. //}
  138. if (dstUnit.IsVisible)
  139. {
  140. return true;
  141. }
  142. if (IsTeammates(src as InstanceUnit, dstUnit))
  143. {
  144. return (dstUnit.Virtual as XmdsVirtual).TeamMemberVisible;
  145. }
  146. return false;
  147. }
  148. //else
  149. //{
  150. // InstancePet dstPet = dst as InstancePet;
  151. // if (dstPet != null && dstPet.Master != null && dstPet.Master == src)
  152. // {
  153. // return true;
  154. // }
  155. //}
  156. return base.IsVisibleAOI(src, dst);
  157. }
  158. #endregion
  159. #region Attack.
  160. public override bool IsAttackable(InstanceUnit src, InstanceUnit target, SkillTemplate.CastTarget expectTarget, AttackReason reason, ITemplateData weapon)
  161. {
  162. // 宠物也能被攻击
  163. //if (target is InstancePet)
  164. //{
  165. // return false;
  166. //}
  167. var sp = (src.Virtual as XmdsVirtual);
  168. if (sp == null)
  169. {
  170. Log.Error("IsAttackable src or src.Virtual is null");
  171. return false;
  172. }
  173. var dp = (target.Virtual as XmdsVirtual);
  174. if (dp == null)
  175. {
  176. Log.Error("IsAttackable target or target.Virtual is null");
  177. return false;
  178. }
  179. #region 安全区域检测. 宠物不会是目标
  180. if (expectTarget == SkillTemplate.CastTarget.Enemy)
  181. {
  182. XmdsVirtual dpPlayer = dp as XmdsVirtual_Player;
  183. if (dpPlayer != null)
  184. {
  185. XmdsVirtual spPlayer = sp as XmdsVirtual_Player;
  186. if (spPlayer == null && sp is XmdsVirtual_Pet)
  187. {
  188. spPlayer = (sp as XmdsVirtual_Pet).GetMaster();
  189. }
  190. if (spPlayer != null && (spPlayer.IsInSafeArea || dpPlayer.IsInSafeArea))
  191. {
  192. return false;
  193. }
  194. }
  195. }
  196. #endregion
  197. #region 中立单位检测.
  198. if (target.Force == 0) //0代表绝对中立.不能被攻击.
  199. {
  200. return false;
  201. }
  202. #endregion
  203. #region 无敌单位.
  204. if (target.IsInvincible && expectTarget == SkillTemplate.CastTarget.Enemy)
  205. {
  206. return false;
  207. }
  208. //追杀怪只能追杀目标
  209. if (!String.IsNullOrEmpty(src.GetAttackPlayer()))
  210. {
  211. if(target.PlayerUUID == null || target.PlayerUUID != src.GetAttackPlayer())
  212. {
  213. return false;
  214. }
  215. }
  216. if(src != target && !JSGModule.IsExpectValidForPet(expectTarget))
  217. {
  218. // 宠物攻击的时候
  219. if (src.IsPet)
  220. {
  221. // 目标是宠物或者非主人
  222. if (target.IsPet || (target.IsPlayer && src.Virtual.GetMasterID() != target.ID))
  223. {
  224. return false;
  225. }
  226. }
  227. // 宠物被攻击的时候
  228. else if (target.IsPet)
  229. {
  230. // 攻击者是宠物或者非主人
  231. //if (src.IsPet || (src.IsPlayer && target.Virtual.GetMasterID() != src.ID))
  232. {
  233. return false;
  234. }
  235. }
  236. }
  237. //被追杀人和怪 可攻击追杀怪
  238. if(!String.IsNullOrEmpty(target.GetAttackPlayer()) && src.PlayerUUID != target.GetAttackPlayer())
  239. {
  240. if (src.IsPet && src.Virtual.GetMasterUnit() != null)
  241. {
  242. if (src.Virtual.GetMasterUnit().PlayerUUID != target.GetAttackPlayer())
  243. {
  244. return false;
  245. }
  246. }
  247. else
  248. {
  249. return false;
  250. }
  251. }
  252. #endregion
  253. #region 隐形对攻击的影响.
  254. //单位隐形时,需要判断搜索方是否为其队友,如果是则无视隐形,否按照攻击逻辑判断.
  255. //if(target.IsDead)
  256. //if (target.IsVisible == false)
  257. // {
  258. // if ((reason == AttackReason.Tracing || reason == AttackReason.Look) &&
  259. // expectTarget == SkillTemplate.CastTarget.Enemy)
  260. // {
  261. // bool attackAble = false;
  262. // var zv = ((target as InstanceUnit).Virtual as XmdsVirtual);
  263. // if (zv.TeamMemberVisible)
  264. // {
  265. // //不是队友看不到单位,搜索时不可见.
  266. // var uuid = ((target as InstanceUnit).Virtual as XmdsVirtual).GetPlayerUUID();
  267. // attackAble = !((src as InstanceUnit).Virtual as XmdsVirtual).IsTeamMember(uuid);
  268. // }
  269. // return attackAble;
  270. // }
  271. // }
  272. #endregion
  273. #region 位面检测.
  274. //隐身状态下,同位面,不可见,但可以被攻击.
  275. if (reason != AttackReason.Attack && !IsVisibleAOI(src, target))//AOI相关.不在同位面.
  276. {
  277. //非攻击性质才算AOI.
  278. return false;
  279. }
  280. #endregion
  281. #region PK等级保护.
  282. if (((target.Virtual) as XmdsVirtual).IsAttackable(src.Virtual as XmdsVirtual) == false)
  283. {
  284. return false;
  285. }
  286. #endregion
  287. #region 技能目标单位类型状态检测.
  288. //攻击作用单位类型.
  289. var unit_type = XmdsSkillProperties.TargetUnitType.ALL;
  290. if (weapon is SkillTemplate && reason == AttackReason.Attack)
  291. {
  292. unit_type = ((weapon as SkillTemplate).Properties as XmdsSkillProperties).NeedTargetType;
  293. }
  294. else if (weapon is SpellTemplate && reason == AttackReason.Attack)
  295. {
  296. unit_type = ((weapon as SpellTemplate).Properties as XmdsSpellProperties).NeedTargetType;
  297. }
  298. switch (unit_type)
  299. {
  300. case XmdsSkillProperties.TargetUnitType.Monster:
  301. if (!(dp is XmdsVirtual_Monster))
  302. {
  303. return false;
  304. }
  305. break;
  306. case XmdsSkillProperties.TargetUnitType.Player:
  307. if (!(dp is XmdsVirtual_Player))
  308. {
  309. return false;
  310. }
  311. break;
  312. case XmdsSkillProperties.TargetUnitType.ExcpetPlayer:
  313. if ((dp is XmdsVirtual_Player))
  314. {
  315. return false;
  316. }
  317. break;
  318. }
  319. bool onlyForDead = false;
  320. //对死人.
  321. if (src.CurrentState != null)
  322. {
  323. InstanceUnit.State s = src.CurrentState;
  324. InstanceUnit.StateSkill ss = s as InstanceUnit.StateSkill;
  325. if (ss != null)
  326. {
  327. if ((ss.SkillData.Properties as XmdsSkillProperties).TargetType == XmdsSkillProperties.XmdsSkillTargetType.AllianceDead)
  328. {
  329. //只对死亡单位有效.
  330. onlyForDead = true;
  331. }
  332. }
  333. }
  334. if (!target.IsActive)
  335. {
  336. if (onlyForDead)
  337. {
  338. /*
  339. switch(expectTarget)
  340. {
  341. case SkillTemplate.CastTarget.Alias:
  342. case SkillTemplate.CastTarget.AlliesExcludeSelf:
  343. return (src.Virtual as XmdsVirtual).IsTeamMember((target.Virtual as XmdsVirtual).GetPlayerUUID());
  344. }
  345. */
  346. //只要是玩家,不管敌友,都可以复活.
  347. return (target is XmdsInstancePlayer);
  348. }
  349. return false;
  350. }
  351. else
  352. {
  353. //对活人.
  354. if (onlyForDead == false)
  355. {
  356. switch (expectTarget)
  357. {
  358. case SkillTemplate.CastTarget.Enemy:
  359. //不是自己人.
  360. return !(src.Virtual as XmdsVirtual).IsAllies((target.Virtual as XmdsVirtual), expectTarget, reason);
  361. case SkillTemplate.CastTarget.PetForMaster:
  362. //if (src.Virtual is XmdsVirtual_Pet)
  363. //{
  364. // if ((src.Virtual as XmdsVirtual_Pet).IsMaster((target.Virtual as XmdsVirtual)))
  365. // return true;
  366. //}
  367. if(src is InstancePet)
  368. {
  369. InstancePet pet = src as InstancePet;
  370. if(pet != null && pet.Master == target)
  371. {
  372. return true;
  373. }
  374. }
  375. return false;
  376. case SkillTemplate.CastTarget.EveryOne:
  377. return JudgeEveryOneAttackable(src, target, expectTarget);
  378. case SkillTemplate.CastTarget.Alias:
  379. case SkillTemplate.CastTarget.AlliesExcludeSelf:
  380. // 可能存在即使队友,又是敌人的,所以如果是敌人就不认队友了,你tmd和我为敌,我就不给你加血
  381. if (!(src.Virtual as XmdsVirtual).IsAllies((target.Virtual as XmdsVirtual), expectTarget, reason))
  382. return false;
  383. if (src == target) { return false; }
  384. return (src.Virtual as XmdsVirtual).IsTeamMember(target);
  385. case SkillTemplate.CastTarget.AlliesIncludeSelf:
  386. // 可能存在即使队友,又是敌人的,所以如果是敌人就不认队友了,你tmd和我为敌,我就不给你加血
  387. if (!(src.Virtual as XmdsVirtual).IsAllies((target.Virtual as XmdsVirtual), expectTarget, reason))
  388. return false;
  389. return (src.Virtual as XmdsVirtual).IsTeamMember(target);
  390. //return (src.Virtual as XmdsVirtual).IsTeamMember((target.Virtual as XmdsVirtual).GetPlayerUUID());
  391. case SkillTemplate.CastTarget.EveryOneExcludeSelf:
  392. return JudgeEveryOneAttackable(src, target, expectTarget);
  393. case SkillTemplate.CastTarget.Self:
  394. return src == target;
  395. case SkillTemplate.CastTarget.EnemyAndSelf:
  396. return src == target || !(src.Virtual as XmdsVirtual).IsAllies((target.Virtual as XmdsVirtual), expectTarget, reason);
  397. case SkillTemplate.CastTarget.NA:
  398. default:
  399. return false;
  400. }
  401. }
  402. return false;
  403. }
  404. #endregion
  405. }
  406. /** 判断所有人类型可攻击模式 */
  407. private bool JudgeEveryOneAttackable(InstanceUnit src, InstanceUnit target, SkillTemplate.CastTarget expectTarget)
  408. {
  409. //if (SkillTemplate.CastTarget.EveryOne == expectTarget)
  410. //{
  411. // return (!target.IsInvincible);
  412. //}
  413. //else if (SkillTemplate.CastTarget.EveryOneExcludeSelf == expectTarget)
  414. //{
  415. // return (src != target) && (!target.IsInvincible);
  416. //}
  417. if (SkillTemplate.CastTarget.EveryOneExcludeSelf == expectTarget && src == target)
  418. {
  419. return false;
  420. }
  421. switch (src.Virtual.GetCurPKMode())
  422. {
  423. case PKMode.Peace://和平模式使用默认出生的force.
  424. if (src.Virtual.GetForceID() == target.Virtual.GetForceID())
  425. {
  426. return src.Virtual.IsAllies(target.Virtual, true, true);
  427. }
  428. return true;
  429. case PKMode.force://阵营模式使用Camp.
  430. if (src.Virtual.GetForceID() == target.Virtual.GetForceID())
  431. {
  432. return false;
  433. }
  434. return !src.Virtual.IsAllies(target.Virtual, true, true);
  435. case PKMode.Guild:
  436. if (src.Virtual.IsGuildMember(target.Virtual.GetGuildID()))
  437. {
  438. return false;
  439. }
  440. return !src.Virtual.IsAllies(target.Virtual, true, true);
  441. case PKMode.Team:
  442. return !src.Virtual.IsAllies(target.Virtual, true, true);
  443. case PKMode.All:
  444. return !(src == target);
  445. case PKMode.Justice:
  446. if (target.Virtual.GetCurPKLevel() == PKLevel.White)
  447. {
  448. return false;
  449. }
  450. return !src.Virtual.IsAllies(target.Virtual, true, true); ;
  451. case PKMode.Server:
  452. if (src.Virtual.IsServerMember(target.Virtual.GetServerID()))
  453. {
  454. return false;
  455. }
  456. return !src.Virtual.IsAllies(target.Virtual, true, true); ;
  457. }
  458. return false;
  459. }
  460. #endregion
  461. #region Region相关.
  462. protected override void InitEditRegion(RegionData rdata)
  463. {
  464. base.InitEditRegion(rdata);
  465. //单位复活点.
  466. ZoneRegion flag = getFlag(rdata.Name) as ZoneRegion;
  467. if (flag != null && rdata.Abilities != null)
  468. {
  469. List<ZoneRegion> temp = null;
  470. foreach (AbilityData td in rdata.Abilities)
  471. {
  472. if (td is XmdsRebirthAbility)
  473. {
  474. XmdsRebirthAbility zra = td as XmdsRebirthAbility;
  475. if (mRebirthRegionMap.TryGetValue(zra.START_Force, out temp))
  476. {
  477. temp.Add(flag);
  478. }
  479. else
  480. {
  481. temp = new List<ZoneRegion>();
  482. temp.Add(flag);
  483. mRebirthRegionMap.Add(zra.START_Force, temp);
  484. }
  485. }
  486. }
  487. }
  488. }
  489. /// <summary>
  490. /// 遍历所有复活点
  491. /// </summary>
  492. /// <param name="force"></param>
  493. /// <param name="action"></param>
  494. public void ForEachRebirthRegion(int force, Action<ZoneRegion> action)
  495. {
  496. List<ZoneRegion> temp = null;
  497. if (mRebirthRegionMap.TryGetValue(force, out temp))
  498. {
  499. for (int i = temp.Count - 1; i >= 0; --i)
  500. {
  501. var rg = temp[i];
  502. action(rg);
  503. }
  504. }
  505. }
  506. /// <summary>
  507. /// 获得最近的复活点
  508. /// </summary>
  509. /// <param name="x"></param>
  510. /// <param name="y"></param>
  511. /// <param name="regionForce"></param>
  512. /// <returns></returns>
  513. public ZoneRegion GetNearestRebirthRegion(float x, float y, int regionForce)
  514. {
  515. using (var list = ListObjectPool<ZoneRegion>.AllocAutoRelease())
  516. {
  517. ZoneRegion ret = null;
  518. float min_value = float.MaxValue;
  519. float len;
  520. this.ForEachRebirthRegion(regionForce, (rg) =>
  521. {
  522. if (rg.Enable)
  523. {
  524. len = MathVector.getDistanceSquare(x, y, rg.X, rg.Y);
  525. if (len < min_value)
  526. {
  527. min_value = len;
  528. ret = rg;
  529. }
  530. }
  531. });
  532. return ret;
  533. }
  534. }
  535. /// <summary>
  536. /// 获得该地图随机的复活点
  537. /// </summary>
  538. /// <param name="regionForce"></param>
  539. /// <returns></returns>
  540. public ZoneRegion GetRandomRebirthRegion(int regionForce)
  541. {
  542. using (var list = ListObjectPool<ZoneRegion>.AllocAutoRelease())
  543. {
  544. ZoneRegion ret = null;
  545. List<ZoneRegion> temp = null;
  546. mRebirthRegionMap.TryGetValue(regionForce, out temp);
  547. //不知道阵营的情况下,用这个逻辑
  548. if(temp == null)
  549. {
  550. mRebirthRegionMap.TryGetValue(-1, out temp);
  551. }
  552. if (temp != null)
  553. {
  554. int num = RandomN.Next(0, temp.Count);
  555. if (num > temp.Count)
  556. {
  557. num = temp.Count - 1;
  558. }
  559. return temp[num];
  560. }
  561. return ret;
  562. }
  563. }
  564. /// <summary>
  565. /// 获得场景下对应阵营的出生点.
  566. /// </summary>
  567. /// <param name="startForce"></param>
  568. /// <returns></returns>
  569. public List<ZoneRegion> GetRebirthRegions(byte startForce)
  570. {
  571. List<ZoneRegion> ret = null;
  572. if (mRebirthRegionMap != null)
  573. {
  574. mRebirthRegionMap.TryGetValue(startForce, out ret);
  575. }
  576. return ret;
  577. }
  578. #endregion
  579. #region Events
  580. internal void callback_OnCombatStateChange(InstanceUnit unit, BattleStatus status)
  581. {
  582. if (mOnCombatStateChange != null)
  583. {
  584. mOnCombatStateChange.Invoke(unit, status);
  585. }
  586. }
  587. public delegate void CombatStateChangeHandler(InstanceUnit unit, BattleStatus status);
  588. [EventTriggerDescAttribute("单位战斗状态改变")]
  589. public event CombatStateChangeHandler OnCombatStateChange { add { mOnCombatStateChange += value; } remove { mOnCombatStateChange -= value; } }
  590. private CombatStateChangeHandler mOnCombatStateChange;
  591. protected override void ClearEvents()
  592. {
  593. mOnCombatStateChange = null;
  594. base.ClearEvents();
  595. }
  596. #endregion
  597. }
  598. }