quest complete with gameobject

This commit is contained in:
Yunfan Li
2023-11-04 23:00:35 +08:00
parent 2b70808c7d
commit 1f6e5627df
15 changed files with 139 additions and 23 deletions

View File

@@ -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"

View File

@@ -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()

View File

@@ -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);
}

View File

@@ -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());

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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");

View File

@@ -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<uint32> 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;
}

View File

@@ -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<uint32> 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

View File

@@ -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<Action>
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<Action>
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

View File

@@ -14,7 +14,7 @@ void QuestStrategy::InitTriggers(std::vector<TriggerNode*>& 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<TriggerNode*>& triggers)

View File

@@ -41,6 +41,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& 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)));

View File

@@ -61,6 +61,9 @@ class WorldPacketTriggerContext : public NamedObjectContext<Trigger>
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<Trigger>
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