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