/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it * and/or modify it under version 2 of the License, or (at your option), any later version. */ #include "PartyMemberToHeal.h" #include "Playerbots.h" #include "ServerFacade.h" class IsTargetOfHealingSpell : public SpellEntryPredicate { public: bool Check(SpellInfo const* spellInfo) override { for (uint8 i = 0; i < 3; ++i) { if (spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL || spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MAX_HEALTH || spellInfo->Effects[i].Effect == SPELL_EFFECT_HEAL_MECHANICAL) return true; } return false; } }; inline bool compareByHealth(Unit const* u1, Unit const* u2) { return u1->GetHealthPct() < u2->GetHealthPct(); } Unit* PartyMemberToHeal::Calculate() { IsTargetOfHealingSpell predicate; Group* group = bot->GetGroup(); if (!group) return bot; bool isRaid = bot->GetGroup()->isRaidGroup(); MinValueCalculator calc(100); for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) { Player* player = gref->GetSource(); if (player->IsGameMaster()) continue; if (player && player->IsAlive()) { uint8 health = player->GetHealthPct(); if (isRaid || health < sPlayerbotAIConfig->mediumHealth || !IsTargetOfSpellCast(player, predicate)) { uint32 probeValue = 100; if (player->GetDistance2d(bot) > sPlayerbotAIConfig->healDistance) { probeValue = health + 30; } else { probeValue = health + player->GetDistance2d(bot) / 10; } // delay Check player to here for better performance if (probeValue < calc.minValue && Check(player)) { calc.probe(probeValue, player); } } } Pet* pet = player->GetPet(); if (pet && pet->IsAlive()) { uint8 health = ((Unit*)pet)->GetHealthPct(); uint32 probeValue = 100; if (isRaid || health < sPlayerbotAIConfig->mediumHealth) probeValue = health + 30; // delay Check pet to here for better performance if (probeValue < calc.minValue && Check(pet)) { calc.probe(probeValue, pet); } } Unit* charm = player->GetCharm(); if (charm && charm->IsAlive()) { uint8 health = charm->GetHealthPct(); uint32 probeValue = 100; if (isRaid || health < sPlayerbotAIConfig->mediumHealth) probeValue = health + 30; // delay Check charm to here for better performance if (probeValue < calc.minValue && Check(charm)) { calc.probe(probeValue, charm); } } } return (Unit*)calc.param; } bool PartyMemberToHeal::Check(Unit* player) { // return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() && // sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f // : 40.0f); return player->GetMapId() == bot->GetMapId() && !player->IsCharmed() && bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 && bot->IsWithinLOSInMap(player); } Unit* PartyMemberToProtect::Calculate() { return nullptr; Group* group = bot->GetGroup(); if (!group) return nullptr; std::vector needProtect; GuidVector attackers = botAI->GetAiObjectContext()->GetValue("attackers")->Get(); for (GuidVector::iterator i = attackers.begin(); i != attackers.end(); ++i) { Unit* unit = botAI->GetUnit(*i); if (!unit) continue; Unit* pVictim = unit->GetVictim(); if (!pVictim || !pVictim->IsPlayer()) continue; if (pVictim == bot) continue; float attackDistance = 30.0f; if (sServerFacade->GetDistance2d(pVictim, unit) > attackDistance) continue; if (botAI->IsTank((Player*)pVictim) && pVictim->GetHealthPct() > 10) continue; else if (pVictim->GetHealthPct() > 30) continue; if (find(needProtect.begin(), needProtect.end(), pVictim) == needProtect.end()) needProtect.push_back(pVictim); } if (needProtect.empty()) return nullptr; sort(needProtect.begin(), needProtect.end(), compareByHealth); return needProtect[0]; }