Files
mod-playerbots/src/Ai/Base/Actions/QueryQuestAction.cpp
bashermens 13fff46fa0 Improper singletons migration to clean Meyer's singletons (cherry-pick) (#2082)
# Pull Request

- Applies the clean and corrected singletons, Meyer pattern. (cherry
picked from @SmashingQuasar )

Testing by just playing the game in various ways. Been tested by myself
@Celandriel and @SmashingQuasar
---

## Complexity & Impact

- Does this change add new decision branches?
    - [x] No
    - [ ] Yes (**explain below**)

- Does this change increase per-bot or per-tick processing?
    - [x] No
    - [ ] Yes (**describe and justify impact**)

- Could this logic scale poorly under load?
    - [x] No
    - [ ] Yes (**explain why**)

---

## Defaults & Configuration

- Does this change modify default bot behavior?
    - [x] No
    - [ ] Yes (**explain why**)

---

## AI Assistance

- Was AI assistance (e.g. ChatGPT or similar tools) used while working
on this change?
    - [x] No
    - [ ] Yes (**explain below**)
---

## Final Checklist

- [x] Stability is not compromised
- [x] Performance impact is understood, tested, and acceptable
- [x] Added logic complexity is justified and explained
- [x] Documentation updated if needed

---

## Notes for Reviewers

Anything that significantly improves realism at the cost of stability or
performance should be carefully discussed
before merging.

---------

Co-authored-by: Nicolas Lebacq <nicolas.cordier@outlook.com>
Co-authored-by: Keleborn <22352763+Celandriel@users.noreply.github.com>
2026-01-30 21:49:37 +01:00

161 lines
4.9 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "QueryQuestAction.h"
#include "ChatHelper.h"
#include "Event.h"
#include "Playerbots.h"
void QueryQuestAction::TellObjective(std::string const name, uint32 available, uint32 required)
{
botAI->TellMaster(chat->FormatQuestObjective(name, available, required));
}
bool QueryQuestAction::Execute(Event event)
{
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
Player* bot = botAI->GetBot();
WorldPosition botPos(bot);
WorldPosition* ptr_botpos = &botPos;
std::string text = event.getParam();
bool travel = false;
if (text.find("travel") != std::string::npos)
{
travel = true;
chat->eraseAllSubStr(text, " travel");
}
PlayerbotChatHandler ch(bot);
uint32 questId = ch.extractQuestId(text);
if (!questId)
{
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 logQuest = bot->GetQuestSlotQuestId(slot);
Quest const* quest = sObjectMgr->GetQuestTemplate(logQuest);
if (!quest)
continue;
if (text.find(quest->GetTitle()) != std::string::npos)
{
questId = quest->GetQuestId();
break;
}
}
}
for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
if (questId != bot->GetQuestSlotQuestId(slot))
continue;
std::ostringstream out;
out << "--- " << chat->FormatQuest(sObjectMgr->GetQuestTemplate(questId)) << " ";
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
{
out << "|c0000FF00completed|r ---";
botAI->TellMaster(out);
}
else
{
out << "|c00FF0000not completed|r ---";
botAI->TellMaster(out);
TellObjectives(questId);
}
if (travel)
{
uint32 limit = 0;
std::vector<TravelDestination*> allDestinations =
TravelMgr::instance().getQuestTravelDestinations(bot, questId, true, true, -1);
std::sort(allDestinations.begin(), allDestinations.end(), [ptr_botpos](TravelDestination* i, TravelDestination* j) {return i->distanceTo(ptr_botpos) < j->distanceTo(ptr_botpos); });
for (auto dest : allDestinations)
{
if (limit > 50)
continue;
std::ostringstream out;
uint32 tpoints = dest->getPoints(true).size();
uint32 apoints = dest->getPoints().size();
out << round(dest->distanceTo(&botPos));
out << " to " << dest->getTitle();
out << " " << apoints;
if (apoints < tpoints)
out << "/" << tpoints;
out << " points.";
if (!dest->isActive(bot))
out << " not active";
botAI->TellMaster(out);
limit++;
}
}
return true;
}
return false;
}
void QueryQuestAction::TellObjectives(uint32 questId)
{
Quest const* questTemplate = sObjectMgr->GetQuestTemplate(questId);
// Checks if the questTemplate is valid
if (!questTemplate)
{
botAI->TellMaster("Quest template not found.");
return;
}
QuestStatusData questStatus = bot->getQuestStatusMap()[questId];
for (uint32 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
{
// Checks for objective text
if (!questTemplate->ObjectiveText[i].empty())
botAI->TellMaster(questTemplate->ObjectiveText[i]);
// Checks for required items
if (questTemplate->RequiredItemId[i])
{
uint32 required = questTemplate->RequiredItemCount[i];
uint32 available = questStatus.ItemCount[i];
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(questTemplate->RequiredItemId[i]);
if (proto)
TellObjective(chat->FormatItem(proto), available, required);
}
// Checks for required NPCs or GOs
if (questTemplate->RequiredNpcOrGo[i])
{
uint32 required = questTemplate->RequiredNpcOrGoCount[i];
uint32 available = questStatus.CreatureOrGOCount[i];
if (questTemplate->RequiredNpcOrGo[i] < 0)
{
if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(-questTemplate->RequiredNpcOrGo[i]))
TellObjective(info->name, available, required);
}
else
{
if (CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(questTemplate->RequiredNpcOrGo[i]))
TellObjective(info->Name, available, required);
}
}
}
}