ArcherHero.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. using Server.MirDatabase;
  2. using Server.MirEnvir;
  3. using System.Buffers;
  4. using System.Drawing;
  5. namespace Server.MirObjects
  6. {
  7. public class ArcherHero : HeroObject
  8. {
  9. public ArcherHero(CharacterInfo info, PlayerObject owner) : base(info, owner) { }
  10. private static Point GetAdjacentPoint(Point currentLocation, Point targetLocation, Point playerLocation)
  11. {
  12. int deltaX = targetLocation.X - currentLocation.X;
  13. int deltaY = targetLocation.Y - currentLocation.Y;
  14. int adjacentX = currentLocation.X - Math.Sign(deltaX);
  15. int adjacentY = currentLocation.Y - Math.Sign(deltaY);
  16. Point awayFromTarget = new Point(adjacentX, adjacentY);
  17. // Check if the calculated point is the same as the player's current location
  18. if (awayFromTarget == playerLocation)
  19. {
  20. // Calculate a new point that is away from the target but not the player's current location
  21. if (deltaX != 0)
  22. {
  23. adjacentX = currentLocation.X + Math.Sign(deltaX);
  24. awayFromTarget = new Point(adjacentX, adjacentY);
  25. }
  26. else if (deltaY != 0)
  27. {
  28. adjacentY = currentLocation.Y + Math.Sign(deltaY);
  29. awayFromTarget = new Point(adjacentX, adjacentY);
  30. }
  31. }
  32. return awayFromTarget;
  33. }
  34. protected override bool InAttackRange()
  35. {
  36. if (Target.CurrentMap != CurrentMap) return false;
  37. if (HasRangedSpell)
  38. return TargetDistance <= ViewRange;
  39. return Target.CurrentLocation != CurrentLocation && Functions.InRange(CurrentLocation, Target.CurrentLocation, 1);
  40. }
  41. protected override void ProcessFriend()
  42. {
  43. if (!CanCast) return;
  44. if (Target != null)
  45. {
  46. if (!HasBuff(BuffType.Concentration))
  47. {
  48. UserMagic magic = GetMagic(Spell.Concentration);
  49. if (CanUseMagic(magic))
  50. {
  51. BeginMagic(magic.Spell, Direction, ObjectID, CurrentLocation);
  52. return;
  53. }
  54. }
  55. }
  56. }
  57. protected override void ProcessAttack()
  58. {
  59. if (!CanCast || Target == null || Target.Dead) return;
  60. if (!HasRangedSpell) return;
  61. TargetDistance = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation);
  62. Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
  63. UserMagic magic;
  64. if (InAttackRange())
  65. {
  66. magic = GetMagic(Spell.PoisonShot);
  67. if (CanUseMagic(magic))
  68. {
  69. if (!Target.PoisonList.Any(p => p.PType == PoisonType.Green))
  70. {
  71. if (!HasBuff(BuffType.PoisonShot))
  72. {
  73. BeginMagic(magic.Spell, Direction, Target.ObjectID, Target.CurrentLocation);
  74. return;
  75. }
  76. }
  77. }
  78. if (GetElementalOrbCount() < 1 || GetElementalOrbCount() > 3)
  79. {
  80. magic = GetMagic(Spell.ElementalShot);
  81. if (CanUseMagic(magic))
  82. {
  83. BeginMagic(magic.Spell, Direction, Target.ObjectID, Target.CurrentLocation);
  84. return;
  85. }
  86. }
  87. magic = GetMagic(Spell.StraightShot);
  88. if (CanUseMagic(magic))
  89. {
  90. BeginMagic(magic.Spell, Direction, Target.ObjectID, Target.CurrentLocation);
  91. return;
  92. }
  93. magic = GetMagic(Spell.None);
  94. {
  95. return;
  96. }
  97. }
  98. magic = GetMagic(Spell.None);
  99. {
  100. return;
  101. }
  102. }
  103. protected override void ProcessTarget()
  104. {
  105. int distanceToPlayer = Functions.MaxDistance(CurrentLocation, Owner.CurrentLocation);
  106. if (Owner.PMode == PetMode.FocusMasterTarget && Target != null && !Target.IsAttackTarget(Owner))
  107. {
  108. Target = null;
  109. return;
  110. }
  111. if (Target == null || !CanAttack) return;
  112. if (HasClassWeapon && CanCast && NextMagicSpell != Spell.None)
  113. {
  114. Magic(NextMagicSpell, NextMagicDirection, NextMagicTargetID, NextMagicLocation);
  115. NextMagicSpell = Spell.None;
  116. }
  117. if (CanMove && !CanAttack && (TargetDistance < 3 && Owner.Info.HeroBehaviour == HeroBehaviour.Attack && distanceToPlayer < 6))
  118. {
  119. Point awayFromTarget = GetAdjacentPoint(CurrentLocation, Target.CurrentLocation, Owner.CurrentLocation);
  120. MoveTo(awayFromTarget);
  121. return;
  122. }
  123. if (CanMove && ((Owner.Info.HeroBehaviour == HeroBehaviour.CounterAttack && distanceToPlayer > 2) || (Owner.Info.HeroBehaviour == HeroBehaviour.Attack && distanceToPlayer > 5)))
  124. {
  125. MoveTo(Owner.Back);
  126. return;
  127. }
  128. if ((CanAttack && Target != null && HasClassWeapon && (NextMagicSpell == Spell.None || !HasRangedSpell || !CanCast)))
  129. {
  130. Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
  131. RangeAttack(Direction, Target.CurrentLocation, Target.ObjectID);
  132. if (Target.Dead)
  133. {
  134. FindTarget();
  135. }
  136. return;
  137. }
  138. if (CanAttack && (!HasWeapon || (HasWeapon && !HasClassWeapon)))
  139. {
  140. if (TargetDistance >= 1 && InAttackRange())
  141. {
  142. Attack();
  143. if (Target.Dead)
  144. {
  145. FindTarget();
  146. return;
  147. }
  148. }
  149. else
  150. {
  151. MoveTo(Target.CurrentLocation);
  152. return;
  153. }
  154. }
  155. }
  156. private bool HasRangedSpell => Info.Magics.Select(x => x.Spell).Intersect(Globals.RangedSpells).Any();
  157. public bool HasWeapon => Info.Equipment[(int)EquipmentSlot.Weapon] != null && Info.Equipment[(int)EquipmentSlot.Weapon].CurrentDura > 0;
  158. public bool HasClassWeapon
  159. {
  160. get
  161. {
  162. var classweapon = Info.Equipment[(int)EquipmentSlot.Weapon];
  163. return classweapon != null && classweapon.Info.RequiredClass == RequiredClass.Archer && classweapon.CurrentDura > 0;
  164. }
  165. }
  166. }
  167. }