XmdsInstancePet.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. using CommonAI.Data;
  2. using CommonAI.Zone;
  3. using CommonAI.Zone.Helper;
  4. using CommonAI.Zone.Instance;
  5. using CommonLang;
  6. using CommonLang.Geometry;
  7. using CommonLang.Vector;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Linq;
  11. using System.Text;
  12. using XmdsCommon.Message;
  13. using XmdsCommon.Plugin;
  14. using XmdsCommonServer.Plugin.XmdsSkillTemplate.DamageCalculator;
  15. using static CommonAI.Zone.SkillTemplate;
  16. namespace XmdsCommonServer.Plugin.Units
  17. {
  18. public class XmdsInstancePet : InstancePet
  19. {
  20. private XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode mCurFollowMode = XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode.ActiveAtk;
  21. //主人当前战斗状态.
  22. private BattleStatus mMasterCombatStatus;
  23. private InstanceUnit mCurAtkUnit = null;
  24. public XmdsInstancePet(InstanceZone zone, UnitInfo info, string name, int force, int level)
  25. : base(zone, info, name, force, level)
  26. {
  27. }
  28. public override bool IsActive
  29. {
  30. get { return (this.Enable) && (this.CurrentHP > 0) && (MasterIsReady() && !IsMasterDead()); }
  31. }
  32. public override bool IsAttackable { get { return (this.Enable && MasterIsReady() && !IsMasterDead()); } }
  33. public override bool IsVisible
  34. {
  35. get
  36. {
  37. if (mMaster != null && mMaster.IsDead() == true)
  38. {
  39. return false;
  40. }
  41. return base.IsVisible;
  42. }
  43. }
  44. public bool MasterIsReady()
  45. {
  46. if (mMaster == null) { return true; }
  47. else
  48. {
  49. if (mMaster is XmdsInstancePlayer)
  50. {
  51. return (mMaster as XmdsInstancePlayer).IsPlayerReady();
  52. }
  53. }
  54. return true;
  55. }
  56. private bool IsMasterDead()
  57. {
  58. if (mMaster == null) { return false; }
  59. return mMaster.IsDead();
  60. }
  61. protected virtual bool CheckFollowMaster() { return true; }
  62. protected override void OnPetUpdate()
  63. {
  64. if (mMaster != null && !IsMasterDead() && MasterIsReady())
  65. {
  66. if (this.CheckFollowMaster() && !CMath.includeRoundPoint(X, Y, Templates.CFG.PET_FOLLOW_DISTANCE_LIMIT, mMaster.X, mMaster.Y))
  67. {
  68. mCurAtkUnit = null;
  69. this.transportToMaster();
  70. }
  71. else
  72. {
  73. //if ((this.Virtual as XmdsVirtual).CombatState != BattleStatus.None)
  74. //{
  75. // float d = 0;
  76. // //非战斗状态.
  77. // d = Templates.CFG.PET_FOLLOW_DISTANCE_MAX;
  78. // if (!CMath.includeRoundPoint(X, Y, d, mMaster.X, mMaster.Y))
  79. // {
  80. // mCurAtkUnit = null;
  81. // this.followMaster();
  82. // }
  83. //}
  84. }
  85. //主人脱战了,并且没有伤害,宠物强行脱战
  86. //2020.9.22修改,宠物可以和怪物撕逼
  87. if (CurrentState is StateIdle || (this.Master.mLastHitOtherTime + XmdsConfig.Instance.OUTOF_BATTLE_PLAYER < CommonLang.CUtils.localTimeMS
  88. && this.Master.mLastDamageTime + XmdsConfig.Instance.OUTOF_BATTLE_PLAYER < CommonLang.CUtils.localTimeMS))
  89. {
  90. mCurAtkUnit = null;
  91. //if ((this.Virtual as XmdsVirtual).CombatState == BattleStatus.None || (this.Virtual as XmdsVirtual).CombatState == BattleStatus.ReadyBattle)
  92. if(this.CheckFollowMaster() && this.Virtual.GetBattleStatus() <= BattleStatus.ReadyBattle)
  93. {
  94. float d = 0;
  95. //战斗状态.
  96. d = Math.Max(XmdsConfig.Instance.PET_IDLE_FOLLOW_MAX_DISTANCE, Master.BodyBlockSize + this.BodyBlockSize);
  97. if (!CMath.includeRoundPoint(X, Y, d, mMaster.X, mMaster.Y))
  98. {
  99. this.followMaster();
  100. }
  101. }
  102. DoSomethingByMode();
  103. }
  104. else if (CurrentState is StateFollowAndAttack)
  105. {
  106. mCurAtkUnit = (CurrentState as StateFollowAndAttack).TargetUnit;
  107. }
  108. }
  109. else if(this.Info.SumType == SummonType.attack && CurrentState is StateIdle)
  110. {
  111. DoSomethingByMode();
  112. }
  113. }
  114. public void SetFollowMode(XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode mode)
  115. {
  116. if (mCurFollowMode != mode)
  117. {
  118. mCurFollowMode = mode;
  119. }
  120. }
  121. // 获取队伍的天命属性加成
  122. public override int GetTeamFateValue(UnitFateType fateType)
  123. {
  124. if(this.Master == null)
  125. {
  126. return 0;
  127. }
  128. return this.Master.GetTeamFateValue(fateType);
  129. }
  130. public void DoSomethingByMode()
  131. {
  132. if (IsNoneSkill) { return; }
  133. //当前模式.
  134. switch (mCurFollowMode)
  135. {
  136. case XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode.ActiveAtk:
  137. if (!IsPetCanAttack() && this.Master.CurrentActionStatus == UnitActionStatus.Move && !(this.CurrentState is StateFollowMaster))
  138. {
  139. this.Virtual.SetCombatState(BattleStatus.None);
  140. this.followMaster();
  141. break;
  142. }
  143. else if (mMasterCombatStatus == BattleStatus.PVP)
  144. {
  145. //优先寻找与主人有PK关联的怪物(IsPlayer).
  146. if (TryAtkMasterEnemy(FindEnemy()))
  147. {
  148. return;
  149. }
  150. else
  151. {
  152. TryAtkSelfEnemy();
  153. return;
  154. }
  155. }
  156. else
  157. {
  158. if (TryAtkSelfEnemy())
  159. {
  160. return;
  161. }
  162. else
  163. {
  164. TryAtkMasterEnemy(FindEnemy());
  165. return;
  166. }
  167. }
  168. case XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode.PassiveAtk:
  169. if (!IsPetCanAttack() && this.Master.CurrentActionStatus == UnitActionStatus.Move && !(this.CurrentState is StateFollowMaster))
  170. {
  171. this.Virtual.SetCombatState(BattleStatus.None);
  172. this.followMaster();
  173. break;
  174. }
  175. else
  176. if (mMasterCombatStatus == BattleStatus.PVP)
  177. {
  178. //优先寻找与主人有PK关联的怪物(IsPlayer).
  179. if (TryAtkMasterEnemy(FindEnemy()))
  180. {
  181. return;
  182. }
  183. }
  184. else if (mMasterCombatStatus == BattleStatus.PVE)
  185. {
  186. if (TryAtkMasterEnemy(FindEnemy()))
  187. {
  188. return;
  189. }
  190. }
  191. //如果没有找到敌人,且自己战斗状态下,攻击自己的敌人
  192. if(this.Virtual.GetBattleStatus() > BattleStatus.ReadyBattle)
  193. {
  194. //找不到再寻找自己的敌人.
  195. if (TryAtkSelfEnemy())
  196. {
  197. return;
  198. }
  199. }
  200. break;
  201. case XmdsCommon.Plugin.XmdsPetConifg.XmdsPetFollowMode.FollowMaster:
  202. //跟随宿主.什么都不做.
  203. break;
  204. default:
  205. break;
  206. }
  207. }
  208. public void OnMasterChangeCombatStatus(BattleStatus status)
  209. {
  210. mMasterCombatStatus = status;
  211. //如果变更为PVP模式,宠物立即切换攻击目标.
  212. if (mMasterCombatStatus == BattleStatus.PVP)
  213. {
  214. if (this.CurrentState is StateSkill)
  215. {
  216. var ss = CurrentState as StateSkill;
  217. ss.block();
  218. }
  219. DoSomethingByMode();
  220. }
  221. }
  222. override public bool IsPet { get { return true; } }
  223. /// <summary>
  224. /// PVP模式下找出与主人有PVP关联且离自己最近的单位.
  225. /// 非PVP模式下找出与主人有战斗关联且离自己最近的单位.
  226. /// </summary>
  227. /// <param name="ispvp"></param>
  228. /// <returns></returns>
  229. private List<HateSystem.HateInfo> FindEnemy()
  230. {
  231. var master = this.Master;
  232. if (master == null)
  233. {
  234. return null;
  235. }
  236. var masterVirtual = (master.Virtual as XmdsVirtual);
  237. if (masterVirtual == null)
  238. {
  239. return null;
  240. }
  241. var hateSystem = masterVirtual.GetHateSystem();
  242. //bool pa = false;
  243. //bool pb = false;
  244. List<HateSystem.HateInfo> list = new List<HateSystem.HateInfo>();
  245. hateSystem.GetHateList(list);
  246. if (list != null && list.Count > 0)
  247. {
  248. list.Sort((a, b) =>
  249. {
  250. //选距离最近的单位.
  251. float da = CMath.getDistanceSquare(a.Unit.X, a.Unit.Y, this.X, this.Y);
  252. float db = CMath.getDistanceSquare(b.Unit.X, b.Unit.Y, this.X, this.Y);
  253. return (int)(da - db);
  254. });
  255. return list;
  256. }
  257. return null;
  258. }
  259. /** 是否可攻击 */
  260. //2021.1.6修改,放弃宠物自行攻击的逻辑,总是被人物束缚,没法攻击自己的敌人
  261. protected virtual bool IsPetCanAttack()
  262. {
  263. var master = this.Master;
  264. if (master != null)
  265. {
  266. if (master.mLastHitOtherTime + XmdsConfig.Instance.OUTOF_BATTLE_PLAYER > CommonLang.CUtils.localTimeMS ||
  267. master.mLastDamageTime + XmdsConfig.Instance.OUTOF_BATTLE_PLAYER > CommonLang.CUtils.localTimeMS ||
  268. this.mLastDamageTime + XmdsConfig.Instance.OUTOF_BATTLE_PLAYER > CommonLang.CUtils.localTimeMS)
  269. {
  270. return true;
  271. }
  272. }
  273. return false;
  274. }
  275. /// <summary>
  276. /// 攻击主人的敌人(优先PLAYER距离最近).
  277. /// </summary>
  278. /// <param name="list"></param>
  279. /// <returns></returns>
  280. private bool TryAtkMasterEnemy(List<HateSystem.HateInfo> list)
  281. {
  282. bool ret = false;
  283. if (list == null || list.Count == 0) { return ret; }
  284. foreach (SkillState skill in SkillStatus)
  285. {
  286. if (skill.LaunchSkill.AutoLaunch && skill.TryLaunch())
  287. {
  288. if(skill.Data.ExpectTarget == CastTarget.PetForMaster)
  289. {
  290. //是否在守卫范围内.
  291. if (CheckInAtkRange(this.Master, skill.Data.AttackRange))
  292. {
  293. if (tryAutoLaunch(skill, this.Master))
  294. {
  295. return true;
  296. }
  297. }
  298. }
  299. else
  300. {
  301. foreach (HateSystem.HateInfo hi in list)
  302. {
  303. InstanceUnit u = hi.Unit;
  304. if (this.IsCanAttack(hi.Unit) && Parent.IsAttackable(this, u, skill.Data.ExpectTarget, AttackReason.Attack, skill.Data))
  305. {
  306. //是否在守卫范围内.
  307. if (CheckInAtkRange(u, skill.Data.AttackRange))
  308. {
  309. //检测是否有可释放技能//
  310. if (tryAutoLaunch(skill, u))
  311. {
  312. return true;
  313. }
  314. }
  315. }
  316. }
  317. }
  318. }
  319. }
  320. return ret;
  321. }
  322. protected virtual bool IsCanAttack(InstanceUnit unit)
  323. {
  324. return unit.IsMonster;
  325. }
  326. protected override bool tryAutoLaunch(SkillState st, InstanceUnit target)
  327. {
  328. if(st == null)
  329. {
  330. return false;
  331. }
  332. //var v = (this.Virtual as XmdsVirtual);
  333. // if (v != null && v.AllowAutoLaunch(st.LaunchSkill.SkillID))
  334. if(st.LaunchSkill.AutoLaunch && st.TryLaunch())
  335. {
  336. changeState(new StateFollowAndAttack(this, target, st.Data.ExpectTarget));
  337. return true;
  338. }
  339. return false;
  340. }
  341. /// <summary>
  342. /// 攻击自身敌人(距离最近).
  343. /// </summary>
  344. /// <returns></returns>
  345. private bool TryAtkSelfEnemy()
  346. {
  347. bool ret = false;
  348. //using (var list = ListObjectPool<InstanceUnit>.AllocAutoRelease())
  349. //{
  350. // //找到离自己最近的单位攻击.
  351. // Parent.getObjectsRoundRange<InstanceUnit>(Collider.Object_BlockBody_TouchRound, X, Y, Info.GuardRange, list , AoiStatus);
  352. // DoAndRemoveCollection.UpdateAndRemove<InstanceUnit>(list, (InstanceUnit u) =>
  353. // {
  354. // return !u.IsActive;
  355. // });
  356. // if (list != null && list.Count > 0)
  357. // {
  358. // list.Sort((a, b) =>
  359. // {
  360. // //选距离最近的单位.
  361. // float da = CMath.getDistanceSquare(a.X, a.Y, this.X, this.Y);
  362. // float db = CMath.getDistanceSquare(b.X, b.Y, this.X, this.Y);
  363. // return (int)(da - db);
  364. // });
  365. // foreach (SkillState skill in SkillStatus)
  366. // {
  367. // if (skill.LaunchSkill.AutoLaunch && skill.TryLaunch())
  368. // {
  369. // foreach (InstanceUnit u in list)
  370. // {
  371. // if (this.IsCanAttack(u) && Parent.IsAttackable(this, u, skill.Data.ExpectTarget, AttackReason.Attack, skill.Data))
  372. // {
  373. // //是否在守卫范围内.
  374. // if (CheckInAtkRange(u, this.Info.GuardRange + skill.Data.AttackRange))
  375. // {
  376. // //检测是否有可释放技能//
  377. // if (tryAutoLaunch(skill, u))
  378. // {
  379. // return true;
  380. // }
  381. // }
  382. // }
  383. // }
  384. // }
  385. // }
  386. // }
  387. //}
  388. return ret;
  389. }
  390. public override void InitSkills(LaunchSkill baseSkill, params LaunchSkill[] skills)
  391. {
  392. if (this.Virtual == null ||
  393. (this.Virtual as XmdsVirtual).IsFinishSkillInit() == false)
  394. {
  395. return;
  396. }
  397. base.InitSkills(baseSkill, skills);
  398. }
  399. /// <summary>
  400. /// 判断该单位是否处在可攻击范围内.
  401. /// </summary>
  402. /// <param name="target"></param>
  403. /// <param name="skillrange"></param>
  404. /// <returns></returns>
  405. private bool CheckInAtkRange(InstanceUnit target, float skillrange)
  406. {
  407. bool ret = false;
  408. //两圆相切.
  409. var atkr = this.GetSkillAttackRange(skillrange);
  410. if (Collider.Object_HitBody_TouchRound(target, this.X, this.Y, atkr))
  411. {
  412. return true;
  413. }
  414. else if(this.SummonerUnit != null)
  415. {
  416. //宠物可以离开宿主的最大范围.
  417. float da = (float)Math.Pow(Templates.CFG.PET_FOLLOW_DISTANCE_MAX, 2);
  418. CommonLang.Geometry.Vector2 v1 = new CommonLang.Geometry.Vector2(this.X, this.Y);
  419. CommonLang.Geometry.Vector2 v2 = new CommonLang.Geometry.Vector2(target.X, target.Y);
  420. //方向.
  421. CommonLang.Geometry.Vector2 dir = (v2 - v1);
  422. dir.Normalize();
  423. var pos = v2 - dir * (atkr * target.BodyHitSize);
  424. float rd = CMath.getDistanceSquare(pos.X, pos.Y, this.SummonerUnit.X, this.SummonerUnit.Y);
  425. //在范围内.
  426. if (rd < da)
  427. {
  428. ret = true;
  429. }
  430. }
  431. return ret;
  432. }
  433. public override bool tryLaunchRandomSkillAndCancelCurrentSkill(InstanceUnit target, bool autoFocusNearTarget = false)
  434. {
  435. //自动战斗不允许中断当前技能施放.
  436. return false;
  437. }
  438. /** 计算并获得伤害 */
  439. public override void PetShareDamage(int baseDmgValue, InstanceUnit sender)
  440. {
  441. XmdsVirtual petVirtual = this.Virtual as XmdsVirtual;
  442. int finalDmg = XmdsDamageCalculator.GetPetDamage(baseDmgValue, petVirtual);
  443. //分发事件
  444. finalDmg = petVirtual.DispatchShareMasterDmgEvent(finalDmg, sender);
  445. this.AddHP(-finalDmg, sender);
  446. }
  447. public override void doSomething()
  448. {
  449. if (CurrentState is StateSkill)
  450. {
  451. var target = mCurAtkUnit;
  452. if (target != null)
  453. {
  454. if (tryMoveScatterTarget(target)) { return; }
  455. }
  456. }
  457. base.doSomething();
  458. }
  459. /// <summary>
  460. /// 攻击间歇,尝试换个位置,避免怪物堆在一个点
  461. /// </summary>
  462. protected virtual bool tryMoveScatterTarget(InstanceUnit target)
  463. {
  464. //只有单位为非碰撞时,才有这个需求//
  465. if (!this.IntersectObj)
  466. {
  467. if (CUtils.RandomPercent(Parent.RandomN, Templates.CFG.AI_NPC_ATTACK_IDLE_SCATTER_PCT))
  468. {
  469. InstanceUnit block = null;
  470. Parent.ForEachNearObjects(X, Y, (InstanceZoneObject o, ref bool cancel) =>
  471. {
  472. if ((o != this) && (o is InstanceUnit) && Parent.TouchObject2(this, o))
  473. {
  474. block = o as InstanceUnit;
  475. cancel = true;
  476. }
  477. });
  478. if (block != null)
  479. {
  480. float degree = MathVector.getDegree(X, Y, target.X, target.Y);
  481. float distance = this.BodyBlockSize + block.BodyBlockSize;
  482. CommonLang.Vector.Vector2 turnL = new CommonLang.Vector.Vector2(X, Y);
  483. CommonLang.Vector.Vector2 turnR = new CommonLang.Vector.Vector2(X, Y);
  484. MathVector.movePolar(turnL, degree + CMath.PI_DIV_2, distance);
  485. MathVector.movePolar(turnR, degree - CMath.PI_DIV_2, distance);
  486. float dl = MathVector.getDistanceSquare(turnL.X, turnL.Y, target.X, target.Y);
  487. float dr = MathVector.getDistanceSquare(turnR.X, turnR.Y, target.X, target.Y);
  488. if (dl < dr)
  489. {
  490. this.startMoveTo(turnL.X, turnL.Y);
  491. }
  492. else
  493. {
  494. this.startMoveTo(turnR.X, turnR.Y);
  495. }
  496. return true;
  497. }
  498. }
  499. }
  500. return false;
  501. }
  502. protected override void Disposing()
  503. {
  504. mCurAtkUnit = null;
  505. base.Disposing();
  506. }
  507. }
  508. }