mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-21 12:37:05 +00:00
RPG update travel flight status (#1445)
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "BroadcastHelper.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "DBCStores.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "GossipDef.h"
|
||||
#include "IVMapMgr.h"
|
||||
@@ -27,7 +29,6 @@
|
||||
#include "StatsWeightCalculator.h"
|
||||
#include "Timer.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "BroadcastHelper.h"
|
||||
#include "World.h"
|
||||
|
||||
bool TellRpgStatusAction::Execute(Event event)
|
||||
@@ -50,7 +51,7 @@ bool StartRpgDoQuestAction::Execute(Event event)
|
||||
PlayerbotChatHandler ch(owner);
|
||||
uint32 questId = ch.extractQuestId(text);
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (quest)
|
||||
if (quest)
|
||||
{
|
||||
botAI->rpgInfo.ChangeToDoQuest(questId, quest);
|
||||
bot->Whisper("Start to do quest " + std::to_string(questId), LANG_UNIVERSAL, owner);
|
||||
@@ -63,102 +64,50 @@ bool StartRpgDoQuestAction::Execute(Event event)
|
||||
bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||
{
|
||||
NewRpgInfo& info = botAI->rpgInfo;
|
||||
/// @TODO: Refactor by transition probability
|
||||
switch (info.status)
|
||||
{
|
||||
case RPG_IDLE:
|
||||
{
|
||||
uint32 roll = urand(1, 100);
|
||||
// IDLE -> NEAR_NPC
|
||||
if (roll <= 30)
|
||||
{
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible new rpg targets");
|
||||
if (possibleTargets.size() >= 3)
|
||||
{
|
||||
info.ChangeToNearNpc();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> GO_INNKEEPER
|
||||
else if (roll <= 45)
|
||||
{
|
||||
WorldPosition pos = SelectRandomInnKeeperPos(bot);
|
||||
if (pos != WorldPosition() && bot->GetExactDist(pos) > 50.0f)
|
||||
{
|
||||
info.ChangeToGoInnkeeper(pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> GO_GRIND
|
||||
else if (roll <= 100)
|
||||
{
|
||||
if (roll >= 60)
|
||||
{
|
||||
std::vector<uint32> availableQuests;
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
||||
continue;
|
||||
|
||||
std::vector<POIInfo> poiInfo;
|
||||
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
||||
{
|
||||
availableQuests.push_back(questId);
|
||||
}
|
||||
}
|
||||
if (availableQuests.size())
|
||||
{
|
||||
uint32 questId = availableQuests[urand(0, availableQuests.size() - 1)];
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (quest)
|
||||
{
|
||||
// IDLE -> DO_QUEST
|
||||
info.ChangeToDoQuest(questId, quest);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldPosition pos = SelectRandomGrindPos(bot);
|
||||
if (pos != WorldPosition())
|
||||
{
|
||||
info.ChangeToGoGrind(pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// IDLE -> REST
|
||||
info.ChangeToRest();
|
||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
return true;
|
||||
return RandomChangeStatus({RPG_GO_CAMP, RPG_GO_GRIND, RPG_WANDER_RANDOM, RPG_WANDER_NPC, RPG_DO_QUEST,
|
||||
RPG_TRAVEL_FLIGHT, RPG_REST});
|
||||
}
|
||||
case RPG_GO_GRIND:
|
||||
{
|
||||
WorldPosition& originalPos = info.go_grind.pos;
|
||||
assert(info.go_grind.pos != WorldPosition());
|
||||
// GO_GRIND -> NEAR_RANDOM
|
||||
// GO_GRIND -> WANDER_RANDOM
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
info.ChangeToNearRandom();
|
||||
info.ChangeToWanderRandom();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RPG_GO_INNKEEPER:
|
||||
case RPG_GO_CAMP:
|
||||
{
|
||||
WorldPosition& originalPos = info.go_innkeeper.pos;
|
||||
assert(info.go_innkeeper.pos != WorldPosition());
|
||||
// GO_INNKEEPER -> NEAR_NPC
|
||||
WorldPosition& originalPos = info.go_camp.pos;
|
||||
assert(info.go_camp.pos != WorldPosition());
|
||||
// GO_CAMP -> WANDER_NPC
|
||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||
{
|
||||
info.ChangeToNearNpc();
|
||||
info.ChangeToWanderNpc();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RPG_NEAR_RANDOM:
|
||||
case RPG_WANDER_RANDOM:
|
||||
{
|
||||
// NEAR_RANDOM -> IDLE
|
||||
if (info.HasStatusPersisted(statusNearRandomDuration))
|
||||
// WANDER_RANDOM -> IDLE
|
||||
if (info.HasStatusPersisted(statusWanderRandomDuration))
|
||||
{
|
||||
info.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RPG_WANDER_NPC:
|
||||
{
|
||||
if (info.HasStatusPersisted(statusWanderNpcDuration))
|
||||
{
|
||||
info.ChangeToIdle();
|
||||
return true;
|
||||
@@ -175,10 +124,11 @@ bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RPG_NEAR_NPC:
|
||||
case RPG_TRAVEL_FLIGHT:
|
||||
{
|
||||
if (info.HasStatusPersisted(statusNearNpcDuration))
|
||||
if (info.flight.inFlight && !bot->IsInFlight())
|
||||
{
|
||||
// flight arrival
|
||||
info.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
@@ -208,26 +158,26 @@ bool NewRpgGoGrindAction::Execute(Event event)
|
||||
return MoveFarTo(botAI->rpgInfo.go_grind.pos);
|
||||
}
|
||||
|
||||
bool NewRpgGoInnKeeperAction::Execute(Event event)
|
||||
bool NewRpgGoCampAction::Execute(Event event)
|
||||
{
|
||||
if (SearchQuestGiverAndAcceptOrReward())
|
||||
return true;
|
||||
|
||||
return MoveFarTo(botAI->rpgInfo.go_innkeeper.pos);
|
||||
return MoveFarTo(botAI->rpgInfo.go_camp.pos);
|
||||
}
|
||||
|
||||
bool NewRpgMoveRandomAction::Execute(Event event)
|
||||
bool NewRpgWanderRandomAction::Execute(Event event)
|
||||
{
|
||||
if (SearchQuestGiverAndAcceptOrReward())
|
||||
return true;
|
||||
|
||||
|
||||
return MoveRandomNear();
|
||||
}
|
||||
|
||||
bool NewRpgMoveNpcAction::Execute(Event event)
|
||||
bool NewRpgWanderNpcAction::Execute(Event event)
|
||||
{
|
||||
NewRpgInfo& info = botAI->rpgInfo;
|
||||
if (!info.near_npc.npcOrGo)
|
||||
if (!info.wander_npc.npcOrGo)
|
||||
{
|
||||
// No npc can be found, switch to IDLE
|
||||
ObjectGuid npcOrGo = ChooseNpcOrGameObjectToInteract();
|
||||
@@ -236,32 +186,32 @@ bool NewRpgMoveNpcAction::Execute(Event event)
|
||||
info.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
info.near_npc.npcOrGo = npcOrGo;
|
||||
info.near_npc.lastReach = 0;
|
||||
info.wander_npc.npcOrGo = npcOrGo;
|
||||
info.wander_npc.lastReach = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.near_npc.npcOrGo);
|
||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.wander_npc.npcOrGo);
|
||||
if (object && IsWithinInteractionDist(object))
|
||||
{
|
||||
if (!info.near_npc.lastReach)
|
||||
if (!info.wander_npc.lastReach)
|
||||
{
|
||||
info.near_npc.lastReach = getMSTime();
|
||||
info.wander_npc.lastReach = getMSTime();
|
||||
if (bot->CanInteractWithQuestGiver(object))
|
||||
InteractWithNpcOrGameObjectForQuest(info.near_npc.npcOrGo);
|
||||
InteractWithNpcOrGameObjectForQuest(info.wander_npc.npcOrGo);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.near_npc.lastReach && GetMSTimeDiffToNow(info.near_npc.lastReach) < npcStayTime)
|
||||
if (info.wander_npc.lastReach && GetMSTimeDiffToNow(info.wander_npc.lastReach) < npcStayTime)
|
||||
return false;
|
||||
|
||||
// has reached the npc for more than `npcStayTime`, select the next target
|
||||
info.near_npc.npcOrGo = ObjectGuid();
|
||||
info.near_npc.lastReach = 0;
|
||||
info.wander_npc.npcOrGo = ObjectGuid();
|
||||
info.wander_npc.lastReach = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveWorldObjectTo(info.near_npc.npcOrGo);
|
||||
return MoveWorldObjectTo(info.wander_npc.npcOrGo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -384,7 +334,7 @@ bool NewRpgDoQuestAction::DoIncompleteQuest()
|
||||
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
||||
botAI->lowPriorityQuest.insert(questId);
|
||||
botAI->rpgStatistic.questAbandoned++;
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||
botAI->rpgInfo.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
@@ -402,7 +352,7 @@ bool NewRpgDoQuestAction::DoCompletedQuest()
|
||||
{
|
||||
uint32 questId = RPG_INFO(quest, questId);
|
||||
const Quest* quest = RPG_INFO(quest, quest);
|
||||
|
||||
|
||||
if (RPG_INFO(quest, objectiveIdx) != -1)
|
||||
{
|
||||
// if quest is completed, back to poi with -1 idx to reward
|
||||
@@ -424,7 +374,7 @@ bool NewRpgDoQuestAction::DoCompletedQuest()
|
||||
// double check for GetQuestPOIPosAndObjectiveIdx
|
||||
if (dz == INVALID_HEIGHT || dz == VMAP_INVALID_HEIGHT_VALUE)
|
||||
return false;
|
||||
|
||||
|
||||
WorldPosition pos(bot->GetMapId(), dx, dy, dz);
|
||||
botAI->rpgInfo.do_quest.lastReachPOI = 0;
|
||||
botAI->rpgInfo.do_quest.pos = pos;
|
||||
@@ -451,9 +401,43 @@ bool NewRpgDoQuestAction::DoCompletedQuest()
|
||||
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
||||
botAI->lowPriorityQuest.insert(questId);
|
||||
botAI->rpgStatistic.questAbandoned++;
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||
botAI->rpgInfo.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewRpgTravelFlightAction::Execute(Event event)
|
||||
{
|
||||
if (bot->IsInFlight())
|
||||
{
|
||||
botAI->rpgInfo.flight.inFlight = true;
|
||||
return false;
|
||||
}
|
||||
Creature* flightMaster = ObjectAccessor::GetCreature(*bot, botAI->rpgInfo.flight.fromFlightMaster);
|
||||
if (!flightMaster || !flightMaster->IsAlive())
|
||||
{
|
||||
botAI->rpgInfo.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
const TaxiNodesEntry* entry = sTaxiNodesStore.LookupEntry(botAI->rpgInfo.flight.toNode);
|
||||
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
||||
{
|
||||
return MoveFarTo(flightMaster);
|
||||
}
|
||||
std::vector<uint32> nodes = {botAI->rpgInfo.flight.fromNode, botAI->rpgInfo.flight.toNode};
|
||||
|
||||
botAI->RemoveShapeshift();
|
||||
if (bot->IsMounted())
|
||||
{
|
||||
bot->Dismount();
|
||||
}
|
||||
if (!bot->ActivateTaxiPathTo(nodes, flightMaster, 0))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} active taxi path {} (from {} to {}) failed", bot->GetName(),
|
||||
flightMaster->GetEntry(), nodes[0], nodes[1]);
|
||||
botAI->rpgInfo.ChangeToIdle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
#include "Duration.h"
|
||||
#include "MovementActions.h"
|
||||
#include "NewRpgBaseAction.h"
|
||||
#include "NewRpgInfo.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "QuestDef.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "NewRpgBaseAction.h"
|
||||
|
||||
class TellRpgStatusAction : public Action
|
||||
{
|
||||
@@ -39,15 +39,16 @@ public:
|
||||
// transitionMat.resize(statusCount, std::vector<int>(statusCount, 0));
|
||||
|
||||
// transitionMat[RPG_IDLE][RPG_GO_GRIND] = 20;
|
||||
// transitionMat[RPG_IDLE][RPG_GO_INNKEEPER] = 15;
|
||||
// transitionMat[RPG_IDLE][RPG_NEAR_NPC] = 30;
|
||||
// transitionMat[RPG_IDLE][RPG_GO_CAMP] = 15;
|
||||
// transitionMat[RPG_IDLE][RPG_WANDER_NPC] = 30;
|
||||
// transitionMat[RPG_IDLE][RPG_DO_QUEST] = 35;
|
||||
}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
// static NewRpgStatusTransitionProb transitionMat;
|
||||
const int32 statusNearNpcDuration = 5 * 60 * 1000;
|
||||
const int32 statusNearRandomDuration = 5 * 60 * 1000;
|
||||
const int32 statusWanderNpcDuration = 5 * 60 * 1000;
|
||||
const int32 statusWanderRandomDuration = 5 * 60 * 1000;
|
||||
const int32 statusRestDuration = 30 * 1000;
|
||||
const int32 statusDoQuestDuration = 30 * 60 * 1000;
|
||||
};
|
||||
@@ -59,25 +60,24 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NewRpgGoInnKeeperAction : public NewRpgBaseAction
|
||||
class NewRpgGoCampAction : public NewRpgBaseAction
|
||||
{
|
||||
public:
|
||||
NewRpgGoInnKeeperAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg go innkeeper") {}
|
||||
NewRpgGoCampAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg go camp") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
class NewRpgMoveRandomAction : public NewRpgBaseAction
|
||||
class NewRpgWanderRandomAction : public NewRpgBaseAction
|
||||
{
|
||||
public:
|
||||
NewRpgMoveRandomAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move random") {}
|
||||
NewRpgWanderRandomAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg wander random") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class NewRpgMoveNpcAction : public NewRpgBaseAction
|
||||
class NewRpgWanderNpcAction : public NewRpgBaseAction
|
||||
{
|
||||
public:
|
||||
NewRpgMoveNpcAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move npcs") {}
|
||||
NewRpgWanderNpcAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move npcs") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
const uint32 npcStayTime = 8 * 1000;
|
||||
@@ -88,11 +88,19 @@ class NewRpgDoQuestAction : public NewRpgBaseAction
|
||||
public:
|
||||
NewRpgDoQuestAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg do quest") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
protected:
|
||||
bool DoIncompleteQuest();
|
||||
bool DoCompletedQuest();
|
||||
|
||||
|
||||
const uint32 poiStayTime = 5 * 60 * 1000;
|
||||
};
|
||||
|
||||
class NewRpgTravelFlightAction : public NewRpgBaseAction
|
||||
{
|
||||
public:
|
||||
NewRpgTravelFlightAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg travel flight") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "NewRpgBaseAction.h"
|
||||
|
||||
#include "BroadcastHelper.h"
|
||||
#include "ChatHelper.h"
|
||||
#include "Creature.h"
|
||||
#include "G3D/Vector2.h"
|
||||
#include "GameObject.h"
|
||||
#include "GossipDef.h"
|
||||
@@ -15,6 +18,7 @@
|
||||
#include "PathGenerator.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Position.h"
|
||||
#include "QuestDef.h"
|
||||
@@ -24,7 +28,6 @@
|
||||
#include "StatsWeightCalculator.h"
|
||||
#include "Timer.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
||||
{
|
||||
@@ -58,12 +61,15 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
||||
botAI->rpgInfo.stuckAttempts = 0;
|
||||
const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId());
|
||||
std::string zone_name = PlayerbotAI::GetLocalizedAreaName(entry);
|
||||
LOG_DEBUG("playerbots", "[New Rpg] Teleport {} from ({},{},{},{}) to ({},{},{},{}) as it stuck when moving far - Zone: {} ({})", bot->GetName(),
|
||||
bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId(),
|
||||
dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.getMapId(), bot->GetZoneId(), zone_name);
|
||||
LOG_DEBUG(
|
||||
"playerbots",
|
||||
"[New RPG] Teleport {} from ({},{},{},{}) to ({},{},{},{}) as it stuck when moving far - Zone: {} ({})",
|
||||
bot->GetName(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId(),
|
||||
dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.getMapId(), bot->GetZoneId(),
|
||||
zone_name);
|
||||
return bot->TeleportTo(dest);
|
||||
}
|
||||
|
||||
|
||||
float dis = bot->GetExactDist(dest);
|
||||
if (dis < pathFinderDis)
|
||||
{
|
||||
@@ -131,7 +137,7 @@ bool NewRpgBaseAction::MoveWorldObjectTo(ObjectGuid guid, float distance)
|
||||
else
|
||||
angle = object->GetOrientation() +
|
||||
(M_PI * irand(-25, 25) / 100.0); // 45 degrees infront of target (leading it's movement)
|
||||
|
||||
|
||||
float rnd = rand_norm();
|
||||
x += cos(angle) * distance * rnd;
|
||||
y += sin(angle) * distance * rnd;
|
||||
@@ -151,7 +157,7 @@ bool NewRpgBaseAction::MoveRandomNear(float moveStep, MovementPriority priority)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
float distance = rand_norm() * moveStep;
|
||||
Map* map = bot->GetMap();
|
||||
const float x = bot->GetPositionX();
|
||||
@@ -190,8 +196,9 @@ bool NewRpgBaseAction::MoveRandomNear(float moveStep, MovementPriority priority)
|
||||
|
||||
bool NewRpgBaseAction::ForceToWait(uint32 duration, MovementPriority priority)
|
||||
{
|
||||
AI_VALUE(LastMovement&, "last movement").Set(bot->GetMapId(),
|
||||
bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(), duration, priority);
|
||||
AI_VALUE(LastMovement&, "last movement")
|
||||
.Set(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(),
|
||||
duration, priority);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,27 +219,27 @@ bool NewRpgBaseAction::InteractWithNpcOrGameObjectForQuest(ObjectGuid guid)
|
||||
// }
|
||||
|
||||
bot->PrepareQuestMenu(guid);
|
||||
const QuestMenu &menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||
const QuestMenu& menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||
if (menu.Empty())
|
||||
return true;
|
||||
|
||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||
{
|
||||
const QuestMenuItem &item = menu.GetItem(idx);
|
||||
const QuestMenuItem& item = menu.GetItem(idx);
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) &&
|
||||
bot->CanAddQuest(quest, false) && IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) && bot->CanAddQuest(quest, false) &&
|
||||
IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||
{
|
||||
AcceptQuest(quest, guid);
|
||||
if (botAI->GetMaster())
|
||||
botAI->TellMasterNoFacing("Quest accepted " + ChatHelper::FormatQuest(quest));
|
||||
BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest);
|
||||
botAI->rpgStatistic.questAccepted++;
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} accept quest {}", bot->GetName(), quest->GetQuestId());
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} accept quest {}", bot->GetName(), quest->GetQuestId());
|
||||
}
|
||||
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
||||
{
|
||||
@@ -241,7 +248,7 @@ bool NewRpgBaseAction::InteractWithNpcOrGameObjectForQuest(ObjectGuid guid)
|
||||
botAI->TellMasterNoFacing("Quest rewarded " + ChatHelper::FormatQuest(quest));
|
||||
BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest);
|
||||
botAI->rpgStatistic.questRewarded++;
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} turned in quest {}", bot->GetName(), quest->GetQuestId());
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} turned in quest {}", bot->GetName(), quest->GetQuestId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -273,11 +280,13 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
||||
return false;
|
||||
|
||||
// Deathstate checks
|
||||
if (!bot->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS))
|
||||
if (!bot->IsAlive() &&
|
||||
!(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS))
|
||||
return false;
|
||||
|
||||
// alive or spirit healer
|
||||
if (!creature->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD))
|
||||
if (!creature->IsAlive() &&
|
||||
!(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD))
|
||||
return false;
|
||||
|
||||
// appropriate npc type
|
||||
@@ -292,11 +301,14 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
||||
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
|
||||
return false;
|
||||
|
||||
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future
|
||||
// pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list)
|
||||
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && !bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
|
||||
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train
|
||||
// dual wield to a shaman :/ too many to change in sql and watch in the future pussywizard: this function is
|
||||
// not used when talking, but when already taking action (buy spell, reset talents, show spell list)
|
||||
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) &&
|
||||
creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS &&
|
||||
!bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
@@ -349,7 +361,7 @@ bool NewRpgBaseAction::IsWithinInteractionDist(Object* questGiver)
|
||||
|
||||
if (!creature->IsWithinDistInMap(bot, INTERACTION_DISTANCE))
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
case TYPEID_GAMEOBJECT:
|
||||
@@ -459,7 +471,8 @@ uint32 NewRpgBaseAction::BestRewardIndex(Quest const* quest)
|
||||
|
||||
bool NewRpgBaseAction::IsQuestWorthDoing(Quest const* quest)
|
||||
{
|
||||
bool isLowLevelQuest = bot->GetLevel() > (bot->GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF));
|
||||
bool isLowLevelQuest =
|
||||
bot->GetLevel() > (bot->GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF));
|
||||
|
||||
if (isLowLevelQuest)
|
||||
return false;
|
||||
@@ -500,7 +513,7 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
||||
if (!questId)
|
||||
freeSlotNum++;
|
||||
}
|
||||
|
||||
|
||||
// it's ok if we have two more free slots
|
||||
if (freeSlotNum >= 2)
|
||||
return false;
|
||||
@@ -514,11 +527,10 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
||||
continue;
|
||||
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!IsQuestWorthDoing(quest) ||
|
||||
!IsQuestCapableDoing(quest) ||
|
||||
if (!IsQuestWorthDoing(quest) || !IsQuestCapableDoing(quest) ||
|
||||
bot->GetQuestStatus(questId) == QUEST_STATUS_FAILED)
|
||||
{
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||
packet << (uint8)i;
|
||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||
@@ -528,7 +540,7 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
||||
dropped++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// drop more than 8 quests at once to avoid repeated accept and drop
|
||||
if (dropped >= 8)
|
||||
return true;
|
||||
@@ -541,10 +553,9 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
||||
continue;
|
||||
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (quest->GetZoneOrSort() < 0 ||
|
||||
(quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != bot->GetZoneId()))
|
||||
if (quest->GetZoneOrSort() < 0 || (quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != bot->GetZoneId()))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||
packet << (uint8)i;
|
||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||
@@ -566,7 +577,7 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
||||
continue;
|
||||
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
||||
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||
packet << (uint8)i;
|
||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||
@@ -604,7 +615,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
||||
return ObjectGuid();
|
||||
|
||||
WorldObject* nearestObject = nullptr;
|
||||
for (ObjectGuid& guid: possibleTargets)
|
||||
for (ObjectGuid& guid : possibleTargets)
|
||||
{
|
||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
||||
|
||||
@@ -613,7 +624,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
||||
|
||||
if (distanceLimit && bot->GetDistance(object) > distanceLimit)
|
||||
continue;
|
||||
|
||||
|
||||
if (CanInteractWithQuestGiver(object) && HasQuestToAcceptOrReward(object))
|
||||
{
|
||||
if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object))
|
||||
@@ -622,7 +633,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjectGuid& guid: possibleGameObjects)
|
||||
for (ObjectGuid& guid : possibleGameObjects)
|
||||
{
|
||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
||||
|
||||
@@ -631,7 +642,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
||||
|
||||
if (distanceLimit && bot->GetDistance(object) > distanceLimit)
|
||||
continue;
|
||||
|
||||
|
||||
if (CanInteractWithQuestGiver(object) && HasQuestToAcceptOrReward(object))
|
||||
{
|
||||
if (!nearestObject || bot->GetExactDist(nearestObject) > bot->GetExactDist(object))
|
||||
@@ -649,7 +660,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
||||
|
||||
if (possibleTargets.empty())
|
||||
return ObjectGuid();
|
||||
|
||||
|
||||
int idx = urand(0, possibleTargets.size() - 1);
|
||||
ObjectGuid guid = possibleTargets[idx];
|
||||
WorldObject* object = ObjectAccessor::GetCreatureOrPetOrVehicle(*bot, guid);
|
||||
@@ -667,17 +678,17 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
||||
{
|
||||
ObjectGuid guid = object->GetGUID();
|
||||
bot->PrepareQuestMenu(guid);
|
||||
const QuestMenu &menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||
const QuestMenu& menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||
if (menu.Empty())
|
||||
return false;
|
||||
|
||||
|
||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||
{
|
||||
const QuestMenuItem &item = menu.GetItem(idx);
|
||||
const QuestMenuItem& item = menu.GetItem(idx);
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||
if (!quest)
|
||||
continue;
|
||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
||||
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
||||
{
|
||||
return true;
|
||||
@@ -685,14 +696,14 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
||||
}
|
||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||
{
|
||||
const QuestMenuItem &item = menu.GetItem(idx);
|
||||
const QuestMenuItem& item = menu.GetItem(idx);
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||
if (!quest)
|
||||
continue;
|
||||
|
||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) &&
|
||||
bot->CanAddQuest(quest, false) && IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) && bot->CanAddQuest(quest, false) &&
|
||||
IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -700,26 +711,29 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::vector<float> GenerateRandomWeights(int n) {
|
||||
static std::vector<float> GenerateRandomWeights(int n)
|
||||
{
|
||||
std::vector<float> weights(n);
|
||||
float sum = 0.0;
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
weights[i] = rand_norm();
|
||||
sum += weights[i];
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
weights[i] /= sum;
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
|
||||
bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo> &poiInfo, bool toComplete)
|
||||
bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo>& poiInfo, bool toComplete)
|
||||
{
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
return false;
|
||||
|
||||
|
||||
const QuestPOIVector* poiVector = sObjectMgr->GetQuestPOIVector(questId);
|
||||
if (!poiVector)
|
||||
{
|
||||
@@ -730,15 +744,15 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
|
||||
if (toComplete && q_status.Status == QUEST_STATUS_COMPLETE)
|
||||
{
|
||||
for (const QuestPOI &qPoi : *poiVector)
|
||||
for (const QuestPOI& qPoi : *poiVector)
|
||||
{
|
||||
if (qPoi.MapId != bot->GetMapId())
|
||||
continue;
|
||||
|
||||
|
||||
// not the poi pos to reward quest
|
||||
if (qPoi.ObjectiveIndex != -1)
|
||||
continue;
|
||||
|
||||
|
||||
if (qPoi.points.size() == 0)
|
||||
continue;
|
||||
|
||||
@@ -746,22 +760,22 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
||||
for (size_t i = 0; i < qPoi.points.size(); i++)
|
||||
{
|
||||
const QuestPOIPoint &point = qPoi.points[i];
|
||||
const QuestPOIPoint& point = qPoi.points[i];
|
||||
dx += point.x * weights[i];
|
||||
dy += point.y * weights[i];
|
||||
}
|
||||
|
||||
|
||||
if (bot->GetDistance2d(dx, dy) >= 1500.0f)
|
||||
continue;
|
||||
|
||||
|
||||
float dz = std::max(bot->GetMap()->GetHeight(dx, dy, MAX_HEIGHT), bot->GetMap()->GetWaterLevel(dx, dy));
|
||||
|
||||
|
||||
if (dz == INVALID_HEIGHT || dz == VMAP_INVALID_HEIGHT_VALUE)
|
||||
continue;
|
||||
|
||||
|
||||
if (bot->GetZoneId() != bot->GetMap()->GetZoneId(bot->GetPhaseMask(), dx, dy, dz))
|
||||
continue;
|
||||
|
||||
|
||||
poiInfo.push_back({{dx, dy}, qPoi.ObjectiveIndex});
|
||||
}
|
||||
|
||||
@@ -781,7 +795,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
int32 npcOrGo = quest->RequiredNpcOrGo[i];
|
||||
if (!npcOrGo)
|
||||
continue;
|
||||
|
||||
|
||||
if (q_status.CreatureOrGOCount[i] < quest->RequiredNpcOrGoCount[i])
|
||||
incompleteObjectiveIdx.push_back(i);
|
||||
}
|
||||
@@ -796,7 +810,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
}
|
||||
|
||||
// Get POIs to go
|
||||
for (const QuestPOI &qPoi : *poiVector)
|
||||
for (const QuestPOI& qPoi : *poiVector)
|
||||
{
|
||||
if (qPoi.MapId != bot->GetMapId())
|
||||
continue;
|
||||
@@ -818,16 +832,16 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
||||
for (size_t i = 0; i < qPoi.points.size(); i++)
|
||||
{
|
||||
const QuestPOIPoint &point = qPoi.points[i];
|
||||
const QuestPOIPoint& point = qPoi.points[i];
|
||||
dx += point.x * weights[i];
|
||||
dy += point.y * weights[i];
|
||||
}
|
||||
|
||||
if (bot->GetDistance2d(dx, dy) >= 1500.0f)
|
||||
continue;
|
||||
|
||||
|
||||
float dz = std::max(bot->GetMap()->GetHeight(dx, dy, MAX_HEIGHT), bot->GetMap()->GetWaterLevel(dx, dy));
|
||||
|
||||
|
||||
if (dz == INVALID_HEIGHT || dz == VMAP_INVALID_HEIGHT_VALUE)
|
||||
continue;
|
||||
|
||||
@@ -837,7 +851,8 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
||||
poiInfo.push_back({{dx, dy}, qPoi.ObjectiveIndex});
|
||||
}
|
||||
|
||||
if (poiInfo.size() == 0) {
|
||||
if (poiInfo.size() == 0)
|
||||
{
|
||||
// LOG_DEBUG("playerbots", "[New rpg] {}: No available poi can be found for quest {}", bot->GetName(), questId);
|
||||
return false;
|
||||
}
|
||||
@@ -872,8 +887,8 @@ WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot)
|
||||
if (bot->GetExactDist(loc) > 2500.0f)
|
||||
continue;
|
||||
|
||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()) !=
|
||||
bot->GetZoneId())
|
||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(),
|
||||
loc.GetPositionZ()) != bot->GetZoneId())
|
||||
continue;
|
||||
|
||||
if (bot->GetExactDist(loc) < hiRange)
|
||||
@@ -897,40 +912,43 @@ WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot)
|
||||
uint32 idx = urand(0, lo_prepared_locs.size() - 1);
|
||||
dest = lo_prepared_locs[idx];
|
||||
}
|
||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random grind pos Map:{} X:{} Y:{} Z:{} ({}+{} available in {})",
|
||||
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random grind pos Map:{} X:{} Y:{} Z:{} ({}+{} available in {})",
|
||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||
hi_prepared_locs.size(), lo_prepared_locs.size() - hi_prepared_locs.size(), locs.size());
|
||||
return dest;
|
||||
}
|
||||
|
||||
WorldPosition NewRpgBaseAction::SelectRandomInnKeeperPos(Player* bot)
|
||||
WorldPosition NewRpgBaseAction::SelectRandomCampPos(Player* bot)
|
||||
{
|
||||
const std::vector<WorldLocation>& locs = IsAlliance(bot->getRace())
|
||||
? sRandomPlayerbotMgr->allianceStarterPerLevelCache[bot->GetLevel()]
|
||||
: sRandomPlayerbotMgr->hordeStarterPerLevelCache[bot->GetLevel()];
|
||||
|
||||
|
||||
bool inCity = false;
|
||||
|
||||
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(bot->GetZoneId()))
|
||||
{
|
||||
if (zone->flags & AREA_FLAG_CAPITAL)
|
||||
inCity = true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<WorldLocation> prepared_locs;
|
||||
for (auto& loc : locs)
|
||||
{
|
||||
if (bot->GetMapId() != loc.GetMapId())
|
||||
continue;
|
||||
|
||||
|
||||
float range = bot->GetLevel() <= 5 ? 500.0f : 2500.0f;
|
||||
if (bot->GetExactDist(loc) > range)
|
||||
continue;
|
||||
|
||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()) !=
|
||||
bot->GetZoneId())
|
||||
if (bot->GetExactDist(loc) < 50.0f)
|
||||
continue;
|
||||
|
||||
|
||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(),
|
||||
loc.GetPositionZ()) != bot->GetZoneId())
|
||||
continue;
|
||||
|
||||
prepared_locs.push_back(loc);
|
||||
}
|
||||
WorldPosition dest{};
|
||||
@@ -939,8 +957,265 @@ WorldPosition NewRpgBaseAction::SelectRandomInnKeeperPos(Player* bot)
|
||||
uint32 idx = urand(0, prepared_locs.size() - 1);
|
||||
dest = prepared_locs[idx];
|
||||
}
|
||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
||||
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||
prepared_locs.size(), locs.size());
|
||||
return dest;
|
||||
}
|
||||
|
||||
bool NewRpgBaseAction::SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint32& fromNode, uint32& toNode)
|
||||
{
|
||||
const std::vector<uint32>& flightMasters = IsAlliance(bot->getRace())
|
||||
? sRandomPlayerbotMgr->allianceFlightMasterCache
|
||||
: sRandomPlayerbotMgr->hordeFlightMasterCache;
|
||||
Creature* nearestFlightMaster = nullptr;
|
||||
for (const uint32& guid : flightMasters)
|
||||
{
|
||||
Creature* flightMaster = ObjectAccessor::GetSpawnedCreatureByDBGUID(bot->GetMapId(), guid);
|
||||
if (!flightMaster)
|
||||
continue;
|
||||
|
||||
if (bot->GetMapId() != flightMaster->GetMapId())
|
||||
continue;
|
||||
|
||||
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > bot->GetDistance(flightMaster))
|
||||
nearestFlightMaster = flightMaster;
|
||||
}
|
||||
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > 500.0f)
|
||||
return false;
|
||||
|
||||
fromNode = sObjectMgr->GetNearestTaxiNode(nearestFlightMaster->GetPositionX(), nearestFlightMaster->GetPositionY(),
|
||||
nearestFlightMaster->GetPositionZ(), nearestFlightMaster->GetMapId(),
|
||||
bot->GetTeamId());
|
||||
|
||||
if (!fromNode)
|
||||
return false;
|
||||
|
||||
std::vector<uint32> availableToNodes;
|
||||
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
|
||||
{
|
||||
if (fromNode == i)
|
||||
continue;
|
||||
|
||||
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
|
||||
|
||||
// check map
|
||||
if (!node || node->map_id != bot->GetMapId() ||
|
||||
(!node->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0])) // dk flight
|
||||
continue;
|
||||
|
||||
// check taxi node known
|
||||
if (!bot->isTaxiCheater() && !bot->m_taxi.IsTaximaskNodeKnown(i))
|
||||
continue;
|
||||
|
||||
// check distance by level
|
||||
if (!botAI->CheckLocationDistanceByLevel(bot, WorldLocation(node->map_id, node->x, node->y, node->z), false))
|
||||
continue;
|
||||
|
||||
// check path
|
||||
uint32 path, cost;
|
||||
sObjectMgr->GetTaxiPath(fromNode, i, path, cost);
|
||||
if (!path)
|
||||
continue;
|
||||
|
||||
// check area level
|
||||
uint32 nodeZoneId = bot->GetMap()->GetZoneId(bot->GetPhaseMask(), node->x, node->y, node->z);
|
||||
bool capital = false;
|
||||
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(nodeZoneId))
|
||||
{
|
||||
capital = zone->flags & AREA_FLAG_CAPITAL;
|
||||
}
|
||||
|
||||
auto itr = sRandomPlayerbotMgr->zone2LevelBracket.find(nodeZoneId);
|
||||
if (!capital && itr == sRandomPlayerbotMgr->zone2LevelBracket.end())
|
||||
continue;
|
||||
|
||||
if (!capital && (bot->GetLevel() < itr->second.low || bot->GetLevel() > itr->second.high))
|
||||
continue;
|
||||
|
||||
availableToNodes.push_back(i);
|
||||
}
|
||||
if (availableToNodes.empty())
|
||||
return false;
|
||||
|
||||
flightMaster = nearestFlightMaster->GetGUID();
|
||||
toNode = availableToNodes[urand(0, availableToNodes.size() - 1)];
|
||||
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random flight taxi node from:{} (node {}) to:{} ({} available)",
|
||||
bot->GetName(), flightMaster.GetEntry(), fromNode, toNode, availableToNodes.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NewRpgBaseAction::RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus)
|
||||
{
|
||||
std::vector<NewRpgStatus> availableStatus;
|
||||
uint32 probSum = 0;
|
||||
for (NewRpgStatus status : candidateStatus)
|
||||
{
|
||||
if (sPlayerbotAIConfig->RpgStatusProbWeight[status] == 0)
|
||||
continue;
|
||||
|
||||
if (CheckRpgStatusAvailable(status))
|
||||
{
|
||||
availableStatus.push_back(status);
|
||||
probSum += sPlayerbotAIConfig->RpgStatusProbWeight[status];
|
||||
}
|
||||
}
|
||||
uint32 rand = urand(1, probSum);
|
||||
uint32 accumulate = 0;
|
||||
NewRpgStatus chosenStatus = RPG_STATUS_END;
|
||||
for (NewRpgStatus status : availableStatus)
|
||||
{
|
||||
accumulate += sPlayerbotAIConfig->RpgStatusProbWeight[status];
|
||||
if (accumulate >= rand)
|
||||
{
|
||||
chosenStatus = status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (chosenStatus)
|
||||
{
|
||||
case RPG_WANDER_RANDOM:
|
||||
{
|
||||
botAI->rpgInfo.ChangeToWanderRandom();
|
||||
return true;
|
||||
}
|
||||
case RPG_WANDER_NPC:
|
||||
{
|
||||
botAI->rpgInfo.ChangeToWanderNpc();
|
||||
return true;
|
||||
}
|
||||
case RPG_GO_GRIND:
|
||||
{
|
||||
WorldPosition pos = SelectRandomGrindPos(bot);
|
||||
if (pos != WorldPosition())
|
||||
{
|
||||
botAI->rpgInfo.ChangeToGoGrind(pos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case RPG_GO_CAMP:
|
||||
{
|
||||
WorldPosition pos = SelectRandomCampPos(bot);
|
||||
if (pos != WorldPosition())
|
||||
{
|
||||
botAI->rpgInfo.ChangeToGoCamp(pos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case RPG_DO_QUEST:
|
||||
{
|
||||
std::vector<uint32> availableQuests;
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
||||
continue;
|
||||
|
||||
std::vector<POIInfo> poiInfo;
|
||||
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
||||
{
|
||||
availableQuests.push_back(questId);
|
||||
}
|
||||
}
|
||||
if (availableQuests.size())
|
||||
{
|
||||
uint32 questId = availableQuests[urand(0, availableQuests.size() - 1)];
|
||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (quest)
|
||||
{
|
||||
botAI->rpgInfo.ChangeToDoQuest(questId, quest);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case RPG_TRAVEL_FLIGHT:
|
||||
{
|
||||
ObjectGuid flightMaster;
|
||||
uint32 fromNode, toNode;
|
||||
if (SelectRandomFlightTaxiNode(flightMaster, fromNode, toNode))
|
||||
{
|
||||
botAI->rpgInfo.ChangeToTravelFlight(flightMaster, fromNode, toNode);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case RPG_IDLE:
|
||||
{
|
||||
botAI->rpgInfo.ChangeToIdle();
|
||||
return true;
|
||||
}
|
||||
case RPG_REST:
|
||||
{
|
||||
botAI->rpgInfo.ChangeToRest();
|
||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
botAI->rpgInfo.ChangeToRest();
|
||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NewRpgBaseAction::CheckRpgStatusAvailable(NewRpgStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case RPG_IDLE:
|
||||
case RPG_REST:
|
||||
return true;
|
||||
case RPG_WANDER_RANDOM:
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "grind target");
|
||||
return target != nullptr;
|
||||
}
|
||||
case RPG_GO_GRIND:
|
||||
{
|
||||
WorldPosition pos = SelectRandomGrindPos(bot);
|
||||
return pos != WorldPosition();
|
||||
}
|
||||
case RPG_GO_CAMP:
|
||||
{
|
||||
WorldPosition pos = SelectRandomCampPos(bot);
|
||||
return pos != WorldPosition();
|
||||
}
|
||||
case RPG_WANDER_NPC:
|
||||
{
|
||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible new rpg targets");
|
||||
return possibleTargets.size() >= 3;
|
||||
}
|
||||
case RPG_DO_QUEST:
|
||||
{
|
||||
std::vector<uint32> availableQuests;
|
||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||
{
|
||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
||||
continue;
|
||||
|
||||
std::vector<POIInfo> poiInfo;
|
||||
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case RPG_TRAVEL_FLIGHT:
|
||||
{
|
||||
ObjectGuid flightMaster;
|
||||
uint32 fromNode, toNode;
|
||||
return SelectRandomFlightTaxiNode(flightMaster, fromNode, toNode);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -4,15 +4,17 @@
|
||||
#include "Duration.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "MovementActions.h"
|
||||
#include "NewRpgInfo.h"
|
||||
#include "NewRpgStrategy.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "QuestDef.h"
|
||||
#include "TravelMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
struct POIInfo {
|
||||
struct POIInfo
|
||||
{
|
||||
G3D::Vector2 pos;
|
||||
int32 objectiveIdx;
|
||||
};
|
||||
@@ -24,15 +26,15 @@ class NewRpgBaseAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
NewRpgBaseAction(PlayerbotAI* botAI, std::string name) : MovementAction(botAI, name) {}
|
||||
|
||||
|
||||
protected:
|
||||
// MOVEMENT RELATED
|
||||
/* MOVEMENT RELATED */
|
||||
bool MoveFarTo(WorldPosition dest);
|
||||
bool MoveWorldObjectTo(ObjectGuid guid, float distance = INTERACTION_DISTANCE);
|
||||
bool MoveRandomNear(float moveStep = 50.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool ForceToWait(uint32 duration, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
|
||||
// QUEST RELATED CHECK
|
||||
/* QUEST RELATED CHECK */
|
||||
ObjectGuid ChooseNpcOrGameObjectToInteract(bool questgiverOnly = false, float distanceLimit = 0.0f);
|
||||
bool HasQuestToAcceptOrReward(WorldObject* object);
|
||||
bool InteractWithNpcOrGameObjectForQuest(ObjectGuid guid);
|
||||
@@ -41,20 +43,24 @@ protected:
|
||||
uint32 BestRewardIndex(Quest const* quest);
|
||||
bool IsQuestWorthDoing(Quest const* quest);
|
||||
bool IsQuestCapableDoing(Quest const* quest);
|
||||
// QUEST RELATED ACTION
|
||||
|
||||
/* QUEST RELATED ACTION */
|
||||
bool SearchQuestGiverAndAcceptOrReward();
|
||||
bool AcceptQuest(Quest const* quest, ObjectGuid guid);
|
||||
bool TurnInQuest(Quest const* quest, ObjectGuid guid);
|
||||
bool OrganizeQuestLog();
|
||||
|
||||
protected:
|
||||
bool GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo> &poiInfo, bool toComplete = false);
|
||||
bool GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo>& poiInfo, bool toComplete = false);
|
||||
static WorldPosition SelectRandomGrindPos(Player* bot);
|
||||
static WorldPosition SelectRandomInnKeeperPos(Player* bot);
|
||||
static WorldPosition SelectRandomCampPos(Player* bot);
|
||||
bool SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint32& fromNode, uint32& toNode);
|
||||
bool RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus);
|
||||
bool CheckRpgStatusAvailable(NewRpgStatus status);
|
||||
|
||||
protected:
|
||||
// WorldPosition dest;
|
||||
const float pathFinderDis = 70.0f; // path finder
|
||||
/* FOR MOVE FAR */
|
||||
const float pathFinderDis = 70.0f;
|
||||
const uint32 stuckTime = 5 * 60 * 1000;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "NewRpgInfo.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
void NewRpgInfo::ChangeToGoGrind(WorldPosition pos)
|
||||
@@ -9,26 +12,26 @@ void NewRpgInfo::ChangeToGoGrind(WorldPosition pos)
|
||||
go_grind.pos = pos;
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToGoInnkeeper(WorldPosition pos)
|
||||
void NewRpgInfo::ChangeToGoCamp(WorldPosition pos)
|
||||
{
|
||||
Reset();
|
||||
status = RPG_GO_INNKEEPER;
|
||||
go_innkeeper = GoInnkeeper();
|
||||
go_innkeeper.pos = pos;
|
||||
status = RPG_GO_CAMP;
|
||||
go_camp = GoCamp();
|
||||
go_camp.pos = pos;
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToNearNpc()
|
||||
void NewRpgInfo::ChangeToWanderNpc()
|
||||
{
|
||||
Reset();
|
||||
status = RPG_NEAR_NPC;
|
||||
near_npc = NearNpc();
|
||||
status = RPG_WANDER_NPC;
|
||||
wander_npc = WanderNpc();
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToNearRandom()
|
||||
void NewRpgInfo::ChangeToWanderRandom()
|
||||
{
|
||||
Reset();
|
||||
status = RPG_NEAR_RANDOM;
|
||||
near_random = NearRandom();
|
||||
status = RPG_WANDER_RANDOM;
|
||||
WANDER_RANDOM = WanderRandom();
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
||||
@@ -40,6 +43,16 @@ void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
||||
do_quest.quest = quest;
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToTravelFlight(ObjectGuid fromFlightMaster, uint32 fromNode, uint32 toNode)
|
||||
{
|
||||
Reset();
|
||||
status = RPG_TRAVEL_FLIGHT;
|
||||
flight = TravelFlight();
|
||||
flight.fromFlightMaster = fromFlightMaster;
|
||||
flight.fromNode = fromNode;
|
||||
flight.toNode = toNode;
|
||||
}
|
||||
|
||||
void NewRpgInfo::ChangeToRest()
|
||||
{
|
||||
Reset();
|
||||
@@ -53,10 +66,7 @@ void NewRpgInfo::ChangeToIdle()
|
||||
status = RPG_IDLE;
|
||||
}
|
||||
|
||||
bool NewRpgInfo::CanChangeTo(NewRpgStatus status)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool NewRpgInfo::CanChangeTo(NewRpgStatus status) { return true; }
|
||||
|
||||
void NewRpgInfo::Reset()
|
||||
{
|
||||
@@ -80,23 +90,25 @@ std::string NewRpgInfo::ToString()
|
||||
{
|
||||
case RPG_GO_GRIND:
|
||||
out << "GO_GRIND";
|
||||
out << "\nGrindPos: " << go_grind.pos.GetMapId() << " " << go_grind.pos.GetPositionX() << " " << go_grind.pos.GetPositionY() << " " << go_grind.pos.GetPositionZ();
|
||||
out << "\nGrindPos: " << go_grind.pos.GetMapId() << " " << go_grind.pos.GetPositionX() << " "
|
||||
<< go_grind.pos.GetPositionY() << " " << go_grind.pos.GetPositionZ();
|
||||
out << "\nlastGoGrind: " << startT;
|
||||
break;
|
||||
case RPG_GO_INNKEEPER:
|
||||
out << "GO_INNKEEPER";
|
||||
out << "\nInnKeeperPos: " << go_innkeeper.pos.GetMapId() << " " << go_innkeeper.pos.GetPositionX() << " " << go_innkeeper.pos.GetPositionY() << " " << go_innkeeper.pos.GetPositionZ();
|
||||
out << "\nlastGoInnKeeper: " << startT;
|
||||
case RPG_GO_CAMP:
|
||||
out << "GO_CAMP";
|
||||
out << "\nCampPos: " << go_camp.pos.GetMapId() << " " << go_camp.pos.GetPositionX() << " "
|
||||
<< go_camp.pos.GetPositionY() << " " << go_camp.pos.GetPositionZ();
|
||||
out << "\nlastGoCamp: " << startT;
|
||||
break;
|
||||
case RPG_NEAR_NPC:
|
||||
out << "NEAR_NPC";
|
||||
out << "\nnpcOrGoEntry: " << near_npc.npcOrGo.GetCounter();
|
||||
out << "\nlastNearNpc: " << startT;
|
||||
out << "\nlastReachNpcOrGo: " << near_npc.lastReach;
|
||||
case RPG_WANDER_NPC:
|
||||
out << "WANDER_NPC";
|
||||
out << "\nnpcOrGoEntry: " << wander_npc.npcOrGo.GetCounter();
|
||||
out << "\nlastWanderNpc: " << startT;
|
||||
out << "\nlastReachNpcOrGo: " << wander_npc.lastReach;
|
||||
break;
|
||||
case RPG_NEAR_RANDOM:
|
||||
out << "NEAR_RANDOM";
|
||||
out << "\nlastNearRandom: " << startT;
|
||||
case RPG_WANDER_RANDOM:
|
||||
out << "WANDER_RANDOM";
|
||||
out << "\nlastWanderRandom: " << startT;
|
||||
break;
|
||||
case RPG_IDLE:
|
||||
out << "IDLE";
|
||||
@@ -109,8 +121,16 @@ std::string NewRpgInfo::ToString()
|
||||
out << "DO_QUEST";
|
||||
out << "\nquestId: " << do_quest.questId;
|
||||
out << "\nobjectiveIdx: " << do_quest.objectiveIdx;
|
||||
out << "\npoiPos: " << do_quest.pos.GetMapId() << " " << do_quest.pos.GetPositionX() << " " << do_quest.pos.GetPositionY() << " " << do_quest.pos.GetPositionZ();
|
||||
out << "\nlastReachPOI: " << do_quest.lastReachPOI;
|
||||
out << "\npoiPos: " << do_quest.pos.GetMapId() << " " << do_quest.pos.GetPositionX() << " "
|
||||
<< do_quest.pos.GetPositionY() << " " << do_quest.pos.GetPositionZ();
|
||||
out << "\nlastReachPOI: " << do_quest.lastReachPOI ? GetMSTimeDiffToNow(do_quest.lastReachPOI) : 0;
|
||||
break;
|
||||
case RPG_TRAVEL_FLIGHT:
|
||||
out << "TRAVEL_FLIGHT";
|
||||
out << "\nfromFlightMaster: " << flight.fromFlightMaster.GetEntry();
|
||||
out << "\nfromNode: " << flight.fromNode;
|
||||
out << "\ntoNode: " << flight.toNode;
|
||||
out << "\ninFlight: " << flight.inFlight;
|
||||
break;
|
||||
default:
|
||||
out << "UNKNOWN";
|
||||
|
||||
@@ -9,67 +9,61 @@
|
||||
#include "Timer.h"
|
||||
#include "TravelMgr.h"
|
||||
|
||||
enum NewRpgStatus: int
|
||||
{
|
||||
RPG_STATUS_START = 0,
|
||||
// Going to far away place
|
||||
RPG_GO_GRIND = 0,
|
||||
RPG_GO_INNKEEPER = 1,
|
||||
// Exploring nearby
|
||||
RPG_NEAR_RANDOM = 2,
|
||||
RPG_NEAR_NPC = 3,
|
||||
// Do Quest (based on quest status)
|
||||
RPG_DO_QUEST = 4,
|
||||
// Taking a break
|
||||
RPG_REST = 5,
|
||||
// Initial status
|
||||
RPG_IDLE = 6,
|
||||
RPG_STATUS_END = 7
|
||||
};
|
||||
|
||||
using NewRpgStatusTransitionProb = std::vector<std::vector<int>>;
|
||||
|
||||
struct NewRpgInfo
|
||||
{
|
||||
NewRpgInfo() {}
|
||||
|
||||
|
||||
// RPG_GO_GRIND
|
||||
struct GoGrind {
|
||||
GoGrind() = default;
|
||||
struct GoGrind
|
||||
{
|
||||
WorldPosition pos{};
|
||||
};
|
||||
// RPG_GO_INNKEEPER
|
||||
struct GoInnkeeper {
|
||||
GoInnkeeper() = default;
|
||||
// RPG_GO_CAMP
|
||||
struct GoCamp
|
||||
{
|
||||
WorldPosition pos{};
|
||||
};
|
||||
// RPG_NEAR_NPC
|
||||
struct NearNpc {
|
||||
NearNpc() = default;
|
||||
// RPG_WANDER_NPC
|
||||
struct WanderNpc
|
||||
{
|
||||
ObjectGuid npcOrGo{};
|
||||
uint32 lastReach{0};
|
||||
};
|
||||
// RPG_NEAR_RANDOM
|
||||
struct NearRandom {
|
||||
NearRandom() = default;
|
||||
// RPG_WANDER_RANDOM
|
||||
struct WanderRandom
|
||||
{
|
||||
WanderRandom() = default;
|
||||
};
|
||||
// NewRpgStatus::QUESTING
|
||||
struct DoQuest {
|
||||
// RPG_DO_QUEST
|
||||
struct DoQuest
|
||||
{
|
||||
const Quest* quest{nullptr};
|
||||
uint32 questId{0};
|
||||
int32 objectiveIdx{0};
|
||||
WorldPosition pos{};
|
||||
uint32 lastReachPOI{0};
|
||||
};
|
||||
// RPG_TRAVEL_FLIGHT
|
||||
struct TravelFlight
|
||||
{
|
||||
ObjectGuid fromFlightMaster{};
|
||||
uint32 fromNode{0};
|
||||
uint32 toNode{0};
|
||||
bool inFlight{false};
|
||||
};
|
||||
// RPG_REST
|
||||
struct Rest {
|
||||
struct Rest
|
||||
{
|
||||
Rest() = default;
|
||||
};
|
||||
struct Idle {
|
||||
struct Idle
|
||||
{
|
||||
};
|
||||
NewRpgStatus status{RPG_IDLE};
|
||||
|
||||
uint32 startT{0}; // start timestamp of the current status
|
||||
uint32 startT{0}; // start timestamp of the current status
|
||||
|
||||
// MOVE_FAR
|
||||
float nearestMoveFarDis{FLT_MAX};
|
||||
@@ -78,22 +72,25 @@ struct NewRpgInfo
|
||||
WorldPosition moveFarPos;
|
||||
// END MOVE_FAR
|
||||
|
||||
union {
|
||||
union
|
||||
{
|
||||
GoGrind go_grind;
|
||||
GoInnkeeper go_innkeeper;
|
||||
NearNpc near_npc;
|
||||
NearRandom near_random;
|
||||
GoCamp go_camp;
|
||||
WanderNpc wander_npc;
|
||||
WanderRandom WANDER_RANDOM;
|
||||
DoQuest do_quest;
|
||||
Rest rest;
|
||||
DoQuest quest;
|
||||
TravelFlight flight;
|
||||
};
|
||||
|
||||
bool HasStatusPersisted(uint32 maxDuration) { return GetMSTimeDiffToNow(startT) > maxDuration; }
|
||||
void ChangeToGoGrind(WorldPosition pos);
|
||||
void ChangeToGoInnkeeper(WorldPosition pos);
|
||||
void ChangeToNearNpc();
|
||||
void ChangeToNearRandom();
|
||||
void ChangeToGoCamp(WorldPosition pos);
|
||||
void ChangeToWanderNpc();
|
||||
void ChangeToWanderRandom();
|
||||
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
||||
void ChangeToTravelFlight(ObjectGuid fromFlightMaster, uint32 fromNode, uint32 toNode);
|
||||
void ChangeToRest();
|
||||
void ChangeToIdle();
|
||||
bool CanChangeTo(NewRpgStatus status);
|
||||
|
||||
@@ -23,16 +23,19 @@ void NewRpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new TriggerNode("go grind status", NextAction::array(0, new NextAction("new rpg go grind", 3.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("go innkeeper status", NextAction::array(0, new NextAction("new rpg go innkeeper", 3.0f), nullptr)));
|
||||
new TriggerNode("go camp status", NextAction::array(0, new NextAction("new rpg go camp", 3.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near random status", NextAction::array(0, new NextAction("new rpg move random", 3.0f), nullptr)));
|
||||
new TriggerNode("wander random status", NextAction::array(0, new NextAction("new rpg wander random", 3.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("near npc status", NextAction::array(0, new NextAction("new rpg move npc", 3.0f), nullptr)));
|
||||
new TriggerNode("wander npc status", NextAction::array(0, new NextAction("new rpg wander npc", 3.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("do quest status", NextAction::array(0, new NextAction("new rpg do quest", 3.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("travel flight status", NextAction::array(0, new NextAction("new rpg travel flight", 3.0f), nullptr)));
|
||||
}
|
||||
|
||||
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
|
||||
Reference in New Issue
Block a user