mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
commit
531282e4be
@ -32,7 +32,7 @@
|
|||||||
# LEVELS
|
# LEVELS
|
||||||
# GEAR
|
# GEAR
|
||||||
# QUESTS
|
# QUESTS
|
||||||
# ACTIVITIES
|
# ACTIVITY
|
||||||
# SPELLS
|
# SPELLS
|
||||||
# STRATEGIES
|
# STRATEGIES
|
||||||
# RPG STRATEGY
|
# RPG STRATEGY
|
||||||
|
|||||||
@ -343,7 +343,7 @@ bool BGJoinAction::isUseful()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check Deserter debuff
|
// check Deserter debuff
|
||||||
if (!bot->CanJoinToBattleground())
|
if (bot->IsDeserter())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check if has free queue slots (pointless as already making sure not in queue)
|
// check if has free queue slots (pointless as already making sure not in queue)
|
||||||
|
|||||||
@ -213,13 +213,7 @@ bool BuyAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vendored)
|
return vendored;
|
||||||
{
|
|
||||||
botAI->TellError("There are no vendors nearby");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
|
bool BuyAction::BuyItem(VendorItemData const* tItems, ObjectGuid vendorguid, ItemTemplate const* proto)
|
||||||
|
|||||||
@ -296,7 +296,7 @@ bool PetitionTurnInAction::isUseful()
|
|||||||
|
|
||||||
bool BuyTabardAction::Execute(Event /*event*/)
|
bool BuyTabardAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"));
|
bool canBuy = botAI->DoSpecificAction("buy", Event("buy tabard", "Hitem:5976:"), true);
|
||||||
if (canBuy && AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)))
|
if (canBuy && AI_VALUE2(uint32, "item count", chat->FormatQItem(5976)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
39
src/Ai/Base/Actions/TellEmblemsAction.cpp
Normal file
39
src/Ai/Base/Actions/TellEmblemsAction.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TellEmblemsAction.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "Event.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
bool TellEmblemsAction::Execute(Event /*event*/)
|
||||||
|
{
|
||||||
|
static std::array<uint32, 6> const emblemIds = {
|
||||||
|
29434, // Badge of Justice
|
||||||
|
40752, // Emblem of Heroism
|
||||||
|
40753, // Emblem of Valor
|
||||||
|
45624, // Emblem of Conquest
|
||||||
|
47241, // Emblem of Triumph
|
||||||
|
49426 // Emblem of Frost
|
||||||
|
};
|
||||||
|
|
||||||
|
botAI->TellMaster("=== Emblems ===");
|
||||||
|
|
||||||
|
for (uint32 itemId : emblemIds)
|
||||||
|
{
|
||||||
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
|
||||||
|
if (!proto)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint32 count = bot->GetItemCount(itemId, false);
|
||||||
|
std::ostringstream out;
|
||||||
|
out << chat->FormatItem(proto, count);
|
||||||
|
botAI->TellMaster(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
21
src/Ai/Base/Actions/TellEmblemsAction.h
Normal file
21
src/Ai/Base/Actions/TellEmblemsAction.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYERBOT_TELLEMBLEMSACTION_H
|
||||||
|
#define _PLAYERBOT_TELLEMBLEMSACTION_H
|
||||||
|
|
||||||
|
#include "InventoryAction.h"
|
||||||
|
|
||||||
|
class PlayerbotAI;
|
||||||
|
|
||||||
|
class TellEmblemsAction : public InventoryAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TellEmblemsAction(PlayerbotAI* botAI) : InventoryAction(botAI, "emblems") {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -5,34 +5,23 @@
|
|||||||
|
|
||||||
#include "TellReputationAction.h"
|
#include "TellReputationAction.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "ReputationMgr.h"
|
#include "ReputationMgr.h"
|
||||||
|
|
||||||
bool TellReputationAction::Execute(Event /*event*/)
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
|
std::string TellReputationAction::BuildReputationLine(FactionEntry const* entry)
|
||||||
{
|
{
|
||||||
Player* master = GetMaster();
|
ReputationMgr& repMgr = bot->GetReputationMgr();
|
||||||
if (!master)
|
ReputationRank rank = repMgr.GetRank(entry);
|
||||||
return false;
|
int32 reputation = repMgr.GetReputation(entry->ID);
|
||||||
|
|
||||||
ObjectGuid selection = master->GetTarget();
|
|
||||||
if (selection.IsEmpty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* unit = ObjectAccessor::GetUnit(*master, selection);
|
|
||||||
if (!unit)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FactionTemplateEntry const* factionTemplate = unit->GetFactionTemplateEntry();
|
|
||||||
uint32 faction = factionTemplate->faction;
|
|
||||||
FactionEntry const* entry = sFactionStore.LookupEntry(faction);
|
|
||||||
int32 reputation = bot->GetReputationMgr().GetReputation(faction);
|
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << entry->name[0] << ": ";
|
out << entry->name[0] << ": |cff";
|
||||||
out << "|cff";
|
|
||||||
|
|
||||||
ReputationRank rank = bot->GetReputationMgr().GetRank(entry);
|
|
||||||
switch (rank)
|
switch (rank)
|
||||||
{
|
{
|
||||||
case REP_HATED:
|
case REP_HATED:
|
||||||
@ -71,7 +60,65 @@ bool TellReputationAction::Execute(Event /*event*/)
|
|||||||
base -= ReputationMgr::PointsInRank[i];
|
base -= ReputationMgr::PointsInRank[i];
|
||||||
|
|
||||||
out << " (" << (reputation - base) << "/" << ReputationMgr::PointsInRank[rank] << ")";
|
out << " (" << (reputation - base) << "/" << ReputationMgr::PointsInRank[rank] << ")";
|
||||||
botAI->TellMaster(out);
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TellReputationAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
std::string const param = event.getParam();
|
||||||
|
if (param == "all")
|
||||||
|
{
|
||||||
|
ReputationMgr& repMgr = bot->GetReputationMgr();
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
|
||||||
|
FactionStateList const& stateList = repMgr.GetStateList();
|
||||||
|
lines.reserve(stateList.size());
|
||||||
|
|
||||||
|
for (auto const& itr : stateList)
|
||||||
|
{
|
||||||
|
FactionState const& faction = itr.second;
|
||||||
|
if (!(faction.Flags & FACTION_FLAG_VISIBLE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (faction.Flags & (FACTION_FLAG_HIDDEN | FACTION_FLAG_INVISIBLE_FORCED) &&
|
||||||
|
!(faction.Flags & FACTION_FLAG_SPECIAL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FactionEntry const* entry = sFactionStore.LookupEntry(faction.ID);
|
||||||
|
if (!entry)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
lines.push_back(BuildReputationLine(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(lines.begin(), lines.end());
|
||||||
|
|
||||||
|
botAI->TellMaster("=== Reputations ===");
|
||||||
|
for (auto const& line : lines)
|
||||||
|
botAI->TellMaster(line);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* master = GetMaster();
|
||||||
|
if (!master)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ObjectGuid selection = master->GetTarget();
|
||||||
|
if (selection.IsEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* unit = ObjectAccessor::GetUnit(*master, selection);
|
||||||
|
if (!unit)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
FactionTemplateEntry const* factionTemplate = unit->GetFactionTemplateEntry();
|
||||||
|
|
||||||
|
FactionEntry const* entry = sFactionStore.LookupEntry(factionTemplate->faction);
|
||||||
|
if (!entry)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
botAI->TellMaster(BuildReputationLine(entry));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,11 @@
|
|||||||
#ifndef _PLAYERBOT_TELLREPUTATIONACTION_H
|
#ifndef _PLAYERBOT_TELLREPUTATIONACTION_H
|
||||||
#define _PLAYERBOT_TELLREPUTATIONACTION_H
|
#define _PLAYERBOT_TELLREPUTATIONACTION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "Action.h"
|
#include "Action.h"
|
||||||
|
|
||||||
|
struct FactionEntry;
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
class TellReputationAction : public Action
|
class TellReputationAction : public Action
|
||||||
@ -16,6 +19,9 @@ public:
|
|||||||
TellReputationAction(PlayerbotAI* botAI) : Action(botAI, "reputation") {}
|
TellReputationAction(PlayerbotAI* botAI) : Action(botAI, "reputation") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string BuildReputationLine(FactionEntry const* entry);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -66,6 +66,7 @@
|
|||||||
#include "TaxiAction.h"
|
#include "TaxiAction.h"
|
||||||
#include "TeleportAction.h"
|
#include "TeleportAction.h"
|
||||||
#include "TellCastFailedAction.h"
|
#include "TellCastFailedAction.h"
|
||||||
|
#include "TellEmblemsAction.h"
|
||||||
#include "TellItemCountAction.h"
|
#include "TellItemCountAction.h"
|
||||||
#include "TellLosAction.h"
|
#include "TellLosAction.h"
|
||||||
#include "TellReputationAction.h"
|
#include "TellReputationAction.h"
|
||||||
@ -120,6 +121,7 @@ public:
|
|||||||
creators["teleport"] = &ChatActionContext::teleport;
|
creators["teleport"] = &ChatActionContext::teleport;
|
||||||
creators["taxi"] = &ChatActionContext::taxi;
|
creators["taxi"] = &ChatActionContext::taxi;
|
||||||
creators["repair"] = &ChatActionContext::repair;
|
creators["repair"] = &ChatActionContext::repair;
|
||||||
|
creators["emblems"] = &ChatActionContext::emblems;
|
||||||
creators["use"] = &ChatActionContext::use;
|
creators["use"] = &ChatActionContext::use;
|
||||||
creators["item count"] = &ChatActionContext::item_count;
|
creators["item count"] = &ChatActionContext::item_count;
|
||||||
creators["equip"] = &ChatActionContext::equip;
|
creators["equip"] = &ChatActionContext::equip;
|
||||||
@ -276,6 +278,7 @@ private:
|
|||||||
static Action* item_count(PlayerbotAI* botAI) { return new TellItemCountAction(botAI); }
|
static Action* item_count(PlayerbotAI* botAI) { return new TellItemCountAction(botAI); }
|
||||||
static Action* use(PlayerbotAI* botAI) { return new UseItemAction(botAI); }
|
static Action* use(PlayerbotAI* botAI) { return new UseItemAction(botAI); }
|
||||||
static Action* repair(PlayerbotAI* botAI) { return new RepairAllAction(botAI); }
|
static Action* repair(PlayerbotAI* botAI) { return new RepairAllAction(botAI); }
|
||||||
|
static Action* emblems(PlayerbotAI* botAI) { return new TellEmblemsAction(botAI); }
|
||||||
static Action* taxi(PlayerbotAI* botAI) { return new TaxiAction(botAI); }
|
static Action* taxi(PlayerbotAI* botAI) { return new TaxiAction(botAI); }
|
||||||
static Action* teleport(PlayerbotAI* botAI) { return new TeleportAction(botAI); }
|
static Action* teleport(PlayerbotAI* botAI) { return new TeleportAction(botAI); }
|
||||||
static Action* release(PlayerbotAI* botAI) { return new ReleaseSpiritAction(botAI); }
|
static Action* release(PlayerbotAI* botAI) { return new ReleaseSpiritAction(botAI); }
|
||||||
|
|||||||
@ -41,6 +41,7 @@ public:
|
|||||||
creators["teleport"] = &ChatTriggerContext::teleport;
|
creators["teleport"] = &ChatTriggerContext::teleport;
|
||||||
creators["taxi"] = &ChatTriggerContext::taxi;
|
creators["taxi"] = &ChatTriggerContext::taxi;
|
||||||
creators["repair"] = &ChatTriggerContext::repair;
|
creators["repair"] = &ChatTriggerContext::repair;
|
||||||
|
creators["emblems"] = &ChatTriggerContext::emblems;
|
||||||
creators["u"] = &ChatTriggerContext::use;
|
creators["u"] = &ChatTriggerContext::use;
|
||||||
creators["use"] = &ChatTriggerContext::use;
|
creators["use"] = &ChatTriggerContext::use;
|
||||||
creators["c"] = &ChatTriggerContext::item_count;
|
creators["c"] = &ChatTriggerContext::item_count;
|
||||||
@ -235,6 +236,7 @@ private:
|
|||||||
static Trigger* item_count(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "c"); }
|
static Trigger* item_count(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "c"); }
|
||||||
static Trigger* use(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "use"); }
|
static Trigger* use(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "use"); }
|
||||||
static Trigger* repair(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "repair"); }
|
static Trigger* repair(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "repair"); }
|
||||||
|
static Trigger* emblems(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "emblems"); }
|
||||||
static Trigger* taxi(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "taxi"); }
|
static Trigger* taxi(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "taxi"); }
|
||||||
static Trigger* teleport(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "teleport"); }
|
static Trigger* teleport(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "teleport"); }
|
||||||
static Trigger* q(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "q"); }
|
static Trigger* q(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "q"); }
|
||||||
|
|||||||
@ -114,6 +114,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
triggers.push_back(new TriggerNode("pet attack", { NextAction("pet attack", relevance) }));
|
triggers.push_back(new TriggerNode("pet attack", { NextAction("pet attack", relevance) }));
|
||||||
triggers.push_back(new TriggerNode("roll", { NextAction("roll", relevance) }));
|
triggers.push_back(new TriggerNode("roll", { NextAction("roll", relevance) }));
|
||||||
triggers.push_back(new TriggerNode("focus heal", { NextAction("focus heal targets", relevance) }));
|
triggers.push_back(new TriggerNode("focus heal", { NextAction("focus heal targets", relevance) }));
|
||||||
|
triggers.push_back(new TriggerNode("emblems", { NextAction("emblems", relevance) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||||
@ -138,6 +139,7 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
|||||||
supported.push_back("teleport");
|
supported.push_back("teleport");
|
||||||
supported.push_back("taxi");
|
supported.push_back("taxi");
|
||||||
supported.push_back("repair");
|
supported.push_back("repair");
|
||||||
|
supported.push_back("emblems");
|
||||||
supported.push_back("talents");
|
supported.push_back("talents");
|
||||||
supported.push_back("spells");
|
supported.push_back("spells");
|
||||||
supported.push_back("co");
|
supported.push_back("co");
|
||||||
@ -202,8 +204,8 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
|||||||
supported.push_back("unlock items");
|
supported.push_back("unlock items");
|
||||||
supported.push_back("unlock traded item");
|
supported.push_back("unlock traded item");
|
||||||
supported.push_back("tame");
|
supported.push_back("tame");
|
||||||
supported.push_back("glyphs"); // Added for custom Glyphs
|
supported.push_back("glyphs");
|
||||||
supported.push_back("glyph equip"); // Added for custom Glyphs
|
supported.push_back("glyph equip");
|
||||||
supported.push_back("pet");
|
supported.push_back("pet");
|
||||||
supported.push_back("pet attack");
|
supported.push_back("pet attack");
|
||||||
supported.push_back("wait for attack time");
|
supported.push_back("wait for attack time");
|
||||||
|
|||||||
@ -297,7 +297,7 @@ bool PlayerWantsInBattlegroundTrigger::IsActive()
|
|||||||
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_IN_PROGRESS)
|
if (bot->GetBattleground() && bot->GetBattleground()->GetStatus() == STATUS_IN_PROGRESS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!bot->CanJoinToBattleground())
|
if (bot->IsDeserter())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -180,19 +180,11 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
delete pItem;
|
delete pItem;
|
||||||
|
|
||||||
if (result != EQUIP_ERR_OK && result != EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
if (result != EQUIP_ERR_OK && result != EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
||||||
{
|
|
||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
}
|
|
||||||
// Check is unique items are equipped or not
|
// Check if unique items are equipped or not
|
||||||
bool needToCheckUnique = false;
|
bool needToCheckUnique = result == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS ||
|
||||||
if (result == EQUIP_ERR_CANT_CARRY_MORE_OF_THIS)
|
itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE);
|
||||||
{
|
|
||||||
needToCheckUnique = true;
|
|
||||||
}
|
|
||||||
else if (itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE))
|
|
||||||
{
|
|
||||||
needToCheckUnique = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needToCheckUnique)
|
if (needToCheckUnique)
|
||||||
{
|
{
|
||||||
@ -206,28 +198,27 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
bool isEquipped = (totalItemCount > bagItemCount);
|
bool isEquipped = (totalItemCount > bagItemCount);
|
||||||
|
|
||||||
if (isEquipped)
|
if (isEquipped)
|
||||||
{
|
|
||||||
return ITEM_USAGE_NONE; // Item is already equipped
|
return ITEM_USAGE_NONE; // Item is already equipped
|
||||||
}
|
|
||||||
// If not equipped, continue processing
|
// If not equipped, continue processing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemProto->Class == ITEM_CLASS_QUIVER)
|
if (itemProto->Class == ITEM_CLASS_QUIVER && bot->getClass() != CLASS_HUNTER)
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
return ITEM_USAGE_NONE;
|
||||||
return ITEM_USAGE_NONE;
|
|
||||||
|
|
||||||
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
||||||
{
|
{
|
||||||
if (itemProto->SubClass != ITEM_SUBCLASS_CONTAINER)
|
if (itemProto->SubClass != ITEM_SUBCLASS_CONTAINER)
|
||||||
return ITEM_USAGE_NONE; // Todo add logic for non-bag containers. We want to look at professions/class and
|
return ITEM_USAGE_NONE; // Todo add logic for non-bag containers. We want to look at professions/class and
|
||||||
// only replace if non-bag is larger than bag.
|
// only replace if non-bag is larger than bag.
|
||||||
|
|
||||||
if (GetSmallestBagSize() >= itemProto->ContainerSlots)
|
if (GetSmallestBagSize() >= itemProto->ContainerSlots)
|
||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
|
|
||||||
return ITEM_USAGE_EQUIP;
|
return ITEM_USAGE_EQUIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemProto->Class == ITEM_CLASS_WEAPON && itemProto->SubClass == ITEM_SUBCLASS_WEAPON_MISC)
|
||||||
|
return ITEM_USAGE_NONE;
|
||||||
|
|
||||||
bool shouldEquip = false;
|
bool shouldEquip = false;
|
||||||
// uint32 statWeight = sRandomItemMgr.GetLiveStatWeight(bot, itemProto->ItemId);
|
// uint32 statWeight = sRandomItemMgr.GetLiveStatWeight(bot, itemProto->ItemId);
|
||||||
StatsWeightCalculator calculator(bot);
|
StatsWeightCalculator calculator(bot);
|
||||||
@ -254,19 +245,14 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true);
|
uint8 dstSlot = botAI->FindEquipSlot(itemProto, NULL_SLOT, true);
|
||||||
// Check if dest wasn't set correctly by CanEquipItem and use FindEquipSlot instead
|
// Check if dest wasn't set correctly by CanEquipItem and use FindEquipSlot instead
|
||||||
// This occurs with unique items that are already in the bots bags when CanEquipItem is called
|
// This occurs with unique items that are already in the bots bags when CanEquipItem is called
|
||||||
if (dest == 0)
|
if (dest == 0 && dstSlot != NULL_SLOT)
|
||||||
{
|
{
|
||||||
if (dstSlot != NULL_SLOT)
|
// Construct dest from dstSlot
|
||||||
{
|
dest = (INVENTORY_SLOT_BAG_0 << 8) | dstSlot;
|
||||||
// Construct dest from dstSlot
|
|
||||||
dest = (INVENTORY_SLOT_BAG_0 << 8) | dstSlot;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1)
|
if (dstSlot == EQUIPMENT_SLOT_FINGER1 || dstSlot == EQUIPMENT_SLOT_TRINKET1)
|
||||||
{
|
|
||||||
possibleSlots = 2;
|
possibleSlots = 2;
|
||||||
}
|
|
||||||
|
|
||||||
// Check weapon case separately to keep things a bit cleaner
|
// Check weapon case separately to keep things a bit cleaner
|
||||||
bool have2HWeapon = false;
|
bool have2HWeapon = false;
|
||||||
@ -283,14 +269,9 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
itemProto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD2);
|
||||||
|
|
||||||
// If the bot can Titan Grip, ignore any 2H weapon that isn't a 2H sword, mace, or axe.
|
// If the bot can Titan Grip, ignore any 2H weapon that isn't a 2H sword, mace, or axe.
|
||||||
if (bot->CanTitanGrip())
|
// If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all.
|
||||||
{
|
if (bot->CanTitanGrip() && itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon)
|
||||||
// If this weapon is 2H but not one of the valid TG weapon types, do not equip it at all.
|
return ITEM_USAGE_NONE;
|
||||||
if (itemProto->InventoryType == INVTYPE_2HWEAPON && !isValidTGWeapon)
|
|
||||||
{
|
|
||||||
return ITEM_USAGE_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now handle the logic for equipping and possible offhand slots
|
// Now handle the logic for equipping and possible offhand slots
|
||||||
// If the bot can Dual Wield and:
|
// If the bot can Dual Wield and:
|
||||||
@ -317,9 +298,7 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
if (shouldEquipInSlot)
|
if (shouldEquipInSlot)
|
||||||
return ITEM_USAGE_EQUIP;
|
return ITEM_USAGE_EQUIP;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return ITEM_USAGE_BAD_EQUIP;
|
return ITEM_USAGE_BAD_EQUIP;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTemplate const* oldItemProto = oldItem->GetTemplate();
|
ItemTemplate const* oldItemProto = oldItem->GetTemplate();
|
||||||
@ -328,22 +307,16 @@ ItemUsage ItemUsageValue::QueryItemUsageForEquip(ItemTemplate const* itemProto,
|
|||||||
{
|
{
|
||||||
// uint32 oldStatWeight = sRandomItemMgr.GetLiveStatWeight(bot, oldItemProto->ItemId);
|
// uint32 oldStatWeight = sRandomItemMgr.GetLiveStatWeight(bot, oldItemProto->ItemId);
|
||||||
if (itemScore || oldScore)
|
if (itemScore || oldScore)
|
||||||
{
|
|
||||||
shouldEquipInSlot = itemScore > oldScore * sPlayerbotAIConfig.equipUpgradeThreshold;
|
shouldEquipInSlot = itemScore > oldScore * sPlayerbotAIConfig.equipUpgradeThreshold;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bigger quiver
|
// Bigger quiver
|
||||||
if (itemProto->Class == ITEM_CLASS_QUIVER)
|
if (itemProto->Class == ITEM_CLASS_QUIVER)
|
||||||
{
|
{
|
||||||
if (!oldItem || oldItemProto->ContainerSlots < itemProto->ContainerSlots)
|
if (!oldItem || oldItemProto->ContainerSlots < itemProto->ContainerSlots)
|
||||||
{
|
|
||||||
return ITEM_USAGE_EQUIP;
|
return ITEM_USAGE_EQUIP;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return ITEM_USAGE_NONE;
|
return ITEM_USAGE_NONE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool existingShouldEquip = true;
|
bool existingShouldEquip = true;
|
||||||
|
|||||||
@ -11,6 +11,22 @@
|
|||||||
#include "AoeValues.h"
|
#include "AoeValues.h"
|
||||||
#include "TargetValue.h"
|
#include "TargetValue.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool PrepareThornsTarget(PlayerbotAI* botAI, Unit* target)
|
||||||
|
{
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Aura* existingThorns = botAI->GetAura("thorns", target, true);
|
||||||
|
if (!existingThorns)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
target->RemoveOwnedAura(existingThorns, AURA_REMOVE_BY_CANCEL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<NextAction> CastAbolishPoisonAction::getAlternatives()
|
std::vector<NextAction> CastAbolishPoisonAction::getAlternatives()
|
||||||
{
|
{
|
||||||
return NextAction::merge({ NextAction("cure poison") },
|
return NextAction::merge({ NextAction("cure poison") },
|
||||||
@ -33,6 +49,21 @@ bool CastLifebloomOnMainTankAction::isUseful()
|
|||||||
return !lifebloom || lifebloom->GetStackAmount() < 3 || lifebloom->GetDuration() < 2000;
|
return !lifebloom || lifebloom->GetStackAmount() < 3 || lifebloom->GetDuration() < 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CastThornsAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
return PrepareThornsTarget(botAI, GetTarget()) && CastBuffSpellAction::Execute(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastThornsOnPartyAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
return PrepareThornsTarget(botAI, GetTarget()) && BuffOnPartyAction::Execute(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastThornsOnMainTankAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
return PrepareThornsTarget(botAI, GetTarget()) && BuffOnMainTankAction::Execute(event);
|
||||||
|
}
|
||||||
|
|
||||||
Value<Unit*>* CastEntanglingRootsCcAction::GetTargetValue()
|
Value<Unit*>* CastEntanglingRootsCcAction::GetTargetValue()
|
||||||
{
|
{
|
||||||
return context->GetValue<Unit*>("cc target", "entangling roots");
|
return context->GetValue<Unit*>("cc target", "entangling roots");
|
||||||
|
|||||||
@ -114,18 +114,24 @@ class CastThornsAction : public CastBuffSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastThornsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "thorns") {}
|
CastThornsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "thorns") {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastThornsOnPartyAction : public BuffOnPartyAction
|
class CastThornsOnPartyAction : public BuffOnPartyAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastThornsOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "thorns") {}
|
CastThornsOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "thorns") {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastThornsOnMainTankAction : public BuffOnMainTankAction
|
class CastThornsOnMainTankAction : public BuffOnMainTankAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastThornsOnMainTankAction(PlayerbotAI* botAI) : BuffOnMainTankAction(botAI, "thorns", false) {}
|
CastThornsOnMainTankAction(PlayerbotAI* botAI) : BuffOnMainTankAction(botAI, "thorns", false) {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLifebloomOnMainTankAction : public BuffOnMainTankAction
|
class CastLifebloomOnMainTankAction : public BuffOnMainTankAction
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDAQ20TRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDAQ20TRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDAQ20TRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDAQ20TRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidAq20Triggers.h"
|
#include "RaidAq20Triggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDAQ20STRATEGY_H
|
#ifndef _PLAYERBOT_RAIDAQ20STRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDAQ20STRATEGY_H
|
#define _PLAYERBOT_RAIDAQ20STRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidAq20Strategy : public Strategy
|
class RaidAq20Strategy : public Strategy
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDBWLTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDBWLTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDBWLTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDBWLTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidBwlTriggers.h"
|
#include "RaidBwlTriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDBWLSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDBWLSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDBWLSTRATEGY_H
|
#define _PLAYERBOT_RAIDBWLSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidBwlStrategy : public Strategy
|
class RaidBwlStrategy : public Strategy
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDEOETRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidEoETriggers.h"
|
#include "RaidEoETriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDEOESTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDEOESTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDEOESTRATEGY_H
|
#define _PLAYERBOT_RAIDEOESTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidEoEStrategy : public Strategy
|
class RaidEoEStrategy : public Strategy
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDGRUULSLAIRTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDGRUULSLAIRTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidGruulsLairTriggers.h"
|
#include "RaidGruulsLairTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidGruulsLairTriggerContext : public NamedObjectContext<Trigger>
|
class RaidGruulsLairTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define _PLAYERBOT_RAIDGRUULSLAIRSTRATEGY_H
|
#define _PLAYERBOT_RAIDGRUULSLAIRSTRATEGY_H
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidGruulsLairStrategy : public Strategy
|
class RaidGruulsLairStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDICCTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDICCTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDICCTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDICCTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidIccTriggers.h"
|
#include "RaidIccTriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDICCSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDICCSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDICCSTRATEGY_H
|
#define _PLAYERBOT_RAIDICCSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "RaidIccMultipliers.h"
|
|
||||||
|
|
||||||
class RaidIccStrategy : public Strategy
|
class RaidIccStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDKARAZHANTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidKarazhanTriggers.h"
|
#include "RaidKarazhanTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidKarazhanTriggerContext : public NamedObjectContext<Trigger>
|
class RaidKarazhanTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define _PLAYERBOT_RAIDKARAZHANSTRATEGY_H_
|
#define _PLAYERBOT_RAIDKARAZHANSTRATEGY_H_
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidKarazhanStrategy : public Strategy
|
class RaidKarazhanStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDMAGTHERIDONTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDMAGTHERIDONTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidMagtheridonTriggers.h"
|
#include "RaidMagtheridonTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidMagtheridonTriggerContext : public NamedObjectContext<Trigger>
|
class RaidMagtheridonTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define _PLAYERBOT_RAIDMAGTHERIDONSTRATEGY_H
|
#define _PLAYERBOT_RAIDMAGTHERIDONSTRATEGY_H
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidMagtheridonStrategy : public Strategy
|
class RaidMagtheridonStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "BossAuraTriggers.h"
|
#include "BossAuraTriggers.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidMcTriggers.h"
|
#include "RaidMcTriggers.h"
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDMCSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDMCSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDMCSTRATEGY_H
|
#define _PLAYERBOT_RAIDMCSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidMcStrategy : public Strategy
|
class RaidMcStrategy : public Strategy
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDNAXXTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidNaxxTriggers.h"
|
#include "RaidNaxxTriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDNAXXSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDNAXXSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDNAXXSTRATEGY_H
|
#define _PLAYERBOT_RAIDNAXXSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidNaxxStrategy : public Strategy
|
class RaidNaxxStrategy : public Strategy
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDOSTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidOsTriggers.h"
|
#include "RaidOsTriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDOSSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDOSSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDOSSTRATEGY_H
|
#define _PLAYERBOT_RAIDOSSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidOsStrategy : public Strategy
|
class RaidOsStrategy : public Strategy
|
||||||
|
|||||||
@ -99,8 +99,12 @@ bool RaidOnyxiaMoveToSafeZoneAction::Execute(Event /*event*/)
|
|||||||
if (bot->IsWithinDist2d(bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bestZone->radius))
|
if (bot->IsWithinDist2d(bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bestZone->radius))
|
||||||
return false; // Already safe
|
return false; // Already safe
|
||||||
|
|
||||||
|
// Stop current spell first
|
||||||
|
bot->AttackStop();
|
||||||
|
bot->InterruptNonMeleeSpells(false);
|
||||||
|
|
||||||
// bot->Yell("Moving to Safe Zone!", LANG_UNIVERSAL);
|
// bot->Yell("Moving to Safe Zone!", LANG_UNIVERSAL);
|
||||||
return MoveTo(bot->GetMapId(), bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bot->GetPositionZ(),
|
return MoveTo(bot->GetMapId(), bestZone->pos.GetPositionX(), bestZone->pos.GetPositionY(), bestZone->pos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDONYXIAACTIONS_H_
|
#ifndef _PLAYERBOT_RAIDONYXIAACTIONS_H_
|
||||||
#define _PLAYERBOT_RAIDONYXIAACTIONS_H_
|
#define _PLAYERBOT_RAIDONYXIAACTIONS_H_
|
||||||
|
|
||||||
#include "Action.h"
|
|
||||||
#include "AttackAction.h"
|
#include "AttackAction.h"
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
@ -45,42 +44,45 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<SafeZone> GetSafeZonesForBreath(uint32 spellId)
|
static std::vector<SafeZone> GetSafeZonesForBreath(uint32 spellId)
|
||||||
{
|
{
|
||||||
// Define your safe zone coordinates based on the map
|
// Safe zone coordinates based on the map
|
||||||
// Example assumes Onyxia's lair map coordinates
|
// Assumes Onyxia's lair map coordinates
|
||||||
float z = bot->GetPositionZ(); // Stay at current height
|
|
||||||
|
|
||||||
switch (spellId)
|
switch (spellId)
|
||||||
{
|
{
|
||||||
case 17086: // N to S
|
case 17086: // N to S
|
||||||
case 18351: // S to N
|
case 18351: // S to N
|
||||||
return {SafeZone{Position(-10.0f, -180.0f, z), 5.0f},
|
return {
|
||||||
SafeZone{Position(-20.0f, -250.0f, z), 5.0f}}; // Bottom Safe Zone
|
SafeZone{Position(-10.0f, -180.0f, -87.0f), 5.0f},
|
||||||
|
SafeZone{Position(-20.0f, -250.0f, -88.0f), 5.0f}
|
||||||
|
}; // Bottom Safe Zone
|
||||||
|
|
||||||
case 18576: // E to W
|
case 18576: // E to W
|
||||||
case 18609: // W to E
|
case 18609: // W to E
|
||||||
return {
|
return {
|
||||||
SafeZone{Position(20.0f, -210.0f, z), 5.0f},
|
SafeZone{Position(20.0f, -210.0f, -85.5f), 5.0f},
|
||||||
SafeZone{Position(-75.0f, -210.0f, z), 5.0f},
|
SafeZone{Position(-75.0f, -210.0f, -83.4f), 5.0f},
|
||||||
}; // Left Safe Zone
|
}; // Left Safe Zone
|
||||||
|
|
||||||
case 18564: // SE to NW
|
case 18564: // SE to NW
|
||||||
case 18584: // NW to SE
|
case 18584: // NW to SE
|
||||||
return {
|
return {
|
||||||
SafeZone{Position(-60.0f, -195.0f, z), 5.0f},
|
SafeZone{Position(-60.0f, -195.0f, -85.0f), 5.0f},
|
||||||
SafeZone{Position(10.0f, -240.0f, z), 5.0f},
|
SafeZone{Position(10.0f, -240.0f, -85.9f), 5.0f},
|
||||||
}; // NW Safe Zone
|
}; // NW Safe Zone
|
||||||
|
|
||||||
case 18596: // SW to NE
|
case 18596: // SW to NE
|
||||||
case 18617: // NE to SW
|
case 18617: // NE to SW
|
||||||
return {
|
return {
|
||||||
SafeZone{Position(7.0f, -185.0f, z), 5.0f},
|
SafeZone{Position(7.0f, -185.0f, -86.2f), 5.0f},
|
||||||
SafeZone{Position(-60.0f, -240.0f, z), 5.0f},
|
SafeZone{Position(-60.0f, -240.0f, -85.2f), 5.0f},
|
||||||
}; // NE Safe Zone
|
}; // NE Safe Zone
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return {SafeZone{Position(0.0f, 0.0f, z), 5.0f}}; // Fallback center - shouldn't ever happen
|
return {
|
||||||
|
SafeZone{Position(-40.0f, -214.0f, -86.6f), 5.0f}
|
||||||
|
}; // Fallback center - shouldn't ever happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDONYXIATRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidOnyxiaTriggers.h"
|
#include "RaidOnyxiaTriggers.h"
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
#define _PLAYERBOT_RAIDSSCTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDSSCTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidSSCTriggers.h"
|
#include "RaidSSCTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidSSCTriggerContext : public NamedObjectContext<Trigger>
|
class RaidSSCTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#define _PLAYERBOT_RAIDSSCSTRATEGY_H_
|
#define _PLAYERBOT_RAIDSSCSTRATEGY_H_
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidSSCStrategy : public Strategy
|
class RaidSSCStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#define _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidTempestKeepTriggers.h"
|
#include "RaidTempestKeepTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidTempestKeepTriggerContext : public NamedObjectContext<Trigger>
|
class RaidTempestKeepTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#define _PLAYERBOT_RAIDTEMPESTKEEPSTRATEGY_H_
|
#define _PLAYERBOT_RAIDTEMPESTKEEPSTRATEGY_H_
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidTempestKeepStrategy : public Strategy
|
class RaidTempestKeepStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDULDUARTRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDULDUARTRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDULDUARTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDULDUARTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidUlduarTriggers.h"
|
#include "RaidUlduarTriggers.h"
|
||||||
#include "BossAuraTriggers.h"
|
#include "BossAuraTriggers.h"
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
#ifndef _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
||||||
#define _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
#define _PLAYERBOT_RAIDULDUARSTRATEGY_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class RaidUlduarStrategy : public Strategy
|
class RaidUlduarStrategy : public Strategy
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#ifndef _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
#ifndef _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
||||||
#define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "BossAuraTriggers.h"
|
#include "BossAuraTriggers.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "RaidVoATriggers.h"
|
#include "RaidVoATriggers.h"
|
||||||
|
|||||||
@ -3,10 +3,6 @@
|
|||||||
#define _PLAYERBOT_RAIDVOASTRATEGY_H
|
#define _PLAYERBOT_RAIDVOASTRATEGY_H
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "string"
|
|
||||||
#include "Trigger.h"
|
|
||||||
#include "vector"
|
|
||||||
|
|
||||||
class RaidVoAStrategy : public Strategy
|
class RaidVoAStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
#define _PLAYERBOT_RAIDZULAMANTRIGGERCONTEXT_H
|
#define _PLAYERBOT_RAIDZULAMANTRIGGERCONTEXT_H
|
||||||
|
|
||||||
#include "RaidZulAmanTriggers.h"
|
#include "RaidZulAmanTriggers.h"
|
||||||
#include "AiObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
class RaidZulAmanTriggerContext : public NamedObjectContext<Trigger>
|
class RaidZulAmanTriggerContext : public NamedObjectContext<Trigger>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#define _PLAYERBOT_RAIDZULAMANSTRATEGY_H_
|
#define _PLAYERBOT_RAIDZULAMANSTRATEGY_H_
|
||||||
|
|
||||||
#include "Strategy.h"
|
#include "Strategy.h"
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidZulAmanStrategy : public Strategy
|
class RaidZulAmanStrategy : public Strategy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "AreaDefines.h"
|
||||||
#include "BroadcastHelper.h"
|
#include "BroadcastHelper.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
#include "G3D/Vector2.h"
|
#include "G3D/Vector2.h"
|
||||||
@ -468,10 +469,14 @@ bool NewRpgTravelFlightAction::Execute(Event /*event*/)
|
|||||||
data.inFlight = true;
|
data.inFlight = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Creature* flightMaster = ObjectAccessor::GetCreature(*bot, data.fromFlightMaster);
|
|
||||||
|
if (bot->GetDistance(data.flightMasterPos) > INTERACTION_DISTANCE)
|
||||||
|
return MoveFarTo(data.flightMasterPos);
|
||||||
|
|
||||||
|
Creature* flightMaster = bot->FindNearestCreature(data.flightMasterEntry, INTERACTION_DISTANCE * 3);
|
||||||
if (!flightMaster || !flightMaster->IsAlive())
|
if (!flightMaster || !flightMaster->IsAlive())
|
||||||
{
|
{
|
||||||
botAI->rpgInfo.ChangeToIdle();
|
info.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
||||||
@ -487,7 +492,8 @@ bool NewRpgTravelFlightAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "[New RPG] {} active taxi path {} (from {} to {}) failed", bot->GetName(),
|
LOG_DEBUG("playerbots", "[New RPG] {} active taxi path {} (from {} to {}) failed", bot->GetName(),
|
||||||
flightMaster->GetEntry(), nodes[0], nodes[nodes.size() - 1]);
|
flightMaster->GetEntry(), nodes[0], nodes[nodes.size() - 1]);
|
||||||
botAI->rpgInfo.ChangeToIdle();
|
info.ChangeToIdle();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1027,19 +1027,21 @@ WorldPosition NewRpgBaseAction::SelectRandomCampPos(Player* bot)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgBaseAction::SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, std::vector<uint32>& path)
|
bool NewRpgBaseAction::SelectRandomFlightTaxiNode(uint32& flightMasterEntry, WorldPosition& flightMasterPos, std::vector<uint32>& path)
|
||||||
{
|
{
|
||||||
flightMaster = sTravelMgr.GetNearestFlightMasterGuid(bot);
|
TravelMgr::FlightMasterInfo const* info = sTravelMgr.GetNearestFlightMasterInfo(bot);
|
||||||
if (!flightMaster)
|
if (!info)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<std::vector<uint32>> availablePaths = sTravelMgr.GetOptimalFlightDestinations(bot);
|
std::vector<std::vector<uint32>> availablePaths = sTravelMgr.GetOptimalFlightDestinations(bot);
|
||||||
if (availablePaths.empty())
|
if (availablePaths.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
flightMasterEntry = info->templateEntry;
|
||||||
|
flightMasterPos = info->pos;
|
||||||
path = availablePaths[urand(0, availablePaths.size() - 1)];
|
path = availablePaths[urand(0, availablePaths.size() - 1)];
|
||||||
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random flight taxi node from:{} (node {}) to:{} ({} available)",
|
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random flight taxi node from:{} (node {}) to:{} ({} available)",
|
||||||
bot->GetName(), flightMaster.GetEntry(), path[0], path[path.size() - 1], availablePaths.size());
|
bot->GetName(), flightMasterEntry, path[0], path[path.size() - 1], availablePaths.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,11 +1141,12 @@ bool NewRpgBaseAction::RandomChangeStatus(std::vector<NewRpgStatus> candidateSta
|
|||||||
}
|
}
|
||||||
case RPG_TRAVEL_FLIGHT:
|
case RPG_TRAVEL_FLIGHT:
|
||||||
{
|
{
|
||||||
ObjectGuid flightMaster;
|
uint32 flightMasterEntry = 0;
|
||||||
|
WorldPosition flightMasterPos;
|
||||||
std::vector<uint32> path;
|
std::vector<uint32> path;
|
||||||
if (SelectRandomFlightTaxiNode(flightMaster, path))
|
if (SelectRandomFlightTaxiNode(flightMasterEntry, flightMasterPos, path))
|
||||||
{
|
{
|
||||||
botAI->rpgInfo.ChangeToTravelFlight(flightMaster, path);
|
botAI->rpgInfo.ChangeToTravelFlight(flightMasterEntry, flightMasterPos, path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1220,9 +1223,10 @@ bool NewRpgBaseAction::CheckRpgStatusAvailable(NewRpgStatus status)
|
|||||||
}
|
}
|
||||||
case RPG_TRAVEL_FLIGHT:
|
case RPG_TRAVEL_FLIGHT:
|
||||||
{
|
{
|
||||||
ObjectGuid flightMaster;
|
uint32 flightMasterEntry = 0;
|
||||||
|
WorldPosition flightMasterPos;
|
||||||
std::vector<uint32> path;
|
std::vector<uint32> path;
|
||||||
return SelectRandomFlightTaxiNode(flightMaster, path);
|
return SelectRandomFlightTaxiNode(flightMasterEntry, flightMasterPos, path);
|
||||||
}
|
}
|
||||||
case RPG_OUTDOOR_PVP:
|
case RPG_OUTDOOR_PVP:
|
||||||
{
|
{
|
||||||
|
|||||||
@ -54,7 +54,7 @@ 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 SelectRandomGrindPos(Player* bot);
|
||||||
static WorldPosition SelectRandomCampPos(Player* bot);
|
static WorldPosition SelectRandomCampPos(Player* bot);
|
||||||
bool SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, std::vector<uint32>& path);
|
bool SelectRandomFlightTaxiNode(uint32& flightMasterEntry, WorldPosition& flightMasterPos, std::vector<uint32>& path);
|
||||||
bool RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus);
|
bool RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus);
|
||||||
bool CheckRpgStatusAvailable(NewRpgStatus status);
|
bool CheckRpgStatusAvailable(NewRpgStatus status);
|
||||||
|
|
||||||
|
|||||||
@ -37,11 +37,12 @@ void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
|||||||
data = do_quest;
|
data = do_quest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToTravelFlight(ObjectGuid fromFlightMaster, std::vector<uint32> path)
|
void NewRpgInfo::ChangeToTravelFlight(uint32 flightMasterEntry, WorldPosition flightMasterPos, std::vector<uint32> path)
|
||||||
{
|
{
|
||||||
startT = getMSTime();
|
startT = getMSTime();
|
||||||
TravelFlight flight;
|
TravelFlight flight;
|
||||||
flight.fromFlightMaster = fromFlightMaster;
|
flight.flightMasterEntry = flightMasterEntry;
|
||||||
|
flight.flightMasterPos = flightMasterPos;
|
||||||
flight.path = std::move(path);
|
flight.path = std::move(path);
|
||||||
flight.inFlight = false;
|
flight.inFlight = false;
|
||||||
data = flight;
|
data = flight;
|
||||||
@ -157,7 +158,7 @@ std::string NewRpgInfo::ToString()
|
|||||||
else if constexpr (std::is_same_v<T, TravelFlight>)
|
else if constexpr (std::is_same_v<T, TravelFlight>)
|
||||||
{
|
{
|
||||||
out << "TRAVEL_FLIGHT";
|
out << "TRAVEL_FLIGHT";
|
||||||
out << "\nfromFlightMaster: " << arg.fromFlightMaster.GetEntry();
|
out << "\nflightMasterEntry: " << arg.flightMasterEntry;
|
||||||
out << "\nfromNode: " << arg.path[0];
|
out << "\nfromNode: " << arg.path[0];
|
||||||
out << "\ntoNode: " << arg.path[arg.path.size() - 1];
|
out << "\ntoNode: " << arg.path[arg.path.size() - 1];
|
||||||
out << "\ninFlight: " << arg.inFlight;
|
out << "\ninFlight: " << arg.inFlight;
|
||||||
|
|||||||
@ -49,7 +49,8 @@ struct NewRpgInfo
|
|||||||
// RPG_TRAVEL_FLIGHT
|
// RPG_TRAVEL_FLIGHT
|
||||||
struct TravelFlight
|
struct TravelFlight
|
||||||
{
|
{
|
||||||
ObjectGuid fromFlightMaster{};
|
uint32 flightMasterEntry{0};
|
||||||
|
WorldPosition flightMasterPos{};
|
||||||
std::vector<uint32> path;
|
std::vector<uint32> path;
|
||||||
bool inFlight{false};
|
bool inFlight{false};
|
||||||
};
|
};
|
||||||
@ -96,7 +97,7 @@ struct NewRpgInfo
|
|||||||
void ChangeToWanderNpc();
|
void ChangeToWanderNpc();
|
||||||
void ChangeToWanderRandom();
|
void ChangeToWanderRandom();
|
||||||
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
||||||
void ChangeToTravelFlight(ObjectGuid fromFlightMaster, std::vector<uint32> path);
|
void ChangeToTravelFlight(uint32 flightMasterEntry, WorldPosition flightMasterPos, std::vector<uint32> path);
|
||||||
void ChangeToOutdoorPvp(ObjectGuid::LowType capturePointSpawnId = 0);
|
void ChangeToOutdoorPvp(ObjectGuid::LowType capturePointSpawnId = 0);
|
||||||
void ChangeToRest();
|
void ChangeToRest();
|
||||||
void ChangeToIdle();
|
void ChangeToIdle();
|
||||||
|
|||||||
@ -619,7 +619,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
|
|||||||
else
|
else
|
||||||
password = accountName;
|
password = accountName;
|
||||||
|
|
||||||
AccountMgr::CreateAccount(accountName, password);
|
sAccountMgr->CreateAccount(accountName, password);
|
||||||
|
|
||||||
LOG_DEBUG("playerbots", "Account {} created for random bots", accountName.c_str());
|
LOG_DEBUG("playerbots", "Account {} created for random bots", accountName.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,9 +54,9 @@
|
|||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "UpdateTime.h"
|
#include "UpdateTime.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include "../../../../src/server/scripts/Spells/spell_dk.cpp"
|
|
||||||
|
|
||||||
const int SPELL_TITAN_GRIP = 49152;
|
constexpr uint32 SPELL_TITAN_GRIP = 49152;
|
||||||
|
constexpr uint32 SPELL_DK_FROST_PRESENCE = 48263;
|
||||||
|
|
||||||
std::vector<std::string> PlayerbotAI::dispel_whitelist = {
|
std::vector<std::string> PlayerbotAI::dispel_whitelist = {
|
||||||
"mutating injection",
|
"mutating injection",
|
||||||
|
|||||||
@ -2077,7 +2077,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot)
|
|||||||
|
|
||||||
bot->DurabilityRepairAll(false, 1.0f, false);
|
bot->DurabilityRepairAll(false, 1.0f, false);
|
||||||
bot->SetFullHealth();
|
bot->SetFullHealth();
|
||||||
bot->SetPvP(true);
|
bot->SetPvP(sWorld->IsPvPRealm());
|
||||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||||
factory.Refresh();
|
factory.Refresh();
|
||||||
|
|
||||||
@ -2642,6 +2642,7 @@ void RandomPlayerbotMgr::OnPlayerLogin(Player* player)
|
|||||||
{
|
{
|
||||||
// ObjectGuid::LowType guid = player->GetGUID().GetCounter(); //not used, conditional could be rewritten for
|
// ObjectGuid::LowType guid = player->GetGUID().GetCounter(); //not used, conditional could be rewritten for
|
||||||
// simplicity. line marked for removal.
|
// simplicity. line marked for removal.
|
||||||
|
player->SetPvP(sWorld->IsPvPRealm());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
|
#include "AreaDefines.h"
|
||||||
#include "Creature.h"
|
#include "Creature.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
@ -28,67 +29,60 @@
|
|||||||
|
|
||||||
// Navigation data
|
// Navigation data
|
||||||
|
|
||||||
enum class CityId : uint8
|
struct Capital
|
||||||
{
|
{
|
||||||
STORMWIND,
|
uint32 zoneId;
|
||||||
IRONFORGE,
|
TeamId team;
|
||||||
DARNASSUS,
|
char const* name;
|
||||||
EXODAR,
|
std::vector<uint16> bankers;
|
||||||
ORGRIMMAR,
|
|
||||||
UNDERCITY,
|
|
||||||
THUNDER_BLUFF,
|
|
||||||
SILVERMOON_CITY,
|
|
||||||
SHATTRATH_CITY,
|
|
||||||
DALARAN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<uint16, std::pair<CityId, TeamId>> bankerToCity = {
|
static const std::vector<Capital> capitals = {
|
||||||
{2455, {CityId::STORMWIND, TEAM_ALLIANCE}}, {2456, {CityId::STORMWIND, TEAM_ALLIANCE}}, {2457, {CityId::STORMWIND, TEAM_ALLIANCE}},
|
{ AREA_STORMWIND_CITY, TEAM_ALLIANCE, "Stormwind", {2455, 2456, 2457} },
|
||||||
{2460, {CityId::IRONFORGE, TEAM_ALLIANCE}}, {2461, {CityId::IRONFORGE, TEAM_ALLIANCE}}, {5099, {CityId::IRONFORGE, TEAM_ALLIANCE}},
|
{ AREA_IRONFORGE, TEAM_ALLIANCE, "Ironforge", {2460, 2461, 5099} },
|
||||||
{4155, {CityId::DARNASSUS, TEAM_ALLIANCE}}, {4208, {CityId::DARNASSUS, TEAM_ALLIANCE}}, {4209, {CityId::DARNASSUS, TEAM_ALLIANCE}},
|
{ AREA_DARNASSUS, TEAM_ALLIANCE, "Darnassus", {4155, 4208, 4209} },
|
||||||
{17773, {CityId::EXODAR, TEAM_ALLIANCE}}, {18350, {CityId::EXODAR, TEAM_ALLIANCE}}, {16710, {CityId::EXODAR, TEAM_ALLIANCE}},
|
{ AREA_THE_EXODAR, TEAM_ALLIANCE, "Exodar", {17773, 18350, 16710} },
|
||||||
{3320, {CityId::ORGRIMMAR, TEAM_HORDE}}, {3309, {CityId::ORGRIMMAR, TEAM_HORDE}}, {3318, {CityId::ORGRIMMAR, TEAM_HORDE}},
|
{ AREA_ORGRIMMAR, TEAM_HORDE, "Orgrimmar", {3320, 3309, 3318} },
|
||||||
{4549, {CityId::UNDERCITY, TEAM_HORDE}}, {2459, {CityId::UNDERCITY, TEAM_HORDE}}, {2458, {CityId::UNDERCITY, TEAM_HORDE}}, {4550, {CityId::UNDERCITY, TEAM_HORDE}},
|
{ AREA_UNDERCITY, TEAM_HORDE, "Undercity", {4549, 2459, 2458, 4550} },
|
||||||
{2996, {CityId::THUNDER_BLUFF, TEAM_HORDE}}, {8356, {CityId::THUNDER_BLUFF, TEAM_HORDE}}, {8357, {CityId::THUNDER_BLUFF, TEAM_HORDE}},
|
{ AREA_THUNDER_BLUFF, TEAM_HORDE, "Thunder Bluff", {2996, 8356, 8357} },
|
||||||
{17631, {CityId::SILVERMOON_CITY, TEAM_HORDE}}, {17632, {CityId::SILVERMOON_CITY, TEAM_HORDE}}, {17633, {CityId::SILVERMOON_CITY, TEAM_HORDE}},
|
{ AREA_SILVERMOON_CITY, TEAM_HORDE, "Silvermoon", {17631, 17632, 17633, 16615, 16616, 16617} },
|
||||||
{16615, {CityId::SILVERMOON_CITY, TEAM_HORDE}}, {16616, {CityId::SILVERMOON_CITY, TEAM_HORDE}}, {16617, {CityId::SILVERMOON_CITY, TEAM_HORDE}},
|
{ AREA_SHATTRATH_CITY, TEAM_NEUTRAL, "Shattrath", {19246, 19338, 19034, 19318} },
|
||||||
{19246, {CityId::SHATTRATH_CITY, TEAM_NEUTRAL}}, {19338, {CityId::SHATTRATH_CITY, TEAM_NEUTRAL}},
|
{ AREA_DALARAN, TEAM_NEUTRAL, "Dalaran", {30604, 30605, 30607, 28675, 28676, 28677, 29530} }
|
||||||
{19034, {CityId::SHATTRATH_CITY, TEAM_NEUTRAL}}, {19318, {CityId::SHATTRATH_CITY, TEAM_NEUTRAL}},
|
|
||||||
{30604, {CityId::DALARAN, TEAM_NEUTRAL}}, {30605, {CityId::DALARAN, TEAM_NEUTRAL}}, {30607, {CityId::DALARAN, TEAM_NEUTRAL}},
|
|
||||||
{28675, {CityId::DALARAN, TEAM_NEUTRAL}}, {28676, {CityId::DALARAN, TEAM_NEUTRAL}}, {28677, {CityId::DALARAN, TEAM_NEUTRAL}}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<CityId, std::vector<uint16>> cityToBankers = {
|
static Capital const* FindCapitalByZone(uint32 zoneId)
|
||||||
{CityId::STORMWIND, {2455, 2456, 2457}},
|
|
||||||
{CityId::IRONFORGE, {2460, 2461, 5099}},
|
|
||||||
{CityId::DARNASSUS, {4155, 4208, 4209}},
|
|
||||||
{CityId::EXODAR, {17773, 18350, 16710}},
|
|
||||||
{CityId::ORGRIMMAR, {3320, 3309, 3318}},
|
|
||||||
{CityId::UNDERCITY, {4549, 2459, 2458, 4550}},
|
|
||||||
{CityId::THUNDER_BLUFF, {2996, 8356, 8357}},
|
|
||||||
{CityId::SILVERMOON_CITY, {17631, 17632, 17633, 16615, 16616, 16617}},
|
|
||||||
{CityId::SHATTRATH_CITY, {19246, 19338, 19034, 19318}},
|
|
||||||
{CityId::DALARAN, {30604, 30605, 30607, 28675, 28676, 28677, 29530}}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int GetCityWeight(CityId city)
|
|
||||||
{
|
{
|
||||||
int weight = 0;
|
for (Capital const& capital : capitals)
|
||||||
switch (city)
|
if (capital.zoneId == zoneId)
|
||||||
|
return &capital;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Capital const* FindCapitalByBanker(uint16 bankerEntry)
|
||||||
|
{
|
||||||
|
for (Capital const& capital : capitals)
|
||||||
|
for (uint16 bankerId : capital.bankers)
|
||||||
|
if (bankerId == bankerEntry)
|
||||||
|
return &capital;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetCityWeight(uint32 zoneId)
|
||||||
|
{
|
||||||
|
switch (zoneId)
|
||||||
{
|
{
|
||||||
case CityId::STORMWIND: weight = sPlayerbotAIConfig.weightTeleToStormwind; break;
|
case AREA_STORMWIND_CITY: return sPlayerbotAIConfig.weightTeleToStormwind;
|
||||||
case CityId::IRONFORGE: weight = sPlayerbotAIConfig.weightTeleToIronforge; break;
|
case AREA_IRONFORGE: return sPlayerbotAIConfig.weightTeleToIronforge;
|
||||||
case CityId::DARNASSUS: weight = sPlayerbotAIConfig.weightTeleToDarnassus; break;
|
case AREA_DARNASSUS: return sPlayerbotAIConfig.weightTeleToDarnassus;
|
||||||
case CityId::EXODAR: weight = sPlayerbotAIConfig.weightTeleToExodar; break;
|
case AREA_THE_EXODAR: return sPlayerbotAIConfig.weightTeleToExodar;
|
||||||
case CityId::ORGRIMMAR: weight = sPlayerbotAIConfig.weightTeleToOrgrimmar; break;
|
case AREA_ORGRIMMAR: return sPlayerbotAIConfig.weightTeleToOrgrimmar;
|
||||||
case CityId::UNDERCITY: weight = sPlayerbotAIConfig.weightTeleToUndercity; break;
|
case AREA_UNDERCITY: return sPlayerbotAIConfig.weightTeleToUndercity;
|
||||||
case CityId::THUNDER_BLUFF: weight = sPlayerbotAIConfig.weightTeleToThunderBluff; break;
|
case AREA_THUNDER_BLUFF: return sPlayerbotAIConfig.weightTeleToThunderBluff;
|
||||||
case CityId::SILVERMOON_CITY: weight = sPlayerbotAIConfig.weightTeleToSilvermoonCity; break;
|
case AREA_SILVERMOON_CITY: return sPlayerbotAIConfig.weightTeleToSilvermoonCity;
|
||||||
case CityId::SHATTRATH_CITY: weight = sPlayerbotAIConfig.weightTeleToShattrathCity; break;
|
case AREA_SHATTRATH_CITY: return sPlayerbotAIConfig.weightTeleToShattrathCity;
|
||||||
case CityId::DALARAN: weight = sPlayerbotAIConfig.weightTeleToDalaran; break;
|
case AREA_DALARAN: return sPlayerbotAIConfig.weightTeleToDalaran;
|
||||||
default: weight = 0; break;
|
|
||||||
}
|
}
|
||||||
return weight;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldPosition::WorldPosition(std::string const str)
|
WorldPosition::WorldPosition(std::string const str)
|
||||||
@ -4369,76 +4363,117 @@ void TravelMgr::Init()
|
|||||||
LOG_INFO("playerbots", "Playerbots Taxi graph and destination cache built.");
|
LOG_INFO("playerbots", "Playerbots Taxi graph and destination cache built.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* TravelMgr::GetNearestFlightMaster(Player* bot)
|
TravelMgr::FlightMasterInfo const* TravelMgr::GetNearestFlightMasterInfo(Player* bot) const
|
||||||
{
|
{
|
||||||
std::map<uint32, WorldPosition>& flightMasterCache =
|
auto const& flightMasterCache =
|
||||||
(bot->GetTeamId() == TEAM_ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache;
|
(bot->GetTeamId() == TEAM_ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache;
|
||||||
|
|
||||||
Creature* nearestFlightMaster = nullptr;
|
FlightMasterInfo const* nearest = nullptr;
|
||||||
float nearestDistance = std::numeric_limits<float>::max();
|
float nearestDistance = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
for (auto const& [entry, pos] : flightMasterCache)
|
for (auto const& [dbGuid, info] : flightMasterCache)
|
||||||
{
|
{
|
||||||
if (pos.GetMapId() != bot->GetMapId())
|
if (info.pos.GetMapId() != bot->GetMapId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float distance = bot->GetExactDist2dSq(pos);
|
float distance = bot->GetExactDist2dSq(info.pos);
|
||||||
if (distance > nearestDistance)
|
if (distance < nearestDistance)
|
||||||
continue;
|
|
||||||
|
|
||||||
Creature* flightMaster = ObjectAccessor::GetSpawnedCreatureByDBGUID(bot->GetMapId(), entry);
|
|
||||||
if (flightMaster)
|
|
||||||
{
|
{
|
||||||
nearestDistance = distance;
|
nearestDistance = distance;
|
||||||
nearestFlightMaster = flightMaster;
|
nearest = &info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nearestFlightMaster;
|
return nearest;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectGuid TravelMgr::GetNearestFlightMasterGuid(Player* bot)
|
std::vector<uint32> TravelMgr::GetFlightNodesInZone(uint32 zoneId, TeamId team, uint32 excludeNode) const
|
||||||
{
|
{
|
||||||
Creature* nearestFlightMaster = GetNearestFlightMaster(bot);
|
auto const& cache = (team == TEAM_ALLIANCE) ? allianceFlightMasterCache : hordeFlightMasterCache;
|
||||||
if (!nearestFlightMaster)
|
std::unordered_set<uint32> seen;
|
||||||
return ObjectGuid::Empty;
|
std::vector<uint32> result;
|
||||||
|
for (auto const& [entry, info] : cache)
|
||||||
return nearestFlightMaster->GetGUID();
|
{
|
||||||
|
if (info.zoneId != zoneId || info.taxiNodeId == 0 || info.taxiNodeId == excludeNode)
|
||||||
|
continue;
|
||||||
|
if (seen.insert(info.taxiNodeId).second)
|
||||||
|
result.push_back(info.taxiNodeId);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<uint32>> TravelMgr::GetOptimalFlightDestinations(Player* bot)
|
std::vector<std::vector<uint32>> TravelMgr::GetOptimalFlightDestinations(Player* bot)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<uint32>> validDestinations;
|
std::vector<std::vector<uint32>> validDestinations;
|
||||||
|
|
||||||
Creature* nearestFlightMaster = GetNearestFlightMaster(bot);
|
FlightMasterInfo const* nearestFlightMaster = GetNearestFlightMasterInfo(bot);
|
||||||
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > 500.0f)
|
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster->pos) > 500.0f)
|
||||||
return validDestinations;
|
return validDestinations;
|
||||||
|
|
||||||
uint32 fromNode = sObjectMgr->GetNearestTaxiNode(nearestFlightMaster->GetPositionX(), nearestFlightMaster->GetPositionY(),
|
uint32 fromNode = nearestFlightMaster->taxiNodeId;
|
||||||
nearestFlightMaster->GetPositionZ(), nearestFlightMaster->GetMapId(),
|
|
||||||
bot->GetTeamId());
|
|
||||||
if (!fromNode)
|
if (!fromNode)
|
||||||
return validDestinations;
|
return validDestinations;
|
||||||
|
|
||||||
std::vector<WorldLocation> candidateLocations;
|
TaxiNodesEntry const* startNode = sTaxiNodesStore.LookupEntry(fromNode);
|
||||||
if (bot->GetLevel() >= 10 && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100)
|
if (!startNode)
|
||||||
candidateLocations = GetCityLocations(bot);
|
return validDestinations;
|
||||||
|
|
||||||
std::vector<WorldLocation> hubLocations = GetTravelHubs(bot);
|
uint32 botLevel = bot->GetLevel();
|
||||||
candidateLocations.insert(candidateLocations.end(), hubLocations.begin(), hubLocations.end());
|
|
||||||
|
|
||||||
for (auto const& loc : candidateLocations)
|
// Bots already in a capital shouldn't have another capital picked as a
|
||||||
|
// flight destination — that just shuffles them between cities.
|
||||||
|
bool botInCapital = false;
|
||||||
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetZoneId()))
|
||||||
|
botInCapital = (area->flags & AREA_FLAG_CAPITAL) != 0;
|
||||||
|
|
||||||
|
//Simplify destination delection. Its either target cities (Based on config value) or target world.
|
||||||
|
std::vector<uint32> candidateZones;
|
||||||
|
if (botLevel >= 10 && !botInCapital && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100)
|
||||||
{
|
{
|
||||||
uint32 candidateNode = sObjectMgr->GetNearestTaxiNode(loc.GetPositionX(), loc.GetPositionY(),
|
TeamId botTeam = bot->GetTeamId();
|
||||||
loc.GetPositionZ(), loc.GetMapId(),
|
for (Capital const& capital : capitals)
|
||||||
bot->GetTeamId());
|
{
|
||||||
if (!candidateNode)
|
if (capital.team != TEAM_NEUTRAL && capital.team != botTeam)
|
||||||
continue;
|
continue;
|
||||||
|
candidateZones.push_back(capital.zoneId);
|
||||||
std::vector<uint32> path = sTravelNodeMap.FindTaxiPath(fromNode, candidateNode);
|
}
|
||||||
if (!path.empty())
|
|
||||||
validDestinations.push_back(path);
|
|
||||||
}
|
}
|
||||||
|
if (candidateZones.empty())
|
||||||
|
{
|
||||||
|
for (auto const& [zoneId, bracket] : zone2LevelBracket)
|
||||||
|
{
|
||||||
|
if (botLevel < bracket.low || botLevel > bracket.high)
|
||||||
|
continue;
|
||||||
|
if (GetFlightNodesInZone(zoneId, bot->GetTeamId(), fromNode).empty())
|
||||||
|
continue;
|
||||||
|
candidateZones.push_back(zoneId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateZones.empty())
|
||||||
|
return validDestinations;
|
||||||
|
|
||||||
|
while (!candidateZones.empty())
|
||||||
|
{
|
||||||
|
uint32 zoneIndex = urand(0, candidateZones.size() - 1);
|
||||||
|
uint32 pickedZone = candidateZones[zoneIndex];
|
||||||
|
|
||||||
|
std::vector<uint32> usableNodes = GetFlightNodesInZone(pickedZone, bot->GetTeamId(), fromNode);
|
||||||
|
|
||||||
|
if (!usableNodes.empty())
|
||||||
|
{
|
||||||
|
uint32 pickedNode = usableNodes[urand(0, usableNodes.size() - 1)];
|
||||||
|
std::vector<uint32> path = sTravelNodeMap.FindTaxiPath(fromNode, pickedNode);
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
validDestinations.push_back(std::move(path));
|
||||||
|
return validDestinations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
candidateZones.erase(candidateZones.begin() + zoneIndex);
|
||||||
|
}
|
||||||
|
|
||||||
return validDestinations;
|
return validDestinations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4472,34 +4507,34 @@ std::vector<WorldLocation> TravelMgr::GetCityLocations(Player* bot)
|
|||||||
return fallbackLocations;
|
return fallbackLocations;
|
||||||
|
|
||||||
TeamId botTeamId = bot->GetTeamId();
|
TeamId botTeamId = bot->GetTeamId();
|
||||||
std::unordered_set<CityId> validBankerCities;
|
std::unordered_set<uint32> validBankerCities;
|
||||||
for (auto& loc : bankerLocsPerLevelCache[level])
|
for (auto& loc : bankerLocsPerLevelCache[level])
|
||||||
{
|
{
|
||||||
auto cityIt = bankerToCity.find(loc.entry);
|
Capital const* capital = FindCapitalByBanker(loc.entry);
|
||||||
if (cityIt == bankerToCity.end())
|
if (!capital)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
TeamId cityTeamId = cityIt->second.second;
|
TeamId cityTeamId = capital->team;
|
||||||
|
|
||||||
if (cityTeamId == botTeamId ||
|
if (cityTeamId == botTeamId ||
|
||||||
(cityTeamId == TEAM_NEUTRAL)
|
(cityTeamId == TEAM_NEUTRAL)
|
||||||
)
|
)
|
||||||
validBankerCities.insert(cityIt->second.first);
|
validBankerCities.insert(capital->zoneId);
|
||||||
}
|
}
|
||||||
// Fallback if no valid cities
|
// Fallback if no valid cities
|
||||||
if (validBankerCities.empty())
|
if (validBankerCities.empty())
|
||||||
return fallbackLocations;
|
return fallbackLocations;
|
||||||
|
|
||||||
// Apply weights to valid cities
|
// Apply weights to valid cities
|
||||||
std::vector<CityId> weightedCities;
|
std::vector<uint32> weightedCities;
|
||||||
for (CityId city : validBankerCities)
|
for (uint32 zoneId : validBankerCities)
|
||||||
{
|
{
|
||||||
int weight = GetCityWeight(city);
|
int weight = GetCityWeight(zoneId);
|
||||||
if (weight <= 0)
|
if (weight <= 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int i = 0; i < weight; ++i)
|
for (int i = 0; i < weight; ++i)
|
||||||
weightedCities.push_back(city);
|
weightedCities.push_back(zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback if no valid cities
|
// Fallback if no valid cities
|
||||||
@ -4507,9 +4542,11 @@ std::vector<WorldLocation> TravelMgr::GetCityLocations(Player* bot)
|
|||||||
return fallbackLocations;
|
return fallbackLocations;
|
||||||
|
|
||||||
// Pick a weighted city randomly, then a random banker in that city
|
// Pick a weighted city randomly, then a random banker in that city
|
||||||
CityId selectedCity = weightedCities[urand(0, weightedCities.size() - 1)];
|
uint32 selectedCity = weightedCities[urand(0, weightedCities.size() - 1)];
|
||||||
|
Capital const* selectedCapital = FindCapitalByZone(selectedCity);
|
||||||
auto const& bankers = cityToBankers.at(selectedCity);
|
if (!selectedCapital)
|
||||||
|
return fallbackLocations;
|
||||||
|
auto const& bankers = selectedCapital->bankers;
|
||||||
uint32 selectedBankerEntry = bankers[urand(0, bankers.size() - 1)];
|
uint32 selectedBankerEntry = bankers[urand(0, bankers.size() - 1)];
|
||||||
auto locIt = bankerEntryToLocation.find(selectedBankerEntry);
|
auto locIt = bankerEntryToLocation.find(selectedBankerEntry);
|
||||||
if (locIt != bankerEntryToLocation.end())
|
if (locIt != bankerEntryToLocation.end())
|
||||||
@ -4520,78 +4557,78 @@ std::vector<WorldLocation> TravelMgr::GetCityLocations(Player* bot)
|
|||||||
|
|
||||||
void TravelMgr::PrepareZone2LevelBracket()
|
void TravelMgr::PrepareZone2LevelBracket()
|
||||||
{
|
{
|
||||||
// Classic WoW - Low - level zones
|
// Classic WoW - starter zones
|
||||||
zone2LevelBracket[1] = {5, 12}; // Dun Morogh
|
zone2LevelBracket[AREA_DUN_MOROGH] = {5, 12};
|
||||||
zone2LevelBracket[12] = {5, 12}; // Elwynn Forest
|
zone2LevelBracket[AREA_ELWYNN_FOREST] = {5, 12};
|
||||||
zone2LevelBracket[14] = {5, 12}; // Durotar
|
zone2LevelBracket[AREA_DUROTAR] = {5, 12};
|
||||||
zone2LevelBracket[85] = {5, 12}; // Tirisfal Glades
|
zone2LevelBracket[AREA_TIRISFAL_GLADES] = {5, 12};
|
||||||
zone2LevelBracket[141] = {5, 12}; // Teldrassil
|
zone2LevelBracket[AREA_TELDRASSIL] = {5, 12};
|
||||||
zone2LevelBracket[215] = {5, 12}; // Mulgore
|
zone2LevelBracket[AREA_MULGORE] = {5, 12};
|
||||||
zone2LevelBracket[3430] = {5, 12}; // Eversong Woods
|
zone2LevelBracket[AREA_EVERSONG_WOODS] = {5, 12};
|
||||||
zone2LevelBracket[3524] = {5, 12}; // Azuremyst Isle
|
zone2LevelBracket[AREA_AZUREMYST_ISLE] = {5, 12};
|
||||||
|
|
||||||
// Classic WoW - Mid - level zones
|
// Classic WoW - low level zones
|
||||||
zone2LevelBracket[17] = {10, 25}; // Barrens
|
zone2LevelBracket[AREA_THE_BARRENS] = {10, 25};
|
||||||
zone2LevelBracket[38] = {10, 20}; // Loch Modan
|
zone2LevelBracket[AREA_LOCH_MODAN] = {10, 20};
|
||||||
zone2LevelBracket[40] = {10, 21}; // Westfall
|
zone2LevelBracket[AREA_WESTFALL] = {10, 21};
|
||||||
zone2LevelBracket[130] = {10, 23}; // Silverpine Forest
|
zone2LevelBracket[AREA_SILVERPINE_FOREST] = {10, 23};
|
||||||
zone2LevelBracket[148] = {10, 21}; // Darkshore
|
zone2LevelBracket[AREA_DARKSHORE] = {10, 21};
|
||||||
zone2LevelBracket[3433] = {10, 22}; // Ghostlands
|
zone2LevelBracket[AREA_GHOSTLANDS] = {10, 22};
|
||||||
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
zone2LevelBracket[AREA_BLOODMYST_ISLE] = {10, 21};
|
||||||
|
|
||||||
// Classic WoW - High - level zones
|
// Classic WoW - mid-level zones
|
||||||
zone2LevelBracket[10] = {19, 33}; // Deadwind Pass
|
zone2LevelBracket[AREA_DUSKWOOD] = {19, 33};
|
||||||
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
zone2LevelBracket[AREA_WETLANDS] = {21, 30};
|
||||||
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
zone2LevelBracket[AREA_REDRIDGE_MOUNTAINS] = {16, 28};
|
||||||
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
zone2LevelBracket[AREA_HILLSBRAD_FOOTHILLS] = {20, 34};
|
||||||
zone2LevelBracket[331] = {18, 33}; // Ashenvale
|
zone2LevelBracket[AREA_ASHENVALE] = {18, 33};
|
||||||
zone2LevelBracket[400] = {24, 36}; // Thousand Needles
|
zone2LevelBracket[AREA_THOUSAND_NEEDLES] = {24, 36};
|
||||||
zone2LevelBracket[406] = {16, 29}; // Stonetalon Mountains
|
zone2LevelBracket[AREA_STONETALON_MOUNTAINS] = {16, 29};
|
||||||
|
|
||||||
// Classic WoW - Higher - level zones
|
// Classic WoW - 30-52 zones
|
||||||
zone2LevelBracket[3] = {36, 46}; // Badlands
|
zone2LevelBracket[AREA_BADLANDS] = {36, 46};
|
||||||
zone2LevelBracket[8] = {36, 46}; // Swamp of Sorrows
|
zone2LevelBracket[AREA_SWAMP_OF_SORROWS] = {36, 46};
|
||||||
zone2LevelBracket[15] = {35, 46}; // Dustwallow Marsh
|
zone2LevelBracket[AREA_DUSTWALLOW_MARSH] = {35, 46};
|
||||||
zone2LevelBracket[16] = {45, 52}; // Azshara
|
zone2LevelBracket[AREA_AZSHARA] = {45, 52};
|
||||||
zone2LevelBracket[33] = {32, 47}; // Stranglethorn Vale
|
zone2LevelBracket[AREA_STRANGLETHORN_VALE] = {32, 47};
|
||||||
zone2LevelBracket[45] = {30, 42}; // Arathi Highlands
|
zone2LevelBracket[AREA_ARATHI_HIGHLANDS] = {30, 42};
|
||||||
zone2LevelBracket[47] = {42, 51}; // Hinterlands
|
zone2LevelBracket[AREA_THE_HINTERLANDS] = {42, 51};
|
||||||
zone2LevelBracket[51] = {45, 51}; // Searing Gorge
|
zone2LevelBracket[AREA_SEARING_GORGE] = {45, 51};
|
||||||
zone2LevelBracket[357] = {40, 52}; // Feralas
|
zone2LevelBracket[AREA_FERALAS] = {40, 52};
|
||||||
zone2LevelBracket[405] = {30, 41}; // Desolace
|
zone2LevelBracket[AREA_DESOLACE] = {30, 41};
|
||||||
zone2LevelBracket[440] = {41, 52}; // Tanaris
|
zone2LevelBracket[AREA_TANARIS] = {41, 52};
|
||||||
|
|
||||||
// Classic WoW - Top - level zones
|
// Classic WoW - top level zones
|
||||||
zone2LevelBracket[4] = {52, 57}; // Blasted Lands
|
zone2LevelBracket[AREA_BLASTED_LANDS] = {52, 57};
|
||||||
zone2LevelBracket[28] = {50, 60}; // Western Plaguelands
|
zone2LevelBracket[AREA_WESTERN_PLAGUELANDS] = {50, 60};
|
||||||
zone2LevelBracket[46] = {51, 60}; // Burning Steppes
|
zone2LevelBracket[AREA_BURNING_STEPPES] = {51, 60};
|
||||||
zone2LevelBracket[139] = {54, 62}; // Eastern Plaguelands
|
zone2LevelBracket[AREA_EASTERN_PLAGUELANDS] = {54, 62};
|
||||||
zone2LevelBracket[361] = {47, 57}; // Felwood
|
zone2LevelBracket[361] = {47, 57}; // Felwood (no AREA_ define)
|
||||||
zone2LevelBracket[490] = {49, 56}; // Un'Goro Crater
|
zone2LevelBracket[490] = {49, 56}; // Un'Goro Crater (no AREA_ define)
|
||||||
zone2LevelBracket[618] = {54, 61}; // Winterspring
|
zone2LevelBracket[AREA_WINTERSPRING] = {54, 61};
|
||||||
zone2LevelBracket[1377] = {54, 63}; // Silithus
|
zone2LevelBracket[AREA_SILITHUS] = {54, 63};
|
||||||
|
|
||||||
// The Burning Crusade - Zones
|
// The Burning Crusade zones
|
||||||
zone2LevelBracket[3483] = {58, 66}; // Hellfire Peninsula
|
zone2LevelBracket[AREA_HELLFIRE_PENINSULA] = {58, 66};
|
||||||
zone2LevelBracket[3518] = {64, 70}; // Nagrand
|
zone2LevelBracket[AREA_NAGRAND] = {64, 70};
|
||||||
zone2LevelBracket[3519] = {62, 73}; // Terokkar Forest
|
zone2LevelBracket[AREA_TEROKKAR_FOREST] = {62, 73};
|
||||||
zone2LevelBracket[3520] = {66, 73}; // Shadowmoon Valley
|
zone2LevelBracket[AREA_SHADOWMOON_VALLEY] = {66, 73};
|
||||||
zone2LevelBracket[3521] = {60, 67}; // Zangarmarsh
|
zone2LevelBracket[AREA_ZANGARMARSH] = {60, 67};
|
||||||
zone2LevelBracket[3522] = {64, 73}; // Blade's Edge Mountains
|
zone2LevelBracket[AREA_BLADES_EDGE_MOUNTAINS] = {64, 73};
|
||||||
zone2LevelBracket[3523] = {67, 73}; // Netherstorm
|
zone2LevelBracket[AREA_NETHERSTORM] = {67, 73};
|
||||||
zone2LevelBracket[4080] = {68, 73}; // Isle of Quel'Danas
|
zone2LevelBracket[AREA_ISLE_OF_QUEL_DANAS] = {68, 73};
|
||||||
|
|
||||||
// Wrath of the Lich King - Zones
|
// Wrath of the Lich King zones
|
||||||
zone2LevelBracket[65] = {71, 77}; // Dragonblight
|
zone2LevelBracket[AREA_DRAGONBLIGHT] = {71, 77};
|
||||||
zone2LevelBracket[66] = {74, 80}; // Zul'Drak
|
zone2LevelBracket[AREA_ZUL_DRAK] = {74, 80};
|
||||||
zone2LevelBracket[67] = {77, 80}; // Storm Peaks
|
zone2LevelBracket[AREA_THE_STORM_PEAKS] = {77, 80};
|
||||||
zone2LevelBracket[210] = {77, 80}; // Icecrown Glacier
|
zone2LevelBracket[210] = {77, 80}; // Icecrown Glacier (no AREA_ define)
|
||||||
zone2LevelBracket[394] = {72, 78}; // Grizzly Hills
|
zone2LevelBracket[AREA_GRIZZLY_HILLS] = {72, 78};
|
||||||
zone2LevelBracket[495] = {68, 74}; // Howling Fjord
|
zone2LevelBracket[AREA_HOWLING_FJORD] = {68, 74};
|
||||||
zone2LevelBracket[2817] = {77, 80}; // Crystalsong Forest
|
zone2LevelBracket[AREA_CRYSTALSONG_FOREST] = {77, 80};
|
||||||
zone2LevelBracket[3537] = {68, 75}; // Borean Tundra
|
zone2LevelBracket[AREA_BOREAN_TUNDRA] = {68, 75};
|
||||||
zone2LevelBracket[3711] = {75, 80}; // Sholazar Basin
|
zone2LevelBracket[AREA_SHOLAZAR_BASIN] = {75, 80};
|
||||||
zone2LevelBracket[4197] = {79, 80}; // Wintergrasp
|
zone2LevelBracket[AREA_WINTERGRASP] = {79, 80};
|
||||||
|
|
||||||
// Override with values from config
|
// Override with values from config
|
||||||
for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig.zoneBrackets)
|
for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig.zoneBrackets)
|
||||||
@ -4650,13 +4687,15 @@ void TravelMgr::PrepareDestinationCache()
|
|||||||
(creatureTemplate->unit_flags & 4096) == 0 &&
|
(creatureTemplate->unit_flags & 4096) == 0 &&
|
||||||
creatureTemplate->rank == 0)
|
creatureTemplate->rank == 0)
|
||||||
{
|
{
|
||||||
uint32 roundX = (x / 50.0f) * 10.0f;
|
uint32 roundX = static_cast<uint32>(std::round(x / 50.0f));
|
||||||
uint32 roundY = (y / 50.0f) * 10.0f;
|
uint32 roundY = static_cast<uint32>(std::round(y / 50.0f));
|
||||||
uint32 roundZ = (z / 50.0f) * 10.0f;
|
uint32 roundZ = static_cast<uint32>(std::round(z / 50.0f));
|
||||||
tempLocsCache[std::make_tuple(mapId, roundX, roundY, roundZ)].push_back(creatureData);
|
tempLocsCache[std::make_tuple(mapId, roundX, roundY, roundZ)].push_back(creatureData);
|
||||||
tempCreatureCache[templateEntry][areaId].push_back(WorldLocation(mapId, x, y, z));
|
tempCreatureCache[templateEntry][areaId].push_back(WorldLocation(mapId, x, y, z));
|
||||||
}
|
}
|
||||||
// FLIGHT MASTERS
|
// FLIGHT MASTERS
|
||||||
|
// Entry 29480 is Grimwing (Storm Peaks)
|
||||||
|
// Entry 3838 is Vesprystus in Rut'Theran. Need Travel Node system to resolve this one.
|
||||||
else if ((creatureTemplate->npcflag & UNIT_NPC_FLAG_FLIGHTMASTER ||
|
else if ((creatureTemplate->npcflag & UNIT_NPC_FLAG_FLIGHTMASTER ||
|
||||||
creatureTemplate->npcflag & UNIT_NPC_FLAG_INNKEEPER) &&
|
creatureTemplate->npcflag & UNIT_NPC_FLAG_INNKEEPER) &&
|
||||||
creatureTemplate->Entry != 3838 && creatureTemplate->Entry != 29480)
|
creatureTemplate->Entry != 3838 && creatureTemplate->Entry != 29480)
|
||||||
@ -4669,23 +4708,39 @@ void TravelMgr::PrepareDestinationCache()
|
|||||||
{
|
{
|
||||||
WorldPosition pos(mapId, x, y, z, orient);
|
WorldPosition pos(mapId, x, y, z, orient);
|
||||||
if (forHorde)
|
if (forHorde)
|
||||||
hordeFlightMasterCache[guid] = pos;
|
{
|
||||||
|
FlightMasterInfo info;
|
||||||
|
info.pos = pos;
|
||||||
|
info.zoneId = areaId;
|
||||||
|
info.taxiNodeId = sObjectMgr->GetNearestTaxiNode(x, y, z, mapId, TEAM_HORDE);
|
||||||
|
info.templateEntry = templateEntry;
|
||||||
|
info.dbGuid = guid;
|
||||||
|
hordeFlightMasterCache[guid] = info;
|
||||||
|
}
|
||||||
|
|
||||||
if (forAlliance)
|
if (forAlliance)
|
||||||
allianceFlightMasterCache[guid] = pos;
|
{
|
||||||
|
FlightMasterInfo info;
|
||||||
|
info.pos = pos;
|
||||||
|
info.zoneId = areaId;
|
||||||
|
info.taxiNodeId = sObjectMgr->GetNearestTaxiNode(x, y, z, mapId, TEAM_ALLIANCE);
|
||||||
|
info.templateEntry = templateEntry;
|
||||||
|
info.dbGuid = guid;
|
||||||
|
allianceFlightMasterCache[guid] = info;
|
||||||
|
}
|
||||||
flightMastersCount++;
|
flightMastersCount++;
|
||||||
|
|
||||||
// Zones that have flight masters but no innkeepers — use flight master as hub
|
// Zones that have flight masters but no innkeepers — use flight master as hub
|
||||||
static const std::set<uint32> zonesWithoutInnkeeper = {
|
static const std::set<uint32> zonesWithoutInnkeeper = {
|
||||||
4, // Blasted Lands (52-57)
|
AREA_BLASTED_LANDS,
|
||||||
16, // Azshara (45-52)
|
AREA_AZSHARA,
|
||||||
28, // Western Plaguelands (50-60)
|
AREA_WESTERN_PLAGUELANDS,
|
||||||
46, // Burning Steppes (51-60)
|
AREA_BURNING_STEPPES,
|
||||||
51, // Searing Gorge (45-51)
|
AREA_SEARING_GORGE,
|
||||||
361, // Felwood (47-57)
|
361, // Felwood (47-57)
|
||||||
490, // Un'Goro Crater (49-56)
|
490, // Un'Goro Crater (49-56)
|
||||||
2817, // Crystalsong Forest (77-80)
|
AREA_CRYSTALSONG_FOREST,
|
||||||
4197 // Wintergrasp (79-80)
|
AREA_WINTERGRASP
|
||||||
};
|
};
|
||||||
if (zonesWithoutInnkeeper.count(areaId))
|
if (zonesWithoutInnkeeper.count(areaId))
|
||||||
{
|
{
|
||||||
@ -4756,7 +4811,7 @@ void TravelMgr::PrepareDestinationCache()
|
|||||||
// Process temporary caches
|
// Process temporary caches
|
||||||
for (auto const& [gridTuple, creatureDataList] : tempLocsCache)
|
for (auto const& [gridTuple, creatureDataList] : tempLocsCache)
|
||||||
{
|
{
|
||||||
if (creatureDataList.size() > 2)
|
if (creatureDataList.size() >= 2)
|
||||||
{
|
{
|
||||||
CreatureTemplate const* creatureTemplate = sObjectMgr->GetCreatureTemplate(creatureDataList[0].id1);
|
CreatureTemplate const* creatureTemplate = sObjectMgr->GetCreatureTemplate(creatureDataList[0].id1);
|
||||||
uint32 level = (creatureTemplate->minlevel + creatureTemplate->maxlevel + 1) / 2;
|
uint32 level = (creatureTemplate->minlevel + creatureTemplate->maxlevel + 1) / 2;
|
||||||
|
|||||||
@ -846,6 +846,21 @@ protected:
|
|||||||
class TravelMgr
|
class TravelMgr
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct NpcLocation
|
||||||
|
{
|
||||||
|
WorldLocation loc;
|
||||||
|
uint32 entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FlightMasterInfo
|
||||||
|
{
|
||||||
|
WorldPosition pos;
|
||||||
|
uint32 zoneId; // resolved once at cache load
|
||||||
|
uint32 taxiNodeId; // DBC taxi node nearest to this flight master
|
||||||
|
uint32 templateEntry; // creature template ID (for ObjectGuid construction)
|
||||||
|
uint32 dbGuid; // DB spawn GUID (for ObjectGuid construction)
|
||||||
|
};
|
||||||
|
|
||||||
static TravelMgr& instance()
|
static TravelMgr& instance()
|
||||||
{
|
{
|
||||||
static TravelMgr instance;
|
static TravelMgr instance;
|
||||||
@ -858,12 +873,14 @@ public:
|
|||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
void Init();
|
void Init();
|
||||||
Creature* GetNearestFlightMaster(Player* bot);
|
|
||||||
ObjectGuid GetNearestFlightMasterGuid(Player* bot);
|
FlightMasterInfo const* GetNearestFlightMasterInfo(Player* bot) const;
|
||||||
std::vector<std::vector<uint32>> GetOptimalFlightDestinations(Player* bot);
|
std::vector<std::vector<uint32>> GetOptimalFlightDestinations(Player* bot);
|
||||||
const std::vector<WorldLocation> GetTeleportLocations(Player* bot);
|
const std::vector<WorldLocation> GetTeleportLocations(Player* bot);
|
||||||
const std::vector<WorldLocation> GetTravelHubs(Player* bot);
|
const std::vector<WorldLocation> GetTravelHubs(Player* bot);
|
||||||
std::vector<WorldLocation> GetCityLocations(Player* bot);
|
std::vector<WorldLocation> GetCityLocations(Player* bot);
|
||||||
|
std::vector<uint32> GetFlightNodesInZone(uint32 zoneId, TeamId team, uint32 excludeNode = 0) const;
|
||||||
|
bool SelectAuctioneerByMap(Player* bot, NpcLocation& outAuctioneer);
|
||||||
const std::vector<WorldLocation>& GetLocsPerLevelCache(uint8 level) { return locsPerLevelCache[level]; }
|
const std::vector<WorldLocation>& GetLocsPerLevelCache(uint8 level) { return locsPerLevelCache[level]; }
|
||||||
|
|
||||||
template <class D, class W, class URBG>
|
template <class D, class W, class URBG>
|
||||||
@ -975,8 +992,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Navigation caches
|
// Navigation caches
|
||||||
std::map<uint32, WorldPosition> allianceFlightMasterCache;
|
std::map<uint32, FlightMasterInfo> allianceFlightMasterCache;
|
||||||
std::map<uint32, WorldPosition> hordeFlightMasterCache;
|
std::map<uint32, FlightMasterInfo> hordeFlightMasterCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> allianceHubsPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> allianceHubsPerLevelCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> hordeHubsPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> hordeHubsPerLevelCache;
|
||||||
std::map<uint8, std::vector<BankerLocation>> bankerLocsPerLevelCache;
|
std::map<uint8, std::vector<BankerLocation>> bankerLocsPerLevelCache;
|
||||||
|
|||||||
@ -2467,7 +2467,7 @@ std::vector<uint32> TravelNodeMap::FindTaxiPath(uint32 fromNode, uint32 toNode)
|
|||||||
TaxiNodesEntry const* startNode = sTaxiNodesStore.LookupEntry(fromNode);
|
TaxiNodesEntry const* startNode = sTaxiNodesStore.LookupEntry(fromNode);
|
||||||
TaxiNodesEntry const* endNode = sTaxiNodesStore.LookupEntry(toNode);
|
TaxiNodesEntry const* endNode = sTaxiNodesStore.LookupEntry(toNode);
|
||||||
|
|
||||||
if (!startNode || !endNode || startNode->map_id != endNode->map_id)
|
if (!startNode || !endNode)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto cacheItr = taxiPathCache.find(fromNode);
|
auto cacheItr = taxiPathCache.find(fromNode);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user