From 1f6e5627dfa0fa32b36c9a8797cc4399ab679c6f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 4 Nov 2023 23:00:35 +0800 Subject: [PATCH] quest complete with gameobject --- conf/playerbots.conf.dist | 6 +- src/PlayerbotAI.cpp | 8 ++- src/RandomPlayerbotFactory.cpp | 2 +- src/RandomPlayerbotMgr.cpp | 1 + src/strategy/actions/AcceptQuestAction.cpp | 2 +- src/strategy/actions/AcceptQuestAction.h | 2 +- src/strategy/actions/ChatShortcutActions.cpp | 5 +- src/strategy/actions/QuestAction.h | 4 +- src/strategy/actions/ResetAiAction.cpp | 30 ++++++++ .../actions/TalkToQuestGiverAction.cpp | 69 +++++++++++++++++-- src/strategy/actions/TalkToQuestGiverAction.h | 18 +++-- .../actions/WorldPacketActionContext.h | 3 + src/strategy/generic/QuestStrategies.cpp | 2 +- .../generic/WorldPacketHandlerStrategy.cpp | 4 ++ .../triggers/WorldPacketTriggerContext.h | 6 ++ 15 files changed, 139 insertions(+), 23 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e15de488..cb64f599 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -163,8 +163,8 @@ AiPlayerbot.AutoEquipUpgradeLoot = 1 AiPlayerbot.EquipUpgradeThreshold = 1.1 # Sync quests with player (Bots will complete quests the moment you hand them in. Bots will ignore looting quest items.) -# Default: 0 (disabled) -AiPlayerbot.SyncQuestWithPlayer = 0 +# Default: 1 (disabled) +AiPlayerbot.SyncQuestWithPlayer = 1 # Bots will auto-complete quests for the player when handing in # Default: 0 (disabled) @@ -318,7 +318,7 @@ AiPlayerbot.RandomBotQuestItems = "6948,5175,5176,5177,5178,16309,12382,13704,11 AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703" # 33(stranglethorn vale),440(tanaris) # PvP Restricted Areas (bots don't pvp) -AiPlayerbot.PvpProhibitedAreaIds = "976,35" +AiPlayerbot.PvpProhibitedAreaIds = "976,35,392" # Spells every random bot will learn on randomize (54197 - cold weather flying) AiPlayerbot.RandomBotSpellIds = "54197" diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index c30989f4..db99021b 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -122,7 +122,7 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object"); masterIncomingPacketHandlers.AddHandler(CMSG_AREATRIGGER, "area trigger"); - masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object"); + // masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object"); masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll"); masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello"); masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello"); @@ -134,7 +134,7 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel 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_PUSHQUESTTOPARTY, "quest share"); masterIncomingPacketHandlers.AddHandler(CMSG_LFG_TELEPORT, "lfg teleport"); masterIncomingPacketHandlers.AddHandler(CMSG_CAST_SPELL, "see spell"); masterIncomingPacketHandlers.AddHandler(CMSG_REPOP_REQUEST, "release spirit"); @@ -167,10 +167,14 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel 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"); + 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"); } PlayerbotAI::~PlayerbotAI() diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index d303360c..1c56bcd7 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -401,7 +401,7 @@ void RandomPlayerbotFactory::CreateRandomBots() } if (bot_creation) { - LOG_INFO("playerbots", "Waiting for {} characters load into database...", totalCharCount); + LOG_INFO("playerbots", "Waiting for {} characters loading into database...", totalCharCount); /* wait for characters load into database, or characters will fail to loggin */ std::this_thread::sleep_for(15ms * totalCharCount); } diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 388f33da..a991ee8e 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1166,6 +1166,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "AND t.minlevel != 65 " "AND t.faction != 35 " "AND t.faction != 474 " + "AND t.faction != 69 " "AND map IN ({}) " "ORDER BY " "t.minlevel;", sPlayerbotAIConfig->randomBotMapsAsString.c_str()); diff --git a/src/strategy/actions/AcceptQuestAction.cpp b/src/strategy/actions/AcceptQuestAction.cpp index 5b935818..003f9866 100644 --- a/src/strategy/actions/AcceptQuestAction.cpp +++ b/src/strategy/actions/AcceptQuestAction.cpp @@ -6,7 +6,7 @@ #include "Event.h" #include "Playerbots.h" -void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, WorldObject* questGiver) +void AcceptAllQuestsAction::ProcessQuest(Quest const* quest, Object* questGiver) { AcceptQuest(quest, questGiver->GetGUID()); bot->PlayDistanceSound(620); diff --git a/src/strategy/actions/AcceptQuestAction.h b/src/strategy/actions/AcceptQuestAction.h index b7061e51..a843fc41 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, WorldObject* questGiver) override; + void ProcessQuest(Quest const* quest, Object* questGiver) override; }; class AcceptQuestAction : public AcceptAllQuestsAction diff --git a/src/strategy/actions/ChatShortcutActions.cpp b/src/strategy/actions/ChatShortcutActions.cpp index 849b0a16..b7f2bd13 100644 --- a/src/strategy/actions/ChatShortcutActions.cpp +++ b/src/strategy/actions/ChatShortcutActions.cpp @@ -198,7 +198,8 @@ bool NaxxChatShortcutAction::Execute(Event event) botAI->Reset(); botAI->ChangeStrategy("+naxx", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+naxx", BOT_STATE_COMBAT); - bot->Say("Add Naxx Strategies!", LANG_UNIVERSAL); + botAI->TellMasterNoFacing("Add Naxx Strategies!"); + // bot->Say("Add Naxx Strategies!", LANG_UNIVERSAL); return true; } @@ -211,6 +212,6 @@ bool BwlChatShortcutAction::Execute(Event event) botAI->Reset(); botAI->ChangeStrategy("+bwl", BOT_STATE_NON_COMBAT); botAI->ChangeStrategy("+bwl", BOT_STATE_COMBAT); - bot->Say("Add Bwl Strategies!", LANG_UNIVERSAL); + botAI->TellMasterNoFacing("Add Bwl Strategies!"); return true; } diff --git a/src/strategy/actions/QuestAction.h b/src/strategy/actions/QuestAction.h index d1c967b7..37f83cb2 100644 --- a/src/strategy/actions/QuestAction.h +++ b/src/strategy/actions/QuestAction.h @@ -6,12 +6,14 @@ #define _PLAYERBOT_QUESTACTION_H #include "Action.h" +#include "Object.h" class ObjectGuid; class Quest; class Player; class PlayerbotAI; class WorldObject; +class Object; class QuestAction : public Action { @@ -22,7 +24,7 @@ class QuestAction : public Action protected: bool CompleteQuest(Player* player, uint32 entry); - virtual void ProcessQuest(Quest const* quest, WorldObject* questGiver) = 0; + virtual void ProcessQuest(Quest const* quest, Object* questGiver) = 0; bool AcceptQuest(Quest const* quest, ObjectGuid questGiver); bool ProcessQuests(ObjectGuid questGiver); bool ProcessQuests(WorldObject* questGiver); diff --git a/src/strategy/actions/ResetAiAction.cpp b/src/strategy/actions/ResetAiAction.cpp index 0fe32dce..c7e5af8b 100644 --- a/src/strategy/actions/ResetAiAction.cpp +++ b/src/strategy/actions/ResetAiAction.cpp @@ -4,11 +4,41 @@ #include "ResetAiAction.h" #include "Event.h" +#include "ObjectGuid.h" #include "Playerbots.h" #include "PlayerbotDbStore.h" +#include "WorldPacket.h" +#include "Group.h" bool ResetAiAction::Execute(Event event) { + if (!event.getPacket().empty()) { + WorldPacket packet = event.getPacket(); + if (packet.GetOpcode() == SMSG_GROUP_LIST) { + uint8 groupType; + Group::MemberSlot slot; + packet >> groupType; + packet >> slot.group; + packet >> slot.flags; + packet >> slot.roles; + if (groupType & GROUPTYPE_LFG) + { + uint8 status; + uint32 dungeon; + packet >> status; + packet >> dungeon; + } + ObjectGuid guid; + uint32 counter; + uint32 membersCount; + packet >> guid; + packet >> counter; + packet >> membersCount; + if (membersCount != 0) { + return false; + } + } + } sPlayerbotDbStore->Reset(botAI); botAI->ResetStrategies(false); botAI->TellMaster("AI was reset to defaults"); diff --git a/src/strategy/actions/TalkToQuestGiverAction.cpp b/src/strategy/actions/TalkToQuestGiverAction.cpp index ad914d04..a26eb583 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.cpp +++ b/src/strategy/actions/TalkToQuestGiverAction.cpp @@ -6,9 +6,11 @@ #include "Event.h" #include "ChatHelper.h" #include "ItemUsageValue.h" +#include "Object.h" #include "Playerbots.h" +#include "WorldPacket.h" -void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, WorldObject* questGiver) +void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver) { std::ostringstream out; out << "Quest "; @@ -56,7 +58,7 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, WorldObject* quest botAI->TellMaster(out); } -void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, WorldObject* questGiver, std::ostringstream& out) +void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out) { uint32 questID = quest->GetQuestId(); @@ -75,7 +77,7 @@ void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, WorldObject* questG } } -void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, WorldObject* questGiver, std::ostringstream& out) +void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out) { if (bot->CanRewardQuest(quest, false)) { @@ -88,7 +90,7 @@ void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, WorldObject* quest } } -void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, WorldObject* questGiver, std::ostringstream& out) +void TalkToQuestGiverAction::RewardSingleItem(Quest const* quest, Object* questGiver, std::ostringstream& out) { int index = 0; ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[index]); @@ -134,7 +136,7 @@ ItemIds TalkToQuestGiverAction::BestRewards(Quest const* quest) } } -void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, WorldObject* questGiver, std::ostringstream& out) +void TalkToQuestGiverAction::RewardMultipleItem(Quest const* quest, Object* questGiver, std::ostringstream& out) { std::set bestIds; @@ -199,3 +201,60 @@ void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostrings botAI->TellMaster(msg); out << "Reward pending"; } + +bool TurnInQueryQuestAction::Execute(Event event) +{ + WorldPacket pakcet = event.getPacket(); + ObjectGuid guid; + uint32 questId; + ObjectGuid unk1; + pakcet >> guid >> questId; + Object* object = ObjectAccessor::GetObjectByTypeMask(*bot, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); + if (!object || (!object->hasQuest(questId) && !object->hasInvolvedQuest(questId))) + { + return false; + } + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + QuestStatus status = bot->GetQuestStatus(quest->GetQuestId()); + Player* master = GetMaster(); + + if (sPlayerbotAIConfig->syncQuestForPlayer && master) + { + PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master); + if (!masterBotAI || masterBotAI->IsRealPlayer()) + { + QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId()); + if (masterStatus == QUEST_STATUS_INCOMPLETE || masterStatus == QUEST_STATUS_FAILED) + CompleteQuest(master, quest->GetQuestId()); + } + } + + if (sPlayerbotAIConfig->syncQuestWithPlayer) + { + if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_FAILED) + { + CompleteQuest(bot, quest->GetQuestId()); + status = bot->GetQuestStatus(quest->GetQuestId()); + } + } + std::ostringstream out; + 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; + } + + 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 442a830e..081bfe4a 100644 --- a/src/strategy/actions/TalkToQuestGiverAction.h +++ b/src/strategy/actions/TalkToQuestGiverAction.h @@ -14,18 +14,24 @@ class WorldObject; class TalkToQuestGiverAction : public QuestAction { public: - TalkToQuestGiverAction(PlayerbotAI* botAI) : QuestAction(botAI, "talk to quest giver") { } + TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { } protected: - void ProcessQuest(Quest const* quest, WorldObject* questGiver) override; + void ProcessQuest(Quest const* quest, Object* questGiver) override; + void TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); private: - void TurnInQuest(Quest const* quest, WorldObject* questGiver, std::ostringstream& out); - void RewardNoItem(Quest const* quest, WorldObject* questGiver, std::ostringstream& out); - void RewardSingleItem(Quest const* quest, WorldObject* questGiver, std::ostringstream& out); + 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, WorldObject* questGiver, std::ostringstream& out); + 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; +}; #endif diff --git a/src/strategy/actions/WorldPacketActionContext.h b/src/strategy/actions/WorldPacketActionContext.h index ed96eecb..2fa38164 100644 --- a/src/strategy/actions/WorldPacketActionContext.h +++ b/src/strategy/actions/WorldPacketActionContext.h @@ -27,6 +27,7 @@ #include "ReadyCheckAction.h" #include "RememberTaxiAction.h" #include "ReviveFromCorpseAction.h" +#include "RewardAction.h" #include "SeeSpellAction.h" #include "SecurityCheckAction.h" #include "TalkToQuestGiverAction.h" @@ -90,6 +91,7 @@ class WorldPacketActionContext : public NamedObjectContext 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; } private: @@ -140,6 +142,7 @@ class WorldPacketActionContext : public NamedObjectContext 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); } }; #endif diff --git a/src/strategy/generic/QuestStrategies.cpp b/src/strategy/generic/QuestStrategies.cpp index 7ea6c656..613b826c 100644 --- a/src/strategy/generic/QuestStrategies.cpp +++ b/src/strategy/generic/QuestStrategies.cpp @@ -14,7 +14,7 @@ void QuestStrategy::InitTriggers(std::vector& triggers) { PassTroughStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("quest share", NextAction::array(0, new NextAction("accept quest share", relevance), nullptr))); + // triggers.push_back(new TriggerNode("quest share", NextAction::array(0, new NextAction("accept quest share", relevance), nullptr))); } void DefaultQuestStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index bf5d2af1..a5c1065d 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -41,6 +41,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger new NextAction("auto learn spell", relevance), new NextAction("auto teleport for level", 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))); diff --git a/src/strategy/triggers/WorldPacketTriggerContext.h b/src/strategy/triggers/WorldPacketTriggerContext.h index 350c7e87..8f08eeda 100644 --- a/src/strategy/triggers/WorldPacketTriggerContext.h +++ b/src/strategy/triggers/WorldPacketTriggerContext.h @@ -61,6 +61,9 @@ class WorldPacketTriggerContext : public NamedObjectContext 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; } private: @@ -111,6 +114,9 @@ class WorldPacketTriggerContext : public NamedObjectContext 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"); } }; #endif