Bot should be more consistent at doing quest +several fixes

This commit is contained in:
Atidot3
2024-07-30 14:45:52 +02:00
parent 30a25ba13f
commit 0008d84f71
34 changed files with 986 additions and 609 deletions

View File

@@ -558,7 +558,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
nonCombatEngine->addStrategies("nc", "food", "chat", "follow", nonCombatEngine->addStrategies("nc", "food", "chat", "follow",
"default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr); "default", "quest", "loot", "gather", "duel", "buff", "mount", "emote", nullptr);
} }
if (sPlayerbotAIConfig->autoSaveMana) { if (sPlayerbotAIConfig->autoSaveMana){
nonCombatEngine->addStrategy("auto save mana"); nonCombatEngine->addStrategy("auto save mana");
} }
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground()) if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
@@ -588,7 +588,9 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
{ {
// nonCombatEngine->addStrategy("travel"); // nonCombatEngine->addStrategy("travel");
nonCombatEngine->addStrategy("rpg"); nonCombatEngine->addStrategy("rpg");
} else { }
else
{
nonCombatEngine->addStrategy("move random"); nonCombatEngine->addStrategy("move random");
} }

View File

@@ -128,15 +128,12 @@ PlayerbotAI::PlayerbotAI(Player* bot) : PlayerbotAIBase(true), bot(bot), chatHel
masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll"); masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll");
masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello"); masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello");
masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_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_ACTIVATETAXI, "activate taxi");
masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXIEXPRESS, "activate taxi"); masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXIEXPRESS, "activate taxi");
masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARALLNODES, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARALLNODES, "taxi done");
masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARNODE, "taxi done"); masterIncomingPacketHandlers.AddHandler(CMSG_TAXICLEARNODE, "taxi done");
masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE, "uninvite"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE, "uninvite");
masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE_GUID, "uninvite guid"); masterIncomingPacketHandlers.AddHandler(CMSG_GROUP_UNINVITE_GUID, "uninvite guid");
masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share");
masterIncomingPacketHandlers.AddHandler(CMSG_LFG_TELEPORT, "lfg teleport"); masterIncomingPacketHandlers.AddHandler(CMSG_LFG_TELEPORT, "lfg teleport");
masterIncomingPacketHandlers.AddHandler(CMSG_CAST_SPELL, "see spell"); masterIncomingPacketHandlers.AddHandler(CMSG_CAST_SPELL, "see spell");
masterIncomingPacketHandlers.AddHandler(CMSG_REPOP_REQUEST, "release spirit"); 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_INVENTORY_CHANGE_FAILURE, "cannot equip");
botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS, "trade status"); botOutgoingPacketHandlers.AddHandler(SMSG_TRADE_STATUS, "trade status");
botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_RESPONSE, "loot response"); 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_ITEM_PUSH_RESULT, "item push result");
botOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command"); botOutgoingPacketHandlers.AddHandler(SMSG_PARTY_COMMAND_RESULT, "party command");
botOutgoingPacketHandlers.AddHandler(SMSG_LEVELUP_INFO, "levelup"); 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_EMOTE, "receive emote");
botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_START_ROLL, "master loot roll"); botOutgoingPacketHandlers.AddHandler(SMSG_LOOT_START_ROLL, "master loot roll");
botOutgoingPacketHandlers.AddHandler(SMSG_ARENA_TEAM_INVITE, "arena team invite"); 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_DESTROYED, "group destroyed");
botOutgoingPacketHandlers.AddHandler(SMSG_GROUP_LIST, "group list"); 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(SMSG_PARTY_COMMAND_RESULT, "party command");
masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK, "ready check"); masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK, "ready check");
masterOutgoingPacketHandlers.AddHandler(MSG_RAID_READY_CHECK_FINISHED, "ready check finished"); 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() PlayerbotAI::~PlayerbotAI()

View File

@@ -114,6 +114,16 @@ void WorldPosition::set(const WorldLocation& pos)
WorldRelocate(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) void WorldPosition::setMapId(uint32 id)
{ {
m_mapId = id; m_mapId = id;
@@ -1061,30 +1071,59 @@ std::string const QuestTravelDestination::getTitle()
bool QuestRelationTravelDestination::isActive(Player* bot) 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 (relation == 0)
{ {
if (questTemplate->GetQuestLevel() >= bot->GetLevel() + 5) if ((int32)questTemplate->GetQuestLevel() >= (int32)bot->GetLevel() + (int32)5)
return false; return false;
//if (questTemplate->XPValue(bot) == 0) // skip for now this quest
// return false; if (getPoints().front()->GetMapId() != bot->GetMapId())
return false;
if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false)) if (!bot->GetMap()->GetEntry()->IsWorldMap() || !bot->CanTakeQuest(questTemplate, false))
return false; return false;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
AiObjectContext* context = botAI->GetAiObjectContext();
uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate); uint32 dialogStatus = sTravelMgr->getDialogStatus(bot, entry, questTemplate);
if (AI_VALUE(bool, "can fight equal")) if (AI_VALUE(bool, "can fight equal"))
{ {
if (dialogStatus != DIALOG_STATUS_AVAILABLE) if (AI_VALUE(uint8, "free quest log slots") < 5)
return false; 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 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; return false;
} }
@@ -1094,25 +1133,14 @@ bool QuestRelationTravelDestination::isActive(Player* bot)
} }
else 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; return false;
if (!bot->CanRewardQuest(questTemplate, false)) //Do not try to hand-in dungeon/elite quests in instances without a group.
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.
if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && !AI_VALUE(bool, "can fight boss")) if ((questTemplate->GetType() == QUEST_TYPE_ELITE || questTemplate->GetType() == QUEST_TYPE_DUNGEON) && !AI_VALUE(bool, "can fight boss"))
{ {
WorldPosition pos(bot); WorldPosition pos(bot);
if (!this->nearestPoint(const_cast<WorldPosition*>(&pos))->isOverworld()) if (!this->nearestPoint(&pos)->isOverworld())
return false; return false;
} }
} }
@@ -4006,7 +4034,45 @@ std::vector<TravelDestination*> TravelMgr::getQuestTravelDestinations(Player* bo
std::vector<TravelDestination*> retTravelLocations; std::vector<TravelDestination*> 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) for (auto& dest : questGivers)
{ {

View File

@@ -95,6 +95,8 @@ class WorldPosition : public WorldLocation
//Setters //Setters
void set(const WorldLocation& pos); void set(const WorldLocation& pos);
void set(const WorldObject* wo);
void set(const WorldPosition& pos);
void setMapId(uint32 id); void setMapId(uint32 id);
void setX(float x); void setX(float x);
void setY(float y); void setY(float y);
@@ -406,7 +408,6 @@ class GuidPosition : public ObjectGuid, public WorldPosition
GuidPosition(WorldObject* wo); GuidPosition(WorldObject* wo);
GuidPosition(CreatureData const& creData); GuidPosition(CreatureData const& creData);
GuidPosition(GameObjectData const& goData); GuidPosition(GameObjectData const& goData);
CreatureTemplate const* GetCreatureTemplate(); CreatureTemplate const* GetCreatureTemplate();
GameObjectTemplate const* GetGameObjectTemplate(); GameObjectTemplate const* GetGameObjectTemplate();

View File

@@ -12,13 +12,30 @@ void Qualified::Qualify(int qual)
qualifier = out.str(); qualifier = out.str();
} }
std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers) std::string const Qualified::MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets)
{ {
std::ostringstream out; std::stringstream out;
for (auto& qualifier : qualifiers) for (uint8 i = 0; i < qualifiers.size(); i++)
out << qualifier << (&qualifier != &qualifiers.back() ? " " : ""); {
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<std::string> Qualified::getMultiQualifiers(std::string const qualifier1) std::vector<std::string> Qualified::getMultiQualifiers(std::string const qualifier1)

View File

@@ -34,7 +34,7 @@ class Qualified
std::string const getQualifier() { return qualifier; } std::string const getQualifier() { return qualifier; }
static std::string const MultiQualify(std::vector<std::string> qualifiers); static std::string const MultiQualify(std::vector<std::string> qualifiers, const std::string& separator, const std::string_view brackets = "{}");
static std::vector<std::string> getMultiQualifiers(std::string const qualifier1); static std::vector<std::string> getMultiQualifiers(std::string const qualifier1);
static int32 getMultiQualifier(std::string const qualifier1, uint32 pos); static int32 getMultiQualifier(std::string const qualifier1, uint32 pos);

View File

@@ -106,6 +106,7 @@ class StrategyContext : public NamedObjectContext<Strategy>
creators["debug move"] = &StrategyContext::debug_move; creators["debug move"] = &StrategyContext::debug_move;
creators["debug rpg"] = &StrategyContext::debug_rpg; creators["debug rpg"] = &StrategyContext::debug_rpg;
creators["debug spell"] = &StrategyContext::debug_spell; creators["debug spell"] = &StrategyContext::debug_spell;
creators["debug quest"] = &StrategyContext::debug_quest;
creators["maintenance"] = &StrategyContext::maintenance; creators["maintenance"] = &StrategyContext::maintenance;
creators["group"] = &StrategyContext::group; creators["group"] = &StrategyContext::group;
creators["guild"] = &StrategyContext::guild; creators["guild"] = &StrategyContext::guild;
@@ -169,6 +170,7 @@ class StrategyContext : public NamedObjectContext<Strategy>
static Strategy* debug_move(PlayerbotAI* botAI) { return new DebugMoveStrategy(botAI); } static Strategy* debug_move(PlayerbotAI* botAI) { return new DebugMoveStrategy(botAI); }
static Strategy* debug_rpg(PlayerbotAI* botAI) { return new DebugRpgStrategy(botAI); } static Strategy* debug_rpg(PlayerbotAI* botAI) { return new DebugRpgStrategy(botAI); }
static Strategy* debug_spell(PlayerbotAI* botAI) { return new DebugSpellStrategy(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* maintenance(PlayerbotAI* botAI) { return new MaintenanceStrategy(botAI); }
static Strategy* group(PlayerbotAI* botAI) { return new GroupStrategy(botAI); } static Strategy* group(PlayerbotAI* botAI) { return new GroupStrategy(botAI); }
static Strategy* guild (PlayerbotAI* botAI) { return new GuildStrategy(botAI); } static Strategy* guild (PlayerbotAI* botAI) { return new GuildStrategy(botAI); }
@@ -228,6 +230,4 @@ class QuestStrategyContext : public NamedObjectContext<Strategy>
static Strategy* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsStrategy(botAI); } static Strategy* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsStrategy(botAI); }
}; };
#endif #endif

View File

@@ -6,54 +6,62 @@
#include "Event.h" #include "Event.h"
#include "Playerbots.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); 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) bool AcceptQuestAction::Execute(Event event)
{ {
Player* master = GetMaster(); Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
if (!master) if (!requester)
return false; return false;
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
ObjectGuid guid; uint64_t guid;
uint32 quest = 0; uint32 quest = 0;
std::string const text = event.getParam(); std::string const text = event.getParam();
PlayerbotChatHandler ch(master); PlayerbotChatHandler ch(requester);
quest = ch.extractQuestId(text); quest = ch.extractQuestId(text);
bool hasAccept = false;
if (event.getPacket().empty()) if (event.getPacket().empty())
{ {
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs"); 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); Unit* unit = botAI->GetUnit(*i);
if (unit && quest && unit->hasQuest(quest)) if (unit && quest && unit->hasQuest(quest))
{ {
guid = unit->GetGUID(); guid = unit->GetGUID().GetRawValue();
break; break;
} }
if (unit && text == "*" && sqrt(bot->GetDistance(unit)) <= INTERACTION_DISTANCE)
if (unit && text == "*" && bot->GetDistance(unit) <= INTERACTION_DISTANCE) hasAccept |= QuestAction::ProcessQuests(unit);
QuestAction::ProcessQuests(unit);
} }
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects no los");
GuidVector gos = AI_VALUE(GuidVector, "nearest game objects"); for (auto i = gos.begin(); i != gos.end(); i++)
for (GuidVector::iterator i = gos.begin(); i != gos.end(); i++)
{ {
GameObject* go = botAI->GetGameObject(*i); GameObject* go = botAI->GetGameObject(*i);
if (go && quest && go->hasQuest(quest)) if (go && quest && go->hasQuest(quest))
{ {
guid = go->GetGUID(); guid = go->GetGUID().GetRawValue();
break; break;
} }
if (go && text == "*" && sqrt(bot->GetDistance(go)) <= INTERACTION_DISTANCE)
if (go && text == "*" && bot->GetDistance(go) <= INTERACTION_DISTANCE) hasAccept |= QuestAction::ProcessQuests(go);
QuestAction::ProcessQuests(go);
} }
} }
else else
@@ -70,7 +78,17 @@ bool AcceptQuestAction::Execute(Event event)
if (!qInfo) if (!qInfo)
return false; 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) bool AcceptQuestShareAction::Execute(Event event)
@@ -112,7 +130,7 @@ bool AcceptQuestShareAction::Execute(Event event)
bot->SetDivider(ObjectGuid::Empty); bot->SetDivider(ObjectGuid::Empty);
} }
if (bot->CanAddQuest( qInfo, false)) if (bot->CanAddQuest(qInfo, false))
{ {
bot->AddQuest(qInfo, master); bot->AddQuest(qInfo, master);
@@ -125,7 +143,7 @@ bool AcceptQuestShareAction::Execute(Event event)
if (qInfo->GetSrcSpell() > 0) if (qInfo->GetSrcSpell() > 0)
{ {
bot->CastSpell( bot, qInfo->GetSrcSpell(), true); bot->CastSpell(bot, qInfo->GetSrcSpell(), true);
} }
botAI->TellMaster("Quest accepted"); botAI->TellMaster("Quest accepted");
@@ -134,3 +152,41 @@ bool AcceptQuestShareAction::Execute(Event event)
return false; 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;
}

View File

@@ -17,7 +17,7 @@ class AcceptAllQuestsAction : public QuestAction
AcceptAllQuestsAction(PlayerbotAI* botAI, std::string const name = "accept all quests") : QuestAction(botAI, name) { } AcceptAllQuestsAction(PlayerbotAI* botAI, std::string const name = "accept all quests") : QuestAction(botAI, name) { }
protected: protected:
void ProcessQuest(Quest const* quest, Object* questGiver) override; bool ProcessQuest(Quest const* quest, Object* questGiver) override;
}; };
class AcceptQuestAction : public AcceptAllQuestsAction class AcceptQuestAction : public AcceptAllQuestsAction
@@ -34,4 +34,10 @@ class AcceptQuestShareAction : public Action
bool Execute(Event event) override; bool Execute(Event event) override;
}; };
class ConfirmQuestAction : public Action {
public:
ConfirmQuestAction(PlayerbotAI* ai) : Action(ai, "confirm quest") {}
bool Execute(Event event);
};
#endif #endif

View File

@@ -30,10 +30,10 @@ bool AutoLearnSpellAction::Execute(Event event)
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out) void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
{ {
if (sPlayerbotAIConfig->autoLearnTrainerSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) if (sPlayerbotAIConfig->autoLearnTrainerSpells)
LearnTrainerSpells(out); LearnTrainerSpells(out);
if (sPlayerbotAIConfig->autoLearnQuestSpells && sRandomPlayerbotMgr->IsRandomBot(bot))// || (!botAI->GetMaster() && sRandomPlayerbotMgr->IsRandomBot(bot))) if (sPlayerbotAIConfig->autoLearnQuestSpells)
LearnQuestSpells(out); LearnQuestSpells(out);
if (sPlayerbotAIConfig->randomBotGuildTalk) if (sPlayerbotAIConfig->randomBotGuildTalk)

View File

@@ -11,6 +11,9 @@
#include "GuildCreateActions.h" #include "GuildCreateActions.h"
#include "PossibleRpgTargetsValue.h" #include "PossibleRpgTargetsValue.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "RpgSubActions.h"
#include "Util.h"
#include "ServerFacade.h"
#include <random> #include <random>
@@ -50,42 +53,77 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target"); GuidPosition currentRpgTarget = AI_VALUE(GuidPosition, "rpg target");
SET_AI_VALUE(GuidPosition, "rpg target", guidP); SET_AI_VALUE(GuidPosition, "rpg target", guidP);
Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); Strategy* rpgStrategy;
std::vector<TriggerNode*> triggerNodes; std::vector<TriggerNode*> triggerNodes;
rpgStrategy->InitTriggers(triggerNodes);
float maxRelevance = 0.0f; float maxRelevance = 0.0f;
for (auto& triggerNode : triggerNodes) for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies())
{ {
Trigger* trigger = context->GetTrigger(triggerNode->getName()); if (strategy.find("rpg") == std::string::npos)
if (trigger) 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) if (trigger)
continue; {
triggerNode->setTrigger(trigger);
trigger = triggerNode->getTrigger(); if (triggerNode->getFirstRelevance() < maxRelevance || triggerNode->getFirstRelevance() > 2.0f)
if (!trigger->IsActive()) continue;
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<RpgEnabled*>(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); SET_AI_VALUE(GuidPosition, "rpg target", currentRpgTarget);
for (std::vector<TriggerNode*>::iterator i = triggerNodes.begin(); i != triggerNodes.end(); i++) if (!maxRelevance)
{ return 0.0;
TriggerNode* trigger = *i;
delete trigger;
}
triggerNodes.clear(); return floor((maxRelevance - 1.0) * 1000.0f);
return (maxRelevance - 1.0) * 1000.0f;
} }
bool ChooseRpgTargetAction::Execute(Event event) bool ChooseRpgTargetAction::Execute(Event event)
@@ -117,7 +155,7 @@ bool ChooseRpgTargetAction::Execute(Event event)
if (urand(0, 9)) if (urand(0, 9))
{ {
for (auto target : ignoreList) for (auto target : ignoreList)
targets.erase(target); targets.erase(target);
} }
@@ -188,7 +226,7 @@ bool ChooseRpgTargetAction::Execute(Event event)
if (targets.empty()) 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(GuidSet&, "ignore rpg target");
RESET_AI_VALUE(GuidPosition, "rpg target"); RESET_AI_VALUE(GuidPosition, "rpg target");
return false; return false;
@@ -241,17 +279,20 @@ bool ChooseRpgTargetAction::isUseful()
if (!botAI->AllowActivity(RPG_ACTIVITY)) if (!botAI->AllowActivity(RPG_ACTIVITY))
return false; 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; return false;
TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target");
if (travelTarget->isTraveling() && isFollowValid(bot, *travelTarget->getPosition())) //if (travelTarget->isTraveling() && AI_VALUE2(bool, "can free move to", *travelTarget->getPosition()))
return false; //return false;
if (AI_VALUE(GuidVector, "possible rpg targets").empty()) if (AI_VALUE(GuidVector, "possible rpg targets").empty())
return false; return false;
//Not stay, not guard, not combat, not trading and group ready.
if (!AI_VALUE(bool, "can move around")) if (!AI_VALUE(bool, "can move around"))
return false; return false;
@@ -310,7 +351,7 @@ bool ChooseRpgTargetAction::isFollowValid(Player* bot, WorldPosition pos)
return true; return true;
if (distance < formation->GetMaxDistance()) if (distance < formation->GetMaxDistance())
return true; return true;
return false; return false;
} }

View File

@@ -28,6 +28,8 @@ class ChooseRpgTargetAction : public Action
private: private:
float getMaxRelevance(GuidPosition guidP); float getMaxRelevance(GuidPosition guidP);
bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids); bool HasSameTarget(ObjectGuid guid, uint32 max, GuidVector const& nearGuids);
std::unordered_map <ObjectGuid, std::string> rgpActionReason;
}; };
class ClearRpgTargetAction : public ChooseRpgTargetAction class ClearRpgTargetAction : public ChooseRpgTargetAction

View File

@@ -9,16 +9,24 @@
bool ChooseTravelTargetAction::Execute(Event event) bool ChooseTravelTargetAction::Execute(Event event)
{ {
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
//Get the current travel target. This target is no longer active. //Get the current travel target. This target is no longer active.
TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get(); TravelTarget* oldTarget = context->GetValue<TravelTarget*>("travel target")->Get();
//Select a new target to travel to. //Select a new target to travel to.
TravelTarget newTarget = TravelTarget(botAI); 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 the new target is not active we failed.
if (!newTarget.isActive()) if (!newTarget.isActive() && !newTarget.isForced())
return false; return false;
setNewTarget(&newTarget, oldTarget); setNewTarget(&newTarget, oldTarget);
@@ -36,6 +44,11 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge
foundTarget = SetGroupTarget(newTarget); //Join groups members 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 //Enpty bags/repair
if (!foundTarget && urand(1, 100) > 10) //90% chance 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")) 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) if (!foundTarget)
foundTarget = SetQuestTarget(newTarget); //Do low level quests 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 foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money
} else { }
else {
foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do
} }
} }
@@ -703,7 +718,7 @@ bool ChooseTravelTargetAction::SetNullTarget(TravelTarget* target)
std::vector<std::string> split(std::string const s, char delim); std::vector<std::string> split(std::string const s, char delim);
char* strstri(char const* haystack, char const* needle); 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); PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
@@ -711,32 +726,54 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
std::vector<TravelDestination*> dests; std::vector<TravelDestination*> dests;
//Zones //Quests
for (auto& d : sTravelMgr->getExploreTravelDestinations(bot, true, true)) if (quests)
{ {
if (strstri(d->getTitle().c_str(), name.c_str())) for (auto& d : sTravelMgr->getQuestTravelDestinations(bot, 0, true, true))
dests.push_back(d); {
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 //Npcs
for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true)) if (npcs)
{ {
if (strstri(d->getTitle().c_str(), name.c_str())) for (auto& d : sTravelMgr->getRpgTravelDestinations(bot, true, true))
dests.push_back(d); {
if (strstri(d->getTitle().c_str(), name.c_str()))
dests.push_back(d);
}
} }
//Mobs //Mobs
for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true)) if (mobs)
{ {
if (strstri(d->getTitle().c_str(), name.c_str())) for (auto& d : sTravelMgr->getGrindTravelDestinations(bot, true, true, 5000.0f))
dests.push_back(d); {
if (strstri(d->getTitle().c_str(), name.c_str()))
dests.push_back(d);
}
} }
//Bosses //Bosses
for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true)) if (bosses)
{ {
if (strstri(d->getTitle().c_str(), name.c_str())) for (auto& d : sTravelMgr->getBossTravelDestinations(bot, true, true))
dests.push_back(d); {
if (strstri(d->getTitle().c_str(), name.c_str()))
dests.push_back(d);
}
} }
WorldPosition botPos(bot); WorldPosition botPos(bot);
@@ -745,9 +782,9 @@ TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::s
return nullptr; return nullptr;
TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j) TravelDestination* dest = *std::min_element(dests.begin(), dests.end(), [botPos](TravelDestination* i, TravelDestination* j)
{ {
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos)); return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos));
}); });
return dest; return dest;
}; };

View File

@@ -22,7 +22,7 @@ class ChooseTravelTargetAction : public MovementAction
bool Execute(Event event) override; bool Execute(Event event) override;
bool isUseful() 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: protected:
void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget); void getNewTarget(TravelTarget* newTarget, TravelTarget* oldTarget);

View File

@@ -101,10 +101,8 @@ void CleanQuestLogAction::DropQuestType(uint8& numQuest, uint8 wantNum, bool isG
if (!quest) if (!quest)
continue; 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
continue; if (quest->GetRequiredClasses())
if (quest->GetRequiredClasses() && (quest->GetRewSpellCast() || quest->GetRewSpell())) // Do not drop class specific quests that learn spells.
continue; continue;
if (wantNum == 100) if (wantNum == 100)

View File

@@ -8,6 +8,8 @@
#include "MovementActions.h" #include "MovementActions.h"
class PlayerbotAI; class PlayerbotAI;
class TravelDestination;
class WorldPosition;
class GoAction : public MovementAction class GoAction : public MovementAction
{ {

View File

@@ -14,8 +14,10 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u
bool QueryQuestAction::Execute(Event event) bool QueryQuestAction::Execute(Event event)
{ {
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
Player* bot = botAI->GetBot(); Player* bot = botAI->GetBot();
WorldPosition botPos(bot); WorldPosition botPos(bot);
WorldPosition* ptr_botpos = &botPos;
std::string text = event.getParam(); std::string text = event.getParam();
bool travel = false; bool travel = false;
@@ -28,7 +30,22 @@ bool QueryQuestAction::Execute(Event event)
PlayerbotChatHandler ch(bot); PlayerbotChatHandler ch(bot);
uint32 questId = ch.extractQuestId(text); uint32 questId = ch.extractQuestId(text);
if (!questId) 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) for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{ {
@@ -55,10 +72,7 @@ bool QueryQuestAction::Execute(Event event)
uint32 limit = 0; uint32 limit = 0;
std::vector<TravelDestination*> allDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1); std::vector<TravelDestination*> allDestinations = sTravelMgr->getQuestTravelDestinations(bot, questId, true, true, -1);
std::sort(allDestinations.begin(), allDestinations.end(), [botPos](TravelDestination* i, TravelDestination* j) std::sort(allDestinations.begin(), allDestinations.end(), [ptr_botpos](TravelDestination* i, TravelDestination* j) {return i->distanceTo(ptr_botpos) < j->distanceTo(ptr_botpos); });
{
return i->distanceTo(const_cast<WorldPosition*>(&botPos)) < j->distanceTo(const_cast<WorldPosition*>(&botPos));
});
for (auto dest : allDestinations) for (auto dest : allDestinations)
{ {
@@ -71,24 +85,18 @@ bool QueryQuestAction::Execute(Event event)
uint32 apoints = dest->getPoints().size(); uint32 apoints = dest->getPoints().size();
out << round(dest->distanceTo(const_cast<WorldPosition*>(&botPos))); out << round(dest->distanceTo(&botPos));
out << " to " << dest->getTitle();
out << " " << apoints;
out << " to " << dest->getTitle();
out << " " << apoints;
if (apoints < tpoints) if (apoints < tpoints)
out << "/" << tpoints; out << "/" << tpoints;
out << " points."; out << " points.";
if (!dest->isActive(bot)) if (!dest->isActive(bot))
out << " not active"; out << " not active";
if (dest->isFull(bot))
out << " crowded";
if (dest->isFull(bot))
out << " crowded";
botAI->TellMaster(out); botAI->TellMaster(out);
limit++; limit++;

View File

@@ -7,27 +7,48 @@
#include "ChatHelper.h" #include "ChatHelper.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ReputationMgr.h" #include "ReputationMgr.h"
#include "ServerFacade.h"
bool QuestAction::Execute(Event event) bool QuestAction::Execute(Event event)
{ {
ObjectGuid guid = event.getObject(); ObjectGuid guid = event.getObject();
Player* master = GetMaster(); Player* master = GetMaster();
if (!master)
{
if (!guid)
guid = bot->GetTarget();
}
else
{
if (!guid)
guid = master->GetTarget();
}
if (!guid) 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<ObjectGuid> gos = AI_VALUE(std::list<ObjectGuid>, "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) bool QuestAction::CompleteQuest(Player* player, uint32 entry)
@@ -67,7 +88,15 @@ bool QuestAction::CompleteQuest(Player* player, uint32 entry)
int32 creature = pQuest->RequiredNpcOrGo[i]; int32 creature = pQuest->RequiredNpcOrGo[i];
uint32 creaturecount = pQuest->RequiredNpcOrGoCount[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)) if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature))
for (uint16 z = 0; z < creaturecount; ++z) 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 (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"); botAI->TellError("Cannot talk to quest giver");
return false; return false;
} }
@@ -160,16 +191,16 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) if (bot->GetQuestStatus(questId) == QUEST_STATUS_COMPLETE)
out << "Already completed"; 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"; out << "Already on";
else else
out << "Can't take"; out << "Can't take";
} }
else if (! bot->SatisfyQuestLog(false)) else if (!bot->SatisfyQuestLog(false))
out << "Quest log is full"; out << "Quest log is full";
else if (! bot->CanAddQuest(quest, false)) else if (!bot->CanAddQuest(quest, false))
out << "Bags are full"; out << "Bags are full";
else else
{ {
@@ -179,7 +210,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
p.rpos(0); p.rpos(0);
bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p); 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); Object* pObject = ObjectAccessor::GetObjectByTypeMask(*bot, questGiver, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);
bot->AddQuest(quest, pObject); bot->AddQuest(quest, pObject);
@@ -196,10 +227,11 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
out << " " << chat->FormatQuest(quest); out << " " << chat->FormatQuest(quest);
botAI->TellMaster(out); botAI->TellMaster(out);
return false; return false;
} }
bool QuestObjectiveCompletedAction::Execute(Event event) bool QuestUpdateCompleteAction::Execute(Event event)
{ {
WorldPacket p(event.getPacket()); WorldPacket p(event.getPacket());
p.rpos(0); p.rpos(0);
@@ -208,17 +240,84 @@ bool QuestObjectiveCompletedAction::Execute(Event event)
ObjectGuid guid; ObjectGuid guid;
p >> questId >> entry >> available >> required >> guid; p >> questId >> entry >> available >> required >> guid;
if (entry & 0x80000000) Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
if (qInfo)
{ {
entry &= 0x7FFFFFFF; if (botAI->HasStrategy("debug quest", BotState::BOT_STATE_NON_COMBAT) || botAI->HasStrategy("debug rpg", BotState::BOT_STATE_COMBAT))
if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(entry)) {
botAI->TellMaster(chat->FormatQuestObjective(info->name, available, required)); bot->Say("Quest [ " + ChatHelper::FormatQuest(qInfo) + " ] completed", LANG_UNIVERSAL);
} }
else botAI->TellMasterNoFacing("Quest completed " + ChatHelper::FormatQuest(qInfo));
{
if (CreatureTemplate const* info = sObjectMgr->GetCreatureTemplate(entry))
botAI->TellMaster(chat->FormatQuestObjective(info->Name, available, required));
} }
return true; 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;
}

View File

@@ -7,6 +7,7 @@
#include "Action.h" #include "Action.h"
#include "Object.h" #include "Object.h"
#include "QuestDef.h"
class ObjectGuid; class ObjectGuid;
class Quest; class Quest;
@@ -17,25 +18,52 @@ class Object;
class QuestAction : public Action class QuestAction : public Action
{ {
public: public:
QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { } QuestAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name) { }
bool Execute(Event event) override; bool Execute(Event event) override;
protected: protected:
bool CompleteQuest(Player* player, uint32 entry); bool CompleteQuest(Player* player, uint32 entry);
virtual void ProcessQuest(Quest const* quest, Object* questGiver) = 0; virtual bool ProcessQuest(Quest const* quest, Object* questGiver) = 0;
bool AcceptQuest(Quest const* quest, ObjectGuid questGiver); bool AcceptQuest(Quest const* quest, ObjectGuid questGiver);
bool ProcessQuests(ObjectGuid questGiver); bool ProcessQuests(ObjectGuid questGiver);
bool ProcessQuests(WorldObject* questGiver); bool ProcessQuests(WorldObject* questGiver);
}; };
class QuestObjectiveCompletedAction : public Action class QuestUpdateCompleteAction : public Action
{ {
public: public:
QuestObjectiveCompletedAction(PlayerbotAI* botAI) : Action(botAI, "quest objective completed") { } 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 #endif

View File

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

View File

@@ -1,26 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, 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

View File

@@ -10,6 +10,7 @@
#include "Formations.h" #include "Formations.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "ServerFacade.h" #include "ServerFacade.h"
#include "RpgSubActions.h"
#include <random> #include <random>
@@ -45,65 +46,109 @@ bool RpgAction::isUseful()
bool RpgAction::SetNextRpgAction() bool RpgAction::SetNextRpgAction()
{ {
Strategy* rpgStrategy = botAI->GetAiObjectContext()->GetStrategy("rpg"); Strategy* rpgStrategy;
std::vector<Action*> actions; std::vector<Action*> actions;
std::vector<uint32> relevances; std::vector<uint32> relevances;
std::vector<TriggerNode*> triggerNodes; std::vector<TriggerNode*> triggerNodes;
rpgStrategy->InitTriggers(triggerNodes);
for (auto& triggerNode : triggerNodes)
for (auto& strategy : botAI->GetAiObjectContext()->GetSupportedStrategies())
{ {
Trigger* trigger = context->GetTrigger(triggerNode->getName()); if (strategy.find("rpg") == std::string::npos)
if (trigger) 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(); if (trigger)
trigger = triggerNode->getTrigger();
bool isChecked = false;
for (int32 i = 0; i < NextAction::size(nextActions); i++)
{ {
NextAction* nextAction = nextActions[i];
if (nextAction->getRelevance() > 2.0f) triggerNode->setTrigger(trigger);
continue;
if (!isChecked && !trigger->IsActive()) NextAction** nextActions = triggerNode->getHandlers();
break;
isChecked = true; Trigger* trigger = triggerNode->getTrigger();
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName()); bool isChecked = false;
if (!action->isPossible() || !action->isUseful()) for (int32 i = 0; i < NextAction::size(nextActions); i++)
continue; {
NextAction* nextAction = nextActions[i];
actions.push_back(action); if (nextAction->getRelevance() > 2.0f)
relevances.push_back((nextAction->getRelevance() - 1) * 1000); continue;
if (!isChecked && !trigger->IsActive())
break;
isChecked = true;
Action* action = botAI->GetAiObjectContext()->GetAction(nextAction->getName());
if (!dynamic_cast<RpgEnabled*>(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()) if (actions.empty())
return false; return false;
if (botAI->HasStrategy("debug rpg", BotState::BOT_STATE_NON_COMBAT))
{
std::vector<std::pair<Action*, uint32>> 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::pair<Action*, uint32>i, std::pair<Action*, uint32> 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)); std::mt19937 gen(time(0));
sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen); sTravelMgr->weighted_shuffle(actions.begin(), actions.end(), relevances.begin(), relevances.end(), gen);
Action* action = actions.front(); Action* action = actions.front();
for (std::vector<TriggerNode*>::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; std::ostringstream out;
delete trigger; 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()); SET_AI_VALUE(std::string, "next rpg action", action->getName());

View File

@@ -13,28 +13,28 @@ class Unit;
class RpgAction : public MovementAction class RpgAction : public MovementAction
{ {
public: public:
RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { } RpgAction(PlayerbotAI* botAI, std::string const name = "rpg") : MovementAction(botAI, name) { }
bool Execute(Event event) override; bool Execute(Event event) override;
bool isUseful() override; bool isUseful() override;
protected: protected:
virtual bool SetNextRpgAction(); virtual bool SetNextRpgAction();
typedef void (RpgAction::*RpgElement)(ObjectGuid guid); typedef void (RpgAction::* RpgElement)(ObjectGuid guid);
bool AddIgnore(ObjectGuid guid); bool AddIgnore(ObjectGuid guid);
bool RemIgnore(ObjectGuid guid); bool RemIgnore(ObjectGuid guid);
bool HasIgnore(ObjectGuid guid); bool HasIgnore(ObjectGuid guid);
}; };
class CRpgAction : public RpgAction class CRpgAction : public RpgAction
{ {
public: public:
CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { } CRpgAction(PlayerbotAI* botAI) : RpgAction(botAI, "crpg") { }
bool isUseful() override; bool isUseful() override;
}; };
#endif #endif

View File

@@ -11,8 +11,9 @@
#include "QuestDef.h" #include "QuestDef.h"
#include "WorldPacket.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; std::ostringstream out;
out << "Quest "; out << "Quest ";
@@ -26,7 +27,7 @@ void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver
{ {
QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId()); QuestStatus masterStatus = master->GetQuestStatus(quest->GetQuestId());
if (masterStatus == QUEST_STATUS_INCOMPLETE || masterStatus == QUEST_STATUS_FAILED) 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)) 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()); status = bot->GetQuestStatus(quest->GetQuestId());
} }
} }
switch (status) switch (status)
{ {
case QUEST_STATUS_COMPLETE: case QUEST_STATUS_COMPLETE:
TurnInQuest(quest, questGiver, out); isCompleted |= TurnInQuest(quest, questGiver, out);
break; break;
case QUEST_STATUS_INCOMPLETE: case QUEST_STATUS_INCOMPLETE:
out << "|cffff0000Incompleted|r"; out << "|cffff0000Incompleted|r";
break; break;
case QUEST_STATUS_NONE: case QUEST_STATUS_NONE:
out << "|cff00ff00Available|r"; AcceptQuest(quest, questGiver->GetGUID());
break; out << "|cff00ff00Available|r";
case QUEST_STATUS_FAILED: break;
out << "|cffff0000Failed|r"; case QUEST_STATUS_FAILED:
break; out << "|cffff0000Failed|r";
default: break;
break; default:
break;
} }
out << ": " << chat->FormatQuest(quest); out << ": " << chat->FormatQuest(quest);
botAI->TellMaster(out); 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(); uint32 questID = quest->GetQuestId();
if (bot->GetQuestRewardStatus(questID)) if (bot->GetQuestRewardStatus(questID))
return; return false;
bot->PlayDistanceSound(621); bot->PlayDistanceSound(621);
@@ -78,6 +82,8 @@ void TalkToQuestGiverAction::TurnInQuest(Quest const* quest, Object* questGiver,
{ {
RewardMultipleItem(quest, questGiver, out); RewardMultipleItem(quest, questGiver, out);
} }
return true;
} }
void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out) void TalkToQuestGiverAction::RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out)
@@ -244,23 +250,23 @@ bool TurnInQueryQuestAction::Execute(Event event)
out << "Quest "; out << "Quest ";
switch (status) switch (status)
{ {
case QUEST_STATUS_COMPLETE: case QUEST_STATUS_COMPLETE:
TurnInQuest(quest, object, out); TurnInQuest(quest, object, out);
break; break;
case QUEST_STATUS_INCOMPLETE: case QUEST_STATUS_INCOMPLETE:
out << "|cffff0000Incompleted|r"; out << "|cffff0000Incompleted|r";
break; break;
case QUEST_STATUS_NONE: case QUEST_STATUS_NONE:
out << "|cff00ff00Available|r"; out << "|cff00ff00Available|r";
break; break;
case QUEST_STATUS_FAILED: case QUEST_STATUS_FAILED:
out << "|cffff0000Failed|r"; out << "|cffff0000Failed|r";
break; break;
case QUEST_STATUS_REWARDED: case QUEST_STATUS_REWARDED:
out << "|cffff0000Rewarded|r"; out << "|cffff0000Rewarded|r";
break; break;
default: default:
break; break;
} }
out << ": " << chat->FormatQuest(quest); out << ": " << chat->FormatQuest(quest);

View File

@@ -13,25 +13,25 @@ class WorldObject;
class TalkToQuestGiverAction : public QuestAction class TalkToQuestGiverAction : public QuestAction
{ {
public: public:
TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { } TalkToQuestGiverAction(PlayerbotAI* botAI, std::string name = "talk to quest giver") : QuestAction(botAI, name) { }
protected: protected:
void ProcessQuest(Quest const* quest, Object* questGiver) override; bool ProcessQuest(Quest const* quest, Object* questGiver) override;
void TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out); bool TurnInQuest(Quest const* quest, Object* questGiver, std::ostringstream& out);
private: private:
void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out); void RewardNoItem(Quest const* quest, Object* questGiver, std::ostringstream& out);
void RewardSingleItem(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); std::set<uint32> BestRewards(Quest const* quest);
void RewardMultipleItem(Quest const* quest, Object* questGiver, std::ostringstream& out); void RewardMultipleItem(Quest const* quest, Object* questGiver, std::ostringstream& out);
void AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip); void AskToSelectReward(Quest const* quest, std::ostringstream& out, bool forEquip);
}; };
class TurnInQueryQuestAction : public TalkToQuestGiverAction class TurnInQueryQuestAction : public TalkToQuestGiverAction
{ {
public: public:
TurnInQueryQuestAction(PlayerbotAI* botAI) : TalkToQuestGiverAction(botAI, "turn in query quest") {} TurnInQueryQuestAction(PlayerbotAI* botAI) : TalkToQuestGiverAction(botAI, "turn in query quest") {}
bool Execute(Event event) override; bool Execute(Event event) override;
}; };
#endif #endif

View File

@@ -463,13 +463,10 @@ bool UseRandomQuestItem::Execute(Event event)
ObjectGuid goTarget; ObjectGuid goTarget;
std::vector<Item*> questItems = AI_VALUE2(std::vector<Item*>, "inventory items", "quest"); std::vector<Item*> questItems = AI_VALUE2(std::vector<Item*>, "inventory items", "quest");
Item* item = nullptr;
uint32 delay = 0;
if (questItems.empty()) if (questItems.empty())
return false; return false;
Item* item = nullptr;
for (uint8 i = 0; i < 5; i++) for (uint8 i = 0; i < 5; i++)
{ {
auto itr = questItems.begin(); auto itr = questItems.begin();
@@ -477,7 +474,6 @@ bool UseRandomQuestItem::Execute(Event event)
Item* questItem = *itr; Item* questItem = *itr;
ItemTemplate const* proto = questItem->GetTemplate(); ItemTemplate const* proto = questItem->GetTemplate();
if (proto->StartQuest) if (proto->StartQuest)
{ {
Quest const* qInfo = sObjectMgr->GetQuestTemplate(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) if (!item)
return false; return false;
if (!goTarget && !unitTarget)
return false;
bool used = UseItem(item, goTarget, nullptr, unitTarget); bool used = UseItem(item, goTarget, nullptr, unitTarget);
if (used) if (used)
botAI->SetNextCheckDelay(delay); botAI->SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
return used; return used;
} }

View File

@@ -24,7 +24,6 @@
#include "QuestAction.h" #include "QuestAction.h"
#include "PassLeadershipToMasterAction.h" #include "PassLeadershipToMasterAction.h"
#include "PetitionSignAction.h" #include "PetitionSignAction.h"
#include "QuestConfirmAcceptAction.h"
#include "ReadyCheckAction.h" #include "ReadyCheckAction.h"
#include "RememberTaxiAction.h" #include "RememberTaxiAction.h"
#include "ReviveFromCorpseAction.h" #include "ReviveFromCorpseAction.h"
@@ -37,116 +36,131 @@
#include "TradeStatusAction.h" #include "TradeStatusAction.h"
#include "UseMeetingStoneAction.h" #include "UseMeetingStoneAction.h"
#include "NamedObjectContext.h" #include "NamedObjectContext.h"
#include "QuestConfirmAcceptAction.h"
class PlayerbotAI; class PlayerbotAI;
class WorldPacketActionContext : public NamedObjectContext<Action> class WorldPacketActionContext : public NamedObjectContext<Action>
{ {
public: public:
WorldPacketActionContext() WorldPacketActionContext()
{ {
creators["accept invitation"] = &WorldPacketActionContext::accept_invitation; creators["accept invitation"] = &WorldPacketActionContext::accept_invitation;
creators["give leader in dungeon"] = &WorldPacketActionContext::give_leader_in_dungeon; creators["give leader in dungeon"] = &WorldPacketActionContext::give_leader_in_dungeon;
creators["leader"] = &WorldPacketActionContext::pass_leadership_to_master; creators["leader"] = &WorldPacketActionContext::pass_leadership_to_master;
creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money; creators["tell not enough money"] = &WorldPacketActionContext::tell_not_enough_money;
creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation; creators["tell not enough reputation"] = &WorldPacketActionContext::tell_not_enough_reputation;
creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip; creators["tell cannot equip"] = &WorldPacketActionContext::tell_cannot_equip;
creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest; creators["loot roll"] = &WorldPacketActionContext::loot_roll;
creators["accept quest"] = &WorldPacketActionContext::accept_quest; creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll;
creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests; creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse;
creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share; creators["find corpse"] = &WorldPacketActionContext::find_corpse;
creators["loot roll"] = &WorldPacketActionContext::loot_roll; creators["auto release"] = &WorldPacketActionContext::auto_release;
creators["master loot roll"] = &WorldPacketActionContext::master_loot_roll; creators["accept resurrect"] = &WorldPacketActionContext::accept_resurrect;
creators["revive from corpse"] = &WorldPacketActionContext::revive_from_corpse; creators["use meeting stone"] = &WorldPacketActionContext::use_meeting_stone;
creators["find corpse"] = &WorldPacketActionContext::find_corpse; creators["area trigger"] = &WorldPacketActionContext::area_trigger;
creators["auto release"] = &WorldPacketActionContext::auto_release; creators["reach area trigger"] = &WorldPacketActionContext::reach_area_trigger;
creators["accept resurrect"] = &WorldPacketActionContext::accept_resurrect; creators["check mount state"] = &WorldPacketActionContext::check_mount_state;
creators["use meeting stone"] = &WorldPacketActionContext::use_meeting_stone; creators["remember taxi"] = &WorldPacketActionContext::remember_taxi;
creators["area trigger"] = &WorldPacketActionContext::area_trigger; creators["accept trade"] = &WorldPacketActionContext::accept_trade;
creators["reach area trigger"] = &WorldPacketActionContext::reach_area_trigger; creators["store loot"] = &WorldPacketActionContext::store_loot;
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;
}
private: // quest
static Action* inventory_change_failure(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } creators["talk to quest giver"] = &WorldPacketActionContext::turn_in_quest;
static Action* guild_accept(PlayerbotAI* botAI) { return new GuildAcceptAction(botAI); } creators["accept quest"] = &WorldPacketActionContext::accept_quest;
static Action* security_check(PlayerbotAI* botAI) { return new SecurityCheckAction(botAI); } creators["confirm quest"] = &WorldPacketActionContext::confirm_quest;
static Action* uninvite(PlayerbotAI* botAI) { return new UninviteAction(botAI); } creators["accept all quests"] = &WorldPacketActionContext::accept_all_quests;
static Action* ready_check_finished(PlayerbotAI* botAI) { return new FinishReadyCheckAction(botAI); } creators["accept quest share"] = &WorldPacketActionContext::accept_quest_share;
static Action* ready_check(PlayerbotAI* botAI) { return new ReadyCheckAction(botAI); } creators["quest update add kill"] = &WorldPacketActionContext::quest_update_add_kill;
static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); } creators["quest update add item"] = &WorldPacketActionContext::quest_update_add_item;
static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); } creators["quest update failed"] = &WorldPacketActionContext::quest_update_failed;
static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); } creators["quest update failed timer"] = &WorldPacketActionContext::quest_update_failed_timer;
static Action* quest_objective_completed(PlayerbotAI* botAI) { return new QuestObjectiveCompletedAction(botAI); } creators["quest update complete"] = &WorldPacketActionContext::quest_update_complete;
static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); }
static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); } creators["party command"] = &WorldPacketActionContext::party_command;
static Action* remember_taxi(PlayerbotAI* botAI) { return new RememberTaxiAction(botAI); } creators["tell cast failed"] = &WorldPacketActionContext::tell_cast_failed;
static Action* check_mount_state(PlayerbotAI* botAI) { return new CheckMountStateAction(botAI); } creators["accept duel"] = &WorldPacketActionContext::accept_duel;
static Action* area_trigger(PlayerbotAI* botAI) { return new AreaTriggerAction(botAI); } creators["ready check"] = &WorldPacketActionContext::ready_check;
static Action* reach_area_trigger(PlayerbotAI* botAI) { return new ReachAreaTriggerAction(botAI); } creators["ready check finished"] = &WorldPacketActionContext::ready_check_finished;
static Action* use_meeting_stone(PlayerbotAI* botAI) { return new UseMeetingStoneAction(botAI); } creators["uninvite"] = &WorldPacketActionContext::uninvite;
static Action* accept_resurrect(PlayerbotAI* botAI) { return new AcceptResurrectAction(botAI); } creators["security check"] = &WorldPacketActionContext::security_check;
static Action* find_corpse(PlayerbotAI* botAI) { return new FindCorpseAction(botAI); } creators["guild accept"] = &WorldPacketActionContext::guild_accept;
static Action* auto_release(PlayerbotAI* botAI) { return new AutoReleaseSpiritAction(botAI); } creators["inventory change failure"] = &WorldPacketActionContext::inventory_change_failure;
static Action* revive_from_corpse(PlayerbotAI* botAI) { return new ReviveFromCorpseAction(botAI); } creators["bg status check"] = &WorldPacketActionContext::bg_status_check;
static Action* accept_invitation(PlayerbotAI* botAI) { return new AcceptInvitationAction(botAI); } creators["bg strategy check"] = &WorldPacketActionContext::bg_strategy_check;
static Action* give_leader_in_dungeon(PlayerbotAI* botAI) { return new GiveLeaderAction(botAI, "I don't know this dungeon, lead the way!"); } creators["bg status"] = &WorldPacketActionContext::bg_status;
static Action* pass_leadership_to_master(PlayerbotAI* botAI) { return new PassLeadershipToMasterAction(botAI); } creators["bg join"] = &WorldPacketActionContext::bg_join;
static Action* tell_not_enough_money(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough money"); } creators["bg leave"] = &WorldPacketActionContext::bg_leave;
static Action* tell_not_enough_reputation(PlayerbotAI* botAI) { return new TellMasterAction(botAI, "Not enough reputation"); } creators["arena tactics"] = &WorldPacketActionContext::arena_tactics;
static Action* tell_cannot_equip(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); } creators["petition sign"] = &WorldPacketActionContext::petition_sign;
static Action* turn_in_quest(PlayerbotAI* botAI) { return new TalkToQuestGiverAction(botAI); } creators["lfg join"] = &WorldPacketActionContext::lfg_join;
static Action* accept_quest(PlayerbotAI* botAI) { return new AcceptQuestAction(botAI); } creators["lfg accept"] = &WorldPacketActionContext::lfg_accept;
static Action* accept_all_quests(PlayerbotAI* botAI) { return new AcceptAllQuestsAction(botAI); } creators["lfg role check"] = &WorldPacketActionContext::lfg_role_check;
static Action* accept_quest_share(PlayerbotAI* botAI) { return new AcceptQuestShareAction(botAI); } creators["lfg leave"] = &WorldPacketActionContext::lfg_leave;
static Action* loot_roll(PlayerbotAI* botAI) { return new LootRollAction(botAI); } creators["lfg teleport"] = &WorldPacketActionContext::lfg_teleport;
static Action* master_loot_roll(PlayerbotAI* botAI) { return new MasterLootRollAction(botAI); } creators["see spell"] = &WorldPacketActionContext::see_spell;
static Action* bg_join(PlayerbotAI* botAI) { return new BGJoinAction(botAI); } creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept;
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); } private:
static Action* bg_strategy_check(PlayerbotAI* botAI) { return new BGStrategyCheckAction(botAI); } static Action* inventory_change_failure(PlayerbotAI* botAI) { return new InventoryChangeFailureAction(botAI); }
static Action* arena_tactics(PlayerbotAI* botAI) { return new ArenaTactics(botAI); } static Action* guild_accept(PlayerbotAI* botAI) { return new GuildAcceptAction(botAI); }
static Action* petition_sign(PlayerbotAI* botAI) { return new PetitionSignAction(botAI); } static Action* security_check(PlayerbotAI* botAI) { return new SecurityCheckAction(botAI); }
static Action* lfg_teleport(PlayerbotAI* botAI) { return new LfgTeleportAction(botAI); } static Action* uninvite(PlayerbotAI* botAI) { return new UninviteAction(botAI); }
static Action* lfg_leave(PlayerbotAI* botAI) { return new LfgLeaveAction(botAI); } static Action* ready_check_finished(PlayerbotAI* botAI) { return new FinishReadyCheckAction(botAI); }
static Action* lfg_accept(PlayerbotAI* botAI) { return new LfgAcceptAction(botAI); } static Action* ready_check(PlayerbotAI* botAI) { return new ReadyCheckAction(botAI); }
static Action* lfg_role_check(PlayerbotAI* botAI) { return new LfgRoleCheckAction(botAI); } static Action* accept_duel(PlayerbotAI* botAI) { return new AcceptDuelAction(botAI); }
static Action* lfg_join(PlayerbotAI* botAI) { return new LfgJoinAction(botAI); } static Action* tell_cast_failed(PlayerbotAI* botAI) { return new TellCastFailedAction(botAI); }
static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); } static Action* party_command(PlayerbotAI* botAI) { return new PartyCommandAction(botAI); }
static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); } static Action* store_loot(PlayerbotAI* botAI) { return new StoreLootAction(botAI); }
static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); } static Action* accept_trade(PlayerbotAI* botAI) { return new TradeStatusAction(botAI); }
static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(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 #endif

View File

@@ -43,4 +43,13 @@ class DebugSpellStrategy : public Strategy
std::string const getName() override { return "debug spell"; } 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 #endif

View File

@@ -14,11 +14,11 @@ void MaintenanceStrategy::InitTriggers(std::vector<TriggerNode*>& 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("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("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("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("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("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 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("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)));
} }

View File

@@ -32,7 +32,6 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
triggers.push_back(new TriggerNode("lfg proposal", NextAction::array(0, new NextAction("lfg accept", relevance), nullptr))); 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("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("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("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("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("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr)));
@@ -43,20 +42,22 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
new NextAction("auto upgrade equip", relevance), new NextAction("auto upgrade equip", relevance),
nullptr))); nullptr)));
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", 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("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("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("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("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))); 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) WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
{ {
supported.push_back("loot roll"); supported.push_back("loot roll");
supported.push_back("check mount state"); supported.push_back("check mount state");
supported.push_back("quest objective completed");
supported.push_back("party command"); supported.push_back("party command");
supported.push_back("ready check"); supported.push_back("ready check");
supported.push_back("uninvite"); supported.push_back("uninvite");
@@ -65,6 +66,14 @@ WorldPacketHandlerStrategy::WorldPacketHandlerStrategy(PlayerbotAI* botAI) : Pas
supported.push_back("random bot update"); supported.push_back("random bot update");
supported.push_back("inventory change failure"); supported.push_back("inventory change failure");
supported.push_back("bg status"); 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<TriggerNode*>& triggers) void ReadyCheckStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)

View File

@@ -11,20 +11,20 @@ class PlayerbotAI;
class WorldPacketHandlerStrategy : public PassTroughStrategy class WorldPacketHandlerStrategy : public PassTroughStrategy
{ {
public: public:
WorldPacketHandlerStrategy(PlayerbotAI* botAI); WorldPacketHandlerStrategy(PlayerbotAI* botAI);
void InitTriggers(std::vector<TriggerNode*>& triggers) override; void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "default"; } std::string const getName() override { return "default"; }
}; };
class ReadyCheckStrategy : public PassTroughStrategy class ReadyCheckStrategy : public PassTroughStrategy
{ {
public: public:
ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { } ReadyCheckStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI) { }
void InitTriggers(std::vector<TriggerNode*>& triggers) override; void InitTriggers(std::vector<TriggerNode*>& triggers) override;
std::string const getName() override { return "ready check"; } std::string const getName() override { return "ready check"; }
}; };
#endif #endif

View File

@@ -114,6 +114,12 @@ bool RpgEndQuestTrigger::IsActive()
if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry())) if (AI_VALUE2(bool, "can turn in quest npc", guidP.GetEntry()))
return true; 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; return false;
} }

View File

@@ -11,112 +11,127 @@
class WorldPacketTriggerContext : public NamedObjectContext<Trigger> class WorldPacketTriggerContext : public NamedObjectContext<Trigger>
{ {
public: public:
WorldPacketTriggerContext() WorldPacketTriggerContext()
{ {
creators["gossip hello"] = &WorldPacketTriggerContext::gossip_hello; creators["gossip hello"] = &WorldPacketTriggerContext::gossip_hello;
creators["group invite"] = &WorldPacketTriggerContext::group_invite; creators["group invite"] = &WorldPacketTriggerContext::group_invite;
creators["group set leader"] = &WorldPacketTriggerContext::group_set_leader; creators["group set leader"] = &WorldPacketTriggerContext::group_set_leader;
creators["not enough money"] = &WorldPacketTriggerContext::no_money; creators["not enough money"] = &WorldPacketTriggerContext::no_money;
creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation; creators["not enough reputation"] = &WorldPacketTriggerContext::no_reputation;
creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip; creators["cannot equip"] = &WorldPacketTriggerContext::cannot_equip;
creators["use game object"] = &WorldPacketTriggerContext::use_game_object; creators["use game object"] = &WorldPacketTriggerContext::use_game_object;
creators["complete quest"] = &WorldPacketTriggerContext::complete_quest; creators["loot roll"] = &WorldPacketTriggerContext::loot_roll;
creators["accept quest"] = &WorldPacketTriggerContext::accept_quest; creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request;
creators["quest share"] = &WorldPacketTriggerContext::quest_share; creators["area trigger"] = &WorldPacketTriggerContext::area_trigger;
creators["loot roll"] = &WorldPacketTriggerContext::loot_roll; creators["within area trigger"] = &WorldPacketTriggerContext::within_area_trigger;
creators["resurrect request"] = &WorldPacketTriggerContext::resurrect_request; creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state;
creators["area trigger"] = &WorldPacketTriggerContext::area_trigger; creators["activate taxi"] = &WorldPacketTriggerContext::taxi;
creators["within area trigger"] = &WorldPacketTriggerContext::within_area_trigger; creators["trade status"] = &WorldPacketTriggerContext::trade_status;
creators["check mount state"] = &WorldPacketTriggerContext::check_mount_state; creators["loot response"] = &WorldPacketTriggerContext::loot_response;
creators["activate taxi"] = &WorldPacketTriggerContext::taxi; creators["out of react range"] = &WorldPacketTriggerContext::out_of_react_range;
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;
}
private: // quest
static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); } creators["complete quest"] = &WorldPacketTriggerContext::complete_quest;
static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); } creators["accept quest"] = &WorldPacketTriggerContext::accept_quest;
static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); } creators["confirm quest"] = &WorldPacketTriggerContext::quest_confirm_accept;
static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); } creators["quest share"] = &WorldPacketTriggerContext::quest_share;
static Trigger* lfg_proposal(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg proposal"); } creators["quest update add kill"] = &WorldPacketTriggerContext::quest_update_add_kill;
static Trigger* lfg_role_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg role check"); } creators["quest update add item"] = &WorldPacketTriggerContext::quest_update_add_item;
static Trigger* lfg_update(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg join"); } creators["quest update failed"] = &WorldPacketTriggerContext::quest_update_failed;
static Trigger* uninvite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite"); } creators["quest update failed timer"] = &WorldPacketTriggerContext::quest_update_failed_timer;
static Trigger* uninvite_guid(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "uninvite guid"); } creators["quest update complete"] = &WorldPacketTriggerContext::quest_update_complete;
static Trigger* ready_check_finished(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "ready check finished"); } creators["questgiver quest details"] = &WorldPacketTriggerContext::questgiver_quest_details;
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"); } creators["item push result"] = &WorldPacketTriggerContext::item_push_result;
static Trigger* taxi_done(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "taxi done"); } creators["party command"] = &WorldPacketTriggerContext::party_command;
static Trigger* party_command(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "party command"); } creators["taxi done"] = &WorldPacketTriggerContext::taxi_done;
static Trigger* item_push_result(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "item push result"); } creators["cast failed"] = &WorldPacketTriggerContext::cast_failed;
static Trigger* quest_objective_completed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest objective completed"); } creators["duel requested"] = &WorldPacketTriggerContext::duel_requested;
static Trigger* out_of_react_range(PlayerbotAI* botAI) { return new OutOfReactRangeTrigger(botAI); } creators["ready check"] = &WorldPacketTriggerContext::ready_check;
static Trigger* loot_response(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot response"); } creators["ready check finished"] = &WorldPacketTriggerContext::ready_check_finished;
static Trigger* trade_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "trade status"); } creators["uninvite"] = &WorldPacketTriggerContext::uninvite;
static Trigger* cannot_equip(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "cannot equip"); } creators["uninvite guid"] = &WorldPacketTriggerContext::uninvite_guid;
static Trigger* check_mount_state(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "check mount state"); } creators["lfg join"] = &WorldPacketTriggerContext::lfg_update;
static Trigger* area_trigger(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "area trigger"); } creators["lfg proposal"] = &WorldPacketTriggerContext::lfg_proposal;
static Trigger* within_area_trigger(PlayerbotAI* botAI) { return new WithinAreaTrigger(botAI); } creators["lfg role check"] = &WorldPacketTriggerContext::lfg_role_check;
static Trigger* resurrect_request(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "resurrect request"); } creators["lfg leave"] = &WorldPacketTriggerContext::lfg_leave;
static Trigger* gossip_hello(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "gossip hello"); } creators["guild invite"] = &WorldPacketTriggerContext::guild_invite;
static Trigger* group_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group invite"); } creators["petition offer"] = &WorldPacketTriggerContext::petition_offer;
static Trigger* group_set_leader(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group set leader"); } creators["lfg teleport"] = &WorldPacketTriggerContext::lfg_teleport;
static Trigger* no_money(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough money"); } creators["inventory change failure"] = &WorldPacketTriggerContext::inventory_change_failure;
static Trigger* no_reputation(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "not enough reputation"); } creators["bg status"] = &WorldPacketTriggerContext::bg_status;
static Trigger* use_game_object(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "use game object"); } creators["levelup"] = &WorldPacketTriggerContext::levelup;
static Trigger* complete_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "complete quest"); } creators["xpgain"] = &WorldPacketTriggerContext::xpgain;
static Trigger* accept_quest(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "accept quest"); } creators["see spell"] = &WorldPacketTriggerContext::seespell;
static Trigger* quest_share(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest share"); } creators["release spirit"] = &WorldPacketTriggerContext::release_spirit;
static Trigger* loot_roll(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "loot roll"); } creators["revive from corpse"] = &WorldPacketTriggerContext::revive_from_corpse;
static Trigger* taxi(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "activate taxi"); } creators["receive emote"] = &WorldPacketTriggerContext::receive_emote;
static Trigger* bg_status(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "bg status"); } creators["receive text emote"] = &WorldPacketTriggerContext::receive_text_emote;
static Trigger* levelup(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "levelup"); } creators["arena team invite"] = &WorldPacketTriggerContext::arena_team_invite;
static Trigger* xpgain(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "xpgain"); } creators["group destroyed"] = &WorldPacketTriggerContext::group_destroyed;
static Trigger* petition_offer(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "petition offer"); } creators["group list"] = &WorldPacketTriggerContext::group_list;
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"); } private:
static Trigger* receive_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive emote"); } static Trigger* inventory_change_failure(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "inventory change failure"); }
static Trigger* receive_text_emote(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "receive text emote"); } static Trigger* guild_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "guild invite"); }
static Trigger* arena_team_invite(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "arena team invite"); } static Trigger* lfg_teleport(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg teleport"); }
static Trigger* quest_confirm_accept(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "quest confirm accept"); } static Trigger* lfg_leave(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg leave"); }
static Trigger* group_destroyed(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group destroyed"); } static Trigger* lfg_proposal(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg proposal"); }
static Trigger* group_list(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "group list"); } static Trigger* lfg_role_check(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "lfg role check"); }
static Trigger* questgiver_quest_details(PlayerbotAI* botAI) { return new WorldPacketTrigger(botAI, "questgiver quest details"); } 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 #endif

View File

@@ -30,6 +30,9 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
Player* master = GetMaster(); Player* master = GetMaster();
if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || !GET_PLAYERBOT_AI(master)))
master = nullptr;
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get(); GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
for (ObjectGuid const guid : attackers) for (ObjectGuid const guid : attackers)
{ {
@@ -46,8 +49,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
float distance = 0; float distance = 0;
Unit* result = nullptr; Unit* result = nullptr;
std::unordered_map<uint32, bool> needForQuestMap;
// std::unordered_map<uint32, bool> needForQuestMap;
for (ObjectGuid const guid : targets) 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()) if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
continue; continue;
// if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end()) if (needForQuestMap.find(unit->GetEntry()) == needForQuestMap.end())
// needForQuestMap[unit->GetEntry()] = needForQuest(unit); needForQuestMap[unit->GetEntry()] = needForQuest(unit);
// if (!needForQuestMap[unit->GetEntry()]) if (!needForQuestMap[unit->GetEntry()])
// if ((urand(0, 100) < 75 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() && {
// context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination"))) Creature* creature = dynamic_cast<Creature*>(unit);
// continue; if ((urand(0, 100) < 60 || (context->GetValue<TravelTarget*>("travel target")->Get()->isWorking() &&
context->GetValue<TravelTarget*>("travel target")->Get()->getDestination()->getName() != "GrindTravelDestination")))
//if (bot->InBattleground() && bot->GetDistance(unit) > 40.0f) {
//continue; continue;
}
}
if (Creature* creature = unit->ToCreature()) if (Creature* creature = unit->ToCreature())
if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate()) if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())