9
3

BotBrain.cpp 5.1 KB

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