Player* PlayerbotClassAI::GetResurrectionTarget(JOB_TYPE type, bool bMustBeOOC) { if (!m_ai) return nullptr; if (!m_bot) return nullptr; if (!m_bot->isAlive() || m_bot->IsInDuel()) return nullptr; if (bMustBeOOC && m_bot->isInCombat()) return nullptr; // First, fill the list of targets if (m_bot->GetGroup()) { // define seperately for sorting purposes - DO NOT CHANGE ORDER! std::vector<heal_priority> targets; Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember || groupMember->isAlive()) continue; JOB_TYPE job = GetTargetJob(groupMember); if (job & type) targets.push_back( heal_priority(groupMember, 0, job) ); } // Sorts according to type: Healers first, tanks next, then master followed by DPS, thanks to the order of the TYPE enum std::sort(targets.begin(), targets.end()); if (targets.size()) return targets.at(0).p; } else if (!m_master->isAlive()) return m_master; return nullptr; }
// Please note that job_type JOB_MANAONLY is a cumulative restriction. JOB_TANK | JOB_HEAL means both; JOB_TANK | JOB_MANAONLY means tanks with powertype MANA (paladins, druids) CombatManeuverReturns PlayerbotClassAI::Buff(bool (*BuffHelper)(PlayerbotAI*, uint32, Unit*), uint32 spellId, uint32 type, bool bMustBeOOC) { if (!m_ai) return RETURN_NO_ACTION_ERROR; if (!m_bot) return RETURN_NO_ACTION_ERROR; if (!m_bot->isAlive() || m_bot->IsInDuel()) return RETURN_NO_ACTION_ERROR; if (bMustBeOOC && m_bot->isInCombat()) return RETURN_NO_ACTION_ERROR; if (spellId == 0) return RETURN_NO_ACTION_OK; // First, fill the list of targets if (m_bot->GetGroup()) { Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember || !groupMember->isAlive() || groupMember->IsInDuel()) continue; JOB_TYPE job = GetTargetJob(groupMember); if (job & type && (!(job & JOB_MANAONLY) || groupMember->getClass() == CLASS_DRUID || groupMember->GetPowerType() == POWER_MANA)) { if (BuffHelper(m_ai, spellId, groupMember)) return RETURN_CONTINUE; } } } else { if (m_master && !m_master->IsInDuel() && (!(GetTargetJob(m_master) & JOB_MANAONLY) || m_master->getClass() == CLASS_DRUID || m_master->GetPowerType() == POWER_MANA)) if (BuffHelper(m_ai, spellId, m_master)) return RETURN_CONTINUE; // Do not check job or power type - any buff you have is always useful to self if (BuffHelper(m_ai, spellId, m_bot)) return RETURN_CONTINUE; } return RETURN_NO_ACTION_OK; }
CombatManeuverReturns PlayerbotPaladinAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; // If target is out of range (40 yards) and is a tank: move towards it // if bot is not asked to stay // Other classes have to adjust their position to the healers // TODO: This code should be common to all healers and will probably // move to a more suitable place like PlayerbotAI::DoCombatMovement() if ((GetTargetJob(target) == JOB_TANK || GetTargetJob(target) == JOB_MAIN_TANK) && m_bot->GetPlayerbotAI()->GetMovementOrder() != PlayerbotAI::MOVEMENT_STAY && !m_ai->In_Reach(target, FLASH_OF_LIGHT)) { m_bot->GetMotionMaster()->MoveFollow(target, 39.0f, m_bot->GetOrientation()); return RETURN_CONTINUE; } uint8 hp = target->GetHealthPercent(); // Everyone is healthy enough, return OK. MUST correlate to highest value below (should be last HP check) if (hp >= 80) return RETURN_NO_ACTION_OK; if (hp < 10 && LAY_ON_HANDS && m_bot->IsSpellReady(LAY_ON_HANDS) && m_ai->In_Reach(target, LAY_ON_HANDS) && m_ai->CastSpell(LAY_ON_HANDS, *target) == SPELL_CAST_OK) return RETURN_CONTINUE; // Target is a moderately wounded healer or a badly wounded not tank? Blessing of Protection! if (BLESSING_OF_PROTECTION > 0 && ((hp < 25 && (GetTargetJob(target) & JOB_HEAL || GetTargetJob(target) & JOB_MAIN_HEAL)) || (hp < 15 && !(GetTargetJob(target) & JOB_TANK) && !(GetTargetJob(target) & JOB_MAIN_TANK))) && m_bot->IsSpellReady(BLESSING_OF_PROTECTION) && m_ai->In_Reach(target, BLESSING_OF_PROTECTION) && !target->HasAura(FORBEARANCE, EFFECT_INDEX_0) && !target->HasAura(BLESSING_OF_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_SHIELD, EFFECT_INDEX_0) && m_ai->CastSpell(BLESSING_OF_PROTECTION, *target) == SPELL_CAST_OK) return RETURN_CONTINUE; // Low HP : activate Divine Favor to make next heal a critical heal if (hp < 25 && DIVINE_FAVOR > 0 && !m_bot->HasAura(DIVINE_FAVOR, EFFECT_INDEX_0) && m_bot->IsSpellReady(DIVINE_FAVOR)) m_ai->CastSpell(DIVINE_FAVOR, *m_bot); if (hp < 40 && HOLY_LIGHT > 0 && m_ai->In_Reach(target, HOLY_LIGHT) && m_ai->CastSpell(HOLY_LIGHT, *target) == SPELL_CAST_OK) return RETURN_CONTINUE; if (hp < 60 && HOLY_SHOCK > 0 && m_ai->In_Reach(target, HOLY_SHOCK) && m_ai->CastSpell(HOLY_SHOCK, *target) == SPELL_CAST_OK) return RETURN_CONTINUE; if (hp < 80 && FLASH_OF_LIGHT > 0 && m_ai->In_Reach(target, FLASH_OF_LIGHT) && m_ai->CastSpell(FLASH_OF_LIGHT, *target) == SPELL_CAST_OK) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget
/** * GetDispelTarget() * return Unit* Returns unit to be dispelled. First checks 'critical' Healer(s), next Tank(s), next Master (if different from:), next DPS. * * return NULL If NULL is returned, no healing is required. At all. * * Will need extensive re-write for co-operation amongst multiple healers. As it stands, multiple healers would all pick the same 'ideal' * healing target. */ Player* PlayerbotClassAI::GetDispelTarget(DispelType dispelType, JOB_TYPE type, bool bMustBeOOC) { if (!m_ai) return nullptr; if (!m_bot) return nullptr; if (!m_bot->isAlive() || m_bot->IsInDuel()) return nullptr; if (bMustBeOOC && m_bot->isInCombat()) return nullptr; // First, fill the list of targets if (m_bot->GetGroup()) { // define seperately for sorting purposes - DO NOT CHANGE ORDER! std::vector<heal_priority> targets; Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember || !groupMember->isAlive()) continue; JOB_TYPE job = GetTargetJob(groupMember); if (job & type) { uint32 dispelMask = GetDispellMask(dispelType); Unit::SpellAuraHolderMap const& auras = groupMember->GetSpellAuraHolderMap(); for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { SpellAuraHolder *holder = itr->second; // Only return group members with negative magic effect if (dispelType == DISPEL_MAGIC && holder->IsPositive()) continue; // poison, disease and curse are always negative: return everyone if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) targets.push_back( heal_priority(groupMember, 0, job) ); } } } // Sorts according to type: Healers first, tanks next, then master followed by DPS, thanks to the order of the TYPE enum std::sort(targets.begin(), targets.end()); if (targets.size()) return targets.at(0).p; } return nullptr; }
CombatManeuverReturns PlayerbotPaladinAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (REDEMPTION && m_ai->CastSpell(REDEMPTION, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } return RETURN_NO_ACTION_ERROR; // not error per se - possibly just OOM } if (PURIFY > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { uint32 DISPEL = CLEANSE > 0 ? CLEANSE : PURIFY; uint32 dispelMask = GetDispellMask(DISPEL_DISEASE); uint32 dispelMask2 = GetDispellMask(DISPEL_POISON); uint32 dispelMask3 = GetDispellMask(DISPEL_MAGIC); Unit::SpellAuraHolderMap const& auras = target->GetSpellAuraHolderMap(); for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { SpellAuraHolder* holder = itr->second; if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) { if (holder->GetSpellProto()->Dispel == DISPEL_DISEASE) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask2) { if (holder->GetSpellProto()->Dispel == DISPEL_POISON) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask3 & (DISPEL == CLEANSE)) { if (holder->GetSpellProto()->Dispel == DISPEL_MAGIC) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } } } uint8 hp = target->GetHealthPercent(); // Everyone is healthy enough, return OK. MUST correlate to highest value below (should be last HP check) if (hp >= 90) return RETURN_NO_ACTION_OK; if (hp < 25 && m_ai->CastSpell(LAY_ON_HANDS, *target)) return RETURN_CONTINUE; // You probably want to save this for tank/healer trouble if (hp < 30 && HAND_OF_PROTECTION > 0 && !target->HasAura(FORBEARANCE, EFFECT_INDEX_0) && !target->HasAura(HAND_OF_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_SHIELD, EFFECT_INDEX_0) && (GetTargetJob(target) & (JOB_HEAL | JOB_TANK)) && m_ai->CastSpell(HAND_OF_PROTECTION, *target)) return RETURN_CONTINUE; // Isn't this more of a group heal spell? if (hp < 40 && m_ai->CastSpell(FLASH_OF_LIGHT, *target)) return RETURN_CONTINUE; if (hp < 60 && m_ai->CastSpell(HOLY_SHOCK, *target)) return RETURN_CONTINUE; if (hp < 90 && m_ai->CastSpell(HOLY_LIGHT, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget
void PlayerbotPaladinAI::CheckAuras() { if (!m_ai) return; if (!m_bot) return; uint32 spec = m_bot->GetSpec(); // If we have resist orders, adjust accordingly if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_RESIST_FROST) { if (!m_bot->HasAura(FROST_RESISTANCE_AURA) && FROST_RESISTANCE_AURA > 0 && !m_bot->HasAura(FROST_RESISTANCE_AURA)) m_ai->CastSpell(FROST_RESISTANCE_AURA); return; } else if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_RESIST_FIRE) { if (!m_bot->HasAura(FIRE_RESISTANCE_AURA) && FIRE_RESISTANCE_AURA > 0 && !m_bot->HasAura(FIRE_RESISTANCE_AURA)) m_ai->CastSpell(FIRE_RESISTANCE_AURA); return; } else if (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_RESIST_SHADOW) { // Shadow protection check is broken, they stack! if (!m_bot->HasAura(SHADOW_RESISTANCE_AURA) && SHADOW_RESISTANCE_AURA > 0 && !m_bot->HasAura(SHADOW_RESISTANCE_AURA)) // /*&& !m_bot->HasAura(PRAYER_OF_SHADOW_PROTECTION)*/ /*&& !m_bot->HasAura(PRAYER_OF_SHADOW_PROTECTION)*/ m_ai->CastSpell(SHADOW_RESISTANCE_AURA); return; } // if there is a tank in the group, use concentration aura bool tankInGroup = false; if (m_bot->GetGroup()) { Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player* groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember) continue; if (GetTargetJob(groupMember) & JOB_TANK || GetTargetJob(groupMember) & JOB_MAIN_TANK) { tankInGroup = true; break; } } } // If we have no resist orders, adjust aura based on spec or tank if (spec == PALADIN_SPEC_PROTECTION || tankInGroup) { if (DEVOTION_AURA > 0 && !m_bot->HasAura(DEVOTION_AURA)) m_ai->CastSpell(DEVOTION_AURA); return; } else if (spec == PALADIN_SPEC_HOLY) { if (CONCENTRATION_AURA > 0 && !m_bot->HasAura(CONCENTRATION_AURA)) m_ai->CastSpell(CONCENTRATION_AURA); return; } else if (spec == PALADIN_SPEC_RETRIBUTION) { if (RETRIBUTION_AURA > 0 && !m_bot->HasAura(RETRIBUTION_AURA)) m_ai->CastSpell(RETRIBUTION_AURA); return; } }
/** * GetHealTarget() * return Unit* Returns unit to be healed. First checks 'critical' Healer(s), next Tank(s), next Master (if different from:), next DPS. * If none of the healths are low enough (or multiple valid targets) against these checks, the lowest health is healed. Having a target * returned does not guarantee it's worth healing, merely that the target does not have 100% health. * * return NULL If NULL is returned, no healing is required. At all. * * Will need extensive re-write for co-operation amongst multiple healers. As it stands, multiple healers would all pick the same 'ideal' * healing target. */ Player* PlayerbotClassAI::GetHealTarget(JOB_TYPE type) { if (!m_ai) return nullptr; if (!m_bot) return nullptr; if (!m_bot->isAlive() || m_bot->IsInDuel()) return nullptr; // define seperately for sorting purposes - DO NOT CHANGE ORDER! std::vector<heal_priority> targets; // First, fill the list of targets if (m_bot->GetGroup()) { Group::MemberSlotList const& groupSlot = m_bot->GetGroup()->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *groupMember = sObjectMgr.GetPlayer(itr->guid); if (!groupMember || !groupMember->isAlive() || groupMember->IsInDuel()) continue; JOB_TYPE job = GetTargetJob(groupMember); if (job & type) targets.push_back( heal_priority(groupMember, (groupMember->GetHealth() * 100 / groupMember->GetMaxHealth()), job) ); } } else { targets.push_back( heal_priority(m_bot, m_bot->GetHealthPercent(), GetTargetJob(m_bot)) ); if (m_master && !m_master->IsInDuel()) targets.push_back( heal_priority(m_master, (m_master->GetHealth() * 100 / m_master->GetMaxHealth()), GetTargetJob(m_master)) ); } // Sorts according to type: Healers first, tanks next, then master followed by DPS, thanks to the order of the TYPE enum std::sort(targets.begin(), targets.end()); uint8 uCount = 0,i = 0; // x is used as 'target found' variable; i is used as the targets iterator throughout all 4 types. int16 x = -1; // Try to find a healer in need of healing (if multiple, the lowest health one) while (true) { // This works because we sorted it above if ( (uCount + i) >= targets.size() || !(targets.at(uCount).type & JOB_HEAL)) break; uCount++; } // We have uCount healers in the targets, check if any qualify for priority healing for (; uCount > 0; uCount--, i++) { if (targets.at(i).hp <= m_MinHealthPercentHealer) if (x == -1 || targets.at(x).hp > targets.at(i).hp) x = i; } if (x > -1) return targets.at(x).p; // Try to find a tank in need of healing (if multiple, the lowest health one) while (true) { if ( (uCount + i) >= targets.size() || !(targets.at(uCount).type & JOB_TANK)) break; uCount++; } for (; uCount > 0; uCount--, i++) { if (targets.at(i).hp <= m_MinHealthPercentTank) if (x == -1 || targets.at(x).hp > targets.at(i).hp) x = i; } if (x > -1) return targets.at(x).p; // Try to find master in need of healing (lowest health one first) if (m_MinHealthPercentMaster != m_MinHealthPercentDPS) { while (true) { if ( (uCount + i) >= targets.size() || !(targets.at(uCount).type & JOB_MASTER)) break; uCount++; } for (; uCount > 0; uCount--, i++) { if (targets.at(i).hp <= m_MinHealthPercentMaster) if (x == -1 || targets.at(x).hp > targets.at(i).hp) x = i; } if (x > -1) return targets.at(x).p; } // Try to find anyone else in need of healing (lowest health one first) while (true) { if ( (uCount + i) >= targets.size() ) break; uCount++; } for (; uCount > 0; uCount--, i++) { if (targets.at(i).hp <= m_MinHealthPercentDPS) if (x == -1 || targets.at(x).hp > targets.at(i).hp) x = i; } if (x > -1) return targets.at(x).p; // Nobody is critical, find anyone hurt at all, return lowest (let the healer sort out if it's worth healing or not) for (i = 0, uCount = targets.size(); uCount > 0; uCount--, i++) { if (targets.at(i).hp < 100) if (x == -1 || targets.at(x).hp > targets.at(i).hp) x = i; } if (x > -1) return targets.at(x).p; return nullptr; }
CombatManeuverReturns PlayerbotPaladinAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (REDEMPTION && m_ai->CastSpell(REDEMPTION, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } return RETURN_NO_ACTION_ERROR; // not error per se - possibly just OOM } uint32 dispel = CLEANSE > 0 ? CLEANSE : PURIFY; // Remove negative magic on group members if orders allow bot to do so if (Player* pCursedTarget = GetDispelTarget(DISPEL_MAGIC)) { if (dispel > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && m_ai->CastSpell(dispel, *pCursedTarget)) return RETURN_CONTINUE; } // Remove poison on group members if orders allow bot to do so if (Player* pPoisonedTarget = GetDispelTarget(DISPEL_POISON)) { m_ai->TellMaster("Has poison %s :", pPoisonedTarget->GetName()); if (dispel > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && m_ai->CastSpell(dispel, *pPoisonedTarget)) return RETURN_CONTINUE; } // Remove disease on group members if orders allow bot to do so if (Player* pDiseasedTarget = GetDispelTarget(DISPEL_DISEASE)) { if (dispel > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0 && m_ai->CastSpell(dispel, *pDiseasedTarget)) return RETURN_CONTINUE; } // Define a tank bot will look at Unit* pMainTank = GetHealTarget(JOB_TANK); // If target is out of range (40 yards) and is a tank: move towards it // Other classes have to adjust their position to the healers // TODO: This code should be common to all healers and will probably // move to a more suitable place if (pMainTank && !m_ai->In_Reach(pMainTank, FLASH_OF_LIGHT)) { m_bot->GetMotionMaster()->MoveFollow(target, 39.0f, m_bot->GetOrientation()); return RETURN_CONTINUE; } uint8 hp = target->GetHealthPercent(); // Everyone is healthy enough, return OK. MUST correlate to highest value below (should be last HP check) if (hp >= 90) return RETURN_NO_ACTION_OK; if (hp < 10 && LAY_ON_HANDS && m_bot->IsSpellReady(LAY_ON_HANDS) && m_ai->In_Reach(target, LAY_ON_HANDS) && m_ai->CastSpell(LAY_ON_HANDS, *target)) return RETURN_CONTINUE; // Target is a moderately wounded healer or a badly wounded not tank? Blessing of Protection! if (BLESSING_OF_PROTECTION > 0 && ((hp < 25 && (GetTargetJob(target) & JOB_HEAL)) || (hp < 15 && !(GetTargetJob(target) & JOB_TANK))) && m_bot->IsSpellReady(BLESSING_OF_PROTECTION) && m_ai->In_Reach(target, BLESSING_OF_PROTECTION) && !target->HasAura(FORBEARANCE, EFFECT_INDEX_0) && !target->HasAura(BLESSING_OF_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_SHIELD, EFFECT_INDEX_0) && m_ai->CastSpell(BLESSING_OF_PROTECTION, *target)) return RETURN_CONTINUE; // Low HP : activate Divine Favor to make next heal a critical heal if (hp < 25 && DIVINE_FAVOR > 0 && !m_bot->HasAura(DIVINE_FAVOR, EFFECT_INDEX_0) && m_bot->IsSpellReady(DIVINE_FAVOR) && m_ai->CastSpell(DIVINE_FAVOR, *m_bot)) return RETURN_CONTINUE; if (hp < 40 && FLASH_OF_LIGHT && m_ai->In_Reach(target, FLASH_OF_LIGHT) && m_ai->CastSpell(FLASH_OF_LIGHT, *target)) return RETURN_CONTINUE; if (hp < 60 && HOLY_SHOCK && m_ai->In_Reach(target, HOLY_SHOCK) && m_ai->CastSpell(HOLY_SHOCK, *target)) return RETURN_CONTINUE; if (hp < 90 && HOLY_LIGHT && m_ai->In_Reach(target, HOLY_LIGHT) && m_ai->CastSpell(HOLY_LIGHT, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget
CombatManeuverReturns PlayerbotPaladinAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (REDEMPTION && m_ai->CastSpell(REDEMPTION, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } return RETURN_NO_ACTION_ERROR; // not error per se - possibly just OOM } if (PURIFY > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { uint32 DISPEL = CLEANSE > 0 ? CLEANSE : PURIFY; uint32 dispelMask = GetDispellMask(DISPEL_DISEASE); uint32 dispelMask2 = GetDispellMask(DISPEL_POISON); uint32 dispelMask3 = GetDispellMask(DISPEL_MAGIC); Unit::SpellAuraHolderMap const& auras = target->GetSpellAuraHolderMap(); for(Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { SpellAuraHolder *holder = itr->second; if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) { if (holder->GetSpellProto()->Dispel == DISPEL_DISEASE) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask2) { if (holder->GetSpellProto()->Dispel == DISPEL_POISON) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask3 & (DISPEL == CLEANSE)) { if (holder->GetSpellProto()->Dispel == DISPEL_MAGIC) { if (m_ai->CastSpell(DISPEL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } } } // Define a tank bot will look at Unit* pMainTank = GetHealTarget(JOB_TANK); // If target is out of range (40 yards) and is a tank: move towards it // Other classes have to adjust their position to the healers // TODO: This code should be common to all healers and will probably // move to a more suitable place if (pMainTank && !m_ai->In_Reach(pMainTank, FLASH_OF_LIGHT)) { m_bot->GetMotionMaster()->MoveFollow(target, 39.0f, m_bot->GetOrientation()); return RETURN_CONTINUE; } uint8 hp = target->GetHealthPercent(); // Everyone is healthy enough, return OK. MUST correlate to highest value below (should be last HP check) if (hp >= 90) return RETURN_NO_ACTION_OK; if (hp < 10 && LAY_ON_HANDS && !m_bot->HasSpellCooldown(LAY_ON_HANDS) && m_ai->In_Reach(target,LAY_ON_HANDS) && m_ai->CastSpell(LAY_ON_HANDS, *target)) return RETURN_CONTINUE; // Target is a moderately wounded healer or a badly wounded not tank? Blessing of Protection! if (BLESSING_OF_PROTECTION > 0 && ((hp < 25 && (GetTargetJob(target) & JOB_HEAL)) || (hp < 15 && !(GetTargetJob(target) & JOB_TANK))) && !m_bot->HasSpellCooldown(BLESSING_OF_PROTECTION) && m_ai->In_Reach(target,BLESSING_OF_PROTECTION) && !target->HasAura(FORBEARANCE, EFFECT_INDEX_0) && !target->HasAura(BLESSING_OF_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_PROTECTION, EFFECT_INDEX_0) && !target->HasAura(DIVINE_SHIELD, EFFECT_INDEX_0) && m_ai->CastSpell(BLESSING_OF_PROTECTION, *target)) return RETURN_CONTINUE; // Low HP : activate Divine Favor to make next heal a critical heal if (hp < 25 && DIVINE_FAVOR > 0 && !m_bot->HasAura(DIVINE_FAVOR, EFFECT_INDEX_0) && !m_bot->HasSpellCooldown(DIVINE_FAVOR) && m_ai->CastSpell (DIVINE_FAVOR, *m_bot)) return RETURN_CONTINUE; if (hp < 40 && FLASH_OF_LIGHT && m_ai->In_Reach(target,FLASH_OF_LIGHT) && m_ai->CastSpell(FLASH_OF_LIGHT, *target)) return RETURN_CONTINUE; if (hp < 60 && HOLY_SHOCK && m_ai->In_Reach(target,HOLY_SHOCK) && m_ai->CastSpell(HOLY_SHOCK, *target)) return RETURN_CONTINUE; if (hp < 90 && HOLY_LIGHT && m_ai->In_Reach(target,HOLY_LIGHT) && m_ai->CastSpell(HOLY_LIGHT, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget