BotBrain.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "BotBrain.h"
  2. #include "../Combat.h"
  3. #include "../Spells.h"
  4. #include "../../common/Log.h"
  5. #include "../Rules/Rules.h"
  6. extern RuleManager rule_manager;
  7. BotBrain::BotBrain(Bot* body) : Brain(body) {
  8. Body = body;
  9. }
  10. BotBrain::~BotBrain() {
  11. }
  12. void BotBrain::Think() {
  13. // No ownder do nothing, probably despawn as owner should never be empty for bots
  14. if (!m_body->GetOwner())
  15. return;
  16. // Not in a group yet then do nothing
  17. if (!m_body->GetGroupMemberInfo())
  18. return;
  19. if (!Body->Alive())
  20. return;
  21. if (Body->IsMezzedOrStunned())
  22. return;
  23. // If combat was processed we can return out
  24. if (ProcessCombat())
  25. return;
  26. // Combat failed to process so do out of combat tasks like follow the player
  27. if (ProcessOutOfCombatSpells())
  28. return;
  29. // put htis here so bots don't try to follow the owner while in combat
  30. if (Body->EngagedInCombat())
  31. return;
  32. // Set target to owner
  33. Spawn* target = GetBody()->GetFollowTarget();
  34. if(target)
  35. {
  36. // Get distance from the owner
  37. float distance = GetBody()->GetDistance(target);
  38. // If out of melee range then move closer
  39. if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
  40. MoveCloser(target);
  41. }
  42. }
  43. bool BotBrain::ProcessCombat() {
  44. SetTarget();
  45. if (Body->GetTarget() && Body->EngagedInCombat()) {
  46. if (Body->GetTarget() && Body->GetTarget()->IsEntity() && Body->AttackAllowed((Entity*)Body->GetTarget())) {
  47. Entity* target = (Entity*)Body->GetTarget();
  48. float distance = Body->GetDistance(target);
  49. if (!ProcessSpell(target, distance)) {
  50. if (Body->ShouldMelee())
  51. ProcessMelee(target, distance);
  52. }
  53. NPC* pet = (NPC*)Body->GetPet();
  54. if (pet) {
  55. if (pet->Brain()->GetHate(target) == 0)
  56. pet->AddHate(target, 1);
  57. }
  58. }
  59. return true;
  60. }
  61. return false;
  62. }
  63. void BotBrain::SetTarget() {
  64. // The target issued from /bot attack
  65. if (Body->GetCombatTarget() && Body->GetCombatTarget()->Alive()) {
  66. Body->SetTarget(Body->GetCombatTarget());
  67. Body->InCombat(true);
  68. return;
  69. }
  70. // Assist
  71. Entity* owner = Body->GetOwner();
  72. if (owner && owner->EngagedInCombat()) {
  73. if (owner->GetTarget() && owner->GetTarget()->IsEntity() && owner->GetTarget()->Alive() && owner->AttackAllowed((Entity*)owner->GetTarget())) {
  74. Body->SetTarget(owner->GetTarget());
  75. Body->InCombat(true);
  76. // Add some hate to keep the bot attacking if
  77. // the player toggles combat off
  78. if (GetHate((Entity*)Body->GetTarget()) == 0)
  79. AddHate((Entity*)Body->GetTarget(), 1);
  80. return;
  81. }
  82. }
  83. // Most hated
  84. Entity* hated = GetMostHated();
  85. if (hated && hated->Alive()) {
  86. if (hated == Body->GetOwner()) {
  87. ClearHate(hated);
  88. }
  89. else {
  90. Body->SetTarget(hated);
  91. Body->InCombat(true);
  92. return;
  93. }
  94. }
  95. // None of the above true so clear target and turn combat off
  96. Body->SetTarget(0);
  97. Body->InCombat(false);
  98. }
  99. bool BotBrain::ProcessSpell(Entity* target, float distance) {
  100. if (Body->IsStifled() || Body->IsFeared())
  101. return false;
  102. if (Body->IsCasting())
  103. return false;
  104. if (!HasRecovered())
  105. return false;
  106. Spell* spell = Body->SelectSpellToCast(distance);
  107. if (spell) {
  108. // Target can change (heals for example) so recalculate distance and if out of range move closer
  109. float distance = Body->GetDistance(Body->GetTarget());
  110. if (distance > spell->GetSpellData()->range) {
  111. if (Body->GetTarget()->IsEntity())
  112. MoveCloser((Spawn*)Body->GetTarget());
  113. }
  114. else {
  115. // stop movement if spell can't be cast while moving
  116. if (!spell->GetSpellData()->cast_while_moving)
  117. Body->CalculateRunningLocation(true);
  118. Body->GetZone()->ProcessSpell(spell, Body, Body->GetTarget());
  119. m_spellRecovery = (int32)(Timer::GetCurrentTime2() + (spell->GetSpellData()->cast_time * 10) + (spell->GetSpellData()->recovery * 10) + 2000);
  120. // recast time
  121. int32 time = Timer::GetCurrentTime2() + (spell->GetSpellData()->recast * 1000);
  122. Body->SetRecast(spell, time);
  123. string str = "I am casting ";
  124. str += spell->GetName();
  125. Body->MessageGroup(str);
  126. }
  127. return true;
  128. }
  129. return false;
  130. }
  131. bool BotBrain::ProcessOutOfCombatSpells() {
  132. if (Body->IsStifled() || Body->IsFeared())
  133. return false;
  134. if (Body->IsCasting())
  135. return false;
  136. if (!HasRecovered())
  137. return false;
  138. Spell* spell = Body->GetHealSpell();
  139. if (!spell)
  140. spell = Body->GetRezSpell();
  141. if (!spell)
  142. spell = Body->GetNextBuffSpell();
  143. if (spell) {
  144. // stop movement if spell can't be cast while moving
  145. if (!spell->GetSpellData()->cast_while_moving)
  146. Body->CalculateRunningLocation(true);
  147. // See if we are in range of target, if not move closer
  148. float distance = Body->GetDistance(Body->GetTarget());
  149. if (distance > spell->GetSpellData()->range) {
  150. if (Body->GetTarget()->IsEntity())
  151. MoveCloser((Spawn*)Body->GetTarget());
  152. }
  153. else {
  154. Body->GetZone()->ProcessSpell(spell, Body, Body->GetTarget());
  155. m_spellRecovery = (int32)(Timer::GetCurrentTime2() + (spell->GetSpellData()->cast_time * 10) + (spell->GetSpellData()->recovery * 10) + 2000);
  156. // recast time
  157. int32 time = Timer::GetCurrentTime2() + (spell->GetSpellData()->recast * 1000);
  158. Body->SetRecast(spell, time);
  159. string str = "I am casting ";
  160. str += spell->GetName();
  161. Body->MessageGroup(str);
  162. }
  163. return true;
  164. }
  165. return false;
  166. }