/* * 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 "GrindTargetValue.h" #include "Playerbots.h" #include "ReputationMgr.h" #include "SharedDefines.h" Unit* GrindTargetValue::Calculate() { uint32 memberCount = 1; Group* group = bot->GetGroup(); if (group) memberCount = group->GetMembersCount(); Unit* target = nullptr; uint32 assistCount = 0; while (!target && assistCount < memberCount) { target = FindTargetForGrinding(assistCount++); } return target; } Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) { uint32 memberCount = 1; Group* group = bot->GetGroup(); Player* master = GetMaster(); GuidVector attackers = context->GetValue("attackers")->Get(); for (ObjectGuid const guid : attackers) { Unit* unit = botAI->GetUnit(guid); if (!unit || !unit->IsAlive()) continue; return unit; } GuidVector targets = *context->GetValue("possible targets"); if (targets.empty()) return nullptr; float distance = 0; Unit* result = nullptr; // std::unordered_map needForQuestMap; for (ObjectGuid const guid : targets) { Unit* unit = botAI->GetUnit(guid); if (!unit) continue; auto &rep = bot->ToPlayer()->GetReputationMgr(); if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid && bot->GetReactionTo(unit) >= REP_NEUTRAL) { continue; } if (!bot->IsHostileTo(unit) && unit->GetNpcFlags() != UNIT_NPC_FLAG_NONE) { continue; } if (!bot->isHonorOrXPTarget(unit)) { continue; } if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > INTERACTION_DISTANCE) continue; if (!bot->InBattleground() && GetTargetingPlayerCount(unit) > assistCount) continue; //if (!bot->InBattleground() && master && master->GetDistance(unit) >= sPlayerbotAIConfig->grindDistance && !sRandomPlayerbotMgr->IsRandomBot(bot)) //continue; if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer()) continue; // if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end()) // needForQuestMap[unit->GetEntry()] = needForQuest(unit); // if (!needForQuestMap[unit->GetEntry()]) // if ((urand(0, 100) < 75 || (context->GetValue("travel target")->Get()->isWorking() && // context->GetValue("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) // continue; //if (bot->InBattleground() && bot->GetDistance(unit) > 40.0f) //continue; if (Creature* creature = unit->ToCreature()) if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate()) if (CreatureTemplate->rank > CREATURE_ELITE_NORMAL && !AI_VALUE(bool, "can fight elite")) continue; if (!bot->IsWithinLOSInMap(unit)) { continue; } if (group) { Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *member = ObjectAccessor::FindPlayer(itr->guid); if (!member || !member->IsAlive()) continue; float d = member->GetDistance(unit); if (!result || d < distance) { distance = d; result = unit; } } } else { float newdistance = bot->GetDistance(unit); if (!result || (newdistance < distance && urand(0, abs(distance - newdistance)) > sPlayerbotAIConfig->sightDistance * 0.1)) { distance = newdistance; result = unit; } } } return result; } bool GrindTargetValue::needForQuest(Unit* target) { bool justCheck = (bot->GetGUID() == target->GetGUID()); QuestStatusMap& questMap = bot->getQuestStatusMap(); for (auto& quest : questMap) { Quest const* questTemplate = sObjectMgr->GetQuestTemplate(quest.first); if (!questTemplate) continue; uint32 questId = questTemplate->GetQuestId(); if (!questId) continue; QuestStatus status = bot->GetQuestStatus(questId); if ((status == QUEST_STATUS_COMPLETE && !bot->GetQuestRewardStatus(questId))) { if (!justCheck && !target->hasInvolvedQuest(questId)) continue; return true; } else if (status == QUEST_STATUS_INCOMPLETE) { QuestStatusData* questStatus = sTravelMgr->getQuestStatus(bot, questId); if (questTemplate->GetQuestLevel() > bot->GetLevel()) continue; for (int j = 0; j < QUEST_OBJECTIVES_COUNT; j++) { int32 entry = questTemplate->RequiredNpcOrGo[j]; if (entry && entry > 0) { int required = questTemplate->RequiredNpcOrGoCount[j]; int available = questStatus->CreatureOrGOCount[j]; if (required && available < required && (target->GetEntry() == entry || justCheck)) return true; } if (justCheck) { int32 itemId = questTemplate->RequiredItemId[j]; if (itemId && itemId > 0) { uint32 required = questTemplate->RequiredItemCount[j]; uint32 available = questStatus->ItemCount[j]; if (required && available < required) return true; } } } if (!justCheck) { if (CreatureTemplate const* data = sObjectMgr->GetCreatureTemplate(target->GetEntry())) { if (uint32 lootId = data->lootid) { if (LootTemplates_Creature.HaveQuestLootForPlayer(lootId, bot)) return true; } } } } } return false; } uint32 GrindTargetValue::GetTargetingPlayerCount(Unit* unit) { Group* group = bot->GetGroup(); if (!group) return 0; uint32 count = 0; Group::MemberSlotList const& groupSlot = group->GetMemberSlots(); for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++) { Player *member = ObjectAccessor::FindPlayer(itr->guid); if (!member || !member->IsAlive() || member == bot) continue; PlayerbotAI* botAI = GET_PLAYERBOT_AI(member); if ((botAI && *botAI->GetAiObjectContext()->GetValue("current target") == unit) || (!botAI && member->GetTarget() == unit->GetGUID())) ++count; } return count; }