diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 3ecfb10d..f1f59e00 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -558,7 +558,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategies("nc", "food", "chat", "follow", "default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr); } - if (sPlayerbotAIConfig->autoSaveMana) { + if (sPlayerbotAIConfig->autoSaveMana){ nonCombatEngine->addStrategy("auto save mana"); } if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground()) @@ -588,7 +588,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const { // nonCombatEngine->addStrategy("travel"); nonCombatEngine->addStrategy("rpg"); - } else { + } + else + { nonCombatEngine->addStrategy("move random"); } diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index fa59ff11..ec0e9bf0 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -128,15 +128,12 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll"); masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello"); masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello"); - masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_COMPLETE_QUEST, "complete quest"); - masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_ACCEPT_QUEST, "accept quest"); masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXI, "activate taxi"); masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXIEXPRESS, "activate taxi"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARALLNODES, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARNODE, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE, "uninvite"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE_GUID, "uninvite guid"); - masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share"); masterIncomingPacketHandlers.AddHandler(CMSG_LFG_TELEPORT, "lfg teleport"); masterIncomingPacketHandlers.AddHandler(CMSG_CAST_SPELL, "see spell"); masterIncomingPacketHandlers.AddHandler(CMSG_REPOP_REQUEST, "release spirit"); @@ -153,7 +150,6 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel botOutgoingPacketHandlers.AddHandler(SMSG_INVENTORY_CHANGE_FAILURE, "cannot equip"); botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS, "trade status"); botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_RESPONSE, "loot response"); - botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest objective completed"); botOutgoingPacketHandlers.AddHandler(SMSG_ITEM_PUSH_RESULT, "item push result"); botOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command"); botOutgoingPacketHandlers.AddHandler(SMSG_LEVELUP_INFO, "levelup"); @@ -168,7 +164,6 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel botOutgoingPacketHandlers.AddHandler(SMSG_EMOTE, "receive emote"); botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_START_ROLL, "master loot roll"); botOutgoingPacketHandlers.AddHandler(SMSG_ARENA_TEAM_INVITE, "arena team invite"); - botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "quest confirm accept"); botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_DESTROYED, "group destroyed"); botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_LIST, "group list"); @@ -176,7 +171,16 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel masterOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command"); masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK, "ready check"); masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK_FINISHED, "ready check finished"); - masterOutgoingPacketHandlers.AddHandler(SMSG_QUESTGIVER_OFFER_REWARD, "questgiver quest details"); + + // quest packet + masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_COMPLETE_QUEST, "complete quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_ACCEPT_QUEST, "accept quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_QUEST_CONFIRM_ACCEPT, "confirm quest"); + masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item"); + botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest"); } PlayerbotAI::~PlayerbotAI() @@ -4736,4 +4740,4 @@ uint8 PlayerbotAI::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool sw // no free position return NULL_SLOT; -} \ No newline at end of file +} diff --git a/src/TravelMgr.cpp b/src/TravelMgr.cpp index a60a59cd..14e288e3 100644 --- a/src/TravelMgr.cpp +++ b/src/TravelMgr.cpp @@ -114,6 +114,16 @@ void WorldPosition::set(const WorldLocation& pos) WorldRelocate(pos); } +void WorldPosition::set(const WorldPosition& pos) +{ + WorldRelocate(pos.m_mapId, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); +} + +void WorldPosition::set(const WorldObject* pos) +{ + WorldRelocate(pos->GetMapId(), pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation()); +} + void WorldPosition::setMapId(uint32 id) { m_mapId = id; @@ -1061,30 +1071,59 @@ std::string const QuestTravelDestination::getTitle() bool QuestRelationTravelDestination::isActive(Player* bot) { + PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); + AiObjectContext* context = botAI->GetAiObjectContext(); + + if (botAI && !botAI->HasStrategy("rpg quest", BOT_STATE_NON_COMBAT)) + return false; + if (relation == 0) { - if (questTemplate->GetQuestLevel() >= bot->GetLevel() + 5) + if ((int32)questTemplate->GetQuestLevel() >= (int32)bot->GetLevel() + (int32)5) return false; - //if (questTemplate->XPValue(bot) == 0) - // return false; + // skip for now this quest + if (getPoints().front()->GetMapId() != bot->GetMapId()) + return false; if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false)) return false; - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); - AiObjectContext* context = botAI->GetAiObjectContext(); - uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); if (AI_VALUE(bool, "can fight equal")) { - if (dialogStatus != DIALOG_STATUS_AVAILABLE) + if (AI_VALUE(uint8, "free quest log slots") < 5) return false; + + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest npc::" + std::to_string(entry))) //Noone has yellow exclamation mark. + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry) + "need quest objective::" + std::to_string(questId))) //Noone can do this quest for a usefull reward. + return false; + + // higher chance bot will do rewarding quest (better gear etc) + if (dialogStatus != DIALOG_STATUS_AVAILABLE) + { + if (dialogStatus != DIALOG_STATUS_LOW_LEVEL_AVAILABLE) + { + bool hasGoodReward = false; + for (uint8 i = 0; i < questTemplate->GetRewChoiceItemsCount(); ++i) + { + ItemUsage usage = AI_VALUE2_LAZY(ItemUsage, "item usage", questTemplate->RewardChoiceItemId[i]); + if (usage == ITEM_USAGE_EQUIP || usage == ITEM_USAGE_REPLACE) + { + hasGoodReward = true; + break; + } + } + } + } } else { - if (dialogStatus != DIALOG_STATUS_LOW_LEVEL_AVAILABLE) + if (!AI_VALUE2(bool, "group or", "following party,near leader,can accept quest low level npc::" + std::to_string(entry))) //Noone can pick up this quest for money. + return false; + + if (AI_VALUE(uint8, "free quest log slots") < 10) return false; } @@ -1094,25 +1133,14 @@ bool QuestRelationTravelDestination::isActive(Player* bot) } else { - if (!bot->IsActiveQuest(questId)) + if (!AI_VALUE2(bool, "group or", "following party,near leader,can turn in quest npc::" + std::to_string(entry))) return false; - if (!bot->CanRewardQuest(questTemplate, false)) - return false; - - uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); - - if (dialogStatus != DIALOG_STATUS_REWARD2 && dialogStatus != DIALOG_STATUS_REWARD && dialogStatus != DIALOG_STATUS_REWARD_REP) - return false; - - PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); - AiObjectContext* context = botAI->GetAiObjectContext(); - - // Do not try to hand-in dungeon/elite quests in instances without a group. + //Do not try to hand-in dungeon/elite quests in instances without a group. if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && !AI_VALUE(bool, "can fight boss")) { WorldPosition pos(bot); - if (!this->nearestPoint(const_cast(&pos))->isOverworld()) + if (!this->nearestPoint(&pos)->isOverworld()) return false; } } @@ -4006,7 +4034,45 @@ std::vector TravelMgr::getQuestTravelDestinations(Player* bo std::vector retTravelLocations; - if (questId == -1) + if (!questId) + { + for (auto& dest : questGivers) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + for (auto& quest : quests) + { + for (auto& dest : quest.second->questTakers) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + + if (!ignoreObjectives) + for (auto& dest : quest.second->questObjectives) + { + if (!ignoreInactive && !dest->isActive(bot)) + continue; + + if (maxDistance > 0 && dest->distanceTo(&botLocation) > maxDistance) + continue; + + retTravelLocations.push_back(dest); + } + } + } + else if (questId == -1) { for (auto& dest : questGivers) { diff --git a/src/TravelMgr.h b/src/TravelMgr.h index 0b4b2e99..2d791477 100644 --- a/src/TravelMgr.h +++ b/src/TravelMgr.h @@ -95,6 +95,8 @@ class WorldPosition : public WorldLocation //Setters void set(const WorldLocation& pos); + void set(const WorldObject* wo); + void set(const WorldPosition& pos); void setMapId(uint32 id); void setX(float x); void setY(float y); @@ -406,7 +408,6 @@ class GuidPosition : public ObjectGuid, public WorldPosition GuidPosition(WorldObject* wo); GuidPosition(CreatureData const& creData); GuidPosition(GameObjectData const& goData); - CreatureTemplate const* GetCreatureTemplate(); GameObjectTemplate const* GetGameObjectTemplate(); diff --git a/src/strategy/NamedObjectContext.cpp b/src/strategy/NamedObjectContext.cpp index 1c53b55f..093575bb 100644 --- a/src/strategy/NamedObjectContext.cpp +++ b/src/strategy/NamedObjectContext.cpp @@ -12,13 +12,30 @@ void Qualified::Qualify(int qual) qualifier = out.str(); } -std::string const Qualified::MultiQualify(std::vector qualifiers) +std::string const Qualified::MultiQualify(std::vector qualifiers, const std::string& separator, const std::string_view brackets) { - std::ostringstream out; - for (auto& qualifier : qualifiers) - out << qualifier << (&qualifier != &qualifiers.back() ? " " : ""); + std::stringstream out; + for (uint8 i = 0; i < qualifiers.size(); i++) + { + const std::string& qualifier = qualifiers[i]; + if (i == qualifiers.size() - 1) + { + out << qualifier; + } + else + { + out << qualifier << separator; + } + } - return out.str(); + if (brackets.empty()) + { + return out.str(); + } + else + { + return brackets[0] + out.str() + brackets[1]; + } } std::vector Qualified::getMultiQualifiers(std::string const qualifier1) diff --git a/src/strategy/NamedObjectContext.h b/src/strategy/NamedObjectContext.h index 7f4509e7..f6ba26cd 100644 --- a/src/strategy/NamedObjectContext.h +++ b/src/strategy/NamedObjectContext.h @@ -34,7 +34,7 @@ class Qualified std::string const getQualifier() { return qualifier; } - static std::string const MultiQualify(std::vector qualifiers); + static std::string const MultiQualify(std::vector qualifiers, const std::string& separator, const std::string_view brackets = "{}"); static std::vector getMultiQualifiers(std::string const qualifier1); static int32 getMultiQualifier(std::string const qualifier1, uint32 pos); diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index 82090440..b745a4ed 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -106,6 +106,7 @@ class StrategyContext : public NamedObjectContext creators["debug move"] = &StrategyContext::debug_move; creators["debug rpg"] = &StrategyContext::debug_rpg; creators["debug spell"] = &StrategyContext::debug_spell; + creators["debug quest"] = &StrategyContext::debug_quest; creators["maintenance"] = &StrategyContext::maintenance; creators["group"] = &StrategyContext::group; creators["guild"] = &StrategyContext::guild; @@ -169,6 +170,7 @@ class StrategyContext : public NamedObjectContext static Strategy* debug_move(PlayerbotAI* botAI) { return new DebugMoveStrategy(botAI); } static Strategy* debug_rpg(PlayerbotAI* botAI) { return new DebugRpgStrategy(botAI); } static Strategy* debug_spell(PlayerbotAI* botAI) { return new DebugSpellStrategy(botAI); } + static Strategy* debug_quest(PlayerbotAI* botAI) { return new DebugQuestStrategy(botAI); } static Strategy* maintenance(PlayerbotAI* botAI) { return new MaintenanceStrategy(botAI); } static Strategy* group(PlayerbotAI* botAI) { return new GroupStrategy(botAI); } static Strategy* guild (PlayerbotAI* botAI) { return new GuildStrategy(botAI); } @@ -228,6 +230,4 @@ class QuestStrategyContext : public NamedObjectContext static Strategy* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsStrategy(botAI); } }; - - #endif diff --git a/src/strategy/actions/AcceptQuestAction.cpp b/src/strategy/actions/AcceptQuestAction.cpp index ec6674cc..59f9716c 100644 --- a/src/strategy/actions/AcceptQuestAction.cpp +++ b/src/strategy/actions/AcceptQuestAction.cpp @@ -6,54 +6,62 @@ #include "Event.h" #include "Playerbots.h" -void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver) +bool AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver) { - AcceptQuest(quest, questGiver->GetGUID()); + if (!AcceptQuest(quest, questGiver->GetGUID())) return false; + + auto text_quest = ChatHelper::FormatQuest(quest); bot->PlayDistanceSound(620); + + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + bot->Say("Quest [ " + text_quest + " ] accepted", LANG_UNIVERSAL); + } + + return true; } bool AcceptQuestAction::Execute(Event event) { - Player* master = GetMaster(); - if (!master) + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + if (!requester) return false; Player* bot = botAI->GetBot(); - ObjectGuid guid; + uint64_t guid; uint32 quest = 0; std::string const text = event.getParam(); - PlayerbotChatHandler ch(master); + PlayerbotChatHandler ch(requester); quest = ch.extractQuestId(text); + bool hasAccept = false; + if (event.getPacket().empty()) { GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); - for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++) + for (auto i = npcs.begin(); i != npcs.end(); i++) { Unit* unit = botAI->GetUnit(*i); if (unit && quest && unit->hasQuest(quest)) { - guid = unit->GetGUID(); + guid = unit->GetGUID().GetRawValue(); break; } - - if (unit && text == "*" && bot->GetDistance(unit) <= INTERACTION_DISTANCE) - QuestAction::ProcessQuests(unit); + if (unit && text == "*" && sqrt(bot->GetDistance(unit)) <= INTERACTION_DISTANCE) + hasAccept |= QuestAction::ProcessQuests(unit); } - - GuidVector gos = AI_VALUE(GuidVector, "nearest game objects"); - for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++) + GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los"); + for (auto i = gos.begin(); i != gos.end(); i++) { GameObject* go = botAI->GetGameObject(*i); if (go && quest && go->hasQuest(quest)) { - guid = go->GetGUID(); + guid = go->GetGUID().GetRawValue(); break; } - - if (go && text == "*" && bot->GetDistance(go) <= INTERACTION_DISTANCE) - QuestAction::ProcessQuests(go); + if (go && text == "*" && sqrt(bot->GetDistance(go)) <= INTERACTION_DISTANCE) + hasAccept |= QuestAction::ProcessQuests(go); } } else @@ -70,7 +78,17 @@ bool AcceptQuestAction::Execute(Event event) if (!qInfo) return false; - return AcceptQuest(qInfo, guid); + hasAccept |= AcceptQuest(qInfo, ObjectGuid(guid)); + + if (hasAccept) + { + std::stringstream ss; + ss << "AcceptQuestAction {" << qInfo->GetTitle() << "} - {" << std::to_string(qInfo->GetQuestId()) << "}"; + LOG_INFO("playerbots", "{}", ss.str().c_str()); + botAI->TellMaster(ss.str()); + } + + return hasAccept; } bool AcceptQuestShareAction::Execute(Event event) @@ -112,7 +130,7 @@ bool AcceptQuestShareAction::Execute(Event event) bot->SetDivider(ObjectGuid::Empty); } - if (bot->CanAddQuest( qInfo, false)) + if (bot->CanAddQuest(qInfo, false)) { bot->AddQuest(qInfo, master); @@ -125,7 +143,7 @@ bool AcceptQuestShareAction::Execute(Event event) if (qInfo->GetSrcSpell() > 0) { - bot->CastSpell( bot, qInfo->GetSrcSpell(), true); + bot->CastSpell(bot, qInfo->GetSrcSpell(), true); } botAI->TellMaster("Quest accepted"); @@ -134,3 +152,41 @@ bool AcceptQuestShareAction::Execute(Event event) return false; } + +bool ConfirmQuestAction::Execute(Event event) +{ + Player* bot = botAI->GetBot(); + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + + WorldPacket& p = event.getPacket(); + p.rpos(0); + uint32 quest; + p >> quest; + Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest); + + quest = qInfo->GetQuestId(); + if (!bot->CanTakeQuest(qInfo, false)) + { + // can't take quest + botAI->TellError("quest_cant_take"); + return false; + } + + if (bot->CanAddQuest(qInfo, false)) + { + bot->AddQuest(qInfo, requester); + + if (bot->CanCompleteQuest(quest)) + bot->CompleteQuest(quest); + + if (qInfo->GetSrcSpell() > 0) + { + bot->CastSpell(bot, qInfo->GetSrcSpell(), true); + } + + botAI->TellMaster("quest_accept"); + return true; + } + + return false; +} diff --git a/src/strategy/actions/AcceptQuestAction.h b/src/strategy/actions/AcceptQuestAction.h index a843fc41..1425cd19 100644 --- a/src/strategy/actions/AcceptQuestAction.h +++ b/src/strategy/actions/AcceptQuestAction.h @@ -17,7 +17,7 @@ class AcceptAllQuestsAction : public QuestAction AcceptAllQuestsAction(PlayerbotAI* botAI, std::string const name = "accept all quests") : QuestAction(botAI, name) { } protected: - void ProcessQuest(Quest const* quest, Object* questGiver) override; + bool ProcessQuest(Quest const* quest, Object* questGiver) override; }; class AcceptQuestAction : public AcceptAllQuestsAction @@ -34,4 +34,10 @@ class AcceptQuestShareAction : public Action bool Execute(Event event) override; }; +class ConfirmQuestAction : public Action { +public: + ConfirmQuestAction(PlayerbotAI* ai) : Action(ai, "confirm quest") {} + bool Execute(Event event); +}; + #endif diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 24205a64..abc4c8bb 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -30,10 +30,10 @@ bool AutoLearnSpellAction::Execute(Event event) void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) { - if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + if (sPlayerbotAIConfig->autoLearnTrainerSpells) LearnTrainerSpells(out); - if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) + if (sPlayerbotAIConfig->autoLearnQuestSpells) LearnQuestSpells(out); if (sPlayerbotAIConfig->randomBotGuildTalk) diff --git a/src/strategy/actions/ChooseRpgTargetAction.cpp b/src/strategy/actions/ChooseRpgTargetAction.cpp index 14b8e865..8054dd9e 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.cpp +++ b/src/strategy/actions/ChooseRpgTargetAction.cpp @@ -11,6 +11,9 @@ #include "GuildCreateActions.h" #include "PossibleRpgTargetsValue.h" #include "Playerbots.h" +#include "RpgSubActions.h" +#include "Util.h" +#include "ServerFacade.h" #include @@ -50,42 +53,77 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP) GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target"); SET_AI_VALUE(GuidPosition, "rpg target", guidP); - Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); + Strategy* rpgStrategy; std::vector triggerNodes; - rpgStrategy->InitTriggers(triggerNodes); float maxRelevance = 0.0f; - for (auto& triggerNode : triggerNodes) + for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies()) { - Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (trigger) + if (strategy.find("rpg") == std::string::npos) + continue; + + if (!botAI->HasStrategy(strategy, BotState::BOT_STATE_NON_COMBAT)) + continue; + + rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy); + + rpgStrategy->InitTriggers(triggerNodes); + + for (auto triggerNode : triggerNodes) { - triggerNode->setTrigger(trigger); + Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f) - continue; + if (trigger) + { + triggerNode->setTrigger(trigger); - trigger = triggerNode->getTrigger(); - if (!trigger->IsActive()) - continue; + if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f) + continue; - maxRelevance = triggerNode->getFirstRelevance(); + Trigger* trigger = triggerNode->getTrigger(); + + if (!trigger->IsActive()) + continue; + + NextAction** nextActions = triggerNode->getHandlers(); + + bool isRpg = false; + + for (int32 i = 0; i < NextAction::size(nextActions); i++) + { + NextAction* nextAction = nextActions[i]; + + Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + + if (dynamic_cast(action)) + isRpg = true; + } + NextAction::destroy(nextActions); + + if (isRpg) + { + maxRelevance = triggerNode->getFirstRelevance(); + rgpActionReason[guidP] = triggerNode->getName(); + } + } } + + for (auto trigger : triggerNodes) + { + delete trigger; + } + + triggerNodes.clear(); } SET_AI_VALUE(GuidPosition, "rpg target", currentRpgTarget); - for (std::vector::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++) - { - TriggerNode* trigger = *i; - delete trigger; - } + if (!maxRelevance) + return 0.0; - triggerNodes.clear(); - - return (maxRelevance - 1.0) * 1000.0f; + return floor((maxRelevance - 1.0) * 1000.0f); } bool ChooseRpgTargetAction::Execute(Event event) @@ -117,7 +155,7 @@ bool ChooseRpgTargetAction::Execute(Event event) if (urand(0, 9)) { - for (auto target : ignoreList) + for (auto target : ignoreList) targets.erase(target); } @@ -188,7 +226,7 @@ bool ChooseRpgTargetAction::Execute(Event event) if (targets.empty()) { - LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} are not available", bot->GetName().c_str(), possibleTargets.size()); + LOG_DEBUG("playerbots", "{} can't choose RPG target: all {} targets are not available", bot->GetName().c_str(), possibleTargets.size()); RESET_AI_VALUE(GuidSet&, "ignore rpg target"); RESET_AI_VALUE(GuidPosition, "rpg target"); return false; @@ -241,17 +279,20 @@ bool ChooseRpgTargetAction::isUseful() if (!botAI->AllowActivity(RPG_ACTIVITY)) return false; - if (AI_VALUE(GuidPosition, "rpg target")) + GuidPosition guidP = AI_VALUE(GuidPosition, "rpg target"); + + if (guidP && guidP.distance(bot) < sPlayerbotAIConfig->reactDistance * 2) return false; TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); - if (travelTarget->isTraveling() && isFollowValid(bot, *travelTarget->getPosition())) - return false; + //if (travelTarget->isTraveling() && AI_VALUE2(bool, "can free move to", *travelTarget->getPosition())) + //return false; if (AI_VALUE(GuidVector, "possible rpg targets").empty()) return false; + //Not stay, not guard, not combat, not trading and group ready. if (!AI_VALUE(bool, "can move around")) return false; @@ -310,7 +351,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos) return true; if (distance < formation->GetMaxDistance()) - return true; + return true; return false; } diff --git a/src/strategy/actions/ChooseRpgTargetAction.h b/src/strategy/actions/ChooseRpgTargetAction.h index a50462c8..9151956a 100644 --- a/src/strategy/actions/ChooseRpgTargetAction.h +++ b/src/strategy/actions/ChooseRpgTargetAction.h @@ -28,6 +28,8 @@ class ChooseRpgTargetAction : public Action private: float getMaxRelevance(GuidPosition guidP); bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids); + + std::unordered_map rgpActionReason; }; class ClearRpgTargetAction : public ChooseRpgTargetAction diff --git a/src/strategy/actions/ChooseTravelTargetAction.cpp b/src/strategy/actions/ChooseTravelTargetAction.cpp index 8ef35bf4..9b700a85 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.cpp +++ b/src/strategy/actions/ChooseTravelTargetAction.cpp @@ -9,16 +9,24 @@ bool ChooseTravelTargetAction::Execute(Event event) { + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + //Get the current travel target. This target is no longer active. TravelTarget* oldTarget = context->GetValue("travel target")->Get(); - //Select a new target to travel to. + //Select a new target to travel to. TravelTarget newTarget = TravelTarget(botAI); - getNewTarget(&newTarget, oldTarget); + + if (!oldTarget) return false; + + if (!oldTarget->isForced() || oldTarget->getStatus() == TravelStatus::TRAVEL_STATUS_EXPIRED) + getNewTarget(&newTarget, oldTarget); + else + newTarget.copyTarget(oldTarget); //If the new target is not active we failed. - if (!newTarget.isActive()) - return false; + if (!newTarget.isActive() && !newTarget.isForced()) + return false; setNewTarget(&newTarget, oldTarget); @@ -36,6 +44,11 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge foundTarget = SetGroupTarget(newTarget); //Join groups members + //Do quests (start, do, end) + if (!foundTarget && urand(1, 100) > 5) //95% chance + { + foundTarget = SetQuestTarget(newTarget, false); //Do any nearby + } //Enpty bags/repair if (!foundTarget && urand(1, 100) > 10) //90% chance if (AI_VALUE2(bool, "group or", "should sell,can sell,following party,near leader") || AI_VALUE2(bool, "group or", "should repair,can repair,following party,near leader")) @@ -53,9 +66,11 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge if (!foundTarget) foundTarget = SetQuestTarget(newTarget); //Do low level quests - } else if (urand(1, 100) > 50) { + } + else if (urand(1, 100) > 50) { foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money - } else { + } + else { foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do } } @@ -703,7 +718,7 @@ bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target) std::vector split(std::string const s, char delim); char* strstri(char const* haystack, char const* needle); -TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name) +TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses) { PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot); @@ -711,32 +726,54 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s std::vector dests; - //Zones - for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) + //Quests + if (quests) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } + } + + //Zones + if (zones) + { + for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } //Npcs - for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + if (npcs) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } //Mobs - for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true)) + if (mobs) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } //Bosses - for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) + if (bosses) { - if (strstri(d->getTitle().c_str(), name.c_str())) - dests.push_back(d); + for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) + { + if (strstri(d->getTitle().c_str(), name.c_str())) + dests.push_back(d); + } } WorldPosition botPos(bot); @@ -745,9 +782,9 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s return nullptr; TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j) - { - return i->distanceTo(const_cast(&botPos)) < j->distanceTo(const_cast(&botPos)); - }); + { + return i->distanceTo(const_cast(&botPos)) < j->distanceTo(const_cast(&botPos)); + }); return dest; }; diff --git a/src/strategy/actions/ChooseTravelTargetAction.h b/src/strategy/actions/ChooseTravelTargetAction.h index 1fdba5f4..a17630ed 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.h +++ b/src/strategy/actions/ChooseTravelTargetAction.h @@ -22,7 +22,7 @@ class ChooseTravelTargetAction : public MovementAction bool Execute(Event event) override; bool isUseful() override; - static TravelDestination* FindDestination(Player* bot, std::string const name); + static TravelDestination* FindDestination(Player* bot, std::string const name, bool zones = true, bool npcs = true, bool quests = true, bool mobs = true, bool bosses = true); protected: void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget); diff --git a/src/strategy/actions/DropQuestAction.cpp b/src/strategy/actions/DropQuestAction.cpp index 6c34001c..979352a2 100644 --- a/src/strategy/actions/DropQuestAction.cpp +++ b/src/strategy/actions/DropQuestAction.cpp @@ -101,10 +101,8 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG if (!quest) continue; - if (quest->GetRequiredClasses() && (quest->GetRewSpellCast() || quest->GetRewSpell())) //Do not drop class specific quests that learn spells. - continue; - - if (quest->GetRequiredClasses() && (quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells. + // Do not drop class quest, may be not rewarding gold but important spells + if (quest->GetRequiredClasses()) continue; if (wantNum == 100) diff --git a/src/strategy/actions/GoAction.h b/src/strategy/actions/GoAction.h index 3ca6b7c1..469f22e0 100644 --- a/src/strategy/actions/GoAction.h +++ b/src/strategy/actions/GoAction.h @@ -8,6 +8,8 @@ #include "MovementActions.h" class PlayerbotAI; +class TravelDestination; +class WorldPosition; class GoAction : public MovementAction { diff --git a/src/strategy/actions/QueryQuestAction.cpp b/src/strategy/actions/QueryQuestAction.cpp index 4ac608bf..e02b27de 100644 --- a/src/strategy/actions/QueryQuestAction.cpp +++ b/src/strategy/actions/QueryQuestAction.cpp @@ -14,8 +14,10 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u 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; @@ -28,7 +30,22 @@ bool QueryQuestAction::Execute(Event event) PlayerbotChatHandler ch(bot); uint32 questId = ch.extractQuestId(text); if (!questId) - return false; + { + 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) { @@ -55,10 +72,7 @@ bool QueryQuestAction::Execute(Event event) uint32 limit = 0; std::vector allDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); - std::sort(allDestinations.begin(), allDestinations.end(), [botPos](TravelDestination* i, TravelDestination* j) - { - return i->distanceTo(const_cast(&botPos)) < j->distanceTo(const_cast(&botPos)); - }); + 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) { @@ -71,24 +85,18 @@ bool QueryQuestAction::Execute(Event event) uint32 apoints = dest->getPoints().size(); - out << round(dest->distanceTo(const_cast(&botPos))); - out << " to " << dest->getTitle(); - out << " " << apoints; + 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"; - if (dest->isFull(bot)) - out << " crowded"; - - if (dest->isFull(bot)) - out << " crowded"; - botAI->TellMaster(out); limit++; diff --git a/src/strategy/actions/QuestAction.cpp b/src/strategy/actions/QuestAction.cpp index e602afd9..8c65c0a1 100644 --- a/src/strategy/actions/QuestAction.cpp +++ b/src/strategy/actions/QuestAction.cpp @@ -7,27 +7,48 @@ #include "ChatHelper.h" #include "Playerbots.h" #include "ReputationMgr.h" +#include "ServerFacade.h" bool QuestAction::Execute(Event event) { ObjectGuid guid = event.getObject(); Player* master = GetMaster(); - if (!master) - { - if (!guid) - guid = bot->GetTarget(); - } - else - { - if (!guid) - guid = master->GetTarget(); - } if (!guid) - return false; + { + if (!master) + { + guid = bot->GetTarget(); + } + else + { + guid = master->GetTarget(); + } + } - return ProcessQuests(guid); + if (guid) + { + return ProcessQuests(guid); + } + + bool result = false; + GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); + for (const auto npc : npcs) + { + Unit* unit = botAI->GetUnit(npc); + if (unit && bot->GetDistance(unit) <= INTERACTION_DISTANCE) + result |= ProcessQuests(unit); + } + std::list gos = AI_VALUE(std::list, "nearest game objects"); + for (const auto go : gos) + { + GameObject* gameobj = botAI->GetGameObject(go); + if (gameobj && bot->GetDistance(gameobj) <= INTERACTION_DISTANCE) + result |= ProcessQuests(gameobj); + } + + return result; } bool QuestAction::CompleteQuest(Player* player, uint32 entry) @@ -67,7 +88,15 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry) int32 creature = pQuest->RequiredNpcOrGo[i]; uint32 creaturecount = pQuest->RequiredNpcOrGoCount[i]; - if (creature > 0) + // TODO check if we need a REQSPELL condition, this methods and sql entry dosent seem implemented ? + /*if (uint32 spell_id = pQuest->GetReqSpell[i]) + { + for (uint16 z = 0; z < creaturecount; ++z) + { + player->CastedCreatureOrGO(creature, ObjectGuid(), spell_id); + } + }*/ + /*else*/ if (creature > 0) { if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature)) for (uint16 z = 0; z < creaturecount; ++z) @@ -127,6 +156,8 @@ bool QuestAction::ProcessQuests(WorldObject* questGiver) if (bot->GetDistance(questGiver) > INTERACTION_DISTANCE && !sPlayerbotAIConfig->syncQuestWithPlayer) { + //if (botAI->HasStrategy("debug", BotState::BOT_STATE_COMBAT) || botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT)) + botAI->TellError("Cannot talk to quest giver"); return false; } @@ -160,16 +191,16 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver) if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) out << "Already completed"; - else if (! bot->CanTakeQuest(quest, false)) + else if (!bot->CanTakeQuest(quest, false)) { - if (! bot->SatisfyQuestStatus(quest, false)) + if (!bot->SatisfyQuestStatus(quest, false)) out << "Already on"; else out << "Can't take"; } - else if (! bot->SatisfyQuestLog(false)) + else if (!bot->SatisfyQuestLog(false)) out << "Quest log is full"; - else if (! bot->CanAddQuest(quest, false)) + else if (!bot->CanAddQuest(quest, false)) out << "Bags are full"; else { @@ -179,7 +210,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver) p.rpos(0); bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); - if (bot->GetQuestStatus(questId ) == QUEST_STATUS_NONE && sPlayerbotAIConfig->syncQuestWithPlayer) + if (bot->GetQuestStatus(questId) == QUEST_STATUS_NONE && sPlayerbotAIConfig->syncQuestWithPlayer) { Object* pObject = ObjectAccessor::GetObjectByTypeMask(*bot, questGiver, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); bot->AddQuest(quest, pObject); @@ -196,10 +227,11 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver) out << " " << chat->FormatQuest(quest); botAI->TellMaster(out); + return false; } -bool QuestObjectiveCompletedAction::Execute(Event event) +bool QuestUpdateCompleteAction::Execute(Event event) { WorldPacket p(event.getPacket()); p.rpos(0); @@ -208,17 +240,84 @@ bool QuestObjectiveCompletedAction::Execute(Event event) ObjectGuid guid; p >> questId >> entry >> available >> required >> guid; - if (entry & 0x80000000) + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); + if (qInfo) { - entry &= 0x7FFFFFFF; - if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(entry)) - botAI->TellMaster(chat->FormatQuestObjective(info->name, available, required)); - } - else - { - if (CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry)) - botAI->TellMaster(chat->FormatQuestObjective(info->Name, available, required)); + if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT)) + { + bot->Say("Quest [ " + ChatHelper::FormatQuest(qInfo) + " ] completed", LANG_UNIVERSAL); + } + botAI->TellMasterNoFacing("Quest completed " + ChatHelper::FormatQuest(qInfo)); } return true; } + +/* +* For creature or gameobject +*/ +bool QuestUpdateAddKillAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 entry, questId, available, required; + ObjectGuid guid; + p >> questId >> entry >> available >> required >> guid; + + std::stringstream ss; + ss << "Update progression kill questid {" << std::to_string(questId) << "} {" << std::to_string(available) << "} / {" << std::to_string(required) << "}"; + botAI->TellMasterNoFacing(ss.str()); + return false; +} + +bool QuestUpdateAddItemAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 itemId, count; + p >> itemId >> count; + + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId); + + std::stringstream ss; + ss << "Update progression itemid {" << std::to_string(itemId) << "} count: {" << std::to_string(count) << "}"; + botAI->TellMasterNoFacing(ss.str()); + + return false; +} + +bool QuestUpdateFailedAction::Execute(Event event) +{ + //opcode SMSG_QUESTUPDATE_FAILED is never sent...(yet?) + return false; +} + +bool QuestUpdateFailedTimerAction::Execute(Event event) +{ + WorldPacket p(event.getPacket()); + p.rpos(0); + + uint32 questId; + p >> questId; + + Player* requester = event.getOwner() ? event.getOwner() : GetMaster(); + + Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId); + + if (qInfo) + { + botAI->TellMaster("Failed timer for " + botAI->GetChatHelper()->FormatQuest(qInfo) +", abandoning"); + } + else + { + botAI->TellMaster("Failed timer for " + std::to_string(questId)); + } + + //drop quest + bot->AbandonQuest(questId); + + return false; +} diff --git a/src/strategy/actions/QuestAction.h b/src/strategy/actions/QuestAction.h index 37f83cb2..efd1cfd0 100644 --- a/src/strategy/actions/QuestAction.h +++ b/src/strategy/actions/QuestAction.h @@ -7,6 +7,7 @@ #include "Action.h" #include "Object.h" +#include "QuestDef.h" class ObjectGuid; class Quest; @@ -17,25 +18,52 @@ class Object; class QuestAction : public Action { - public: - QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { } +public: + QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { } - bool Execute(Event event) override; + bool Execute(Event event) override; - protected: - bool CompleteQuest(Player* player, uint32 entry); - virtual void ProcessQuest(Quest const* quest, Object* questGiver) = 0; - bool AcceptQuest(Quest const* quest, ObjectGuid questGiver); - bool ProcessQuests(ObjectGuid questGiver); - bool ProcessQuests(WorldObject* questGiver); +protected: + bool CompleteQuest(Player* player, uint32 entry); + virtual bool ProcessQuest(Quest const* quest, Object* questGiver) = 0; + bool AcceptQuest(Quest const* quest, ObjectGuid questGiver); + bool ProcessQuests(ObjectGuid questGiver); + bool ProcessQuests(WorldObject* questGiver); }; -class QuestObjectiveCompletedAction : public Action +class QuestUpdateCompleteAction : public Action { - public: - QuestObjectiveCompletedAction(PlayerbotAI* botAI) : Action(botAI, "quest objective completed") { } +public: + QuestUpdateCompleteAction(PlayerbotAI* ai) : Action(ai, "quest update complete") {} + bool Execute(Event event) override; +}; - bool Execute(Event event) override; +class QuestUpdateAddKillAction : public Action +{ +public: + QuestUpdateAddKillAction(PlayerbotAI* ai) : Action(ai, "quest update add kill") {} + bool Execute(Event event) override; +}; + +class QuestUpdateAddItemAction : public Action +{ +public: + QuestUpdateAddItemAction(PlayerbotAI* ai) : Action(ai, "quest update add item") {} + bool Execute(Event event) override;; +}; + +class QuestUpdateFailedAction : public Action +{ +public: + QuestUpdateFailedAction(PlayerbotAI* ai) : Action(ai, "quest update failed") {} + bool Execute(Event event) override; +}; + +class QuestUpdateFailedTimerAction : public Action +{ +public: + QuestUpdateFailedTimerAction(PlayerbotAI* ai) : Action(ai, "quest update failed timer") {} + bool Execute(Event event) override; }; #endif diff --git a/src/strategy/actions/QuestConfirmAcceptAction.cpp b/src/strategy/actions/QuestConfirmAcceptAction.cpp deleted file mode 100644 index a3bd6bb9..00000000 --- a/src/strategy/actions/QuestConfirmAcceptAction.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "QuestConfirmAcceptAction.h" -#include "WorldPacket.h" - -bool QuestConfirmAcceptAction::Execute(Event event) -{ - WorldPacket packet(event.getPacket()); - uint32 questId; - packet >> questId; - - WorldPacket sendPacket(CMSG_QUEST_CONFIRM_ACCEPT); - sendPacket << questId; - Quest const* quest = sObjectMgr->GetQuestTemplate(questId); - if (!quest || !bot->CanAddQuest(quest, true)) { - return false; - } - std::ostringstream out; - out << "Quest: " << chat->FormatQuest(quest) << " confirm accept"; - botAI->TellMaster(out); - bot->GetSession()->HandleQuestConfirmAccept(sendPacket); - return true; -} \ No newline at end of file diff --git a/src/strategy/actions/QuestConfirmAcceptAction.h b/src/strategy/actions/QuestConfirmAcceptAction.h deleted file mode 100644 index 5b10b292..00000000 --- a/src/strategy/actions/QuestConfirmAcceptAction.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -#ifndef _PLAYERBOT_QUESTCONFIRMACCEPTACTION_H -#define _PLAYERBOT_QUESTCONFIRMACCEPTACTION_H - -#include "AiObjectContext.h" -#include "PlayerbotAI.h" -#include "QuestAction.h" -#include "Player.h" - -class ObjectGuid; -class Quest; -class Player; -class PlayerbotAI; -class WorldObject; - -class QuestConfirmAcceptAction : public Action -{ - public: - QuestConfirmAcceptAction(PlayerbotAI* botAI) : Action(botAI, "quest confirm accept") {} - bool Execute(Event event) override; -}; - -#endif \ No newline at end of file diff --git a/src/strategy/actions/RpgAction.cpp b/src/strategy/actions/RpgAction.cpp index b413d3a1..9b163a45 100644 --- a/src/strategy/actions/RpgAction.cpp +++ b/src/strategy/actions/RpgAction.cpp @@ -10,6 +10,7 @@ #include "Formations.h" #include "Playerbots.h" #include "ServerFacade.h" +#include "RpgSubActions.h" #include @@ -45,65 +46,109 @@ bool RpgAction::isUseful() bool RpgAction::SetNextRpgAction() { - Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); - + Strategy* rpgStrategy; std::vector actions; std::vector relevances; std::vector triggerNodes; - rpgStrategy->InitTriggers(triggerNodes); - for (auto& triggerNode : triggerNodes) + + for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies()) { - Trigger* trigger = context->GetTrigger(triggerNode->getName()); - if (trigger) + if (strategy.find("rpg") == std::string::npos) + continue; + + rpgStrategy = botAI->GetAiObjectContext()->GetStrategy(strategy); + + rpgStrategy->InitTriggers(triggerNodes); + + for (auto& triggerNode : triggerNodes) { - triggerNode->setTrigger(trigger); + Trigger* trigger = context->GetTrigger(triggerNode->getName()); - NextAction** nextActions = triggerNode->getHandlers(); - - trigger = triggerNode->getTrigger(); - - bool isChecked = false; - for (int32 i = 0; i < NextAction::size(nextActions); i++) + if (trigger) { - NextAction* nextAction = nextActions[i]; - if (nextAction->getRelevance() > 2.0f) - continue; + triggerNode->setTrigger(trigger); - if (!isChecked && !trigger->IsActive()) - break; + NextAction** nextActions = triggerNode->getHandlers(); - isChecked = true; + Trigger* trigger = triggerNode->getTrigger(); - Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + bool isChecked = false; - if (!action->isPossible() || !action->isUseful()) - continue; + for (int32 i = 0; i < NextAction::size(nextActions); i++) + { + NextAction* nextAction = nextActions[i]; - actions.push_back(action); - relevances.push_back((nextAction->getRelevance() - 1) * 1000); + if (nextAction->getRelevance() > 2.0f) + continue; + + if (!isChecked && !trigger->IsActive()) + break; + + isChecked = true; + + Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); + if (!dynamic_cast(action) || !action->isPossible() || !action->isUseful()) + continue; + + actions.push_back(action); + relevances.push_back((nextAction->getRelevance() - 1) * 1000); + } + NextAction::destroy(nextActions); } - - NextAction::destroy(nextActions); } + + for (const auto i : triggerNodes) + { + delete i; + } + triggerNodes.clear(); } if (actions.empty()) return false; + if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT)) + { + std::vector> sortedActions; + + for (int i = 0; i < actions.size(); i++) + sortedActions.push_back(std::make_pair(actions[i], relevances[i])); + + std::sort(sortedActions.begin(), sortedActions.end(), [](std::pairi, std::pair j) {return i.second > j.second; }); + + std::stringstream ss; + ss << "------" << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject()) << "------"; + bot->Say(ss.str(), LANG_UNIVERSAL); + botAI->TellMasterNoFacing(ss.str()); + + for (auto action : sortedActions) + { + std::ostringstream out; + + out << " " << action.first->getName() << " " << action.second; + + botAI->TellMasterNoFacing(out); + } + } + std::mt19937 gen(time(0)); + sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen); Action* action = actions.front(); - for (std::vector::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++) + if ((botAI->HasStrategy("debug", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT))) { - TriggerNode* trigger = *i; - delete trigger; - } + std::ostringstream out; + out << "do: "; + out << chat->FormatWorldobject(AI_VALUE(GuidPosition, "rpg target").GetWorldObject()); - triggerNodes.clear(); + out << " " << action->getName(); + + botAI->TellMasterNoFacing(out); + } SET_AI_VALUE(std::string, "next rpg action", action->getName()); diff --git a/src/strategy/actions/RpgAction.h b/src/strategy/actions/RpgAction.h index fe6843b2..631e2e5d 100644 --- a/src/strategy/actions/RpgAction.h +++ b/src/strategy/actions/RpgAction.h @@ -13,28 +13,28 @@ class Unit; class RpgAction : public MovementAction { - public: - RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { } +public: + RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { } - bool Execute(Event event) override; - bool isUseful() override; + bool Execute(Event event) override; + bool isUseful() override; - protected: - virtual bool SetNextRpgAction(); +protected: + virtual bool SetNextRpgAction(); - typedef void (RpgAction::*RpgElement)(ObjectGuid guid); + typedef void (RpgAction::* RpgElement)(ObjectGuid guid); - bool AddIgnore(ObjectGuid guid); - bool RemIgnore(ObjectGuid guid); - bool HasIgnore(ObjectGuid guid); + bool AddIgnore(ObjectGuid guid); + bool RemIgnore(ObjectGuid guid); + bool HasIgnore(ObjectGuid guid); }; class CRpgAction : public RpgAction { - public: - CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { } +public: + CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { } - bool isUseful() override; + bool isUseful() override; }; #endif diff --git a/src/strategy/actions/TalkToQuestGiverAction.cpp b/src/strategy/actions/TalkToQuestGiverAction.cpp index 78f2879c..000aad98 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.cpp +++ b/src/strategy/actions/TalkToQuestGiverAction.cpp @@ -11,8 +11,9 @@ #include "QuestDef.h" #include "WorldPacket.h" -void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver) +bool TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver) { + bool isCompleted = false; std::ostringstream out; out << "Quest "; @@ -26,7 +27,7 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver { QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId()); if (masterStatus == QUEST_STATUS_INCOMPLETE || masterStatus == QUEST_STATUS_FAILED) - CompleteQuest(master, quest->GetQuestId()); + isCompleted |= CompleteQuest(master, quest->GetQuestId()); } } @@ -34,39 +35,42 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver { if (master && master->GetQuestStatus(quest->GetQuestId()) == QUEST_STATUS_COMPLETE && (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED)) { - CompleteQuest(bot, quest->GetQuestId()); + isCompleted |= CompleteQuest(bot, quest->GetQuestId()); status = bot->GetQuestStatus(quest->GetQuestId()); } } switch (status) { - case QUEST_STATUS_COMPLETE: - TurnInQuest(quest, questGiver, out); - break; - case QUEST_STATUS_INCOMPLETE: - out << "|cffff0000Incompleted|r"; - break; - case QUEST_STATUS_NONE: - out << "|cff00ff00Available|r"; - break; - case QUEST_STATUS_FAILED: - out << "|cffff0000Failed|r"; - break; - default: - break; + case QUEST_STATUS_COMPLETE: + isCompleted |= TurnInQuest(quest, questGiver, out); + break; + case QUEST_STATUS_INCOMPLETE: + out << "|cffff0000Incompleted|r"; + break; + case QUEST_STATUS_NONE: + AcceptQuest(quest, questGiver->GetGUID()); + out << "|cff00ff00Available|r"; + break; + case QUEST_STATUS_FAILED: + out << "|cffff0000Failed|r"; + break; + default: + break; } out << ": " << chat->FormatQuest(quest); botAI->TellMaster(out); + + return isCompleted; } -void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out) +bool TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out) { uint32 questID = quest->GetQuestId(); if (bot->GetQuestRewardStatus(questID)) - return; + return false; bot->PlayDistanceSound(621); @@ -78,6 +82,8 @@ void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, { RewardMultipleItem(quest, questGiver, out); } + + return true; } void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out) @@ -244,26 +250,26 @@ bool TurnInQueryQuestAction::Execute(Event event) out << "Quest "; switch (status) { - case QUEST_STATUS_COMPLETE: - TurnInQuest(quest, object, out); - break; - case QUEST_STATUS_INCOMPLETE: - out << "|cffff0000Incompleted|r"; - break; - case QUEST_STATUS_NONE: - out << "|cff00ff00Available|r"; - break; - case QUEST_STATUS_FAILED: - out << "|cffff0000Failed|r"; - break; - case QUEST_STATUS_REWARDED: - out << "|cffff0000Rewarded|r"; - break; - default: - break; + case QUEST_STATUS_COMPLETE: + TurnInQuest(quest, object, out); + break; + case QUEST_STATUS_INCOMPLETE: + out << "|cffff0000Incompleted|r"; + break; + case QUEST_STATUS_NONE: + out << "|cff00ff00Available|r"; + break; + case QUEST_STATUS_FAILED: + out << "|cffff0000Failed|r"; + break; + case QUEST_STATUS_REWARDED: + out << "|cffff0000Rewarded|r"; + break; + default: + break; } out << ": " << chat->FormatQuest(quest); botAI->TellMaster(out); return true; -} \ No newline at end of file +} diff --git a/src/strategy/actions/TalkToQuestGiverAction.h b/src/strategy/actions/TalkToQuestGiverAction.h index 081bfe4a..8f716441 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.h +++ b/src/strategy/actions/TalkToQuestGiverAction.h @@ -13,25 +13,25 @@ class WorldObject; class TalkToQuestGiverAction : public QuestAction { - public: - TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { } +public: + TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { } - protected: - void ProcessQuest(Quest const* quest, Object* questGiver) override; - void TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); +protected: + bool ProcessQuest(Quest const* quest, Object* questGiver) override; + bool TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); - private: - void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out); - void RewardSingleItem(Quest const* quest, Object* questGiver, std::ostringstream& out); - std::set BestRewards(Quest const* quest); - void RewardMultipleItem(Quest const* quest, Object* questGiver, std::ostringstream& out); - void AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip); +private: + void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out); + void RewardSingleItem(Quest const* quest, Object* questGiver, std::ostringstream& out); + std::set BestRewards(Quest const* quest); + void RewardMultipleItem(Quest const* quest, Object* questGiver, std::ostringstream& out); + void AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip); }; class TurnInQueryQuestAction : public TalkToQuestGiverAction { - public: - TurnInQueryQuestAction(PlayerbotAI* botAI) : TalkToQuestGiverAction(botAI, "turn in query quest") {} - bool Execute(Event event) override; +public: + TurnInQueryQuestAction(PlayerbotAI* botAI) : TalkToQuestGiverAction(botAI, "turn in query quest") {} + bool Execute(Event event) override; }; #endif diff --git a/src/strategy/actions/UseItemAction.cpp b/src/strategy/actions/UseItemAction.cpp index 0c8b49f3..736d7c22 100644 --- a/src/strategy/actions/UseItemAction.cpp +++ b/src/strategy/actions/UseItemAction.cpp @@ -463,13 +463,10 @@ bool UseRandomQuestItem::Execute(Event event) ObjectGuid goTarget; std::vector questItems = AI_VALUE2(std::vector, "inventory items", "quest"); - - Item* item = nullptr; - uint32 delay = 0; - if (questItems.empty()) return false; + Item* item = nullptr; for (uint8 i = 0; i < 5; i++) { auto itr = questItems.begin(); @@ -477,7 +474,6 @@ bool UseRandomQuestItem::Execute(Event event) Item* questItem = *itr; ItemTemplate const* proto = questItem->GetTemplate(); - if (proto->StartQuest) { Quest const* qInfo = sObjectMgr->GetQuestTemplate(proto->StartQuest); @@ -488,61 +484,14 @@ bool UseRandomQuestItem::Execute(Event event) } } - uint32 spellId = proto->Spells[0].SpellId; - if (spellId) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - - GuidVector npcs = AI_VALUE(GuidVector, ("nearest npcs")); - for (auto& npc : npcs) - { - Unit* unit = botAI->GetUnit(npc); - if (botAI->CanCastSpell(spellId, unit, false)) - { - item = questItem; - unitTarget = unit; - break; - } - } - - GuidVector gos = AI_VALUE(GuidVector, ("nearest game objects")); - for (auto& go : gos) - { - GameObject* gameObject = botAI->GetGameObject(go); - GameObjectTemplate const* goInfo = gameObject->GetGOInfo(); - if (!goInfo->GetLockId()) - continue; - - LockEntry const* lock = sLockStore.LookupEntry(goInfo->GetLockId()); - for (uint8 i = 0; i < MAX_LOCK_CASE; ++i) - { - if (!lock->Type[i]) - continue; - if (lock->Type[i] != LOCK_KEY_ITEM) - continue; - - if (lock->Index[i] == proto->ItemId) - { - item = questItem; - goTarget = go; - unitTarget = nullptr; - break; - } - } - } - } } if (!item) return false; - if (!goTarget && !unitTarget) - return false; - bool used = UseItem(item, goTarget, nullptr, unitTarget); - if (used) - botAI->SetNextCheckDelay(delay); + botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown); return used; } diff --git a/src/strategy/actions/WorldPacketActionContext.h b/src/strategy/actions/WorldPacketActionContext.h index 4646da2f..ded2380b 100644 --- a/src/strategy/actions/WorldPacketActionContext.h +++ b/src/strategy/actions/WorldPacketActionContext.h @@ -24,7 +24,6 @@ #include "QuestAction.h" #include "PassLeadershipToMasterAction.h" #include "PetitionSignAction.h" -#include "QuestConfirmAcceptAction.h" #include "ReadyCheckAction.h" #include "RememberTaxiAction.h" #include "ReviveFromCorpseAction.h" @@ -37,116 +36,131 @@ #include "TradeStatusAction.h" #include "UseMeetingStoneAction.h" #include "NamedObjectContext.h" -#include "QuestConfirmAcceptAction.h" class PlayerbotAI; class WorldPacketActionContext : public NamedObjectContext { - public: - WorldPacketActionContext() - { - creators["accept invitation"] = &WorldPacketActionContext::accept_invitation; - creators["give leader in dungeon"] = &WorldPacketActionContext::give_leader_in_dungeon; - creators["leader"] = &WorldPacketActionContext::pass_leadership_to_master; - creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money; - creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation; - creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip; - creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest; - creators["accept quest"] = &WorldPacketActionContext::accept_quest; - creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests; - creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share; - creators["loot roll"] = &WorldPacketActionContext::loot_roll; - creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll; - creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse; - creators["find corpse"] = &WorldPacketActionContext::find_corpse; - creators["auto release"] = &WorldPacketActionContext::auto_release; - creators["accept resurrect"] = &WorldPacketActionContext::accept_resurrect; - creators["use meeting stone"] = &WorldPacketActionContext::use_meeting_stone; - creators["area trigger"] = &WorldPacketActionContext::area_trigger; - creators["reach area trigger"] = &WorldPacketActionContext::reach_area_trigger; - creators["check mount state"] = &WorldPacketActionContext::check_mount_state; - creators["remember taxi"] = &WorldPacketActionContext::remember_taxi; - creators["accept trade"] = &WorldPacketActionContext::accept_trade; - creators["store loot"] = &WorldPacketActionContext::store_loot; - creators["quest objective completed"] = &WorldPacketActionContext::quest_objective_completed; - creators["party command"] = &WorldPacketActionContext::party_command; - creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed; - creators["accept duel"] = &WorldPacketActionContext::accept_duel; - creators["ready check"] = &WorldPacketActionContext::ready_check; - creators["ready check finished"] = &WorldPacketActionContext::ready_check_finished; - creators["uninvite"] = &WorldPacketActionContext::uninvite; - creators["security check"] = &WorldPacketActionContext::security_check; - creators["guild accept"] = &WorldPacketActionContext::guild_accept; - creators["inventory change failure"] = &WorldPacketActionContext::inventory_change_failure; - creators["bg status check"] = &WorldPacketActionContext::bg_status_check; - creators["bg strategy check"] = &WorldPacketActionContext::bg_strategy_check; - creators["bg status"] = &WorldPacketActionContext::bg_status; - creators["bg join"] = &WorldPacketActionContext::bg_join; - creators["bg leave"] = &WorldPacketActionContext::bg_leave; - creators["arena tactics"] = &WorldPacketActionContext::arena_tactics; - creators["petition sign"] = &WorldPacketActionContext::petition_sign; - creators["lfg join"] = &WorldPacketActionContext::lfg_join; - creators["lfg accept"] = &WorldPacketActionContext::lfg_accept; - creators["lfg role check"] = &WorldPacketActionContext::lfg_role_check; - creators["lfg leave"] = &WorldPacketActionContext::lfg_leave; - creators["lfg teleport"] = &WorldPacketActionContext::lfg_teleport; - creators["see spell"] = &WorldPacketActionContext::see_spell; - creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept; - creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest; - creators["quest confirm accept"] = &WorldPacketActionContext::quest_confirm_accept; - } +public: + WorldPacketActionContext() + { + creators["accept invitation"] = &WorldPacketActionContext::accept_invitation; + creators["give leader in dungeon"] = &WorldPacketActionContext::give_leader_in_dungeon; + creators["leader"] = &WorldPacketActionContext::pass_leadership_to_master; + creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money; + creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation; + creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip; + creators["loot roll"] = &WorldPacketActionContext::loot_roll; + creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll; + creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse; + creators["find corpse"] = &WorldPacketActionContext::find_corpse; + creators["auto release"] = &WorldPacketActionContext::auto_release; + creators["accept resurrect"] = &WorldPacketActionContext::accept_resurrect; + creators["use meeting stone"] = &WorldPacketActionContext::use_meeting_stone; + creators["area trigger"] = &WorldPacketActionContext::area_trigger; + creators["reach area trigger"] = &WorldPacketActionContext::reach_area_trigger; + creators["check mount state"] = &WorldPacketActionContext::check_mount_state; + creators["remember taxi"] = &WorldPacketActionContext::remember_taxi; + creators["accept trade"] = &WorldPacketActionContext::accept_trade; + creators["store loot"] = &WorldPacketActionContext::store_loot; - private: - static Action* inventory_change_failure(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } - static Action* guild_accept(PlayerbotAI* botAI) { return new GuildAcceptAction(botAI); } - static Action* security_check(PlayerbotAI* botAI) { return new SecurityCheckAction(botAI); } - static Action* uninvite(PlayerbotAI* botAI) { return new UninviteAction(botAI); } - static Action* ready_check_finished(PlayerbotAI* botAI) { return new FinishReadyCheckAction(botAI); } - static Action* ready_check(PlayerbotAI* botAI) { return new ReadyCheckAction(botAI); } - static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); } - static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); } - static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); } - static Action* quest_objective_completed(PlayerbotAI* botAI) { return new QuestObjectiveCompletedAction(botAI); } - static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); } - static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); } - static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); } - static Action* check_mount_state(PlayerbotAI* botAI) { return new CheckMountStateAction(botAI); } - static Action* area_trigger(PlayerbotAI* botAI) { return new AreaTriggerAction(botAI); } - static Action* reach_area_trigger(PlayerbotAI* botAI) { return new ReachAreaTriggerAction(botAI); } - static Action* use_meeting_stone(PlayerbotAI* botAI) { return new UseMeetingStoneAction(botAI); } - static Action* accept_resurrect(PlayerbotAI* botAI) { return new AcceptResurrectAction(botAI); } - static Action* find_corpse(PlayerbotAI* botAI) { return new FindCorpseAction(botAI); } - static Action* auto_release(PlayerbotAI* botAI) { return new AutoReleaseSpiritAction(botAI); } - static Action* revive_from_corpse(PlayerbotAI* botAI) { return new ReviveFromCorpseAction(botAI); } - static Action* accept_invitation(PlayerbotAI* botAI) { return new AcceptInvitationAction(botAI); } - static Action* give_leader_in_dungeon(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); } - static Action* pass_leadership_to_master(PlayerbotAI* botAI) { return new PassLeadershipToMasterAction(botAI); } - static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); } - static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); } - static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } - static Action* turn_in_quest(PlayerbotAI* botAI) { return new TalkToQuestGiverAction(botAI); } - static Action* accept_quest(PlayerbotAI* botAI) { return new AcceptQuestAction(botAI); } - static Action* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsAction(botAI); } - static Action* accept_quest_share(PlayerbotAI* botAI) { return new AcceptQuestShareAction(botAI); } - static Action* loot_roll(PlayerbotAI* botAI) { return new LootRollAction(botAI); } - static Action* master_loot_roll(PlayerbotAI* botAI) { return new MasterLootRollAction(botAI); } - static Action* bg_join(PlayerbotAI* botAI) { return new BGJoinAction(botAI); } - static Action* bg_leave(PlayerbotAI* botAI) { return new BGLeaveAction(botAI); } - static Action* bg_status(PlayerbotAI* botAI) { return new BGStatusAction(botAI); } - static Action* bg_status_check(PlayerbotAI* botAI) { return new BGStatusCheckAction(botAI); } - static Action* bg_strategy_check(PlayerbotAI* botAI) { return new BGStrategyCheckAction(botAI); } - static Action* arena_tactics(PlayerbotAI* botAI) { return new ArenaTactics(botAI); } - static Action* petition_sign(PlayerbotAI* botAI) { return new PetitionSignAction(botAI); } - static Action* lfg_teleport(PlayerbotAI* botAI) { return new LfgTeleportAction(botAI); } - static Action* lfg_leave(PlayerbotAI* botAI) { return new LfgLeaveAction(botAI); } - static Action* lfg_accept(PlayerbotAI* botAI) { return new LfgAcceptAction(botAI); } - static Action* lfg_role_check(PlayerbotAI* botAI) { return new LfgRoleCheckAction(botAI); } - static Action* lfg_join(PlayerbotAI* botAI) { return new LfgJoinAction(botAI); } - static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); } - static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); } - static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); } - static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); } + // quest + creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest; + creators["accept quest"] = &WorldPacketActionContext::accept_quest; + creators["confirm quest"] = &WorldPacketActionContext::confirm_quest; + creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests; + creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share; + creators["quest update add kill"] = &WorldPacketActionContext::quest_update_add_kill; + creators["quest update add item"] = &WorldPacketActionContext::quest_update_add_item; + creators["quest update failed"] = &WorldPacketActionContext::quest_update_failed; + creators["quest update failed timer"] = &WorldPacketActionContext::quest_update_failed_timer; + creators["quest update complete"] = &WorldPacketActionContext::quest_update_complete; + + creators["party command"] = &WorldPacketActionContext::party_command; + creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed; + creators["accept duel"] = &WorldPacketActionContext::accept_duel; + creators["ready check"] = &WorldPacketActionContext::ready_check; + creators["ready check finished"] = &WorldPacketActionContext::ready_check_finished; + creators["uninvite"] = &WorldPacketActionContext::uninvite; + creators["security check"] = &WorldPacketActionContext::security_check; + creators["guild accept"] = &WorldPacketActionContext::guild_accept; + creators["inventory change failure"] = &WorldPacketActionContext::inventory_change_failure; + creators["bg status check"] = &WorldPacketActionContext::bg_status_check; + creators["bg strategy check"] = &WorldPacketActionContext::bg_strategy_check; + creators["bg status"] = &WorldPacketActionContext::bg_status; + creators["bg join"] = &WorldPacketActionContext::bg_join; + creators["bg leave"] = &WorldPacketActionContext::bg_leave; + creators["arena tactics"] = &WorldPacketActionContext::arena_tactics; + creators["petition sign"] = &WorldPacketActionContext::petition_sign; + creators["lfg join"] = &WorldPacketActionContext::lfg_join; + creators["lfg accept"] = &WorldPacketActionContext::lfg_accept; + creators["lfg role check"] = &WorldPacketActionContext::lfg_role_check; + creators["lfg leave"] = &WorldPacketActionContext::lfg_leave; + creators["lfg teleport"] = &WorldPacketActionContext::lfg_teleport; + creators["see spell"] = &WorldPacketActionContext::see_spell; + creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept; + } + +private: + static Action* inventory_change_failure(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } + static Action* guild_accept(PlayerbotAI* botAI) { return new GuildAcceptAction(botAI); } + static Action* security_check(PlayerbotAI* botAI) { return new SecurityCheckAction(botAI); } + static Action* uninvite(PlayerbotAI* botAI) { return new UninviteAction(botAI); } + static Action* ready_check_finished(PlayerbotAI* botAI) { return new FinishReadyCheckAction(botAI); } + static Action* ready_check(PlayerbotAI* botAI) { return new ReadyCheckAction(botAI); } + static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); } + static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); } + static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); } + static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); } + static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); } + static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); } + static Action* check_mount_state(PlayerbotAI* botAI) { return new CheckMountStateAction(botAI); } + static Action* area_trigger(PlayerbotAI* botAI) { return new AreaTriggerAction(botAI); } + static Action* reach_area_trigger(PlayerbotAI* botAI) { return new ReachAreaTriggerAction(botAI); } + static Action* use_meeting_stone(PlayerbotAI* botAI) { return new UseMeetingStoneAction(botAI); } + static Action* accept_resurrect(PlayerbotAI* botAI) { return new AcceptResurrectAction(botAI); } + static Action* find_corpse(PlayerbotAI* botAI) { return new FindCorpseAction(botAI); } + static Action* auto_release(PlayerbotAI* botAI) { return new AutoReleaseSpiritAction(botAI); } + static Action* revive_from_corpse(PlayerbotAI* botAI) { return new ReviveFromCorpseAction(botAI); } + static Action* accept_invitation(PlayerbotAI* botAI) { return new AcceptInvitationAction(botAI); } + static Action* give_leader_in_dungeon(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); } + static Action* pass_leadership_to_master(PlayerbotAI* botAI) { return new PassLeadershipToMasterAction(botAI); } + static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); } + static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); } + static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } + + // quest + static Action* quest_update_add_kill(PlayerbotAI* ai) { return new QuestUpdateAddKillAction(ai); } + static Action* quest_update_add_item(PlayerbotAI* ai) { return new QuestUpdateAddItemAction(ai); } + static Action* quest_update_failed(PlayerbotAI* ai) { return new QuestUpdateFailedAction(ai); } + static Action* quest_update_failed_timer(PlayerbotAI* ai) { return new QuestUpdateFailedTimerAction(ai); } + static Action* quest_update_complete(PlayerbotAI* botAI) { return new QuestUpdateCompleteAction(botAI); } + + static Action* turn_in_quest(PlayerbotAI* botAI) { return new TalkToQuestGiverAction(botAI); } + static Action* accept_quest(PlayerbotAI* botAI) { return new AcceptQuestAction(botAI); } + static Action* confirm_quest(PlayerbotAI* ai) { return new ConfirmQuestAction(ai); } + static Action* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsAction(botAI); } + static Action* accept_quest_share(PlayerbotAI* botAI) { return new AcceptQuestShareAction(botAI); } + //static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); } + //static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); } + + + static Action* loot_roll(PlayerbotAI* botAI) { return new LootRollAction(botAI); } + static Action* master_loot_roll(PlayerbotAI* botAI) { return new MasterLootRollAction(botAI); } + static Action* bg_join(PlayerbotAI* botAI) { return new BGJoinAction(botAI); } + static Action* bg_leave(PlayerbotAI* botAI) { return new BGLeaveAction(botAI); } + static Action* bg_status(PlayerbotAI* botAI) { return new BGStatusAction(botAI); } + static Action* bg_status_check(PlayerbotAI* botAI) { return new BGStatusCheckAction(botAI); } + static Action* bg_strategy_check(PlayerbotAI* botAI) { return new BGStrategyCheckAction(botAI); } + static Action* arena_tactics(PlayerbotAI* botAI) { return new ArenaTactics(botAI); } + static Action* petition_sign(PlayerbotAI* botAI) { return new PetitionSignAction(botAI); } + static Action* lfg_teleport(PlayerbotAI* botAI) { return new LfgTeleportAction(botAI); } + static Action* lfg_leave(PlayerbotAI* botAI) { return new LfgLeaveAction(botAI); } + static Action* lfg_accept(PlayerbotAI* botAI) { return new LfgAcceptAction(botAI); } + static Action* lfg_role_check(PlayerbotAI* botAI) { return new LfgRoleCheckAction(botAI); } + static Action* lfg_join(PlayerbotAI* botAI) { return new LfgJoinAction(botAI); } + static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); } + static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); } }; #endif diff --git a/src/strategy/generic/DebugStrategy.h b/src/strategy/generic/DebugStrategy.h index 55d59408..403bc40b 100644 --- a/src/strategy/generic/DebugStrategy.h +++ b/src/strategy/generic/DebugStrategy.h @@ -43,4 +43,13 @@ class DebugSpellStrategy : public Strategy std::string const getName() override { return "debug spell"; } }; +class DebugQuestStrategy : public Strategy +{ +public: + DebugQuestStrategy(PlayerbotAI* botAI) : Strategy(botAI) { } + + uint32 GetType() const override { return STRATEGY_TYPE_NONCOMBAT | STRATEGY_TYPE_COMBAT; } + std::string const getName() override { return "debug quest"; } +}; + #endif diff --git a/src/strategy/generic/MaintenanceStrategy.cpp b/src/strategy/generic/MaintenanceStrategy.cpp index 46b1f044..db1a9e13 100644 --- a/src/strategy/generic/MaintenanceStrategy.cpp +++ b/src/strategy/generic/MaintenanceStrategy.cpp @@ -14,11 +14,11 @@ void MaintenanceStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("clean quest log", 6.0f), nullptr))); triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random recipe", 1.0f), nullptr))); - triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("use random quest item", 10.0f), nullptr))); triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("disenchant random item", 1.0f), nullptr))); triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("enchant random item", 1.0f), nullptr))); triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("smart destroy item", 1.0f), nullptr))); triggers.push_back(new TriggerNode("move stuck", NextAction::array(0, new NextAction("reset", 1.0f), nullptr))); // triggers.push_back(new TriggerNode("move long stuck", NextAction::array(0, new NextAction("hearthstone", 0.9f), new NextAction("repop", 0.8f), nullptr))); + triggers.push_back(new TriggerNode("random", NextAction::array(0, new NextAction("use random quest item", 0.9f), nullptr))); } diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index 2db5ed84..4b4d5610 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -32,31 +32,32 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back(new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); triggers.push_back(new TriggerNode("lfg proposal active", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); triggers.push_back(new TriggerNode("arena team invite", NextAction::array(0, new NextAction("arena team accept", relevance), nullptr))); - triggers.push_back(new TriggerNode("quest confirm accept", NextAction::array(0, new NextAction("quest confirm accept", relevance), nullptr))); //triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", relevance), nullptr))); triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr))); triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr))); - triggers.push_back(new TriggerNode("levelup", NextAction::array(0, - new NextAction("auto teleport for level", relevance + 3), - new NextAction("auto talents", relevance + 2), - new NextAction("auto learn spell", relevance + 1), - new NextAction("auto upgrade equip", relevance), + triggers.push_back(new TriggerNode("levelup", NextAction::array(0, + new NextAction("auto teleport for level", relevance + 3), + new NextAction("auto talents", relevance + 2), + new NextAction("auto learn spell", relevance + 1), + new NextAction("auto upgrade equip", relevance), nullptr))); // triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); - triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); - + triggers.push_back(new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); triggers.push_back(new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr))); triggers.push_back(new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr))); triggers.push_back(new TriggerNode("revive from corpse", NextAction::array(0, new NextAction("revive from corpse", relevance), nullptr))); triggers.push_back(new TriggerNode("master loot roll", NextAction::array(0, new NextAction("master loot roll", relevance), nullptr))); + + // quest ? + //triggers.push_back(new TriggerNode("quest confirm", NextAction::array(0, new NextAction("quest confirm", relevance), nullptr))); + //triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); } WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { supported.push_back("loot roll"); supported.push_back("check mount state"); - supported.push_back("quest objective completed"); supported.push_back("party command"); supported.push_back("ready check"); supported.push_back("uninvite"); @@ -65,6 +66,14 @@ WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : Pas supported.push_back("random bot update"); supported.push_back("inventory change failure"); supported.push_back("bg status"); + + // quests + supported.push_back("quest update add kill"); + supported.push_back("quest update add item"); + supported.push_back("quest update failed"); + supported.push_back("quest update failed timer"); + supported.push_back("quest update complete"); + supported.push_back("confirm quest"); } void ReadyCheckStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.h b/src/strategy/generic/WorldPacketHandlerStrategy.h index 2333877f..7083dda1 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.h +++ b/src/strategy/generic/WorldPacketHandlerStrategy.h @@ -11,20 +11,20 @@ class PlayerbotAI; class WorldPacketHandlerStrategy : public PassTroughStrategy { - public: - WorldPacketHandlerStrategy(PlayerbotAI* botAI); +public: + WorldPacketHandlerStrategy(PlayerbotAI* botAI); - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "default"; } + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "default"; } }; class ReadyCheckStrategy : public PassTroughStrategy { - public: - ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { } +public: + ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { } - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "ready check"; } + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "ready check"; } }; #endif diff --git a/src/strategy/triggers/RpgTriggers.cpp b/src/strategy/triggers/RpgTriggers.cpp index b500ad89..eee38718 100644 --- a/src/strategy/triggers/RpgTriggers.cpp +++ b/src/strategy/triggers/RpgTriggers.cpp @@ -114,6 +114,12 @@ bool RpgEndQuestTrigger::IsActive() if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry())) return true; + if (!AI_VALUE2(bool, "can accept quest low level npc", guidP.GetEntry())) + return false; + + if (guidP.GetEntry() == AI_VALUE(TravelTarget*, "travel target")->getEntry()) + return true; + return false; } diff --git a/src/strategy/triggers/WorldPacketTriggerContext.h b/src/strategy/triggers/WorldPacketTriggerContext.h index 8f08eeda..4424317b 100644 --- a/src/strategy/triggers/WorldPacketTriggerContext.h +++ b/src/strategy/triggers/WorldPacketTriggerContext.h @@ -11,112 +11,127 @@ class WorldPacketTriggerContext : public NamedObjectContext { - public: - WorldPacketTriggerContext() - { - creators["gossip hello"] = &WorldPacketTriggerContext::gossip_hello; - creators["group invite"] = &WorldPacketTriggerContext::group_invite; - creators["group set leader"] = &WorldPacketTriggerContext::group_set_leader; - creators["not enough money"] = &WorldPacketTriggerContext::no_money; - creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation; - creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip; - creators["use game object"] = &WorldPacketTriggerContext::use_game_object; - creators["complete quest"] = &WorldPacketTriggerContext::complete_quest; - creators["accept quest"] = &WorldPacketTriggerContext::accept_quest; - creators["quest share"] = &WorldPacketTriggerContext::quest_share; - creators["loot roll"] = &WorldPacketTriggerContext::loot_roll; - creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request; - creators["area trigger"] = &WorldPacketTriggerContext::area_trigger; - creators["within area trigger"] = &WorldPacketTriggerContext::within_area_trigger; - creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state; - creators["activate taxi"] = &WorldPacketTriggerContext::taxi; - creators["trade status"] = &WorldPacketTriggerContext::trade_status; - creators["loot response"] = &WorldPacketTriggerContext::loot_response; - creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range; - creators["quest objective completed"] = &WorldPacketTriggerContext::quest_objective_completed; - creators["item push result"] = &WorldPacketTriggerContext::item_push_result; - creators["party command"] = &WorldPacketTriggerContext::party_command; - creators["taxi done"] = &WorldPacketTriggerContext::taxi_done; - creators["cast failed"] = &WorldPacketTriggerContext::cast_failed; - creators["duel requested"] = &WorldPacketTriggerContext::duel_requested; - creators["ready check"] = &WorldPacketTriggerContext::ready_check; - creators["ready check finished"] = &WorldPacketTriggerContext::ready_check_finished; - creators["uninvite"] = &WorldPacketTriggerContext::uninvite; - creators["uninvite guid"] = &WorldPacketTriggerContext::uninvite_guid; - creators["lfg join"] = &WorldPacketTriggerContext::lfg_update; - creators["lfg proposal"] = &WorldPacketTriggerContext::lfg_proposal; - creators["lfg role check"] = &WorldPacketTriggerContext::lfg_role_check; - creators["lfg leave"] = &WorldPacketTriggerContext::lfg_leave; - creators["guild invite"] = &WorldPacketTriggerContext::guild_invite; - creators["petition offer"] = &WorldPacketTriggerContext::petition_offer; - creators["lfg teleport"] = &WorldPacketTriggerContext::lfg_teleport; - creators["inventory change failure"] = &WorldPacketTriggerContext::inventory_change_failure; - creators["bg status"] = &WorldPacketTriggerContext::bg_status; - creators["levelup"] = &WorldPacketTriggerContext::levelup; - creators["xpgain"] = &WorldPacketTriggerContext::xpgain; - creators["see spell"] = &WorldPacketTriggerContext::seespell; - creators["release spirit"] = &WorldPacketTriggerContext::release_spirit; - creators["revive from corpse"] = &WorldPacketTriggerContext::revive_from_corpse; - creators["receive emote"] = &WorldPacketTriggerContext::receive_emote; - creators["receive text emote"] = &WorldPacketTriggerContext::receive_text_emote; - creators["arena team invite"] = &WorldPacketTriggerContext::arena_team_invite; - creators["quest confirm accept"] = &WorldPacketTriggerContext::quest_confirm_accept; - creators["group destroyed"] = &WorldPacketTriggerContext::group_destroyed; - creators["group list"] = &WorldPacketTriggerContext::group_list; - creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details; - } +public: + WorldPacketTriggerContext() + { + creators["gossip hello"] = &WorldPacketTriggerContext::gossip_hello; + creators["group invite"] = &WorldPacketTriggerContext::group_invite; + creators["group set leader"] = &WorldPacketTriggerContext::group_set_leader; + creators["not enough money"] = &WorldPacketTriggerContext::no_money; + creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation; + creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip; + creators["use game object"] = &WorldPacketTriggerContext::use_game_object; + creators["loot roll"] = &WorldPacketTriggerContext::loot_roll; + creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request; + creators["area trigger"] = &WorldPacketTriggerContext::area_trigger; + creators["within area trigger"] = &WorldPacketTriggerContext::within_area_trigger; + creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state; + creators["activate taxi"] = &WorldPacketTriggerContext::taxi; + creators["trade status"] = &WorldPacketTriggerContext::trade_status; + creators["loot response"] = &WorldPacketTriggerContext::loot_response; + creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range; - private: - static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); } - static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); } - static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); } - static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); } - static Trigger* lfg_proposal(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg proposal"); } - static Trigger* lfg_role_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg role check"); } - static Trigger* lfg_update(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg join"); } - static Trigger* uninvite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite"); } - static Trigger* uninvite_guid(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite guid"); } - static Trigger* ready_check_finished(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check finished"); } - static Trigger* ready_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check"); } - static Trigger* duel_requested(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "duel requested"); } - static Trigger* cast_failed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cast failed"); } - static Trigger* taxi_done(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "taxi done"); } - static Trigger* party_command(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "party command"); } - static Trigger* item_push_result(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "item push result"); } - static Trigger* quest_objective_completed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest objective completed"); } - static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); } - static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); } - static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); } - static Trigger* cannot_equip(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cannot equip"); } - static Trigger* check_mount_state(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "check mount state"); } - static Trigger* area_trigger(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "area trigger"); } - static Trigger* within_area_trigger(PlayerbotAI* botAI) { return new WithinAreaTrigger(botAI); } - static Trigger* resurrect_request(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "resurrect request"); } - static Trigger* gossip_hello(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "gossip hello"); } - static Trigger* group_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group invite"); } - static Trigger* group_set_leader(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group set leader"); } - static Trigger* no_money(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough money"); } - static Trigger* no_reputation(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough reputation"); } - static Trigger* use_game_object(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "use game object"); } - static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); } - static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); } - static Trigger* quest_share(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest share"); } - static Trigger* loot_roll(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot roll"); } - static Trigger* taxi(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "activate taxi"); } - static Trigger* bg_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "bg status"); } - static Trigger* levelup(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "levelup"); } - static Trigger* xpgain(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "xpgain"); } - static Trigger* petition_offer(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "petition offer"); } - static Trigger* seespell(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "see spell"); } - static Trigger* release_spirit(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "release spirit"); } - static Trigger* revive_from_corpse(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "revive from corpse"); } - static Trigger* receive_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive emote"); } - static Trigger* receive_text_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive text emote"); } - static Trigger* arena_team_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "arena team invite"); } - static Trigger* quest_confirm_accept(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest confirm accept"); } - static Trigger* group_destroyed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group destroyed"); } - static Trigger* group_list(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group list"); } - static Trigger* questgiver_quest_details(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "questgiver quest details"); } + // quest + creators["complete quest"] = &WorldPacketTriggerContext::complete_quest; + creators["accept quest"] = &WorldPacketTriggerContext::accept_quest; + creators["confirm quest"] = &WorldPacketTriggerContext::quest_confirm_accept; + creators["quest share"] = &WorldPacketTriggerContext::quest_share; + creators["quest update add kill"] = &WorldPacketTriggerContext::quest_update_add_kill; + creators["quest update add item"] = &WorldPacketTriggerContext::quest_update_add_item; + creators["quest update failed"] = &WorldPacketTriggerContext::quest_update_failed; + creators["quest update failed timer"] = &WorldPacketTriggerContext::quest_update_failed_timer; + creators["quest update complete"] = &WorldPacketTriggerContext::quest_update_complete; + creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details; + + + creators["item push result"] = &WorldPacketTriggerContext::item_push_result; + creators["party command"] = &WorldPacketTriggerContext::party_command; + creators["taxi done"] = &WorldPacketTriggerContext::taxi_done; + creators["cast failed"] = &WorldPacketTriggerContext::cast_failed; + creators["duel requested"] = &WorldPacketTriggerContext::duel_requested; + creators["ready check"] = &WorldPacketTriggerContext::ready_check; + creators["ready check finished"] = &WorldPacketTriggerContext::ready_check_finished; + creators["uninvite"] = &WorldPacketTriggerContext::uninvite; + creators["uninvite guid"] = &WorldPacketTriggerContext::uninvite_guid; + creators["lfg join"] = &WorldPacketTriggerContext::lfg_update; + creators["lfg proposal"] = &WorldPacketTriggerContext::lfg_proposal; + creators["lfg role check"] = &WorldPacketTriggerContext::lfg_role_check; + creators["lfg leave"] = &WorldPacketTriggerContext::lfg_leave; + creators["guild invite"] = &WorldPacketTriggerContext::guild_invite; + creators["petition offer"] = &WorldPacketTriggerContext::petition_offer; + creators["lfg teleport"] = &WorldPacketTriggerContext::lfg_teleport; + creators["inventory change failure"] = &WorldPacketTriggerContext::inventory_change_failure; + creators["bg status"] = &WorldPacketTriggerContext::bg_status; + creators["levelup"] = &WorldPacketTriggerContext::levelup; + creators["xpgain"] = &WorldPacketTriggerContext::xpgain; + creators["see spell"] = &WorldPacketTriggerContext::seespell; + creators["release spirit"] = &WorldPacketTriggerContext::release_spirit; + creators["revive from corpse"] = &WorldPacketTriggerContext::revive_from_corpse; + creators["receive emote"] = &WorldPacketTriggerContext::receive_emote; + creators["receive text emote"] = &WorldPacketTriggerContext::receive_text_emote; + creators["arena team invite"] = &WorldPacketTriggerContext::arena_team_invite; + creators["group destroyed"] = &WorldPacketTriggerContext::group_destroyed; + creators["group list"] = &WorldPacketTriggerContext::group_list; + } + +private: + static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); } + static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); } + static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); } + static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); } + static Trigger* lfg_proposal(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg proposal"); } + static Trigger* lfg_role_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg role check"); } + static Trigger* lfg_update(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg join"); } + static Trigger* uninvite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite"); } + static Trigger* uninvite_guid(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite guid"); } + static Trigger* ready_check_finished(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check finished"); } + static Trigger* ready_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check"); } + static Trigger* duel_requested(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "duel requested"); } + static Trigger* cast_failed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cast failed"); } + static Trigger* taxi_done(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "taxi done"); } + static Trigger* party_command(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "party command"); } + static Trigger* item_push_result(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "item push result"); } + + // quest + static Trigger* quest_update_add_kill(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add kill"); } + static Trigger* quest_update_add_item(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update add item"); } + static Trigger* quest_update_failed(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed"); } + static Trigger* quest_update_failed_timer(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update failed timer"); } + static Trigger* quest_update_complete(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest update complete"); } + static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); } + static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); } + static Trigger* quest_confirm_accept(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "confirm quest"); } + static Trigger* quest_share(PlayerbotAI* ai) { return new WorldPacketTrigger(ai, "quest share"); } + static Trigger* questgiver_quest_details(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "questgiver quest details"); } + + static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); } + static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); } + static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); } + static Trigger* cannot_equip(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cannot equip"); } + static Trigger* check_mount_state(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "check mount state"); } + static Trigger* area_trigger(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "area trigger"); } + static Trigger* within_area_trigger(PlayerbotAI* botAI) { return new WithinAreaTrigger(botAI); } + static Trigger* resurrect_request(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "resurrect request"); } + static Trigger* gossip_hello(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "gossip hello"); } + static Trigger* group_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group invite"); } + static Trigger* group_set_leader(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group set leader"); } + static Trigger* no_money(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough money"); } + static Trigger* no_reputation(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough reputation"); } + static Trigger* use_game_object(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "use game object"); } + static Trigger* loot_roll(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot roll"); } + static Trigger* taxi(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "activate taxi"); } + static Trigger* bg_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "bg status"); } + static Trigger* levelup(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "levelup"); } + static Trigger* xpgain(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "xpgain"); } + static Trigger* petition_offer(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "petition offer"); } + static Trigger* seespell(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "see spell"); } + static Trigger* release_spirit(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "release spirit"); } + static Trigger* revive_from_corpse(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "revive from corpse"); } + static Trigger* receive_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive emote"); } + static Trigger* receive_text_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive text emote"); } + static Trigger* arena_team_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "arena team invite"); } + static Trigger* group_destroyed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group destroyed"); } + static Trigger* group_list(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group list"); } }; #endif diff --git a/src/strategy/values/GrindTargetValue.cpp b/src/strategy/values/GrindTargetValue.cpp index 0be03904..55051d4d 100644 --- a/src/strategy/values/GrindTargetValue.cpp +++ b/src/strategy/values/GrindTargetValue.cpp @@ -30,6 +30,9 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) Group* group = bot->GetGroup(); Player* master = GetMaster(); + if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || !GET_PLAYERBOT_AI(master))) + master = nullptr; + GuidVector attackers = context->GetValue("attackers")->Get(); for (ObjectGuid const guid : attackers) { @@ -46,8 +49,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) float distance = 0; Unit* result = nullptr; - - // std::unordered_map needForQuestMap; + std::unordered_map needForQuestMap; for (ObjectGuid const guid : targets) { @@ -81,16 +83,18 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) 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.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 (!needForQuestMap[unit->GetEntry()]) + { + Creature* creature = dynamic_cast(unit); + if ((urand(0, 100) < 60 || (context->GetValue("travel target")->Get()->isWorking() && + context->GetValue("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) + { + continue; + } + } if (Creature* creature = unit->ToCreature()) if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())