/** * 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; }
bool PlayerbotPriestAI::HealTarget(Unit* target) { PlayerbotAI* ai = GetAI(); uint8 hp = target->GetHealth() * 100 / target->GetMaxHealth(); if (CURE_DISEASE > 0 && ai->GetCombatOrder() != PlayerbotAI::ORDERS_NODISPEL) { uint32 dispelMask = GetDispellMask(DISPEL_DISEASE); 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) ai->CastSpell(CURE_DISEASE, *target); return false; } } } if (hp >= 80) return false; if (hp < 25 && FLASH_HEAL && ai->CastSpell(FLASH_HEAL, *target)) return true; else if (hp < 30 && GREATER_HEAL > 0 && ai->CastSpell(GREATER_HEAL, *target)) return true; else if (hp < 33 && BINDING_HEAL > 0 && ai->CastSpell(BINDING_HEAL, *target)) return true; else if (hp < 40 && PRAYER_OF_HEALING > 0 && ai->CastSpell(PRAYER_OF_HEALING, *target)) return true; else if (hp < 50 && CIRCLE_OF_HEALING > 0 && ai->CastSpell(CIRCLE_OF_HEALING, *target)) return true; else if (hp < 60 && HEAL > 0 && ai->CastSpell(HEAL, *target)) return true; else if (hp < 80 && RENEW > 0 && !target->HasAura(RENEW) && ai->CastSpell(RENEW, *target)) return true; else return false; } // end HealTarget
bool PlayerbotClassAI::castDispel (uint32 dispelSpell, Unit *dTarget, bool checkFirst, bool castExistingAura, bool skipFriendlyCheck, bool skipEquipStanceCheck) { if (dispelSpell == 0 || !dTarget ) return false; //if (!canCast(dispelSpell, dTarget, true)) return false; //Needless cpu cycles wasted, usually a playerbot can cast a dispell const SpellEntry *dSpell = GetSpellStore()->LookupEntry(dispelSpell); if (!dSpell) return false; for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i) { if (dSpell->Effect[i] != (uint32)SPELL_EFFECT_DISPEL) continue; uint32 dispel_type = dSpell->EffectMiscValue[i]; uint32 dispelMask = GetDispellMask(DispelType(dispel_type)); Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if ((1<<aura->GetSpellProto()->Dispel) & dispelMask) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; // do not remove positive auras if friendly target // negative auras if non-friendly target if(positive == dTarget->IsFriendlyTo(GetPlayerBot())) continue; } // If there is a successfull match return, else continue searching. if (CastSpell(dSpell, dTarget, checkFirst, castExistingAura, skipFriendlyCheck, skipEquipStanceCheck)) { return true; } } } } return false; }
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
bool PlayerbotClassAI::castSelfCCBreakers (uint32 castList[]) { uint32 dispelSpell = 0; Player *dTarget = GetPlayerBot(); /* dispelSpell = (uint32) R_ESCAPE_ARTIST; // this is script effect, Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if ( ( aura->GetSpellProto()->Mechanic == MECHANIC_SNARE ) || ( aura->GetSpellProto()->Mechanic == MECHANIC_ROOT ) ) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; // do not remove positive auras if friendly target // negative auras if non-friendly target if(positive == dTarget->IsFriendlyTo(caster)) continue; } return castSpell(dispelSpell, dTarget); } } return false; */ // racial abilities /* if( GetPlayerBot()->getRace() == RACE_BLOODELF && !pTarget->HasAura( ARCANE_TORRENT,0 ) && castSpell( ARCANE_TORRENT,pTarget ) ) { //GetPlayerBot()->Say("Arcane Torrent!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_HUMAN && (GetPlayerBot()->HasUnitState( UNIT_STAT_STUNNED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_FEAR ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_DECREASE_SPEED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_CHARM )) && castSpell( EVERY_MAN_FOR_HIMSELF, GetPlayerBot() ) ) { //GetPlayerBot()->Say("EVERY MAN FOR HIMSELF!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_UNDEAD_PLAYER && (GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_FEAR ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_CHARM )) && castSpell( WILL_OF_THE_FORSAKEN, GetPlayerBot() ) ) { // GetPlayerBot()->Say("WILL OF THE FORSAKEN!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_DWARF && GetPlayerBot()->HasAuraState( AURA_STATE_DEADLY_POISON ) && castSpell( STONEFORM, GetPlayerBot() ) ) { //GetPlayerBot()->Say("STONEFORM!", LANG_UNIVERSAL); } else if( GetPlayerBot()->getRace() == RACE_GNOME && (GetPlayerBot()->HasUnitState( UNIT_STAT_STUNNED ) || GetPlayerBot()->HasAuraType( SPELL_AURA_MOD_DECREASE_SPEED )) && castSpell( ESCAPE_ARTIST, GetPlayerBot() ) ) { // GetPlayerBot()->Say("ESCAPE ARTIST!", LANG_UNIVERSAL); } */ for (uint8 j = 0; j < sizeof (castList); j++) { dispelSpell = castList[j]; if (dispelSpell == 0 || !dTarget->HasSpell(dispelSpell) || !CanCast(dispelSpell, dTarget, true)) continue; SpellEntry const *dSpell = GetSpellStore()->LookupEntry(dispelSpell); if (!dSpell) continue; for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS ; ++i) { if (dSpell->Effect[i] != (uint32)SPELL_EFFECT_DISPEL && dSpell->Effect[i] != (uint32)SPELL_EFFECT_APPLY_AURA) continue; if (dSpell->Effect[i] == (uint32)SPELL_EFFECT_APPLY_AURA && ( (dSpell->EffectApplyAuraName[i] != (uint32) SPELL_AURA_MECHANIC_IMMUNITY) || (dSpell->EffectApplyAuraName[i] != (uint32) SPELL_AURA_DISPEL_IMMUNITY) )) continue; Unit::AuraMap const& auras = dTarget->GetOwnedAuras(); for (Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { Aura * aura = itr->second; AuraApplication * aurApp = aura->GetApplicationOfTarget(dTarget->GetGUID()); if (!aurApp) continue; if (aura->GetSpellProto() && ( (dSpell->Effect[i] == (uint32)SPELL_EFFECT_DISPEL && ((1<<aura->GetSpellProto()->Dispel) & GetDispellMask(DispelType(dSpell->EffectMiscValue[i]))) ) || (dSpell->EffectApplyAuraName[i] == (uint32) SPELL_AURA_MECHANIC_IMMUNITY && ( GetAllSpellMechanicMask(aura->GetSpellProto()) & ( 1 << dSpell->EffectMiscValue[i]) ) ) || (dSpell->EffectApplyAuraName[i] == (uint32) SPELL_AURA_DISPEL_IMMUNITY && ( (1<<aura->GetSpellProto()->Dispel) & GetDispellMask(DispelType(dSpell->EffectMiscValue[i])) ) ) ) ) { if(aura->GetSpellProto()->Dispel == DISPEL_MAGIC) { bool positive = aurApp->IsPositive() ? (!(aura->GetSpellProto()->AttributesEx & SPELL_ATTR0_UNK7)) : false; if(positive)continue; } return CastSpell(dispelSpell, dTarget, false); } } } } return false; }
bool PlayerbotDruidAI::HealTarget(Unit *target) { PlayerbotAI* ai = GetAI(); uint8 hp = target->GetHealth() * 100 / target->GetMaxHealth(); //If spell exists and orders say we should be dispelling if ((REMOVE_CURSE > 0 || ABOLISH_POISON > 0) && ai->GetCombatOrder() != PlayerbotAI::ORDERS_NODISPEL) { //This does something important(lol) uint32 dispelMask = GetDispellMask(DISPEL_CURSE); uint32 dispelMask2 = GetDispellMask(DISPEL_POISON); //Get a list of all the targets auras(spells affecting target) Unit::SpellAuraHolderMap const& auras = target->GetSpellAuraHolderMap(); //Iterate through the auras for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) { SpellAuraHolderPtr holder = itr->second; //I dont know what this does but it doesn't work without it if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) { //If the spell is dispellable and we can dispel it, do so if ((holder->GetSpellProto()->Dispel == DISPEL_CURSE) & (REMOVE_CURSE > 0)) ai->CastSpell(REMOVE_CURSE, *target); return false; } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask2) { if ((holder->GetSpellProto()->Dispel == DISPEL_POISON) & (ABOLISH_POISON > 0)) ai->CastSpell(ABOLISH_POISON, *target); return false; } } } if (hp >= 70) return false; // Reset form if needed GoBuffForm(GetPlayerBot()); if (hp < 70 && REJUVENATION > 0 && !target->HasAura(REJUVENATION) && ai->CastSpell(REJUVENATION, *target)) return true; if (hp < 60 && LIFEBLOOM > 0 && !target->HasAura(LIFEBLOOM) && ai->CastSpell(LIFEBLOOM, *target)) return true; if (hp < 55 && REGROWTH > 0 && !target->HasAura(REGROWTH) && ai->CastSpell(REGROWTH, *target)) return true; if (hp < 50 && SWIFTMEND > 0 && (target->HasAura(REJUVENATION) || target->HasAura(REGROWTH)) && ai->CastSpell(SWIFTMEND, *target)) return true; if (hp < 45 && WILD_GROWTH > 0 && !target->HasAura(WILD_GROWTH) && ai->CastSpell(WILD_GROWTH, *target)) return true; if (hp < 30 && NOURISH > 0 && ai->CastSpell(NOURISH, *target)) return true; if (hp < 25 && HEALING_TOUCH > 0 && ai->CastSpell(HEALING_TOUCH, *target)) return true; return false; } // end HealTarget
CombatManeuverReturns PlayerbotShamanAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (ANCESTRAL_SPIRIT && m_ai->CastSpell(ANCESTRAL_SPIRIT, *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 } // Dispel if necessary if ((CURE_DISEASE_SHAMAN > 0 || CURE_POISON_SHAMAN > 0) && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { uint32 dispelMask = GetDispellMask(DISPEL_POISON); uint32 dispelMask2 = GetDispellMask(DISPEL_DISEASE); 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_POISON) { if (m_ai->CastSpell(CURE_POISON_SHAMAN, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask2) { if (holder->GetSpellProto()->Dispel == DISPEL_DISEASE) { if (m_ai->CastSpell(CURE_DISEASE_SHAMAN, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } } } // Everyone is healthy enough, return OK. MUST correlate to highest value below (should be last HP check) if (target->GetHealthPercent() >= 80) return RETURN_NO_ACTION_OK; // Technically the best rotation is CHAIN + LHW + LHW subbing in HW for trouble (bad mana efficiency) if (target->GetHealthPercent() < 30 && HEALING_WAVE > 0 && m_ai->CastSpell(HEALING_WAVE, *target)) return RETURN_CONTINUE; if (target->GetHealthPercent() < 50 && LESSER_HEALING_WAVE > 0 && m_ai->CastSpell(LESSER_HEALING_WAVE, *target)) return RETURN_CONTINUE; if (target->GetHealthPercent() < 80 && CHAIN_HEAL > 0 && m_ai->CastSpell(CHAIN_HEAL, *target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget
CombatManeuverReturns PlayerbotPriestAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (RESURRECTION && m_ai->CastSpell(RESURRECTION, *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 (CURE_DISEASE > 0 && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { uint32 dispelMask = GetDispellMask(DISPEL_DISEASE); 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) { m_ai->CastSpell(CURE_DISEASE, *target); return RETURN_CONTINUE; } } } } uint8 hp = target->GetHealthPercent(); uint8 hpSelf = m_ai->GetHealthPercent(); if (hp >= 90) return RETURN_NO_ACTION_OK; // TODO: Integrate shield here if (hp < 35 && FLASH_HEAL > 0 && m_ai->CastSpell(FLASH_HEAL, *target)) return RETURN_CONTINUE; if (hp < 45 && GREATER_HEAL > 0 && m_ai->CastSpell(GREATER_HEAL, *target)) return RETURN_CONTINUE; // Heals target AND self for equal amount if (hp < 60 && hpSelf < 80 && BINDING_HEAL > 0 && m_ai->CastSpell(BINDING_HEAL, *target)) return RETURN_CONTINUE; if (hp < 60 && PRAYER_OF_MENDING > 0 && !target->HasAura(PRAYER_OF_MENDING, EFFECT_INDEX_0) && CastSpell(PRAYER_OF_MENDING, target)) return RETURN_FINISHED_FIRST_MOVES; if (hp < 60 && HEAL > 0 && m_ai->CastSpell(HEAL, *target)) return RETURN_CONTINUE; if (hp < 90 && RENEW > 0 && !target->HasAura(RENEW) && m_ai->CastSpell(RENEW, *target)) return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 40 && PRAYER_OF_HEALING > 0 && m_ai->CastSpell(PRAYER_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; // Group heal. Not really useful until a group check is available? //if (hp < 50 && CIRCLE_OF_HEALING > 0 && m_ai->CastSpell(CIRCLE_OF_HEALING, *target) & RETURN_CONTINUE) // return RETURN_CONTINUE; return RETURN_NO_ACTION_OK; } // 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
CombatManeuverReturns PlayerbotDruidAI::HealPlayer(Player* target) { CombatManeuverReturns r = PlayerbotClassAI::HealPlayer(target); if (r != RETURN_NO_ACTION_OK) return r; if (!target->isAlive()) { if (m_bot->isInCombat()) { // TODO: Add check for cooldown if (REBIRTH && m_ai->In_Reach(target,REBIRTH) && m_ai->CastSpell(REBIRTH, *target)) { std::string msg = "Resurrecting "; msg += target->GetName(); m_bot->Say(msg, LANG_UNIVERSAL); return RETURN_CONTINUE; } } else { if (REVIVE && m_ai->In_Reach(target,REVIVE) && m_ai->CastSpell(REVIVE, *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 spell exists and orders say we should be dispelling if ((REMOVE_CURSE > 0 || ABOLISH_POISON > 0) && (m_ai->GetCombatOrder() & PlayerbotAI::ORDERS_NODISPEL) == 0) { //This does something important(lol) uint32 dispelMask = GetDispellMask(DISPEL_CURSE); uint32 dispelMask2 = GetDispellMask(DISPEL_POISON); //Get a list of all the targets auras(spells affecting target) Unit::SpellAuraHolderMap const& auras = target->GetSpellAuraHolderMap(); //Iterate through the auras for (Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); itr++) { SpellAuraHolder *holder = itr->second; //I dont know what this does but it doesn't work without it if ((1 << holder->GetSpellProto()->Dispel) & dispelMask) { //If the spell is dispellable and we can dispel it, do so if ((holder->GetSpellProto()->Dispel == DISPEL_CURSE) & (REMOVE_CURSE > 0)) { if (CastSpell(REMOVE_CURSE, target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_ERROR; } } else if ((1 << holder->GetSpellProto()->Dispel) & dispelMask2) { if ((holder->GetSpellProto()->Dispel == DISPEL_POISON) & (ABOLISH_POISON > 0)) { if (CastSpell(ABOLISH_POISON, 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; // Reset form if needed if (!m_bot->HasAura(TREE_OF_LIFE) || TREE_OF_LIFE == 0) GoBuffForm(GetPlayerBot()); // Start heals. Do lowest HP checks at the top if (hp < 30) { // TODO: Use in conjunction with Nature's Swiftness if (HEALING_TOUCH > 0 && m_ai->In_Reach(target,HEALING_TOUCH) && (NOURISH == 0 /*|| CastSpell(NATURES_SWIFTNESS)*/ ) && CastSpell(HEALING_TOUCH, target)) return RETURN_CONTINUE; if (NOURISH > 0 && m_ai->In_Reach(target,NOURISH) && CastSpell(NOURISH, target)) return RETURN_CONTINUE; } if (hp < 45 && WILD_GROWTH > 0 && m_ai->In_Reach(target,WILD_GROWTH) && !target->HasAura(WILD_GROWTH) && CastSpell(WILD_GROWTH, target)) return RETURN_CONTINUE; if (hp < 50 && SWIFTMEND > 0 && m_ai->In_Reach(target,SWIFTMEND) && (target->HasAura(REJUVENATION) || target->HasAura(REGROWTH)) && CastSpell(SWIFTMEND, target)) return RETURN_CONTINUE; if (hp < 60 && REGROWTH > 0 && m_ai->In_Reach(target,REGROWTH) && !target->HasAura(REGROWTH) && CastSpell(REGROWTH, target)) return RETURN_CONTINUE; if (hp < 65 && LIFEBLOOM > 0 && m_ai->In_Reach(target,LIFEBLOOM) && !target->HasAura(LIFEBLOOM) && CastSpell(LIFEBLOOM, target)) return RETURN_CONTINUE; if (hp < 90 && REJUVENATION > 0 && m_ai->In_Reach(target,REJUVENATION) && !target->HasAura(REJUVENATION) && CastSpell(REJUVENATION, target)) return RETURN_CONTINUE; return RETURN_NO_ACTION_UNKNOWN; } // end HealTarget