mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
RPG update travel flight status (#1445)
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
# ACTIVITIES
|
# ACTIVITIES
|
||||||
# SPELLS
|
# SPELLS
|
||||||
# STRATEGIES
|
# STRATEGIES
|
||||||
|
# RPG STRATEGY
|
||||||
# TELEPORTS
|
# TELEPORTS
|
||||||
# BATTLEGROUND & ARENA & PVP
|
# BATTLEGROUND & ARENA & PVP
|
||||||
# INTERVALS
|
# INTERVALS
|
||||||
@@ -756,11 +757,6 @@ AiPlayerbot.RandomBotGroupNearby = 0
|
|||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AutoDoQuests = 1
|
AiPlayerbot.AutoDoQuests = 1
|
||||||
|
|
||||||
# Randombots will behave more like real players (experimental)
|
|
||||||
# This option will override AiPlayerbot.AutoDoQuests, RandomBotTeleLowerLevel, and RandomBotTeleHigherLevel
|
|
||||||
# Default: 1 (enabled)
|
|
||||||
AiPlayerbot.EnableNewRpgStrategy = 1
|
|
||||||
|
|
||||||
# Quest items to keep in bots' inventories (do not destroy)
|
# Quest items to keep in bots' inventories (do not destroy)
|
||||||
AiPlayerbot.RandomBotQuestItems = "5175,5176,5177,5178,6948,11000,12382,13704,16309"
|
AiPlayerbot.RandomBotQuestItems = "5175,5176,5177,5178,6948,11000,12382,13704,16309"
|
||||||
|
|
||||||
@@ -818,36 +814,34 @@ AiPlayerbot.NonCombatStrategies = ""
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# TELEPORTS
|
# RPG STRATEGY
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
# Maps where bots can be teleported to
|
# Randombots will behave more like real players (experimental)
|
||||||
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
# This option will override AiPlayerbot.AutoDoQuests, RandomBotTeleLowerLevel, and RandomBotTeleHigherLevel
|
||||||
|
|
||||||
# Probabilty bots teleport to banker (city)
|
|
||||||
# Default: 0.25
|
|
||||||
AiPlayerbot.ProbTeleToBankers = 0.25
|
|
||||||
|
|
||||||
# How far randombots are teleported after death
|
|
||||||
AiPlayerbot.RandomBotTeleportDistance = 100
|
|
||||||
|
|
||||||
# How many levels below the lowest-level creature in a zone, can a bot be
|
|
||||||
# This will have no effect if AiPlayerbot.EnableNewRpgStrategy is enabled
|
|
||||||
# Default: 1 (randombot will leave if they are more than 1 level lower)
|
|
||||||
AiPlayerbot.RandomBotTeleLowerLevel = 1
|
|
||||||
|
|
||||||
# How many levels above the highest-level creature in a zone, can a bot be
|
|
||||||
# This will have no effect if AiPlayerbot.EnableNewRpgStrategy is enabled
|
|
||||||
# Default: 3 (randombot will leave if they are more than 3 levels higher)
|
|
||||||
AiPlayerbot.RandomBotTeleHigherLevel = 3
|
|
||||||
|
|
||||||
# Bots automatically teleport to another place for leveling on levelup
|
|
||||||
# Default: 1 (enabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.AutoTeleportForLevel = 1
|
AiPlayerbot.EnableNewRpgStrategy = 1
|
||||||
|
|
||||||
|
# Control probability weights for RPG status of bots. Takes effect only when the status meets its premise.
|
||||||
|
# Sum of weights need not be 100. Set to 0 to disable the status.
|
||||||
|
#
|
||||||
|
# WanderRandom (Default: 15 Move randomly nearby to find and kill mobs)
|
||||||
|
# WanderNpc (Default: 20 Randomly interact with nearby NPCs)
|
||||||
|
# GoGrind (Default: 15 Go to nearby level-appropriate locations to grind for killing mobs)
|
||||||
|
# GoCamp (Default: 10 Return to a nearby camp depending on innkeeper/flightmaster)
|
||||||
|
# DoQuest (Default: 60 Select quest from the quest log and head to the location to attempt completion)
|
||||||
|
# TravelFlight (Default: 15 Go to the nearest flightmaster and fly to a level-appropriate area)
|
||||||
|
# Rest (Default: 5 Take a break for a while and do nothing)
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.WanderRandom = 15
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.WanderNpc = 20
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.GoGrind = 15
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.GoCamp = 10
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.DoQuest = 60
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.TravelFlight = 15
|
||||||
|
AiPlayerbot.RpgStatusProbWeight.Rest = 5
|
||||||
|
|
||||||
# Bots' minimum and maximum level when teleporting in and out of a zone, according to the new RPG strategy
|
# Bots' minimum and maximum level when teleporting in and out of a zone, according to the new RPG strategy
|
||||||
# Requires EnableNewRpgStrategy enabled
|
|
||||||
# Format: AiPlayerbot.ZoneBracket.zoneID = minLevel,maxLevel
|
# Format: AiPlayerbot.ZoneBracket.zoneID = minLevel,maxLevel
|
||||||
#
|
#
|
||||||
# Classic WoW - Low-level zones:
|
# Classic WoW - Low-level zones:
|
||||||
@@ -987,6 +981,40 @@ AiPlayerbot.ZoneBracket.4197 = 79,80
|
|||||||
#
|
#
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
# TELEPORTS
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
# Maps where bots can be teleported to
|
||||||
|
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
||||||
|
|
||||||
|
# Probabilty bots teleport to banker (city)
|
||||||
|
# Default: 0.25
|
||||||
|
AiPlayerbot.ProbTeleToBankers = 0.25
|
||||||
|
|
||||||
|
# How far randombots are teleported after death
|
||||||
|
AiPlayerbot.RandomBotTeleportDistance = 100
|
||||||
|
|
||||||
|
# How many levels below the lowest-level creature in a zone, can a bot be
|
||||||
|
# This will have no effect if AiPlayerbot.EnableNewRpgStrategy is enabled
|
||||||
|
# Default: 1 (randombot will leave if they are more than 1 level lower)
|
||||||
|
AiPlayerbot.RandomBotTeleLowerLevel = 1
|
||||||
|
|
||||||
|
# How many levels above the highest-level creature in a zone, can a bot be
|
||||||
|
# This will have no effect if AiPlayerbot.EnableNewRpgStrategy is enabled
|
||||||
|
# Default: 3 (randombot will leave if they are more than 3 levels higher)
|
||||||
|
AiPlayerbot.RandomBotTeleHigherLevel = 3
|
||||||
|
|
||||||
|
# Bots automatically teleport to another place for leveling on levelup
|
||||||
|
# Default: 1 (enabled)
|
||||||
|
AiPlayerbot.AutoTeleportForLevel = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
####################################################################################################
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# BATTLEGROUNDS & ARENAS & PVP
|
# BATTLEGROUNDS & ARENAS & PVP
|
||||||
#
|
#
|
||||||
@@ -1066,7 +1094,7 @@ AiPlayerbot.RandomBotArenaTeamMinRating = 1000
|
|||||||
AiPlayerbot.DeleteRandomBotArenaTeams = 0
|
AiPlayerbot.DeleteRandomBotArenaTeams = 0
|
||||||
|
|
||||||
# PvP Restricted Zones (bots don't pvp)
|
# PvP Restricted Zones (bots don't pvp)
|
||||||
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,139"
|
AiPlayerbot.PvpProhibitedZoneIds = "2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,139,3951"
|
||||||
|
|
||||||
# PvP Restricted Areas (bots don't pvp)
|
# PvP Restricted Areas (bots don't pvp)
|
||||||
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080"
|
AiPlayerbot.PvpProhibitedAreaIds = "976,35,392,2268,4161,4010,4317,4312,3649,3887,3958,3724,4080"
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
|||||||
masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share");
|
masterIncomingPacketHandlers.AddHandler(CMSG_PUSHQUESTTOPARTY, "quest share");
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_COMPLETE, "quest update complete");
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_KILL, "quest update add kill");
|
||||||
// botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item"); // SMSG_QUESTUPDATE_ADD_ITEM no longer used
|
// SMSG_QUESTUPDATE_ADD_ITEM no longer used
|
||||||
|
// botOutgoingPacketHandlers.AddHandler(SMSG_QUESTUPDATE_ADD_ITEM, "quest update add item");
|
||||||
botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest");
|
botOutgoingPacketHandlers.AddHandler(SMSG_QUEST_CONFIRM_ACCEPT, "confirm quest");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1291,11 +1292,6 @@ void PlayerbotAI::DoNextAction(bool min)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot->HasUnitState(UNIT_STATE_IN_FLIGHT))
|
|
||||||
{
|
|
||||||
SetNextCheckDelay(sPlayerbotAIConfig->passiveDelay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change engine if just died
|
// Change engine if just died
|
||||||
bool isBotAlive = bot->IsAlive();
|
bool isBotAlive = bot->IsAlive();
|
||||||
@@ -2358,7 +2354,6 @@ std::string PlayerbotAI::GetLocalizedCreatureName(uint32 entry)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string PlayerbotAI::GetLocalizedGameObjectName(uint32 entry)
|
std::string PlayerbotAI::GetLocalizedGameObjectName(uint32 entry)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -3330,7 +3325,8 @@ bool PlayerbotAI::CastSpell(uint32 spellId, Unit* target, Item* itemTarget)
|
|||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Spell cast failed - ";
|
out << "Spell cast failed - ";
|
||||||
out << "Spell ID: " << spellId << " (" << ChatHelper::FormatSpell(spellInfo) << "), ";
|
out << "Spell ID: " << spellId << " (" << ChatHelper::FormatSpell(spellInfo) << "), ";
|
||||||
out << "Error Code: " << static_cast<int>(result) << " (0x" << std::hex << static_cast<int>(result) << std::dec << "), ";
|
out << "Error Code: " << static_cast<int>(result) << " (0x" << std::hex << static_cast<int>(result)
|
||||||
|
<< std::dec << "), ";
|
||||||
out << "Bot: " << bot->GetName() << ", ";
|
out << "Bot: " << bot->GetName() << ", ";
|
||||||
|
|
||||||
// Check spell target type
|
// Check spell target type
|
||||||
@@ -4312,7 +4308,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
if (!player || !player->IsInWorld())
|
if (!player || !player->IsInWorld())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Player* connectedPlayer = ObjectAccessor::FindPlayer(player->GetGUID());
|
Player* connectedPlayer = ObjectAccessor::FindPlayer(player->GetGUID());
|
||||||
if (!connectedPlayer)
|
if (!connectedPlayer)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -4434,38 +4430,38 @@ void PlayerbotAI::RemoveShapeshift()
|
|||||||
// https://wowpedia.fandom.com/wiki/API_GetAverageItemLevel
|
// https://wowpedia.fandom.com/wiki/API_GetAverageItemLevel
|
||||||
uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
||||||
{
|
{
|
||||||
constexpr uint8 TOTAL_SLOTS = 17; // every slot except Body & Tabard
|
constexpr uint8 TOTAL_SLOTS = 17; // every slot except Body & Tabard
|
||||||
uint32 sumLevel = 0;
|
uint32 sumLevel = 0;
|
||||||
|
|
||||||
/* ---------- 0. Detect “ignore off-hand” situations --------- */
|
/* ---------- 0. Detect “ignore off-hand” situations --------- */
|
||||||
Item* main = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
Item* main = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||||
Item* off = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
Item* off = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||||
|
|
||||||
bool ignoreOffhand = false; // true → divisor = 16
|
bool ignoreOffhand = false; // true → divisor = 16
|
||||||
if (main)
|
if (main)
|
||||||
{
|
{
|
||||||
bool twoHand = (main->GetTemplate()->InventoryType == INVTYPE_2HWEAPON);
|
bool twoHand = (main->GetTemplate()->InventoryType == INVTYPE_2HWEAPON);
|
||||||
if (twoHand && !player->HasAura(SPELL_TITAN_GRIP))
|
if (twoHand && !player->HasAura(SPELL_TITAN_GRIP))
|
||||||
ignoreOffhand = true; // classic 2-hander
|
ignoreOffhand = true; // classic 2-hander
|
||||||
}
|
}
|
||||||
else if (!off) // both hands empty
|
else if (!off) // both hands empty
|
||||||
ignoreOffhand = true;
|
ignoreOffhand = true;
|
||||||
|
|
||||||
/* ---------- 1. Sum up item-levels -------------------------- */
|
/* ---------- 1. Sum up item-levels -------------------------- */
|
||||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||||
{
|
{
|
||||||
if (slot == EQUIPMENT_SLOT_BODY || slot == EQUIPMENT_SLOT_TABARD)
|
if (slot == EQUIPMENT_SLOT_BODY || slot == EQUIPMENT_SLOT_TABARD)
|
||||||
continue; // Blizzard never counts these
|
continue; // Blizzard never counts these
|
||||||
|
|
||||||
if (ignoreOffhand && slot == EQUIPMENT_SLOT_OFFHAND)
|
if (ignoreOffhand && slot == EQUIPMENT_SLOT_OFFHAND)
|
||||||
continue; // skip off-hand in 2-H case
|
continue; // skip off-hand in 2-H case
|
||||||
|
|
||||||
if (Item* it = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
if (Item* it = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||||
sumLevel += it->GetTemplate()->ItemLevel; // missing items add 0
|
sumLevel += it->GetTemplate()->ItemLevel; // missing items add 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- 2. Divide by 17 or 16 -------------------------- */
|
/* ---------- 2. Divide by 17 or 16 -------------------------- */
|
||||||
const uint8 divisor = ignoreOffhand ? TOTAL_SLOTS - 1 : TOTAL_SLOTS; // 16 or 17
|
const uint8 divisor = ignoreOffhand ? TOTAL_SLOTS - 1 : TOTAL_SLOTS; // 16 or 17
|
||||||
return sumLevel / divisor;
|
return sumLevel / divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4492,7 +4488,7 @@ uint32 PlayerbotAI::GetEquipGearScore(Player* player)
|
|||||||
mh_type = item->GetTemplate()->InventoryType;
|
mh_type = item->GetTemplate()->InventoryType;
|
||||||
if (!player->HasAura(SPELL_TITAN_GRIP) && mh_type == INVTYPE_2HWEAPON && i == SLOT_MAIN_HAND)
|
if (!player->HasAura(SPELL_TITAN_GRIP) && mh_type == INVTYPE_2HWEAPON && i == SLOT_MAIN_HAND)
|
||||||
sum += item->GetTemplate()->ItemLevel;
|
sum += item->GetTemplate()->ItemLevel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 gs = uint32(sum / count);
|
uint32 gs = uint32(sum / count);
|
||||||
@@ -4730,7 +4726,7 @@ void PlayerbotAI::_fillGearScoreData(Player* player, Item* item, std::vector<uin
|
|||||||
case INVTYPE_SHOULDERS:
|
case INVTYPE_SHOULDERS:
|
||||||
(*gearScore)[EQUIPMENT_SLOT_SHOULDERS] = std::max((*gearScore)[EQUIPMENT_SLOT_SHOULDERS], level);
|
(*gearScore)[EQUIPMENT_SLOT_SHOULDERS] = std::max((*gearScore)[EQUIPMENT_SLOT_SHOULDERS], level);
|
||||||
break;
|
break;
|
||||||
case INVTYPE_BODY: //Shouldn't be considered when calculating average ilevel
|
case INVTYPE_BODY: // Shouldn't be considered when calculating average ilevel
|
||||||
(*gearScore)[EQUIPMENT_SLOT_BODY] = std::max((*gearScore)[EQUIPMENT_SLOT_BODY], level);
|
(*gearScore)[EQUIPMENT_SLOT_BODY] = std::max((*gearScore)[EQUIPMENT_SLOT_BODY], level);
|
||||||
break;
|
break;
|
||||||
case INVTYPE_CHEST:
|
case INVTYPE_CHEST:
|
||||||
@@ -5108,48 +5104,50 @@ Item* PlayerbotAI::FindBandage() const
|
|||||||
|
|
||||||
Item* PlayerbotAI::FindOpenableItem() const
|
Item* PlayerbotAI::FindOpenableItem() const
|
||||||
{
|
{
|
||||||
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
return FindItemInInventory(
|
||||||
{
|
[this](ItemTemplate const* itemTemplate) -> bool
|
||||||
return (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT) &&
|
{
|
||||||
(itemTemplate->LockID == 0 || !this->bot->GetItemByEntry(itemTemplate->ItemId)->IsLocked());
|
return (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT) &&
|
||||||
});
|
(itemTemplate->LockID == 0 || !this->bot->GetItemByEntry(itemTemplate->ItemId)->IsLocked());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Item* PlayerbotAI::FindLockedItem() const
|
Item* PlayerbotAI::FindLockedItem() const
|
||||||
{
|
{
|
||||||
return FindItemInInventory([this](ItemTemplate const* itemTemplate) -> bool
|
return FindItemInInventory(
|
||||||
{
|
[this](ItemTemplate const* itemTemplate) -> bool
|
||||||
if (!this->bot->HasSkill(SKILL_LOCKPICKING)) // Ensure bot has Lockpicking skill
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (itemTemplate->LockID == 0) // Ensure the item is actually locked
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Item* item = this->bot->GetItemByEntry(itemTemplate->ItemId);
|
|
||||||
if (!item || !item->IsLocked()) // Ensure item instance is locked
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if bot has enough Lockpicking skill
|
|
||||||
LockEntry const* lockInfo = sLockStore.LookupEntry(itemTemplate->LockID);
|
|
||||||
if (!lockInfo)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (uint8 j = 0; j < 8; ++j)
|
|
||||||
{
|
{
|
||||||
if (lockInfo->Type[j] == LOCK_KEY_SKILL)
|
if (!this->bot->HasSkill(SKILL_LOCKPICKING)) // Ensure bot has Lockpicking skill
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (itemTemplate->LockID == 0) // Ensure the item is actually locked
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Item* item = this->bot->GetItemByEntry(itemTemplate->ItemId);
|
||||||
|
if (!item || !item->IsLocked()) // Ensure item instance is locked
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if bot has enough Lockpicking skill
|
||||||
|
LockEntry const* lockInfo = sLockStore.LookupEntry(itemTemplate->LockID);
|
||||||
|
if (!lockInfo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (uint8 j = 0; j < 8; ++j)
|
||||||
{
|
{
|
||||||
uint32 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
|
if (lockInfo->Type[j] == LOCK_KEY_SKILL)
|
||||||
if (skillId == SKILL_LOCKPICKING)
|
|
||||||
{
|
{
|
||||||
uint32 requiredSkill = lockInfo->Skill[j];
|
uint32 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
|
||||||
uint32 botSkill = this->bot->GetSkillValue(SKILL_LOCKPICKING);
|
if (skillId == SKILL_LOCKPICKING)
|
||||||
return botSkill >= requiredSkill;
|
{
|
||||||
|
uint32 requiredSkill = lockInfo->Skill[j];
|
||||||
|
uint32 botSkill = this->bot->GetSkillValue(SKILL_LOCKPICKING);
|
||||||
|
return botSkill >= requiredSkill;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
static const uint32 uPriorizedSharpStoneIds[8] = {ADAMANTITE_SHARPENING_DISPLAYID, FEL_SHARPENING_DISPLAYID,
|
||||||
@@ -6072,6 +6070,35 @@ ChatChannelSource PlayerbotAI::GetChatChannelSource(Player* bot, uint32 type, st
|
|||||||
return ChatChannelSource::SRC_UNDEFINED;
|
return ChatChannelSource::SRC_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerbotAI::CheckLocationDistanceByLevel(Player* player, const WorldLocation& loc, bool fromStartUp)
|
||||||
|
{
|
||||||
|
if (player->GetLevel() > 16)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
float dis = 0.0f;
|
||||||
|
if (fromStartUp)
|
||||||
|
{
|
||||||
|
PlayerInfo const* pInfo = sObjectMgr->GetPlayerInfo(player->getRace(true), player->getClass());
|
||||||
|
if (loc.GetMapId() != pInfo->mapId)
|
||||||
|
return false;
|
||||||
|
dis = loc.GetExactDist(pInfo->positionX, pInfo->positionY, pInfo->positionZ);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (loc.GetMapId() != player->GetMapId())
|
||||||
|
return false;
|
||||||
|
dis = loc.GetExactDist(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
float bound = 10000.0f;
|
||||||
|
if (player->GetLevel() <= 4)
|
||||||
|
bound = 500.0f;
|
||||||
|
else if (player->GetLevel() <= 10)
|
||||||
|
bound = 2500.0f;
|
||||||
|
|
||||||
|
return dis <= bound;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const Quest*> PlayerbotAI::GetAllCurrentQuests()
|
std::vector<const Quest*> PlayerbotAI::GetAllCurrentQuests()
|
||||||
{
|
{
|
||||||
std::vector<const Quest*> result;
|
std::vector<const Quest*> result;
|
||||||
@@ -6347,17 +6374,16 @@ void PlayerbotAI::AddTimedEvent(std::function<void()> callback, uint32 delayMs)
|
|||||||
class LambdaEvent final : public BasicEvent
|
class LambdaEvent final : public BasicEvent
|
||||||
{
|
{
|
||||||
std::function<void()> _cb;
|
std::function<void()> _cb;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit LambdaEvent(std::function<void()> cb) : _cb(std::move(cb)) {}
|
explicit LambdaEvent(std::function<void()> cb) : _cb(std::move(cb)) {}
|
||||||
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
||||||
{
|
{
|
||||||
_cb();
|
_cb();
|
||||||
return true; // remove after execution
|
return true; // remove after execution
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Every Player already owns an EventMap called m_Events
|
// Every Player already owns an EventMap called m_Events
|
||||||
bot->m_Events.AddEvent(
|
bot->m_Events.AddEvent(new LambdaEvent(std::move(callback)), bot->m_Events.CalculateTime(delayMs));
|
||||||
new LambdaEvent(std::move(callback)),
|
|
||||||
bot->m_Events.CalculateTime(delayMs));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -545,6 +545,8 @@ public:
|
|||||||
bool IsSafe(WorldObject* obj);
|
bool IsSafe(WorldObject* obj);
|
||||||
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
||||||
|
|
||||||
|
bool CheckLocationDistanceByLevel(Player* player, const WorldLocation &loc, bool fromStartUp = false);
|
||||||
|
|
||||||
bool HasCheat(BotCheatMask mask)
|
bool HasCheat(BotCheatMask mask)
|
||||||
{
|
{
|
||||||
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "NewRpgInfo.h"
|
||||||
#include "PlayerbotDungeonSuggestionMgr.h"
|
#include "PlayerbotDungeonSuggestionMgr.h"
|
||||||
#include "PlayerbotFactory.h"
|
#include "PlayerbotFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
@@ -148,7 +149,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
LoadList<std::vector<uint32>>(
|
LoadList<std::vector<uint32>>(
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedZoneIds",
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedZoneIds",
|
||||||
"2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,"
|
"2255,656,2361,2362,2363,976,35,2268,3425,392,541,1446,3828,3712,3738,3565,"
|
||||||
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395"),
|
"3539,3623,4152,3988,4658,4284,4418,4436,4275,4323,4395,3703,4298,139,3951"),
|
||||||
pvpProhibitedZoneIds);
|
pvpProhibitedZoneIds);
|
||||||
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds", "976,35"),
|
LoadList<std::vector<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.PvpProhibitedAreaIds", "976,35"),
|
||||||
pvpProhibitedAreaIds);
|
pvpProhibitedAreaIds);
|
||||||
@@ -585,7 +586,16 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
autoLearnQuestSpells = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoLearnQuestSpells", false);
|
||||||
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
autoTeleportForLevel = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoTeleportForLevel", false);
|
||||||
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
|
autoDoQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.AutoDoQuests", true);
|
||||||
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", false);
|
enableNewRpgStrategy = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableNewRpgStrategy", true);
|
||||||
|
|
||||||
|
RpgStatusProbWeight[RPG_WANDER_RANDOM] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderRandom", 15);
|
||||||
|
RpgStatusProbWeight[RPG_WANDER_NPC] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.WanderNpc", 20);
|
||||||
|
RpgStatusProbWeight[RPG_GO_GRIND] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoGrind", 15);
|
||||||
|
RpgStatusProbWeight[RPG_GO_CAMP] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.GoCamp", 10);
|
||||||
|
RpgStatusProbWeight[RPG_DO_QUEST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.DoQuest", 60);
|
||||||
|
RpgStatusProbWeight[RPG_TRAVEL_FLIGHT] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.TravelFlight", 15);
|
||||||
|
RpgStatusProbWeight[RPG_REST] = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgStatusProbWeight.Rest", 5);
|
||||||
|
|
||||||
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
syncLevelWithPlayers = sConfigMgr->GetOption<bool>("AiPlayerbot.SyncLevelWithPlayers", false);
|
||||||
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
|
freeFood = sConfigMgr->GetOption<bool>("AiPlayerbot.FreeFood", true);
|
||||||
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
randomBotGroupNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGroupNearby", true);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_PLAYERbotAICONFIG_H
|
#define _PLAYERBOT_PLAYERbotAICONFIG_H
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "DBCEnums.h"
|
#include "DBCEnums.h"
|
||||||
@@ -34,6 +35,26 @@ enum class HealingManaEfficiency : uint8
|
|||||||
SUPERIOR = 32
|
SUPERIOR = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum NewRpgStatus : int
|
||||||
|
{
|
||||||
|
RPG_STATUS_START = 0,
|
||||||
|
// Going to far away place
|
||||||
|
RPG_GO_GRIND = 0,
|
||||||
|
RPG_GO_CAMP = 1,
|
||||||
|
// Exploring nearby
|
||||||
|
RPG_WANDER_RANDOM = 2,
|
||||||
|
RPG_WANDER_NPC = 3,
|
||||||
|
// Do Quest (based on quest status)
|
||||||
|
RPG_DO_QUEST = 4,
|
||||||
|
// Travel
|
||||||
|
RPG_TRAVEL_FLIGHT = 5,
|
||||||
|
// Taking a break
|
||||||
|
RPG_REST = 6,
|
||||||
|
// Initial status
|
||||||
|
RPG_IDLE = 7,
|
||||||
|
RPG_STATUS_END = 8
|
||||||
|
};
|
||||||
|
|
||||||
#define MAX_SPECNO 20
|
#define MAX_SPECNO 20
|
||||||
#define MAX_WORLDBUFF_SPECNO 3
|
#define MAX_WORLDBUFF_SPECNO 3
|
||||||
|
|
||||||
@@ -315,6 +336,7 @@ public:
|
|||||||
bool autoLearnTrainerSpells;
|
bool autoLearnTrainerSpells;
|
||||||
bool autoDoQuests;
|
bool autoDoQuests;
|
||||||
bool enableNewRpgStrategy;
|
bool enableNewRpgStrategy;
|
||||||
|
std::unordered_map<NewRpgStatus, uint32> RpgStatusProbWeight;
|
||||||
bool syncLevelWithPlayers;
|
bool syncLevelWithPlayers;
|
||||||
bool freeFood;
|
bool freeFood;
|
||||||
bool autoLearnQuestSpells;
|
bool autoLearnQuestSpells;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "RandomPlayerbotMgr.h"
|
#include "RandomPlayerbotMgr.h"
|
||||||
|
|
||||||
|
#include <WorldSessionMgr.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/thread/thread.hpp>
|
#include <boost/thread/thread.hpp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#include "MapMgr.h"
|
#include "MapMgr.h"
|
||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "NewRpgStrategy.h"
|
#include "NewRpgStrategy.h"
|
||||||
|
#include "ObjectGuid.h"
|
||||||
#include "PerformanceMonitor.h"
|
#include "PerformanceMonitor.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
@@ -42,16 +45,16 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "Position.h"
|
#include "Position.h"
|
||||||
#include "Random.h"
|
#include "Random.h"
|
||||||
|
#include "RandomPlayerbotFactory.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "UpdateTime.h"
|
#include "UpdateTime.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "RandomPlayerbotFactory.h"
|
|
||||||
#include <WorldSessionMgr.h>
|
|
||||||
|
|
||||||
struct GuidClassRaceInfo {
|
struct GuidClassRaceInfo
|
||||||
|
{
|
||||||
ObjectGuid::LowType guid;
|
ObjectGuid::LowType guid;
|
||||||
uint32 rClass;
|
uint32 rClass;
|
||||||
uint32 rRace;
|
uint32 rRace;
|
||||||
@@ -179,7 +182,7 @@ RandomPlayerbotMgr::RandomPlayerbotMgr() : PlayerbotHolder(), processTicks(0)
|
|||||||
sPlayerbotCommandServer->Start();
|
sPlayerbotCommandServer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
BattlegroundData.clear(); // Clear here and here only.
|
BattlegroundData.clear(); // Clear here and here only.
|
||||||
|
|
||||||
// Cleanup on server start: orphaned pet data that's often left behind by bot pets that no longer exist in the DB
|
// Cleanup on server start: orphaned pet data that's often left behind by bot pets that no longer exist in the DB
|
||||||
CharacterDatabase.Execute("DELETE FROM pet_aura WHERE guid NOT IN (SELECT id FROM character_pet)");
|
CharacterDatabase.Execute("DELETE FROM pet_aura WHERE guid NOT IN (SELECT id FROM character_pet)");
|
||||||
@@ -385,8 +388,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
time(nullptr) > RealPlayerLastTimeSeen + sPlayerbotAIConfig->disabledWithoutRealPlayerLogoutDelay)
|
time(nullptr) > RealPlayerLastTimeSeen + sPlayerbotAIConfig->disabledWithoutRealPlayerLogoutDelay)
|
||||||
{
|
{
|
||||||
LogoutAllBots();
|
LogoutAllBots();
|
||||||
LOG_INFO("playerbots",
|
LOG_INFO("playerbots", "Logout all bots due no real player session.");
|
||||||
"Logout all bots due no real player session.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,11 +435,12 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100;
|
uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100;
|
||||||
uint32 maxNewBots = onlineBotCount < maxAllowedBotCount &&
|
uint32 maxNewBots =
|
||||||
|
onlineBotCount < maxAllowedBotCount &&
|
||||||
(sPlayerbotAIConfig->disabledWithoutRealPlayer == false ||
|
(sPlayerbotAIConfig->disabledWithoutRealPlayer == false ||
|
||||||
(realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer))
|
(realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer))
|
||||||
? maxAllowedBotCount - onlineBotCount
|
? maxAllowedBotCount - onlineBotCount
|
||||||
: 0;
|
: 0;
|
||||||
uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots);
|
uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots);
|
||||||
|
|
||||||
if (!availableBots.empty())
|
if (!availableBots.empty())
|
||||||
@@ -527,7 +530,8 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
uint32 remainder = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) % totalRatio;
|
uint32 remainder = maxAllowedBotCount * (sPlayerbotAIConfig->randomBotAllianceRatio) % totalRatio;
|
||||||
|
|
||||||
// Fix #1082: Randomly add one based on reminder
|
// Fix #1082: Randomly add one based on reminder
|
||||||
if (remainder && urand(1, totalRatio) <= remainder) {
|
if (remainder && urand(1, totalRatio) <= remainder)
|
||||||
|
{
|
||||||
allowedAllianceCount++;
|
allowedAllianceCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +544,8 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
if (sPlayerbotAIConfig->enablePeriodicOnlineOffline)
|
||||||
{
|
{
|
||||||
// minus addclass bots account
|
// minus addclass bots account
|
||||||
int32 baseAccount = RandomPlayerbotFactory::CalculateTotalAccountCount() - sPlayerbotAIConfig->addClassAccountPoolSize;
|
int32 baseAccount =
|
||||||
|
RandomPlayerbotFactory::CalculateTotalAccountCount() - sPlayerbotAIConfig->addClassAccountPoolSize;
|
||||||
|
|
||||||
if (baseAccount <= 0 || baseAccount > sPlayerbotAIConfig->randomBotAccounts.size())
|
if (baseAccount <= 0 || baseAccount > sPlayerbotAIConfig->randomBotAccounts.size())
|
||||||
{
|
{
|
||||||
@@ -559,7 +564,8 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
|
|
||||||
std::vector<GuidClassRaceInfo> allGuidInfos;
|
std::vector<GuidClassRaceInfo> allGuidInfos;
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
Field* fields = result->Fetch();
|
Field* fields = result->Fetch();
|
||||||
GuidClassRaceInfo info;
|
GuidClassRaceInfo info;
|
||||||
info.guid = fields[0].Get<uint32>();
|
info.guid = fields[0].Get<uint32>();
|
||||||
@@ -573,7 +579,8 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
std::shuffle(allGuidInfos.begin(), allGuidInfos.end(), rnd);
|
std::shuffle(allGuidInfos.begin(), allGuidInfos.end(), rnd);
|
||||||
|
|
||||||
std::vector<uint32> guids;
|
std::vector<uint32> guids;
|
||||||
for (const auto& info : allGuidInfos) {
|
for (const auto& info : allGuidInfos)
|
||||||
|
{
|
||||||
ObjectGuid::LowType guid = info.guid;
|
ObjectGuid::LowType guid = info.guid;
|
||||||
uint32 rClass = info.rClass;
|
uint32 rClass = info.rClass;
|
||||||
uint32 rRace = info.rRace;
|
uint32 rRace = info.rRace;
|
||||||
@@ -590,8 +597,10 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
if (std::find(currentBots.begin(), currentBots.end(), guid) != currentBots.end())
|
if (std::find(currentBots.begin(), currentBots.end(), guid) != currentBots.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->disableDeathKnightLogin) {
|
if (sPlayerbotAIConfig->disableDeathKnightLogin)
|
||||||
if (rClass == CLASS_DEATH_KNIGHT) {
|
{
|
||||||
|
if (rClass == CLASS_DEATH_KNIGHT)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -602,9 +611,12 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
|
|||||||
if (factionNotAllowed)
|
if (factionNotAllowed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isAlliance) {
|
if (isAlliance)
|
||||||
|
{
|
||||||
allowedAllianceCount--;
|
allowedAllianceCount--;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
allowedHordeCount--;
|
allowedHordeCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,13 +721,15 @@ std::vector<uint32> parseBrackets(const std::string& str)
|
|||||||
|
|
||||||
void RandomPlayerbotMgr::CheckBgQueue()
|
void RandomPlayerbotMgr::CheckBgQueue()
|
||||||
{
|
{
|
||||||
if (!BgCheckTimer) {
|
if (!BgCheckTimer)
|
||||||
|
{
|
||||||
BgCheckTimer = time(nullptr);
|
BgCheckTimer = time(nullptr);
|
||||||
return; // Exit immediately after initializing the timer
|
return; // Exit immediately after initializing the timer
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time(nullptr) < BgCheckTimer) {
|
if (time(nullptr) < BgCheckTimer)
|
||||||
return; // No need to proceed if the current time is less than the timer
|
{
|
||||||
|
return; // No need to proceed if the current time is less than the timer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the timer to the current time
|
// Update the timer to the current time
|
||||||
@@ -777,7 +791,8 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
isRated = ginfo.IsRated;
|
isRated = ginfo.IsRated;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bgQueue.IsPlayerInvitedToRatedArena(player->GetGUID()) || (player->InArena() && player->GetBattleground()->isRated()))
|
if (bgQueue.IsPlayerInvitedToRatedArena(player->GetGUID()) ||
|
||||||
|
(player->InArena() && player->GetBattleground()->isRated()))
|
||||||
isRated = true;
|
isRated = true;
|
||||||
|
|
||||||
if (isRated)
|
if (isRated)
|
||||||
@@ -800,7 +815,8 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
uint32 instanceId = player->GetBattleground()->GetInstanceID();
|
uint32 instanceId = player->GetBattleground()->GetInstanceID();
|
||||||
|
|
||||||
instanceIds = &BattlegroundData[queueTypeId][bracketId].bgInstances;
|
instanceIds = &BattlegroundData[queueTypeId][bracketId].bgInstances;
|
||||||
if (instanceIds && std::find(instanceIds->begin(), instanceIds->end(), instanceId) == instanceIds->end())
|
if (instanceIds &&
|
||||||
|
std::find(instanceIds->begin(), instanceIds->end(), instanceId) == instanceIds->end())
|
||||||
instanceIds->push_back(instanceId);
|
instanceIds->push_back(instanceId);
|
||||||
|
|
||||||
BattlegroundData[queueTypeId][bracketId].bgInstanceCount = instanceIds->size();
|
BattlegroundData[queueTypeId][bracketId].bgInstanceCount = instanceIds->size();
|
||||||
@@ -906,7 +922,8 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
instanceIds = &BattlegroundData[queueTypeId][bracketId].bgInstances;
|
instanceIds = &BattlegroundData[queueTypeId][bracketId].bgInstances;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instanceIds && std::find(instanceIds->begin(), instanceIds->end(), instanceId) == instanceIds->end())
|
if (instanceIds &&
|
||||||
|
std::find(instanceIds->begin(), instanceIds->end(), instanceId) == instanceIds->end())
|
||||||
instanceIds->push_back(instanceId);
|
instanceIds->push_back(instanceId);
|
||||||
|
|
||||||
if (isArena)
|
if (isArena)
|
||||||
@@ -927,7 +944,7 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
// If enabled, wait for all bots to have logged in before queueing for Arena's / BG's
|
// If enabled, wait for all bots to have logged in before queueing for Arena's / BG's
|
||||||
if (sPlayerbotAIConfig->randomBotAutoJoinBG && playerBots.size() >= GetMaxAllowedBotCount())
|
if (sPlayerbotAIConfig->randomBotAutoJoinBG && playerBots.size() >= GetMaxAllowedBotCount())
|
||||||
{
|
{
|
||||||
uint32 randomBotAutoJoinArenaBracket = sPlayerbotAIConfig->randomBotAutoJoinArenaBracket;
|
uint32 randomBotAutoJoinArenaBracket = sPlayerbotAIConfig->randomBotAutoJoinArenaBracket;
|
||||||
uint32 randomBotAutoJoinBGRatedArena2v2Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena2v2Count;
|
uint32 randomBotAutoJoinBGRatedArena2v2Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena2v2Count;
|
||||||
uint32 randomBotAutoJoinBGRatedArena3v3Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena3v3Count;
|
uint32 randomBotAutoJoinBGRatedArena3v3Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena3v3Count;
|
||||||
uint32 randomBotAutoJoinBGRatedArena5v5Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena5v5Count;
|
uint32 randomBotAutoJoinBGRatedArena5v5Count = sPlayerbotAIConfig->randomBotAutoJoinBGRatedArena5v5Count;
|
||||||
@@ -946,14 +963,16 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
|
|
||||||
// Check both bgInstanceCount / bgInstances.size
|
// Check both bgInstanceCount / bgInstances.size
|
||||||
// to help counter against potentional inconsistencies
|
// to help counter against potentional inconsistencies
|
||||||
auto updateRatedArenaInstanceCount = [&](uint32 queueType, uint32 bracket, uint32 minCount) {
|
auto updateRatedArenaInstanceCount = [&](uint32 queueType, uint32 bracket, uint32 minCount)
|
||||||
|
{
|
||||||
if (BattlegroundData[queueType][bracket].activeRatedArenaQueue == 0 &&
|
if (BattlegroundData[queueType][bracket].activeRatedArenaQueue == 0 &&
|
||||||
BattlegroundData[queueType][bracket].ratedArenaInstanceCount < minCount &&
|
BattlegroundData[queueType][bracket].ratedArenaInstanceCount < minCount &&
|
||||||
BattlegroundData[queueType][bracket].ratedArenaInstances.size() < minCount)
|
BattlegroundData[queueType][bracket].ratedArenaInstances.size() < minCount)
|
||||||
BattlegroundData[queueType][bracket].activeRatedArenaQueue = 1;
|
BattlegroundData[queueType][bracket].activeRatedArenaQueue = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto updateBGInstanceCount = [&](uint32 queueType, std::vector<uint32> brackets, uint32 minCount) {
|
auto updateBGInstanceCount = [&](uint32 queueType, std::vector<uint32> brackets, uint32 minCount)
|
||||||
|
{
|
||||||
for (uint32 bracket : brackets)
|
for (uint32 bracket : brackets)
|
||||||
{
|
{
|
||||||
if (BattlegroundData[queueType][bracket].activeBgQueue == 0 &&
|
if (BattlegroundData[queueType][bracket].activeBgQueue == 0 &&
|
||||||
@@ -964,9 +983,12 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update rated arena instance counts
|
// Update rated arena instance counts
|
||||||
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_2v2, randomBotAutoJoinArenaBracket, randomBotAutoJoinBGRatedArena2v2Count);
|
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_2v2, randomBotAutoJoinArenaBracket,
|
||||||
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_3v3, randomBotAutoJoinArenaBracket, randomBotAutoJoinBGRatedArena3v3Count);
|
randomBotAutoJoinBGRatedArena2v2Count);
|
||||||
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_5v5, randomBotAutoJoinArenaBracket, randomBotAutoJoinBGRatedArena5v5Count);
|
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_3v3, randomBotAutoJoinArenaBracket,
|
||||||
|
randomBotAutoJoinBGRatedArena3v3Count);
|
||||||
|
updateRatedArenaInstanceCount(BATTLEGROUND_QUEUE_5v5, randomBotAutoJoinArenaBracket,
|
||||||
|
randomBotAutoJoinBGRatedArena5v5Count);
|
||||||
|
|
||||||
// Update battleground instance counts
|
// Update battleground instance counts
|
||||||
updateBGInstanceCount(BATTLEGROUND_QUEUE_IC, icBrackets, randomBotAutoJoinBGICCount);
|
updateBGInstanceCount(BATTLEGROUND_QUEUE_IC, icBrackets, randomBotAutoJoinBGICCount);
|
||||||
@@ -1045,7 +1067,8 @@ void RandomPlayerbotMgr::LogBattlegroundInfo()
|
|||||||
if (bgInfo.minLevel == 0)
|
if (bgInfo.minLevel == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LOG_INFO("playerbots", "BG:{} {}: Player ({}:{}) Bot ({}:{}) Total (A:{} H:{}), Instances {}, Active Queue: {}", _bgType,
|
LOG_INFO("playerbots",
|
||||||
|
"BG:{} {}: Player ({}:{}) Bot ({}:{}) Total (A:{} H:{}), Instances {}, Active Queue: {}", _bgType,
|
||||||
std::to_string(bgInfo.minLevel) + "-" + std::to_string(bgInfo.maxLevel),
|
std::to_string(bgInfo.minLevel) + "-" + std::to_string(bgInfo.maxLevel),
|
||||||
bgInfo.bgAlliancePlayerCount, bgInfo.bgHordePlayerCount, bgInfo.bgAllianceBotCount,
|
bgInfo.bgAlliancePlayerCount, bgInfo.bgHordePlayerCount, bgInfo.bgAllianceBotCount,
|
||||||
bgInfo.bgHordeBotCount, bgInfo.bgAlliancePlayerCount + bgInfo.bgAllianceBotCount,
|
bgInfo.bgHordeBotCount, bgInfo.bgAlliancePlayerCount + bgInfo.bgAllianceBotCount,
|
||||||
@@ -1153,7 +1176,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
|||||||
{
|
{
|
||||||
if (player)
|
if (player)
|
||||||
LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: log out", bot, IsAlliance(player->getRace()) ? "A" : "H",
|
LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: log out", bot, IsAlliance(player->getRace()) ? "A" : "H",
|
||||||
player->GetLevel(), player->GetName().c_str());
|
player->GetLevel(), player->GetName().c_str());
|
||||||
else
|
else
|
||||||
LOG_DEBUG("playerbots", "Bot #{}: log out", bot);
|
LOG_DEBUG("playerbots", "Bot #{}: log out", bot);
|
||||||
|
|
||||||
@@ -1239,7 +1262,7 @@ bool RandomPlayerbotMgr::ProcessBot(uint32 bot)
|
|||||||
if (player && !logout && !isValid)
|
if (player && !logout && !isValid)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: log out", bot, IsAlliance(player->getRace()) ? "A" : "H",
|
LOG_DEBUG("playerbots", "Bot #{} {}:{} <{}>: log out", bot, IsAlliance(player->getRace()) ? "A" : "H",
|
||||||
player->GetLevel(), player->GetName().c_str());
|
player->GetLevel(), player->GetName().c_str());
|
||||||
LogoutPlayerBot(botGUID);
|
LogoutPlayerBot(botGUID);
|
||||||
currentBots.remove(bot);
|
currentBots.remove(bot);
|
||||||
SetEventValue(bot, "logout", 1,
|
SetEventValue(bot, "logout", 1,
|
||||||
@@ -1481,22 +1504,9 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
z = 0.05f + ground;
|
z = 0.05f + ground;
|
||||||
PlayerInfo const* pInfo = sObjectMgr->GetPlayerInfo(bot->getRace(true), bot->getClass());
|
|
||||||
float dis = loc.GetExactDist(pInfo->positionX, pInfo->positionY, pInfo->positionZ);
|
|
||||||
|
|
||||||
// yunfan: distance check for low level
|
if (!botAI->CheckLocationDistanceByLevel(bot, loc, true))
|
||||||
if (bot->GetLevel() <= 4 && (loc.GetMapId() != pInfo->mapId || dis > 500.0f))
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (bot->GetLevel() <= 10 && (loc.GetMapId() != pInfo->mapId || dis > 2500.0f))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bot->GetLevel() <= 16 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const LocaleConstant& locale = sWorld->GetDefaultDbcLocale();
|
const LocaleConstant& locale = sWorld->GetDefaultDbcLocale();
|
||||||
LOG_DEBUG("playerbots",
|
LOG_DEBUG("playerbots",
|
||||||
@@ -1513,7 +1523,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prevent blink to be detected by visible real players
|
// Prevent blink to be detected by visible real players
|
||||||
if (dis < 150.0f && botAI->HasPlayerNearby(150.0f))
|
if (botAI->HasPlayerNearby(150.0f))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1541,80 +1551,81 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
|
|||||||
void RandomPlayerbotMgr::PrepareZone2LevelBracket()
|
void RandomPlayerbotMgr::PrepareZone2LevelBracket()
|
||||||
{
|
{
|
||||||
// Classic WoW - Low - level zones
|
// Classic WoW - Low - level zones
|
||||||
zone2LevelBracket[1] = {5, 12}; // Dun Morogh
|
zone2LevelBracket[1] = {5, 12}; // Dun Morogh
|
||||||
zone2LevelBracket[12] = {5, 12}; // Elwynn Forest
|
zone2LevelBracket[12] = {5, 12}; // Elwynn Forest
|
||||||
zone2LevelBracket[14] = {5, 12}; // Durotar
|
zone2LevelBracket[14] = {5, 12}; // Durotar
|
||||||
zone2LevelBracket[85] = {5, 12}; // Tirisfal Glades
|
zone2LevelBracket[85] = {5, 12}; // Tirisfal Glades
|
||||||
zone2LevelBracket[141] = {5, 12}; // Teldrassil
|
zone2LevelBracket[141] = {5, 12}; // Teldrassil
|
||||||
zone2LevelBracket[215] = {5, 12}; // Mulgore
|
zone2LevelBracket[215] = {5, 12}; // Mulgore
|
||||||
zone2LevelBracket[3430] = {5, 12}; // Eversong Woods
|
zone2LevelBracket[3430] = {5, 12}; // Eversong Woods
|
||||||
zone2LevelBracket[3524] = {5, 12}; // Azuremyst Isle
|
zone2LevelBracket[3524] = {5, 12}; // Azuremyst Isle
|
||||||
|
|
||||||
// Classic WoW - Mid - level zones
|
// Classic WoW - Mid - level zones
|
||||||
zone2LevelBracket[17] = {10, 25}; // Barrens
|
zone2LevelBracket[17] = {10, 25}; // Barrens
|
||||||
zone2LevelBracket[38] = {10, 20}; // Loch Modan
|
zone2LevelBracket[38] = {10, 20}; // Loch Modan
|
||||||
zone2LevelBracket[40] = {10, 21}; // Westfall
|
zone2LevelBracket[40] = {10, 21}; // Westfall
|
||||||
zone2LevelBracket[130] = {10, 23}; // Silverpine Forest
|
zone2LevelBracket[130] = {10, 23}; // Silverpine Forest
|
||||||
zone2LevelBracket[148] = {10, 21}; // Darkshore
|
zone2LevelBracket[148] = {10, 21}; // Darkshore
|
||||||
zone2LevelBracket[3433] = {10, 22}; // Ghostlands
|
zone2LevelBracket[3433] = {10, 22}; // Ghostlands
|
||||||
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
zone2LevelBracket[3525] = {10, 21}; // Bloodmyst Isle
|
||||||
|
|
||||||
// Classic WoW - High - level zones
|
// Classic WoW - High - level zones
|
||||||
zone2LevelBracket[10] = {19, 33}; // Deadwind Pass
|
zone2LevelBracket[10] = {19, 33}; // Deadwind Pass
|
||||||
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
zone2LevelBracket[11] = {21, 30}; // Wetlands
|
||||||
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
zone2LevelBracket[44] = {16, 28}; // Redridge Mountains
|
||||||
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
zone2LevelBracket[267] = {20, 34}; // Hillsbrad Foothills
|
||||||
zone2LevelBracket[331] = {18, 33}; // Ashenvale
|
zone2LevelBracket[331] = {18, 33}; // Ashenvale
|
||||||
zone2LevelBracket[400] = {24, 36}; // Thousand Needles
|
zone2LevelBracket[400] = {24, 36}; // Thousand Needles
|
||||||
zone2LevelBracket[406] = {16, 29}; // Stonetalon Mountains
|
zone2LevelBracket[406] = {16, 29}; // Stonetalon Mountains
|
||||||
|
|
||||||
// Classic WoW - Higher - level zones
|
// Classic WoW - Higher - level zones
|
||||||
zone2LevelBracket[3] = {36, 46}; // Badlands
|
zone2LevelBracket[3] = {36, 46}; // Badlands
|
||||||
zone2LevelBracket[8] = {36, 46}; // Swamp of Sorrows
|
zone2LevelBracket[8] = {36, 46}; // Swamp of Sorrows
|
||||||
zone2LevelBracket[15] = {35, 46}; // Dustwallow Marsh
|
zone2LevelBracket[15] = {35, 46}; // Dustwallow Marsh
|
||||||
zone2LevelBracket[16] = {45, 52}; // Azshara
|
zone2LevelBracket[16] = {45, 52}; // Azshara
|
||||||
zone2LevelBracket[33] = {32, 47}; // Stranglethorn Vale
|
zone2LevelBracket[33] = {32, 47}; // Stranglethorn Vale
|
||||||
zone2LevelBracket[45] = {30, 42}; // Arathi Highlands
|
zone2LevelBracket[45] = {30, 42}; // Arathi Highlands
|
||||||
zone2LevelBracket[47] = {42, 51}; // Hinterlands
|
zone2LevelBracket[47] = {42, 51}; // Hinterlands
|
||||||
zone2LevelBracket[51] = {45, 51}; // Searing Gorge
|
zone2LevelBracket[51] = {45, 51}; // Searing Gorge
|
||||||
zone2LevelBracket[357] = {40, 52}; // Feralas
|
zone2LevelBracket[357] = {40, 52}; // Feralas
|
||||||
zone2LevelBracket[405] = {30, 41}; // Desolace
|
zone2LevelBracket[405] = {30, 41}; // Desolace
|
||||||
zone2LevelBracket[440] = {41, 52}; // Tanaris
|
zone2LevelBracket[440] = {41, 52}; // Tanaris
|
||||||
|
|
||||||
// Classic WoW - Top - level zones
|
// Classic WoW - Top - level zones
|
||||||
zone2LevelBracket[4] = {52, 57}; // Blasted Lands
|
zone2LevelBracket[4] = {52, 57}; // Blasted Lands
|
||||||
zone2LevelBracket[28] = {50, 60}; // Western Plaguelands
|
zone2LevelBracket[28] = {50, 60}; // Western Plaguelands
|
||||||
zone2LevelBracket[46] = {51, 60}; // Burning Steppes
|
zone2LevelBracket[46] = {51, 60}; // Burning Steppes
|
||||||
zone2LevelBracket[139] = {54, 62}; // Eastern Plaguelands
|
zone2LevelBracket[139] = {54, 62}; // Eastern Plaguelands
|
||||||
zone2LevelBracket[361] = {47, 57}; // Felwood
|
zone2LevelBracket[361] = {47, 57}; // Felwood
|
||||||
zone2LevelBracket[490] = {49, 56}; // Un'Goro Crater
|
zone2LevelBracket[490] = {49, 56}; // Un'Goro Crater
|
||||||
zone2LevelBracket[618] = {54, 61}; // Winterspring
|
zone2LevelBracket[618] = {54, 61}; // Winterspring
|
||||||
zone2LevelBracket[1377] = {54, 63}; // Silithus
|
zone2LevelBracket[1377] = {54, 63}; // Silithus
|
||||||
|
|
||||||
// The Burning Crusade - Zones
|
// The Burning Crusade - Zones
|
||||||
zone2LevelBracket[3483] = {58, 66}; // Hellfire Peninsula
|
zone2LevelBracket[3483] = {58, 66}; // Hellfire Peninsula
|
||||||
zone2LevelBracket[3518] = {64, 70}; // Nagrand
|
zone2LevelBracket[3518] = {64, 70}; // Nagrand
|
||||||
zone2LevelBracket[3519] = {62, 73}; // Terokkar Forest
|
zone2LevelBracket[3519] = {62, 73}; // Terokkar Forest
|
||||||
zone2LevelBracket[3520] = {66, 73}; // Shadowmoon Valley
|
zone2LevelBracket[3520] = {66, 73}; // Shadowmoon Valley
|
||||||
zone2LevelBracket[3521] = {60, 67}; // Zangarmarsh
|
zone2LevelBracket[3521] = {60, 67}; // Zangarmarsh
|
||||||
zone2LevelBracket[3522] = {64, 73}; // Blade's Edge Mountains
|
zone2LevelBracket[3522] = {64, 73}; // Blade's Edge Mountains
|
||||||
zone2LevelBracket[3523] = {67, 73}; // Netherstorm
|
zone2LevelBracket[3523] = {67, 73}; // Netherstorm
|
||||||
zone2LevelBracket[4080] = {68, 73}; // Isle of Quel'Danas
|
zone2LevelBracket[4080] = {68, 73}; // Isle of Quel'Danas
|
||||||
|
|
||||||
// Wrath of the Lich King - Zones
|
// Wrath of the Lich King - Zones
|
||||||
zone2LevelBracket[65] = {71, 77}; // Dragonblight
|
zone2LevelBracket[65] = {71, 77}; // Dragonblight
|
||||||
zone2LevelBracket[66] = {74, 80}; // Zul'Drak
|
zone2LevelBracket[66] = {74, 80}; // Zul'Drak
|
||||||
zone2LevelBracket[67] = {77, 80}; // Storm Peaks
|
zone2LevelBracket[67] = {77, 80}; // Storm Peaks
|
||||||
zone2LevelBracket[210] = {77, 80}; // Icecrown Glacier
|
zone2LevelBracket[210] = {77, 80}; // Icecrown Glacier
|
||||||
zone2LevelBracket[394] = {72, 78}; // Grizzly Hills
|
zone2LevelBracket[394] = {72, 78}; // Grizzly Hills
|
||||||
zone2LevelBracket[495] = {68, 74}; // Howling Fjord
|
zone2LevelBracket[495] = {68, 74}; // Howling Fjord
|
||||||
zone2LevelBracket[2817] = {77, 80}; // Crystalsong Forest
|
zone2LevelBracket[2817] = {77, 80}; // Crystalsong Forest
|
||||||
zone2LevelBracket[3537] = {68, 75}; // Borean Tundra
|
zone2LevelBracket[3537] = {68, 75}; // Borean Tundra
|
||||||
zone2LevelBracket[3711] = {75, 80}; // Sholazar Basin
|
zone2LevelBracket[3711] = {75, 80}; // Sholazar Basin
|
||||||
zone2LevelBracket[4197] = {79, 80}; // Wintergrasp
|
zone2LevelBracket[4197] = {79, 80}; // Wintergrasp
|
||||||
|
|
||||||
// Override with values from config
|
// Override with values from config
|
||||||
for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig->zoneBrackets) {
|
for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig->zoneBrackets)
|
||||||
|
{
|
||||||
zone2LevelBracket[zoneId] = {bracketPair.first, bracketPair.second};
|
zone2LevelBracket[zoneId] = {bracketPair.first, bracketPair.second};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1696,25 +1707,27 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||||
{
|
{
|
||||||
PrepareZone2LevelBracket();
|
PrepareZone2LevelBracket();
|
||||||
LOG_INFO("playerbots", "Preparing innkeepers locations for level...");
|
LOG_INFO("playerbots", "Preparing innkeepers / flightmasters locations for level...");
|
||||||
results = WorldDatabase.Query(
|
results = WorldDatabase.Query(
|
||||||
"SELECT "
|
"SELECT "
|
||||||
"map, "
|
"map, "
|
||||||
"position_x, "
|
"position_x, "
|
||||||
"position_y, "
|
"position_y, "
|
||||||
"position_z, "
|
"position_z, "
|
||||||
"orientation, "
|
"orientation, "
|
||||||
"t.faction, "
|
"t.faction, "
|
||||||
"t.entry "
|
"t.entry, "
|
||||||
"FROM "
|
"t.npcflag, "
|
||||||
"creature c "
|
"c.guid "
|
||||||
"INNER JOIN creature_template t on c.id1 = t.entry "
|
"FROM "
|
||||||
"WHERE "
|
"creature c "
|
||||||
"t.npcflag & 73728 "
|
"INNER JOIN creature_template t on c.id1 = t.entry "
|
||||||
"AND map IN ({}) "
|
"WHERE "
|
||||||
"ORDER BY "
|
"t.npcflag & 73728 "
|
||||||
"t.minlevel;",
|
"AND map IN ({}) "
|
||||||
sPlayerbotAIConfig->randomBotMapsAsString.c_str());
|
"ORDER BY "
|
||||||
|
"t.minlevel;",
|
||||||
|
sPlayerbotAIConfig->randomBotMapsAsString.c_str());
|
||||||
collected_locs = 0;
|
collected_locs = 0;
|
||||||
if (results)
|
if (results)
|
||||||
{
|
{
|
||||||
@@ -1727,7 +1740,9 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
float z = fields[3].Get<float>();
|
float z = fields[3].Get<float>();
|
||||||
float orient = fields[4].Get<float>();
|
float orient = fields[4].Get<float>();
|
||||||
uint32 faction = fields[5].Get<uint32>();
|
uint32 faction = fields[5].Get<uint32>();
|
||||||
uint32 tEntry = fields[6].Get<uint32>();
|
uint32 tEntry = fields[6].Get<uint32>();
|
||||||
|
uint32 tNpcflag = fields[7].Get<uint32>();
|
||||||
|
uint32 guid = fields[8].Get<uint32>();
|
||||||
|
|
||||||
if (tEntry == 3838 || tEntry == 29480)
|
if (tEntry == 3838 || tEntry == 29480)
|
||||||
continue;
|
continue;
|
||||||
@@ -1739,6 +1754,19 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
Map* map = sMapMgr->FindMap(loc.GetMapId(), 0);
|
Map* map = sMapMgr->FindMap(loc.GetMapId(), 0);
|
||||||
if (!map)
|
if (!map)
|
||||||
continue;
|
continue;
|
||||||
|
bool forHorde = !(entry->hostileMask & 4);
|
||||||
|
bool forAlliance = !(entry->hostileMask & 2);
|
||||||
|
if (tNpcflag & UNIT_NPC_FLAG_FLIGHTMASTER)
|
||||||
|
{
|
||||||
|
if (forHorde)
|
||||||
|
{
|
||||||
|
hordeFlightMasterCache.push_back(guid);
|
||||||
|
}
|
||||||
|
if (forAlliance)
|
||||||
|
{
|
||||||
|
allianceFlightMasterCache.push_back(guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z));
|
const AreaTableEntry* area = sAreaTableStore.LookupEntry(map->GetAreaId(PHASEMASK_NORMAL, x, y, z));
|
||||||
uint32 zoneId = area->zone ? area->zone : area->ID;
|
uint32 zoneId = area->zone ? area->zone : area->ID;
|
||||||
if (zone2LevelBracket.find(zoneId) == zone2LevelBracket.end())
|
if (zone2LevelBracket.find(zoneId) == zone2LevelBracket.end())
|
||||||
@@ -1746,15 +1774,16 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
LevelBracket bracket = zone2LevelBracket[zoneId];
|
LevelBracket bracket = zone2LevelBracket[zoneId];
|
||||||
for (int i = bracket.low; i <= bracket.high; i++)
|
for (int i = bracket.low; i <= bracket.high; i++)
|
||||||
{
|
{
|
||||||
if (!(entry->hostileMask & 4))
|
if (forHorde)
|
||||||
{
|
{
|
||||||
hordeStarterPerLevelCache[i].push_back(loc);
|
hordeStarterPerLevelCache[i].push_back(loc);
|
||||||
}
|
}
|
||||||
if (!(entry->hostileMask & 2))
|
if (forAlliance)
|
||||||
{
|
{
|
||||||
allianceStarterPerLevelCache[i].push_back(loc);
|
allianceStarterPerLevelCache[i].push_back(loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (results->NextRow());
|
} while (results->NextRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1849,7 +1878,9 @@ void RandomPlayerbotMgr::PrepareAddclassCache()
|
|||||||
/// @FIXME: Modifying RandomBotAccountCount may cause the original addclass bots to be converted into rndbots,
|
/// @FIXME: Modifying RandomBotAccountCount may cause the original addclass bots to be converted into rndbots,
|
||||||
// which needs to be fixed by separating the two accounts in implementation
|
// which needs to be fixed by separating the two accounts in implementation
|
||||||
size_t poolSize = sPlayerbotAIConfig->addClassAccountPoolSize;
|
size_t poolSize = sPlayerbotAIConfig->addClassAccountPoolSize;
|
||||||
size_t start = sPlayerbotAIConfig->randomBotAccounts.size() > poolSize ? sPlayerbotAIConfig->randomBotAccounts.size() - poolSize : 0;
|
size_t start = sPlayerbotAIConfig->randomBotAccounts.size() > poolSize
|
||||||
|
? sPlayerbotAIConfig->randomBotAccounts.size() - poolSize
|
||||||
|
: 0;
|
||||||
int32 collected = 0;
|
int32 collected = 0;
|
||||||
for (size_t i = start; i < sPlayerbotAIConfig->randomBotAccounts.size(); i++)
|
for (size_t i = start; i < sPlayerbotAIConfig->randomBotAccounts.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -2061,7 +2092,8 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot)
|
|||||||
{
|
{
|
||||||
level = maxLevel;
|
level = maxLevel;
|
||||||
}
|
}
|
||||||
else if (roll <= (100 * (sPlayerbotAIConfig->randomBotMaxLevelChance + sPlayerbotAIConfig->randomBotMinLevelChance)))
|
else if (roll <=
|
||||||
|
(100 * (sPlayerbotAIConfig->randomBotMaxLevelChance + sPlayerbotAIConfig->randomBotMinLevelChance)))
|
||||||
{
|
{
|
||||||
level = minLevel;
|
level = minLevel;
|
||||||
}
|
}
|
||||||
@@ -2281,7 +2313,8 @@ bool RandomPlayerbotMgr::IsAddclassBot(ObjectGuid::LowType bot)
|
|||||||
continue;
|
continue;
|
||||||
for (uint8 isAlliance = 0; isAlliance <= 1; isAlliance++)
|
for (uint8 isAlliance = 0; isAlliance <= 1; isAlliance++)
|
||||||
{
|
{
|
||||||
if (addclassCache[GetTeamClassIdx(isAlliance, claz)].find(guid) != addclassCache[GetTeamClassIdx(isAlliance, claz)].end())
|
if (addclassCache[GetTeamClassIdx(isAlliance, claz)].find(guid) !=
|
||||||
|
addclassCache[GetTeamClassIdx(isAlliance, claz)].end())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2626,8 +2659,8 @@ void RandomPlayerbotMgr::OnBotLoginInternal(Player* const bot)
|
|||||||
{
|
{
|
||||||
if (_isBotLogging)
|
if (_isBotLogging)
|
||||||
{
|
{
|
||||||
LOG_INFO("playerbots", "{}/{} Bot {} logged in", playerBots.size(), sRandomPlayerbotMgr->GetMaxAllowedBotCount(),
|
LOG_INFO("playerbots", "{}/{} Bot {} logged in", playerBots.size(),
|
||||||
bot->GetName().c_str());
|
sRandomPlayerbotMgr->GetMaxAllowedBotCount(), bot->GetName().c_str());
|
||||||
|
|
||||||
if (playerBots.size() == sRandomPlayerbotMgr->GetMaxAllowedBotCount())
|
if (playerBots.size() == sRandomPlayerbotMgr->GetMaxAllowedBotCount())
|
||||||
{
|
{
|
||||||
@@ -2725,7 +2758,8 @@ void RandomPlayerbotMgr::OnPlayerLogin(Player* player)
|
|||||||
|
|
||||||
if (IsRandomBot(player))
|
if (IsRandomBot(player))
|
||||||
{
|
{
|
||||||
//ObjectGuid::LowType guid = player->GetGUID().GetCounter(); //not used, conditional could be rewritten for simplicity. line marked for removal.
|
// ObjectGuid::LowType guid = player->GetGUID().GetCounter(); //not used, conditional could be rewritten for
|
||||||
|
// simplicity. line marked for removal.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2788,8 +2822,8 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
uint32 changeStrategy = 0;
|
uint32 changeStrategy = 0;
|
||||||
uint32 dead = 0;
|
uint32 dead = 0;
|
||||||
uint32 combat = 0;
|
uint32 combat = 0;
|
||||||
//uint32 revive = 0; //not used, line marked for removal.
|
// uint32 revive = 0; //not used, line marked for removal.
|
||||||
uint32 taxi = 0;
|
uint32 inFlight = 0;
|
||||||
uint32 moving = 0;
|
uint32 moving = 0;
|
||||||
uint32 mounted = 0;
|
uint32 mounted = 0;
|
||||||
uint32 inBg = 0;
|
uint32 inBg = 0;
|
||||||
@@ -2847,6 +2881,10 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
{
|
{
|
||||||
++moving;
|
++moving;
|
||||||
}
|
}
|
||||||
|
if (bot->IsInFlight())
|
||||||
|
{
|
||||||
|
++inFlight;
|
||||||
|
}
|
||||||
if (bot->IsMounted())
|
if (bot->IsMounted())
|
||||||
{
|
{
|
||||||
++mounted;
|
++mounted;
|
||||||
@@ -2883,7 +2921,6 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots level:");
|
LOG_INFO("playerbots", "Bots level:");
|
||||||
// uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
// uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||||
uint32_t currentAlliance = 0, currentHorde = 0;
|
uint32_t currentAlliance = 0, currentHorde = 0;
|
||||||
@@ -2908,20 +2945,24 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
LOG_INFO("playerbots", "Bots race:");
|
LOG_INFO("playerbots", "Bots race:");
|
||||||
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
for (uint8 race = RACE_HUMAN; race < MAX_RACES; ++race)
|
||||||
{
|
{
|
||||||
if (perRace[race]) {
|
if (perRace[race])
|
||||||
|
{
|
||||||
uint32 lvl = lvlPerRace[race] * 10 / perRace[race];
|
uint32 lvl = lvlPerRace[race] * 10 / perRace[race];
|
||||||
float flvl = lvl / 10.0f;
|
float flvl = lvl / 10.0f;
|
||||||
LOG_INFO("playerbots", " {}: {}, avg lvl: {}", ChatHelper::FormatRace(race).c_str(), perRace[race], flvl);
|
LOG_INFO("playerbots", " {}: {}, avg lvl: {}", ChatHelper::FormatRace(race).c_str(), perRace[race],
|
||||||
|
flvl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots class:");
|
LOG_INFO("playerbots", "Bots class:");
|
||||||
for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls)
|
for (uint8 cls = CLASS_WARRIOR; cls < MAX_CLASSES; ++cls)
|
||||||
{
|
{
|
||||||
if (perClass[cls]) {
|
if (perClass[cls])
|
||||||
|
{
|
||||||
uint32 lvl = lvlPerClass[cls] * 10 / perClass[cls];
|
uint32 lvl = lvlPerClass[cls] * 10 / perClass[cls];
|
||||||
float flvl = lvl / 10.0f;
|
float flvl = lvl / 10.0f;
|
||||||
LOG_INFO("playerbots", " {}: {}, avg lvl: {}", ChatHelper::FormatClass(cls).c_str(), perClass[cls], flvl);
|
LOG_INFO("playerbots", " {}: {}, avg lvl: {}", ChatHelper::FormatClass(cls).c_str(), perClass[cls],
|
||||||
|
flvl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2939,57 +2980,30 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
// LOG_INFO("playerbots", " change_strategy: {}", changeStrategy);
|
// LOG_INFO("playerbots", " change_strategy: {}", changeStrategy);
|
||||||
// LOG_INFO("playerbots", " revive: {}", revive);
|
// LOG_INFO("playerbots", " revive: {}", revive);
|
||||||
|
|
||||||
LOG_INFO("playerbots", " On taxi: {}", taxi);
|
LOG_INFO("playerbots", " In flight: {}", inFlight);
|
||||||
LOG_INFO("playerbots", " On mount: {}", mounted);
|
LOG_INFO("playerbots", " On mount: {}", mounted);
|
||||||
LOG_INFO("playerbots", " In combat: {}", combat);
|
LOG_INFO("playerbots", " In combat: {}", combat);
|
||||||
LOG_INFO("playerbots", " In BG: {}", inBg);
|
LOG_INFO("playerbots", " In BG: {}", inBg);
|
||||||
LOG_INFO("playerbots", " In Rest: {}", rest);
|
LOG_INFO("playerbots", " In Rest: {}", rest);
|
||||||
LOG_INFO("playerbots", " Dead: {}", dead);
|
LOG_INFO("playerbots", " Dead: {}", dead);
|
||||||
|
|
||||||
// LOG_INFO("playerbots", "Bots zone:");
|
|
||||||
// for (auto &[zond_id, counter] : zoneCount)
|
|
||||||
// {
|
|
||||||
// const AreaTableEntry* entry = sAreaTableStore.LookupEntry(zond_id);
|
|
||||||
// std::string name = PlayerbotAI::GetLocalizedAreaName(entry);
|
|
||||||
// LOG_INFO("playerbots", " {}: {}", name, counter);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
if (sPlayerbotAIConfig->enableNewRpgStrategy)
|
||||||
{
|
{
|
||||||
LOG_INFO("playerbots", "Bots rpg status:");
|
LOG_INFO("playerbots", "Bots rpg status:");
|
||||||
LOG_INFO("playerbots", " Idle: {}, Rest: {}, GoGrind: {}, GoInnkeeper: {}, MoveRandom: {}, MoveNpc: {}, DoQuest: {}",
|
LOG_INFO("playerbots",
|
||||||
rpgStatusCount[RPG_IDLE], rpgStatusCount[RPG_REST], rpgStatusCount[RPG_GO_GRIND], rpgStatusCount[RPG_GO_INNKEEPER],
|
" Idle: {}, Rest: {}, GoGrind: {}, GoCamp: {}, MoveRandom: {}, MoveNpc: {}, DoQuest: {}, "
|
||||||
rpgStatusCount[RPG_NEAR_RANDOM], rpgStatusCount[RPG_NEAR_NPC], rpgStatusCount[RPG_DO_QUEST]);
|
"TravelFlight: {}",
|
||||||
|
rpgStatusCount[RPG_IDLE], rpgStatusCount[RPG_REST], rpgStatusCount[RPG_GO_GRIND],
|
||||||
|
rpgStatusCount[RPG_GO_CAMP], rpgStatusCount[RPG_WANDER_RANDOM], rpgStatusCount[RPG_WANDER_NPC],
|
||||||
|
rpgStatusCount[RPG_DO_QUEST], rpgStatusCount[RPG_TRAVEL_FLIGHT]);
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots total quests:");
|
LOG_INFO("playerbots", "Bots total quests:");
|
||||||
LOG_INFO("playerbots", " Accepted: {}, Rewarded: {}, Dropped: {}",
|
LOG_INFO("playerbots", " Accepted: {}, Rewarded: {}, Dropped: {}", rpgStasticTotal.questAccepted,
|
||||||
rpgStasticTotal.questAccepted, rpgStasticTotal.questRewarded, rpgStasticTotal.questDropped);
|
rpgStasticTotal.questRewarded, rpgStasticTotal.questDropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots engine:", dead);
|
LOG_INFO("playerbots", "Bots engine:", dead);
|
||||||
LOG_INFO("playerbots", " Non-combat: {}, Combat: {}, Dead: {}", engine_noncombat, engine_combat, engine_dead);
|
LOG_INFO("playerbots", " Non-combat: {}, Combat: {}, Dead: {}", engine_noncombat, engine_combat, engine_dead);
|
||||||
|
|
||||||
// LOG_INFO("playerbots", "Bots questing:");
|
|
||||||
// LOG_INFO("playerbots", " Picking quests: {}",
|
|
||||||
// stateCount[TRAVEL_STATE_TRAVEL_PICK_UP_QUEST] + stateCount[TRAVEL_STATE_WORK_PICK_UP_QUEST]);
|
|
||||||
// LOG_INFO("playerbots", " Doing quests: {}",
|
|
||||||
// stateCount[TRAVEL_STATE_TRAVEL_DO_QUEST] + stateCount[TRAVEL_STATE_WORK_DO_QUEST]);
|
|
||||||
// LOG_INFO("playerbots", " Completing quests: {}",
|
|
||||||
// stateCount[TRAVEL_STATE_TRAVEL_HAND_IN_QUEST] + stateCount[TRAVEL_STATE_WORK_HAND_IN_QUEST]);
|
|
||||||
// LOG_INFO("playerbots", " Idling: {}", stateCount[TRAVEL_STATE_IDLE]);
|
|
||||||
|
|
||||||
/*sort(questCount.begin(), questCount.end(), [](std::pair<Quest const*, int32> i, std::pair<Quest const*, int32> j)
|
|
||||||
{return i.second > j.second; });
|
|
||||||
|
|
||||||
LOG_INFO("playerbots", "Bots top quests:");
|
|
||||||
|
|
||||||
uint32 cnt = 0;
|
|
||||||
for (auto& quest : questCount)
|
|
||||||
{
|
|
||||||
LOG_INFO("playerbots", " [{}]: {} ({})", quest.second, quest.first->GetTitle().c_str(),
|
|
||||||
quest.first->GetQuestLevel()); cnt++; if (cnt > 25) break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double RandomPlayerbotMgr::GetBuyMultiplier(Player* bot)
|
double RandomPlayerbotMgr::GetBuyMultiplier(Player* bot)
|
||||||
|
|||||||
@@ -180,6 +180,8 @@ public:
|
|||||||
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> locsPerLevelCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> allianceStarterPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> allianceStarterPerLevelCache;
|
||||||
std::map<uint8, std::vector<WorldLocation>> hordeStarterPerLevelCache;
|
std::map<uint8, std::vector<WorldLocation>> hordeStarterPerLevelCache;
|
||||||
|
std::vector<uint32> allianceFlightMasterCache;
|
||||||
|
std::vector<uint32> hordeFlightMasterCache;
|
||||||
struct LevelBracket {
|
struct LevelBracket {
|
||||||
uint32 low;
|
uint32 low;
|
||||||
uint32 high;
|
uint32 high;
|
||||||
|
|||||||
@@ -246,10 +246,11 @@ public:
|
|||||||
|
|
||||||
creators["new rpg status update"] = &ActionContext::new_rpg_status_update;
|
creators["new rpg status update"] = &ActionContext::new_rpg_status_update;
|
||||||
creators["new rpg go grind"] = &ActionContext::new_rpg_go_grind;
|
creators["new rpg go grind"] = &ActionContext::new_rpg_go_grind;
|
||||||
creators["new rpg go innkeeper"] = &ActionContext::new_rpg_go_innkeeper;
|
creators["new rpg go camp"] = &ActionContext::new_rpg_go_camp;
|
||||||
creators["new rpg move random"] = &ActionContext::new_rpg_move_random;
|
creators["new rpg wander random"] = &ActionContext::new_rpg_wander_random;
|
||||||
creators["new rpg move npc"] = &ActionContext::new_rpg_move_npc;
|
creators["new rpg wander npc"] = &ActionContext::new_rpg_wander_npc;
|
||||||
creators["new rpg do quest"] = &ActionContext::new_rpg_do_quest;
|
creators["new rpg do quest"] = &ActionContext::new_rpg_do_quest;
|
||||||
|
creators["new rpg travel flight"] = &ActionContext::new_rpg_travel_flight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -430,10 +431,11 @@ private:
|
|||||||
|
|
||||||
static Action* new_rpg_status_update(PlayerbotAI* ai) { return new NewRpgStatusUpdateAction(ai); }
|
static Action* new_rpg_status_update(PlayerbotAI* ai) { return new NewRpgStatusUpdateAction(ai); }
|
||||||
static Action* new_rpg_go_grind(PlayerbotAI* ai) { return new NewRpgGoGrindAction(ai); }
|
static Action* new_rpg_go_grind(PlayerbotAI* ai) { return new NewRpgGoGrindAction(ai); }
|
||||||
static Action* new_rpg_go_innkeeper(PlayerbotAI* ai) { return new NewRpgGoInnKeeperAction(ai); }
|
static Action* new_rpg_go_camp(PlayerbotAI* ai) { return new NewRpgGoCampAction(ai); }
|
||||||
static Action* new_rpg_move_random(PlayerbotAI* ai) { return new NewRpgMoveRandomAction(ai); }
|
static Action* new_rpg_wander_random(PlayerbotAI* ai) { return new NewRpgWanderRandomAction(ai); }
|
||||||
static Action* new_rpg_move_npc(PlayerbotAI* ai) { return new NewRpgMoveNpcAction(ai); }
|
static Action* new_rpg_wander_npc(PlayerbotAI* ai) { return new NewRpgWanderNpcAction(ai); }
|
||||||
static Action* new_rpg_do_quest(PlayerbotAI* ai) { return new NewRpgDoQuestAction(ai); }
|
static Action* new_rpg_do_quest(PlayerbotAI* ai) { return new NewRpgDoQuestAction(ai); }
|
||||||
|
static Action* new_rpg_travel_flight(PlayerbotAI* ai) { return new NewRpgTravelFlightAction(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "BroadcastHelper.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
|
#include "DBCStores.h"
|
||||||
#include "G3D/Vector2.h"
|
#include "G3D/Vector2.h"
|
||||||
#include "GossipDef.h"
|
#include "GossipDef.h"
|
||||||
#include "IVMapMgr.h"
|
#include "IVMapMgr.h"
|
||||||
@@ -27,7 +29,6 @@
|
|||||||
#include "StatsWeightCalculator.h"
|
#include "StatsWeightCalculator.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "BroadcastHelper.h"
|
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
|
|
||||||
bool TellRpgStatusAction::Execute(Event event)
|
bool TellRpgStatusAction::Execute(Event event)
|
||||||
@@ -63,102 +64,50 @@ bool StartRpgDoQuestAction::Execute(Event event)
|
|||||||
bool NewRpgStatusUpdateAction::Execute(Event event)
|
bool NewRpgStatusUpdateAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
NewRpgInfo& info = botAI->rpgInfo;
|
NewRpgInfo& info = botAI->rpgInfo;
|
||||||
/// @TODO: Refactor by transition probability
|
|
||||||
switch (info.status)
|
switch (info.status)
|
||||||
{
|
{
|
||||||
case RPG_IDLE:
|
case RPG_IDLE:
|
||||||
{
|
{
|
||||||
uint32 roll = urand(1, 100);
|
return RandomChangeStatus({RPG_GO_CAMP, RPG_GO_GRIND, RPG_WANDER_RANDOM, RPG_WANDER_NPC, RPG_DO_QUEST,
|
||||||
// IDLE -> NEAR_NPC
|
RPG_TRAVEL_FLIGHT, RPG_REST});
|
||||||
if (roll <= 30)
|
|
||||||
{
|
|
||||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible new rpg targets");
|
|
||||||
if (possibleTargets.size() >= 3)
|
|
||||||
{
|
|
||||||
info.ChangeToNearNpc();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// IDLE -> GO_INNKEEPER
|
|
||||||
else if (roll <= 45)
|
|
||||||
{
|
|
||||||
WorldPosition pos = SelectRandomInnKeeperPos(bot);
|
|
||||||
if (pos != WorldPosition() && bot->GetExactDist(pos) > 50.0f)
|
|
||||||
{
|
|
||||||
info.ChangeToGoInnkeeper(pos);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// IDLE -> GO_GRIND
|
|
||||||
else if (roll <= 100)
|
|
||||||
{
|
|
||||||
if (roll >= 60)
|
|
||||||
{
|
|
||||||
std::vector<uint32> availableQuests;
|
|
||||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
|
||||||
{
|
|
||||||
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
|
||||||
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::vector<POIInfo> poiInfo;
|
|
||||||
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
|
||||||
{
|
|
||||||
availableQuests.push_back(questId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (availableQuests.size())
|
|
||||||
{
|
|
||||||
uint32 questId = availableQuests[urand(0, availableQuests.size() - 1)];
|
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
|
||||||
if (quest)
|
|
||||||
{
|
|
||||||
// IDLE -> DO_QUEST
|
|
||||||
info.ChangeToDoQuest(questId, quest);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WorldPosition pos = SelectRandomGrindPos(bot);
|
|
||||||
if (pos != WorldPosition())
|
|
||||||
{
|
|
||||||
info.ChangeToGoGrind(pos);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// IDLE -> REST
|
|
||||||
info.ChangeToRest();
|
|
||||||
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
case RPG_GO_GRIND:
|
case RPG_GO_GRIND:
|
||||||
{
|
{
|
||||||
WorldPosition& originalPos = info.go_grind.pos;
|
WorldPosition& originalPos = info.go_grind.pos;
|
||||||
assert(info.go_grind.pos != WorldPosition());
|
assert(info.go_grind.pos != WorldPosition());
|
||||||
// GO_GRIND -> NEAR_RANDOM
|
// GO_GRIND -> WANDER_RANDOM
|
||||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||||
{
|
{
|
||||||
info.ChangeToNearRandom();
|
info.ChangeToWanderRandom();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RPG_GO_INNKEEPER:
|
case RPG_GO_CAMP:
|
||||||
{
|
{
|
||||||
WorldPosition& originalPos = info.go_innkeeper.pos;
|
WorldPosition& originalPos = info.go_camp.pos;
|
||||||
assert(info.go_innkeeper.pos != WorldPosition());
|
assert(info.go_camp.pos != WorldPosition());
|
||||||
// GO_INNKEEPER -> NEAR_NPC
|
// GO_CAMP -> WANDER_NPC
|
||||||
if (bot->GetExactDist(originalPos) < 10.0f)
|
if (bot->GetExactDist(originalPos) < 10.0f)
|
||||||
{
|
{
|
||||||
info.ChangeToNearNpc();
|
info.ChangeToWanderNpc();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RPG_NEAR_RANDOM:
|
case RPG_WANDER_RANDOM:
|
||||||
{
|
{
|
||||||
// NEAR_RANDOM -> IDLE
|
// WANDER_RANDOM -> IDLE
|
||||||
if (info.HasStatusPersisted(statusNearRandomDuration))
|
if (info.HasStatusPersisted(statusWanderRandomDuration))
|
||||||
|
{
|
||||||
|
info.ChangeToIdle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RPG_WANDER_NPC:
|
||||||
|
{
|
||||||
|
if (info.HasStatusPersisted(statusWanderNpcDuration))
|
||||||
{
|
{
|
||||||
info.ChangeToIdle();
|
info.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
@@ -175,10 +124,11 @@ bool NewRpgStatusUpdateAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RPG_NEAR_NPC:
|
case RPG_TRAVEL_FLIGHT:
|
||||||
{
|
{
|
||||||
if (info.HasStatusPersisted(statusNearNpcDuration))
|
if (info.flight.inFlight && !bot->IsInFlight())
|
||||||
{
|
{
|
||||||
|
// flight arrival
|
||||||
info.ChangeToIdle();
|
info.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -208,15 +158,15 @@ bool NewRpgGoGrindAction::Execute(Event event)
|
|||||||
return MoveFarTo(botAI->rpgInfo.go_grind.pos);
|
return MoveFarTo(botAI->rpgInfo.go_grind.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgGoInnKeeperAction::Execute(Event event)
|
bool NewRpgGoCampAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
if (SearchQuestGiverAndAcceptOrReward())
|
if (SearchQuestGiverAndAcceptOrReward())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return MoveFarTo(botAI->rpgInfo.go_innkeeper.pos);
|
return MoveFarTo(botAI->rpgInfo.go_camp.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgMoveRandomAction::Execute(Event event)
|
bool NewRpgWanderRandomAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
if (SearchQuestGiverAndAcceptOrReward())
|
if (SearchQuestGiverAndAcceptOrReward())
|
||||||
return true;
|
return true;
|
||||||
@@ -224,10 +174,10 @@ bool NewRpgMoveRandomAction::Execute(Event event)
|
|||||||
return MoveRandomNear();
|
return MoveRandomNear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgMoveNpcAction::Execute(Event event)
|
bool NewRpgWanderNpcAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
NewRpgInfo& info = botAI->rpgInfo;
|
NewRpgInfo& info = botAI->rpgInfo;
|
||||||
if (!info.near_npc.npcOrGo)
|
if (!info.wander_npc.npcOrGo)
|
||||||
{
|
{
|
||||||
// No npc can be found, switch to IDLE
|
// No npc can be found, switch to IDLE
|
||||||
ObjectGuid npcOrGo = ChooseNpcOrGameObjectToInteract();
|
ObjectGuid npcOrGo = ChooseNpcOrGameObjectToInteract();
|
||||||
@@ -236,32 +186,32 @@ bool NewRpgMoveNpcAction::Execute(Event event)
|
|||||||
info.ChangeToIdle();
|
info.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
info.near_npc.npcOrGo = npcOrGo;
|
info.wander_npc.npcOrGo = npcOrGo;
|
||||||
info.near_npc.lastReach = 0;
|
info.wander_npc.lastReach = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.near_npc.npcOrGo);
|
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, info.wander_npc.npcOrGo);
|
||||||
if (object && IsWithinInteractionDist(object))
|
if (object && IsWithinInteractionDist(object))
|
||||||
{
|
{
|
||||||
if (!info.near_npc.lastReach)
|
if (!info.wander_npc.lastReach)
|
||||||
{
|
{
|
||||||
info.near_npc.lastReach = getMSTime();
|
info.wander_npc.lastReach = getMSTime();
|
||||||
if (bot->CanInteractWithQuestGiver(object))
|
if (bot->CanInteractWithQuestGiver(object))
|
||||||
InteractWithNpcOrGameObjectForQuest(info.near_npc.npcOrGo);
|
InteractWithNpcOrGameObjectForQuest(info.wander_npc.npcOrGo);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.near_npc.lastReach && GetMSTimeDiffToNow(info.near_npc.lastReach) < npcStayTime)
|
if (info.wander_npc.lastReach && GetMSTimeDiffToNow(info.wander_npc.lastReach) < npcStayTime)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// has reached the npc for more than `npcStayTime`, select the next target
|
// has reached the npc for more than `npcStayTime`, select the next target
|
||||||
info.near_npc.npcOrGo = ObjectGuid();
|
info.wander_npc.npcOrGo = ObjectGuid();
|
||||||
info.near_npc.lastReach = 0;
|
info.wander_npc.lastReach = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return MoveWorldObjectTo(info.near_npc.npcOrGo);
|
return MoveWorldObjectTo(info.wander_npc.npcOrGo);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -384,7 +334,7 @@ bool NewRpgDoQuestAction::DoIncompleteQuest()
|
|||||||
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
||||||
botAI->lowPriorityQuest.insert(questId);
|
botAI->lowPriorityQuest.insert(questId);
|
||||||
botAI->rpgStatistic.questAbandoned++;
|
botAI->rpgStatistic.questAbandoned++;
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} marked as abandoned quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||||
botAI->rpgInfo.ChangeToIdle();
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -451,9 +401,43 @@ bool NewRpgDoQuestAction::DoCompletedQuest()
|
|||||||
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
/// @TODO: It may be better to make lowPriorityQuest a global set shared by all bots (or saved in db)
|
||||||
botAI->lowPriorityQuest.insert(questId);
|
botAI->lowPriorityQuest.insert(questId);
|
||||||
botAI->rpgStatistic.questAbandoned++;
|
botAI->rpgStatistic.questAbandoned++;
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} marked as abandoned quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} marked as abandoned quest {}", bot->GetName(), questId);
|
||||||
botAI->rpgInfo.ChangeToIdle();
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NewRpgTravelFlightAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
if (bot->IsInFlight())
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.flight.inFlight = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Creature* flightMaster = ObjectAccessor::GetCreature(*bot, botAI->rpgInfo.flight.fromFlightMaster);
|
||||||
|
if (!flightMaster || !flightMaster->IsAlive())
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const TaxiNodesEntry* entry = sTaxiNodesStore.LookupEntry(botAI->rpgInfo.flight.toNode);
|
||||||
|
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
||||||
|
{
|
||||||
|
return MoveFarTo(flightMaster);
|
||||||
|
}
|
||||||
|
std::vector<uint32> nodes = {botAI->rpgInfo.flight.fromNode, botAI->rpgInfo.flight.toNode};
|
||||||
|
|
||||||
|
botAI->RemoveShapeshift();
|
||||||
|
if (bot->IsMounted())
|
||||||
|
{
|
||||||
|
bot->Dismount();
|
||||||
|
}
|
||||||
|
if (!bot->ActivateTaxiPathTo(nodes, flightMaster, 0))
|
||||||
|
{
|
||||||
|
LOG_DEBUG("playerbots", "[New RPG] {} active taxi path {} (from {} to {}) failed", bot->GetName(),
|
||||||
|
flightMaster->GetEntry(), nodes[0], nodes[1]);
|
||||||
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -3,15 +3,15 @@
|
|||||||
|
|
||||||
#include "Duration.h"
|
#include "Duration.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
|
#include "NewRpgBaseAction.h"
|
||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "NewRpgStrategy.h"
|
#include "NewRpgStrategy.h"
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "ObjectDefines.h"
|
#include "ObjectDefines.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
#include "QuestDef.h"
|
#include "QuestDef.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "NewRpgBaseAction.h"
|
|
||||||
|
|
||||||
class TellRpgStatusAction : public Action
|
class TellRpgStatusAction : public Action
|
||||||
{
|
{
|
||||||
@@ -39,15 +39,16 @@ public:
|
|||||||
// transitionMat.resize(statusCount, std::vector<int>(statusCount, 0));
|
// transitionMat.resize(statusCount, std::vector<int>(statusCount, 0));
|
||||||
|
|
||||||
// transitionMat[RPG_IDLE][RPG_GO_GRIND] = 20;
|
// transitionMat[RPG_IDLE][RPG_GO_GRIND] = 20;
|
||||||
// transitionMat[RPG_IDLE][RPG_GO_INNKEEPER] = 15;
|
// transitionMat[RPG_IDLE][RPG_GO_CAMP] = 15;
|
||||||
// transitionMat[RPG_IDLE][RPG_NEAR_NPC] = 30;
|
// transitionMat[RPG_IDLE][RPG_WANDER_NPC] = 30;
|
||||||
// transitionMat[RPG_IDLE][RPG_DO_QUEST] = 35;
|
// transitionMat[RPG_IDLE][RPG_DO_QUEST] = 35;
|
||||||
}
|
}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// static NewRpgStatusTransitionProb transitionMat;
|
// static NewRpgStatusTransitionProb transitionMat;
|
||||||
const int32 statusNearNpcDuration = 5 * 60 * 1000;
|
const int32 statusWanderNpcDuration = 5 * 60 * 1000;
|
||||||
const int32 statusNearRandomDuration = 5 * 60 * 1000;
|
const int32 statusWanderRandomDuration = 5 * 60 * 1000;
|
||||||
const int32 statusRestDuration = 30 * 1000;
|
const int32 statusRestDuration = 30 * 1000;
|
||||||
const int32 statusDoQuestDuration = 30 * 60 * 1000;
|
const int32 statusDoQuestDuration = 30 * 60 * 1000;
|
||||||
};
|
};
|
||||||
@@ -59,25 +60,24 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NewRpgGoInnKeeperAction : public NewRpgBaseAction
|
class NewRpgGoCampAction : public NewRpgBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NewRpgGoInnKeeperAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg go innkeeper") {}
|
NewRpgGoCampAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg go camp") {}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NewRpgWanderRandomAction : public NewRpgBaseAction
|
||||||
class NewRpgMoveRandomAction : public NewRpgBaseAction
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NewRpgMoveRandomAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move random") {}
|
NewRpgWanderRandomAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg wander random") {}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NewRpgMoveNpcAction : public NewRpgBaseAction
|
class NewRpgWanderNpcAction : public NewRpgBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NewRpgMoveNpcAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move npcs") {}
|
NewRpgWanderNpcAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg move npcs") {}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
const uint32 npcStayTime = 8 * 1000;
|
const uint32 npcStayTime = 8 * 1000;
|
||||||
@@ -88,6 +88,7 @@ class NewRpgDoQuestAction : public NewRpgBaseAction
|
|||||||
public:
|
public:
|
||||||
NewRpgDoQuestAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg do quest") {}
|
NewRpgDoQuestAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg do quest") {}
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool DoIncompleteQuest();
|
bool DoIncompleteQuest();
|
||||||
bool DoCompletedQuest();
|
bool DoCompletedQuest();
|
||||||
@@ -95,4 +96,11 @@ protected:
|
|||||||
const uint32 poiStayTime = 5 * 60 * 1000;
|
const uint32 poiStayTime = 5 * 60 * 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NewRpgTravelFlightAction : public NewRpgBaseAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NewRpgTravelFlightAction(PlayerbotAI* botAI) : NewRpgBaseAction(botAI, "new rpg travel flight") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
#include "NewRpgBaseAction.h"
|
#include "NewRpgBaseAction.h"
|
||||||
|
|
||||||
|
#include "BroadcastHelper.h"
|
||||||
#include "ChatHelper.h"
|
#include "ChatHelper.h"
|
||||||
|
#include "Creature.h"
|
||||||
#include "G3D/Vector2.h"
|
#include "G3D/Vector2.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
#include "GossipDef.h"
|
#include "GossipDef.h"
|
||||||
@@ -15,6 +18,7 @@
|
|||||||
#include "PathGenerator.h"
|
#include "PathGenerator.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "Position.h"
|
#include "Position.h"
|
||||||
#include "QuestDef.h"
|
#include "QuestDef.h"
|
||||||
@@ -24,7 +28,6 @@
|
|||||||
#include "StatsWeightCalculator.h"
|
#include "StatsWeightCalculator.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "BroadcastHelper.h"
|
|
||||||
|
|
||||||
bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
||||||
{
|
{
|
||||||
@@ -58,9 +61,12 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
|||||||
botAI->rpgInfo.stuckAttempts = 0;
|
botAI->rpgInfo.stuckAttempts = 0;
|
||||||
const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId());
|
const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId());
|
||||||
std::string zone_name = PlayerbotAI::GetLocalizedAreaName(entry);
|
std::string zone_name = PlayerbotAI::GetLocalizedAreaName(entry);
|
||||||
LOG_DEBUG("playerbots", "[New Rpg] Teleport {} from ({},{},{},{}) to ({},{},{},{}) as it stuck when moving far - Zone: {} ({})", bot->GetName(),
|
LOG_DEBUG(
|
||||||
bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId(),
|
"playerbots",
|
||||||
dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.getMapId(), bot->GetZoneId(), zone_name);
|
"[New RPG] Teleport {} from ({},{},{},{}) to ({},{},{},{}) as it stuck when moving far - Zone: {} ({})",
|
||||||
|
bot->GetName(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetMapId(),
|
||||||
|
dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), dest.getMapId(), bot->GetZoneId(),
|
||||||
|
zone_name);
|
||||||
return bot->TeleportTo(dest);
|
return bot->TeleportTo(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +196,9 @@ bool NewRpgBaseAction::MoveRandomNear(float moveStep, MovementPriority priority)
|
|||||||
|
|
||||||
bool NewRpgBaseAction::ForceToWait(uint32 duration, MovementPriority priority)
|
bool NewRpgBaseAction::ForceToWait(uint32 duration, MovementPriority priority)
|
||||||
{
|
{
|
||||||
AI_VALUE(LastMovement&, "last movement").Set(bot->GetMapId(),
|
AI_VALUE(LastMovement&, "last movement")
|
||||||
bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(), duration, priority);
|
.Set(bot->GetMapId(), bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), bot->GetOrientation(),
|
||||||
|
duration, priority);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,27 +219,27 @@ bool NewRpgBaseAction::InteractWithNpcOrGameObjectForQuest(ObjectGuid guid)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
bot->PrepareQuestMenu(guid);
|
bot->PrepareQuestMenu(guid);
|
||||||
const QuestMenu &menu = bot->PlayerTalkClass->GetQuestMenu();
|
const QuestMenu& menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||||
if (menu.Empty())
|
if (menu.Empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||||
{
|
{
|
||||||
const QuestMenuItem &item = menu.GetItem(idx);
|
const QuestMenuItem& item = menu.GetItem(idx);
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||||
if (!quest)
|
if (!quest)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) &&
|
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) && bot->CanAddQuest(quest, false) &&
|
||||||
bot->CanAddQuest(quest, false) && IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||||
{
|
{
|
||||||
AcceptQuest(quest, guid);
|
AcceptQuest(quest, guid);
|
||||||
if (botAI->GetMaster())
|
if (botAI->GetMaster())
|
||||||
botAI->TellMasterNoFacing("Quest accepted " + ChatHelper::FormatQuest(quest));
|
botAI->TellMasterNoFacing("Quest accepted " + ChatHelper::FormatQuest(quest));
|
||||||
BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest);
|
BroadcastHelper::BroadcastQuestAccepted(botAI, bot, quest);
|
||||||
botAI->rpgStatistic.questAccepted++;
|
botAI->rpgStatistic.questAccepted++;
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} accept quest {}", bot->GetName(), quest->GetQuestId());
|
LOG_DEBUG("playerbots", "[New RPG] {} accept quest {}", bot->GetName(), quest->GetQuestId());
|
||||||
}
|
}
|
||||||
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
||||||
{
|
{
|
||||||
@@ -241,7 +248,7 @@ bool NewRpgBaseAction::InteractWithNpcOrGameObjectForQuest(ObjectGuid guid)
|
|||||||
botAI->TellMasterNoFacing("Quest rewarded " + ChatHelper::FormatQuest(quest));
|
botAI->TellMasterNoFacing("Quest rewarded " + ChatHelper::FormatQuest(quest));
|
||||||
BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest);
|
BroadcastHelper::BroadcastQuestTurnedIn(botAI, bot, quest);
|
||||||
botAI->rpgStatistic.questRewarded++;
|
botAI->rpgStatistic.questRewarded++;
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} turned in quest {}", bot->GetName(), quest->GetQuestId());
|
LOG_DEBUG("playerbots", "[New RPG] {} turned in quest {}", bot->GetName(), quest->GetQuestId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -273,11 +280,13 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Deathstate checks
|
// Deathstate checks
|
||||||
if (!bot->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS))
|
if (!bot->IsAlive() &&
|
||||||
|
!(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// alive or spirit healer
|
// alive or spirit healer
|
||||||
if (!creature->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD))
|
if (!creature->IsAlive() &&
|
||||||
|
!(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// appropriate npc type
|
// appropriate npc type
|
||||||
@@ -292,9 +301,12 @@ bool NewRpgBaseAction::CanInteractWithQuestGiver(Object* questGiver)
|
|||||||
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
|
if (creature->GetReactionTo(bot) <= REP_UNFRIENDLY)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train dual wield to a shaman :/ too many to change in sql and watch in the future
|
// pussywizard: many npcs have missing conditions for class training and rogue trainer can for eg. train
|
||||||
// pussywizard: this function is not used when talking, but when already taking action (buy spell, reset talents, show spell list)
|
// dual wield to a shaman :/ too many to change in sql and watch in the future pussywizard: this function is
|
||||||
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS && !bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
|
// not used when talking, but when already taking action (buy spell, reset talents, show spell list)
|
||||||
|
if (npcflagmask & (UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_TRAINER_CLASS) &&
|
||||||
|
creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS &&
|
||||||
|
!bot->IsClass((Classes)creature->GetCreatureTemplate()->trainer_class, CLASS_CONTEXT_CLASS_TRAINER))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -459,7 +471,8 @@ uint32 NewRpgBaseAction::BestRewardIndex(Quest const* quest)
|
|||||||
|
|
||||||
bool NewRpgBaseAction::IsQuestWorthDoing(Quest const* quest)
|
bool NewRpgBaseAction::IsQuestWorthDoing(Quest const* quest)
|
||||||
{
|
{
|
||||||
bool isLowLevelQuest = bot->GetLevel() > (bot->GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF));
|
bool isLowLevelQuest =
|
||||||
|
bot->GetLevel() > (bot->GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF));
|
||||||
|
|
||||||
if (isLowLevelQuest)
|
if (isLowLevelQuest)
|
||||||
return false;
|
return false;
|
||||||
@@ -514,11 +527,10 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
if (!IsQuestWorthDoing(quest) ||
|
if (!IsQuestWorthDoing(quest) || !IsQuestCapableDoing(quest) ||
|
||||||
!IsQuestCapableDoing(quest) ||
|
|
||||||
bot->GetQuestStatus(questId) == QUEST_STATUS_FAILED)
|
bot->GetQuestStatus(questId) == QUEST_STATUS_FAILED)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||||
packet << (uint8)i;
|
packet << (uint8)i;
|
||||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||||
@@ -541,10 +553,9 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
if (quest->GetZoneOrSort() < 0 ||
|
if (quest->GetZoneOrSort() < 0 || (quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != bot->GetZoneId()))
|
||||||
(quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != bot->GetZoneId()))
|
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||||
packet << (uint8)i;
|
packet << (uint8)i;
|
||||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||||
@@ -566,7 +577,7 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
LOG_DEBUG("playerbots", "[New rpg] {} drop quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||||
packet << (uint8)i;
|
packet << (uint8)i;
|
||||||
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
bot->GetSession()->HandleQuestLogRemoveQuest(packet);
|
||||||
@@ -604,7 +615,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
|||||||
return ObjectGuid();
|
return ObjectGuid();
|
||||||
|
|
||||||
WorldObject* nearestObject = nullptr;
|
WorldObject* nearestObject = nullptr;
|
||||||
for (ObjectGuid& guid: possibleTargets)
|
for (ObjectGuid& guid : possibleTargets)
|
||||||
{
|
{
|
||||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
||||||
|
|
||||||
@@ -622,7 +633,7 @@ ObjectGuid NewRpgBaseAction::ChooseNpcOrGameObjectToInteract(bool questgiverOnly
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ObjectGuid& guid: possibleGameObjects)
|
for (ObjectGuid& guid : possibleGameObjects)
|
||||||
{
|
{
|
||||||
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
WorldObject* object = ObjectAccessor::GetWorldObject(*bot, guid);
|
||||||
|
|
||||||
@@ -667,17 +678,17 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
|||||||
{
|
{
|
||||||
ObjectGuid guid = object->GetGUID();
|
ObjectGuid guid = object->GetGUID();
|
||||||
bot->PrepareQuestMenu(guid);
|
bot->PrepareQuestMenu(guid);
|
||||||
const QuestMenu &menu = bot->PlayerTalkClass->GetQuestMenu();
|
const QuestMenu& menu = bot->PlayerTalkClass->GetQuestMenu();
|
||||||
if (menu.Empty())
|
if (menu.Empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||||
{
|
{
|
||||||
const QuestMenuItem &item = menu.GetItem(idx);
|
const QuestMenuItem& item = menu.GetItem(idx);
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||||
if (!quest)
|
if (!quest)
|
||||||
continue;
|
continue;
|
||||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||||
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
if (status == QUEST_STATUS_COMPLETE && bot->CanRewardQuest(quest, 0, false))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -685,14 +696,14 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
|||||||
}
|
}
|
||||||
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
for (uint8 idx = 0; idx < menu.GetMenuItemCount(); idx++)
|
||||||
{
|
{
|
||||||
const QuestMenuItem &item = menu.GetItem(idx);
|
const QuestMenuItem& item = menu.GetItem(idx);
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(item.QuestId);
|
||||||
if (!quest)
|
if (!quest)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const QuestStatus &status = bot->GetQuestStatus(item.QuestId);
|
const QuestStatus& status = bot->GetQuestStatus(item.QuestId);
|
||||||
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) &&
|
if (status == QUEST_STATUS_NONE && bot->CanTakeQuest(quest, false) && bot->CanAddQuest(quest, false) &&
|
||||||
bot->CanAddQuest(quest, false) && IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
IsQuestWorthDoing(quest) && IsQuestCapableDoing(quest))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -700,21 +711,24 @@ bool NewRpgBaseAction::HasQuestToAcceptOrReward(WorldObject* object)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<float> GenerateRandomWeights(int n) {
|
static std::vector<float> GenerateRandomWeights(int n)
|
||||||
|
{
|
||||||
std::vector<float> weights(n);
|
std::vector<float> weights(n);
|
||||||
float sum = 0.0;
|
float sum = 0.0;
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
weights[i] = rand_norm();
|
weights[i] = rand_norm();
|
||||||
sum += weights[i];
|
sum += weights[i];
|
||||||
}
|
}
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
weights[i] /= sum;
|
weights[i] /= sum;
|
||||||
}
|
}
|
||||||
return weights;
|
return weights;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo> &poiInfo, bool toComplete)
|
bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector<POIInfo>& poiInfo, bool toComplete)
|
||||||
{
|
{
|
||||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
if (!quest)
|
if (!quest)
|
||||||
@@ -730,7 +744,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
|||||||
|
|
||||||
if (toComplete && q_status.Status == QUEST_STATUS_COMPLETE)
|
if (toComplete && q_status.Status == QUEST_STATUS_COMPLETE)
|
||||||
{
|
{
|
||||||
for (const QuestPOI &qPoi : *poiVector)
|
for (const QuestPOI& qPoi : *poiVector)
|
||||||
{
|
{
|
||||||
if (qPoi.MapId != bot->GetMapId())
|
if (qPoi.MapId != bot->GetMapId())
|
||||||
continue;
|
continue;
|
||||||
@@ -746,7 +760,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
|||||||
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
||||||
for (size_t i = 0; i < qPoi.points.size(); i++)
|
for (size_t i = 0; i < qPoi.points.size(); i++)
|
||||||
{
|
{
|
||||||
const QuestPOIPoint &point = qPoi.points[i];
|
const QuestPOIPoint& point = qPoi.points[i];
|
||||||
dx += point.x * weights[i];
|
dx += point.x * weights[i];
|
||||||
dy += point.y * weights[i];
|
dy += point.y * weights[i];
|
||||||
}
|
}
|
||||||
@@ -796,7 +810,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get POIs to go
|
// Get POIs to go
|
||||||
for (const QuestPOI &qPoi : *poiVector)
|
for (const QuestPOI& qPoi : *poiVector)
|
||||||
{
|
{
|
||||||
if (qPoi.MapId != bot->GetMapId())
|
if (qPoi.MapId != bot->GetMapId())
|
||||||
continue;
|
continue;
|
||||||
@@ -818,7 +832,7 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
|||||||
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
std::vector<float> weights = GenerateRandomWeights(qPoi.points.size());
|
||||||
for (size_t i = 0; i < qPoi.points.size(); i++)
|
for (size_t i = 0; i < qPoi.points.size(); i++)
|
||||||
{
|
{
|
||||||
const QuestPOIPoint &point = qPoi.points[i];
|
const QuestPOIPoint& point = qPoi.points[i];
|
||||||
dx += point.x * weights[i];
|
dx += point.x * weights[i];
|
||||||
dy += point.y * weights[i];
|
dy += point.y * weights[i];
|
||||||
}
|
}
|
||||||
@@ -837,7 +851,8 @@ bool NewRpgBaseAction::GetQuestPOIPosAndObjectiveIdx(uint32 questId, std::vector
|
|||||||
poiInfo.push_back({{dx, dy}, qPoi.ObjectiveIndex});
|
poiInfo.push_back({{dx, dy}, qPoi.ObjectiveIndex});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (poiInfo.size() == 0) {
|
if (poiInfo.size() == 0)
|
||||||
|
{
|
||||||
// LOG_DEBUG("playerbots", "[New rpg] {}: No available poi can be found for quest {}", bot->GetName(), questId);
|
// LOG_DEBUG("playerbots", "[New rpg] {}: No available poi can be found for quest {}", bot->GetName(), questId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -872,8 +887,8 @@ WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot)
|
|||||||
if (bot->GetExactDist(loc) > 2500.0f)
|
if (bot->GetExactDist(loc) > 2500.0f)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()) !=
|
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(),
|
||||||
bot->GetZoneId())
|
loc.GetPositionZ()) != bot->GetZoneId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bot->GetExactDist(loc) < hiRange)
|
if (bot->GetExactDist(loc) < hiRange)
|
||||||
@@ -897,13 +912,13 @@ WorldPosition NewRpgBaseAction::SelectRandomGrindPos(Player* bot)
|
|||||||
uint32 idx = urand(0, lo_prepared_locs.size() - 1);
|
uint32 idx = urand(0, lo_prepared_locs.size() - 1);
|
||||||
dest = lo_prepared_locs[idx];
|
dest = lo_prepared_locs[idx];
|
||||||
}
|
}
|
||||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random grind pos Map:{} X:{} Y:{} Z:{} ({}+{} available in {})",
|
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random grind pos Map:{} X:{} Y:{} Z:{} ({}+{} available in {})",
|
||||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||||
hi_prepared_locs.size(), lo_prepared_locs.size() - hi_prepared_locs.size(), locs.size());
|
hi_prepared_locs.size(), lo_prepared_locs.size() - hi_prepared_locs.size(), locs.size());
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldPosition NewRpgBaseAction::SelectRandomInnKeeperPos(Player* bot)
|
WorldPosition NewRpgBaseAction::SelectRandomCampPos(Player* bot)
|
||||||
{
|
{
|
||||||
const std::vector<WorldLocation>& locs = IsAlliance(bot->getRace())
|
const std::vector<WorldLocation>& locs = IsAlliance(bot->getRace())
|
||||||
? sRandomPlayerbotMgr->allianceStarterPerLevelCache[bot->GetLevel()]
|
? sRandomPlayerbotMgr->allianceStarterPerLevelCache[bot->GetLevel()]
|
||||||
@@ -927,8 +942,11 @@ WorldPosition NewRpgBaseAction::SelectRandomInnKeeperPos(Player* bot)
|
|||||||
if (bot->GetExactDist(loc) > range)
|
if (bot->GetExactDist(loc) > range)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ()) !=
|
if (bot->GetExactDist(loc) < 50.0f)
|
||||||
bot->GetZoneId())
|
continue;
|
||||||
|
|
||||||
|
if (!inCity && bot->GetMap()->GetZoneId(bot->GetPhaseMask(), loc.GetPositionX(), loc.GetPositionY(),
|
||||||
|
loc.GetPositionZ()) != bot->GetZoneId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
prepared_locs.push_back(loc);
|
prepared_locs.push_back(loc);
|
||||||
@@ -939,8 +957,265 @@ WorldPosition NewRpgBaseAction::SelectRandomInnKeeperPos(Player* bot)
|
|||||||
uint32 idx = urand(0, prepared_locs.size() - 1);
|
uint32 idx = urand(0, prepared_locs.size() - 1);
|
||||||
dest = prepared_locs[idx];
|
dest = prepared_locs[idx];
|
||||||
}
|
}
|
||||||
LOG_DEBUG("playerbots", "[New Rpg] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random inn keeper pos Map:{} X:{} Y:{} Z:{} ({} available in {})",
|
||||||
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
bot->GetName(), dest.GetMapId(), dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(),
|
||||||
prepared_locs.size(), locs.size());
|
prepared_locs.size(), locs.size());
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NewRpgBaseAction::SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint32& fromNode, uint32& toNode)
|
||||||
|
{
|
||||||
|
const std::vector<uint32>& flightMasters = IsAlliance(bot->getRace())
|
||||||
|
? sRandomPlayerbotMgr->allianceFlightMasterCache
|
||||||
|
: sRandomPlayerbotMgr->hordeFlightMasterCache;
|
||||||
|
Creature* nearestFlightMaster = nullptr;
|
||||||
|
for (const uint32& guid : flightMasters)
|
||||||
|
{
|
||||||
|
Creature* flightMaster = ObjectAccessor::GetSpawnedCreatureByDBGUID(bot->GetMapId(), guid);
|
||||||
|
if (!flightMaster)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bot->GetMapId() != flightMaster->GetMapId())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > bot->GetDistance(flightMaster))
|
||||||
|
nearestFlightMaster = flightMaster;
|
||||||
|
}
|
||||||
|
if (!nearestFlightMaster || bot->GetDistance(nearestFlightMaster) > 500.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fromNode = sObjectMgr->GetNearestTaxiNode(nearestFlightMaster->GetPositionX(), nearestFlightMaster->GetPositionY(),
|
||||||
|
nearestFlightMaster->GetPositionZ(), nearestFlightMaster->GetMapId(),
|
||||||
|
bot->GetTeamId());
|
||||||
|
|
||||||
|
if (!fromNode)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::vector<uint32> availableToNodes;
|
||||||
|
for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
|
||||||
|
{
|
||||||
|
if (fromNode == i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
|
||||||
|
|
||||||
|
// check map
|
||||||
|
if (!node || node->map_id != bot->GetMapId() ||
|
||||||
|
(!node->MountCreatureID[bot->GetTeamId() == TEAM_ALLIANCE ? 1 : 0])) // dk flight
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check taxi node known
|
||||||
|
if (!bot->isTaxiCheater() && !bot->m_taxi.IsTaximaskNodeKnown(i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check distance by level
|
||||||
|
if (!botAI->CheckLocationDistanceByLevel(bot, WorldLocation(node->map_id, node->x, node->y, node->z), false))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check path
|
||||||
|
uint32 path, cost;
|
||||||
|
sObjectMgr->GetTaxiPath(fromNode, i, path, cost);
|
||||||
|
if (!path)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check area level
|
||||||
|
uint32 nodeZoneId = bot->GetMap()->GetZoneId(bot->GetPhaseMask(), node->x, node->y, node->z);
|
||||||
|
bool capital = false;
|
||||||
|
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(nodeZoneId))
|
||||||
|
{
|
||||||
|
capital = zone->flags & AREA_FLAG_CAPITAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itr = sRandomPlayerbotMgr->zone2LevelBracket.find(nodeZoneId);
|
||||||
|
if (!capital && itr == sRandomPlayerbotMgr->zone2LevelBracket.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!capital && (bot->GetLevel() < itr->second.low || bot->GetLevel() > itr->second.high))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
availableToNodes.push_back(i);
|
||||||
|
}
|
||||||
|
if (availableToNodes.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
flightMaster = nearestFlightMaster->GetGUID();
|
||||||
|
toNode = availableToNodes[urand(0, availableToNodes.size() - 1)];
|
||||||
|
LOG_DEBUG("playerbots", "[New RPG] Bot {} select random flight taxi node from:{} (node {}) to:{} ({} available)",
|
||||||
|
bot->GetName(), flightMaster.GetEntry(), fromNode, toNode, availableToNodes.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NewRpgBaseAction::RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus)
|
||||||
|
{
|
||||||
|
std::vector<NewRpgStatus> availableStatus;
|
||||||
|
uint32 probSum = 0;
|
||||||
|
for (NewRpgStatus status : candidateStatus)
|
||||||
|
{
|
||||||
|
if (sPlayerbotAIConfig->RpgStatusProbWeight[status] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (CheckRpgStatusAvailable(status))
|
||||||
|
{
|
||||||
|
availableStatus.push_back(status);
|
||||||
|
probSum += sPlayerbotAIConfig->RpgStatusProbWeight[status];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32 rand = urand(1, probSum);
|
||||||
|
uint32 accumulate = 0;
|
||||||
|
NewRpgStatus chosenStatus = RPG_STATUS_END;
|
||||||
|
for (NewRpgStatus status : availableStatus)
|
||||||
|
{
|
||||||
|
accumulate += sPlayerbotAIConfig->RpgStatusProbWeight[status];
|
||||||
|
if (accumulate >= rand)
|
||||||
|
{
|
||||||
|
chosenStatus = status;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (chosenStatus)
|
||||||
|
{
|
||||||
|
case RPG_WANDER_RANDOM:
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToWanderRandom();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RPG_WANDER_NPC:
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToWanderNpc();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RPG_GO_GRIND:
|
||||||
|
{
|
||||||
|
WorldPosition pos = SelectRandomGrindPos(bot);
|
||||||
|
if (pos != WorldPosition())
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToGoGrind(pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RPG_GO_CAMP:
|
||||||
|
{
|
||||||
|
WorldPosition pos = SelectRandomCampPos(bot);
|
||||||
|
if (pos != WorldPosition())
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToGoCamp(pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RPG_DO_QUEST:
|
||||||
|
{
|
||||||
|
std::vector<uint32> availableQuests;
|
||||||
|
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||||
|
{
|
||||||
|
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||||
|
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector<POIInfo> poiInfo;
|
||||||
|
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
||||||
|
{
|
||||||
|
availableQuests.push_back(questId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (availableQuests.size())
|
||||||
|
{
|
||||||
|
uint32 questId = availableQuests[urand(0, availableQuests.size() - 1)];
|
||||||
|
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
|
if (quest)
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToDoQuest(questId, quest);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RPG_TRAVEL_FLIGHT:
|
||||||
|
{
|
||||||
|
ObjectGuid flightMaster;
|
||||||
|
uint32 fromNode, toNode;
|
||||||
|
if (SelectRandomFlightTaxiNode(flightMaster, fromNode, toNode))
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToTravelFlight(flightMaster, fromNode, toNode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RPG_IDLE:
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case RPG_REST:
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToRest();
|
||||||
|
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
botAI->rpgInfo.ChangeToRest();
|
||||||
|
bot->SetStandState(UNIT_STAND_STATE_SIT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NewRpgBaseAction::CheckRpgStatusAvailable(NewRpgStatus status)
|
||||||
|
{
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case RPG_IDLE:
|
||||||
|
case RPG_REST:
|
||||||
|
return true;
|
||||||
|
case RPG_WANDER_RANDOM:
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "grind target");
|
||||||
|
return target != nullptr;
|
||||||
|
}
|
||||||
|
case RPG_GO_GRIND:
|
||||||
|
{
|
||||||
|
WorldPosition pos = SelectRandomGrindPos(bot);
|
||||||
|
return pos != WorldPosition();
|
||||||
|
}
|
||||||
|
case RPG_GO_CAMP:
|
||||||
|
{
|
||||||
|
WorldPosition pos = SelectRandomCampPos(bot);
|
||||||
|
return pos != WorldPosition();
|
||||||
|
}
|
||||||
|
case RPG_WANDER_NPC:
|
||||||
|
{
|
||||||
|
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible new rpg targets");
|
||||||
|
return possibleTargets.size() >= 3;
|
||||||
|
}
|
||||||
|
case RPG_DO_QUEST:
|
||||||
|
{
|
||||||
|
std::vector<uint32> availableQuests;
|
||||||
|
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||||
|
{
|
||||||
|
uint32 questId = bot->GetQuestSlotQuestId(slot);
|
||||||
|
if (botAI->lowPriorityQuest.find(questId) != botAI->lowPriorityQuest.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector<POIInfo> poiInfo;
|
||||||
|
if (GetQuestPOIPosAndObjectiveIdx(questId, poiInfo, true))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case RPG_TRAVEL_FLIGHT:
|
||||||
|
{
|
||||||
|
ObjectGuid flightMaster;
|
||||||
|
uint32 fromNode, toNode;
|
||||||
|
return SelectRandomFlightTaxiNode(flightMaster, fromNode, toNode);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -4,15 +4,17 @@
|
|||||||
#include "Duration.h"
|
#include "Duration.h"
|
||||||
#include "LastMovementValue.h"
|
#include "LastMovementValue.h"
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
|
#include "NewRpgInfo.h"
|
||||||
#include "NewRpgStrategy.h"
|
#include "NewRpgStrategy.h"
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "ObjectDefines.h"
|
#include "ObjectDefines.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
#include "QuestDef.h"
|
#include "QuestDef.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
|
|
||||||
struct POIInfo {
|
struct POIInfo
|
||||||
|
{
|
||||||
G3D::Vector2 pos;
|
G3D::Vector2 pos;
|
||||||
int32 objectiveIdx;
|
int32 objectiveIdx;
|
||||||
};
|
};
|
||||||
@@ -26,13 +28,13 @@ public:
|
|||||||
NewRpgBaseAction(PlayerbotAI* botAI, std::string name) : MovementAction(botAI, name) {}
|
NewRpgBaseAction(PlayerbotAI* botAI, std::string name) : MovementAction(botAI, name) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// MOVEMENT RELATED
|
/* MOVEMENT RELATED */
|
||||||
bool MoveFarTo(WorldPosition dest);
|
bool MoveFarTo(WorldPosition dest);
|
||||||
bool MoveWorldObjectTo(ObjectGuid guid, float distance = INTERACTION_DISTANCE);
|
bool MoveWorldObjectTo(ObjectGuid guid, float distance = INTERACTION_DISTANCE);
|
||||||
bool MoveRandomNear(float moveStep = 50.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
bool MoveRandomNear(float moveStep = 50.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
bool ForceToWait(uint32 duration, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
bool ForceToWait(uint32 duration, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||||
|
|
||||||
// QUEST RELATED CHECK
|
/* QUEST RELATED CHECK */
|
||||||
ObjectGuid ChooseNpcOrGameObjectToInteract(bool questgiverOnly = false, float distanceLimit = 0.0f);
|
ObjectGuid ChooseNpcOrGameObjectToInteract(bool questgiverOnly = false, float distanceLimit = 0.0f);
|
||||||
bool HasQuestToAcceptOrReward(WorldObject* object);
|
bool HasQuestToAcceptOrReward(WorldObject* object);
|
||||||
bool InteractWithNpcOrGameObjectForQuest(ObjectGuid guid);
|
bool InteractWithNpcOrGameObjectForQuest(ObjectGuid guid);
|
||||||
@@ -41,20 +43,24 @@ protected:
|
|||||||
uint32 BestRewardIndex(Quest const* quest);
|
uint32 BestRewardIndex(Quest const* quest);
|
||||||
bool IsQuestWorthDoing(Quest const* quest);
|
bool IsQuestWorthDoing(Quest const* quest);
|
||||||
bool IsQuestCapableDoing(Quest const* quest);
|
bool IsQuestCapableDoing(Quest const* quest);
|
||||||
// QUEST RELATED ACTION
|
|
||||||
|
/* QUEST RELATED ACTION */
|
||||||
bool SearchQuestGiverAndAcceptOrReward();
|
bool SearchQuestGiverAndAcceptOrReward();
|
||||||
bool AcceptQuest(Quest const* quest, ObjectGuid guid);
|
bool AcceptQuest(Quest const* quest, ObjectGuid guid);
|
||||||
bool TurnInQuest(Quest const* quest, ObjectGuid guid);
|
bool TurnInQuest(Quest const* quest, ObjectGuid guid);
|
||||||
bool OrganizeQuestLog();
|
bool OrganizeQuestLog();
|
||||||
|
|
||||||
protected:
|
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 SelectRandomInnKeeperPos(Player* bot);
|
static WorldPosition SelectRandomCampPos(Player* bot);
|
||||||
|
bool SelectRandomFlightTaxiNode(ObjectGuid& flightMaster, uint32& fromNode, uint32& toNode);
|
||||||
|
bool RandomChangeStatus(std::vector<NewRpgStatus> candidateStatus);
|
||||||
|
bool CheckRpgStatusAvailable(NewRpgStatus status);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// WorldPosition dest;
|
/* FOR MOVE FAR */
|
||||||
const float pathFinderDis = 70.0f; // path finder
|
const float pathFinderDis = 70.0f;
|
||||||
const uint32 stuckTime = 5 * 60 * 1000;
|
const uint32 stuckTime = 5 * 60 * 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToGoGrind(WorldPosition pos)
|
void NewRpgInfo::ChangeToGoGrind(WorldPosition pos)
|
||||||
@@ -9,26 +12,26 @@ void NewRpgInfo::ChangeToGoGrind(WorldPosition pos)
|
|||||||
go_grind.pos = pos;
|
go_grind.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToGoInnkeeper(WorldPosition pos)
|
void NewRpgInfo::ChangeToGoCamp(WorldPosition pos)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
status = RPG_GO_INNKEEPER;
|
status = RPG_GO_CAMP;
|
||||||
go_innkeeper = GoInnkeeper();
|
go_camp = GoCamp();
|
||||||
go_innkeeper.pos = pos;
|
go_camp.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToNearNpc()
|
void NewRpgInfo::ChangeToWanderNpc()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
status = RPG_NEAR_NPC;
|
status = RPG_WANDER_NPC;
|
||||||
near_npc = NearNpc();
|
wander_npc = WanderNpc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToNearRandom()
|
void NewRpgInfo::ChangeToWanderRandom()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
status = RPG_NEAR_RANDOM;
|
status = RPG_WANDER_RANDOM;
|
||||||
near_random = NearRandom();
|
WANDER_RANDOM = WanderRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
||||||
@@ -40,6 +43,16 @@ void NewRpgInfo::ChangeToDoQuest(uint32 questId, const Quest* quest)
|
|||||||
do_quest.quest = quest;
|
do_quest.quest = quest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewRpgInfo::ChangeToTravelFlight(ObjectGuid fromFlightMaster, uint32 fromNode, uint32 toNode)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
status = RPG_TRAVEL_FLIGHT;
|
||||||
|
flight = TravelFlight();
|
||||||
|
flight.fromFlightMaster = fromFlightMaster;
|
||||||
|
flight.fromNode = fromNode;
|
||||||
|
flight.toNode = toNode;
|
||||||
|
}
|
||||||
|
|
||||||
void NewRpgInfo::ChangeToRest()
|
void NewRpgInfo::ChangeToRest()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
@@ -53,10 +66,7 @@ void NewRpgInfo::ChangeToIdle()
|
|||||||
status = RPG_IDLE;
|
status = RPG_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgInfo::CanChangeTo(NewRpgStatus status)
|
bool NewRpgInfo::CanChangeTo(NewRpgStatus status) { return true; }
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NewRpgInfo::Reset()
|
void NewRpgInfo::Reset()
|
||||||
{
|
{
|
||||||
@@ -80,23 +90,25 @@ std::string NewRpgInfo::ToString()
|
|||||||
{
|
{
|
||||||
case RPG_GO_GRIND:
|
case RPG_GO_GRIND:
|
||||||
out << "GO_GRIND";
|
out << "GO_GRIND";
|
||||||
out << "\nGrindPos: " << go_grind.pos.GetMapId() << " " << go_grind.pos.GetPositionX() << " " << go_grind.pos.GetPositionY() << " " << go_grind.pos.GetPositionZ();
|
out << "\nGrindPos: " << go_grind.pos.GetMapId() << " " << go_grind.pos.GetPositionX() << " "
|
||||||
|
<< go_grind.pos.GetPositionY() << " " << go_grind.pos.GetPositionZ();
|
||||||
out << "\nlastGoGrind: " << startT;
|
out << "\nlastGoGrind: " << startT;
|
||||||
break;
|
break;
|
||||||
case RPG_GO_INNKEEPER:
|
case RPG_GO_CAMP:
|
||||||
out << "GO_INNKEEPER";
|
out << "GO_CAMP";
|
||||||
out << "\nInnKeeperPos: " << go_innkeeper.pos.GetMapId() << " " << go_innkeeper.pos.GetPositionX() << " " << go_innkeeper.pos.GetPositionY() << " " << go_innkeeper.pos.GetPositionZ();
|
out << "\nCampPos: " << go_camp.pos.GetMapId() << " " << go_camp.pos.GetPositionX() << " "
|
||||||
out << "\nlastGoInnKeeper: " << startT;
|
<< go_camp.pos.GetPositionY() << " " << go_camp.pos.GetPositionZ();
|
||||||
|
out << "\nlastGoCamp: " << startT;
|
||||||
break;
|
break;
|
||||||
case RPG_NEAR_NPC:
|
case RPG_WANDER_NPC:
|
||||||
out << "NEAR_NPC";
|
out << "WANDER_NPC";
|
||||||
out << "\nnpcOrGoEntry: " << near_npc.npcOrGo.GetCounter();
|
out << "\nnpcOrGoEntry: " << wander_npc.npcOrGo.GetCounter();
|
||||||
out << "\nlastNearNpc: " << startT;
|
out << "\nlastWanderNpc: " << startT;
|
||||||
out << "\nlastReachNpcOrGo: " << near_npc.lastReach;
|
out << "\nlastReachNpcOrGo: " << wander_npc.lastReach;
|
||||||
break;
|
break;
|
||||||
case RPG_NEAR_RANDOM:
|
case RPG_WANDER_RANDOM:
|
||||||
out << "NEAR_RANDOM";
|
out << "WANDER_RANDOM";
|
||||||
out << "\nlastNearRandom: " << startT;
|
out << "\nlastWanderRandom: " << startT;
|
||||||
break;
|
break;
|
||||||
case RPG_IDLE:
|
case RPG_IDLE:
|
||||||
out << "IDLE";
|
out << "IDLE";
|
||||||
@@ -109,8 +121,16 @@ std::string NewRpgInfo::ToString()
|
|||||||
out << "DO_QUEST";
|
out << "DO_QUEST";
|
||||||
out << "\nquestId: " << do_quest.questId;
|
out << "\nquestId: " << do_quest.questId;
|
||||||
out << "\nobjectiveIdx: " << do_quest.objectiveIdx;
|
out << "\nobjectiveIdx: " << do_quest.objectiveIdx;
|
||||||
out << "\npoiPos: " << do_quest.pos.GetMapId() << " " << do_quest.pos.GetPositionX() << " " << do_quest.pos.GetPositionY() << " " << do_quest.pos.GetPositionZ();
|
out << "\npoiPos: " << do_quest.pos.GetMapId() << " " << do_quest.pos.GetPositionX() << " "
|
||||||
out << "\nlastReachPOI: " << do_quest.lastReachPOI;
|
<< do_quest.pos.GetPositionY() << " " << do_quest.pos.GetPositionZ();
|
||||||
|
out << "\nlastReachPOI: " << do_quest.lastReachPOI ? GetMSTimeDiffToNow(do_quest.lastReachPOI) : 0;
|
||||||
|
break;
|
||||||
|
case RPG_TRAVEL_FLIGHT:
|
||||||
|
out << "TRAVEL_FLIGHT";
|
||||||
|
out << "\nfromFlightMaster: " << flight.fromFlightMaster.GetEntry();
|
||||||
|
out << "\nfromNode: " << flight.fromNode;
|
||||||
|
out << "\ntoNode: " << flight.toNode;
|
||||||
|
out << "\ninFlight: " << flight.inFlight;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
out << "UNKNOWN";
|
out << "UNKNOWN";
|
||||||
|
|||||||
@@ -9,24 +9,6 @@
|
|||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "TravelMgr.h"
|
#include "TravelMgr.h"
|
||||||
|
|
||||||
enum NewRpgStatus: int
|
|
||||||
{
|
|
||||||
RPG_STATUS_START = 0,
|
|
||||||
// Going to far away place
|
|
||||||
RPG_GO_GRIND = 0,
|
|
||||||
RPG_GO_INNKEEPER = 1,
|
|
||||||
// Exploring nearby
|
|
||||||
RPG_NEAR_RANDOM = 2,
|
|
||||||
RPG_NEAR_NPC = 3,
|
|
||||||
// Do Quest (based on quest status)
|
|
||||||
RPG_DO_QUEST = 4,
|
|
||||||
// Taking a break
|
|
||||||
RPG_REST = 5,
|
|
||||||
// Initial status
|
|
||||||
RPG_IDLE = 6,
|
|
||||||
RPG_STATUS_END = 7
|
|
||||||
};
|
|
||||||
|
|
||||||
using NewRpgStatusTransitionProb = std::vector<std::vector<int>>;
|
using NewRpgStatusTransitionProb = std::vector<std::vector<int>>;
|
||||||
|
|
||||||
struct NewRpgInfo
|
struct NewRpgInfo
|
||||||
@@ -34,42 +16,54 @@ struct NewRpgInfo
|
|||||||
NewRpgInfo() {}
|
NewRpgInfo() {}
|
||||||
|
|
||||||
// RPG_GO_GRIND
|
// RPG_GO_GRIND
|
||||||
struct GoGrind {
|
struct GoGrind
|
||||||
GoGrind() = default;
|
{
|
||||||
WorldPosition pos{};
|
WorldPosition pos{};
|
||||||
};
|
};
|
||||||
// RPG_GO_INNKEEPER
|
// RPG_GO_CAMP
|
||||||
struct GoInnkeeper {
|
struct GoCamp
|
||||||
GoInnkeeper() = default;
|
{
|
||||||
WorldPosition pos{};
|
WorldPosition pos{};
|
||||||
};
|
};
|
||||||
// RPG_NEAR_NPC
|
// RPG_WANDER_NPC
|
||||||
struct NearNpc {
|
struct WanderNpc
|
||||||
NearNpc() = default;
|
{
|
||||||
ObjectGuid npcOrGo{};
|
ObjectGuid npcOrGo{};
|
||||||
uint32 lastReach{0};
|
uint32 lastReach{0};
|
||||||
};
|
};
|
||||||
// RPG_NEAR_RANDOM
|
// RPG_WANDER_RANDOM
|
||||||
struct NearRandom {
|
struct WanderRandom
|
||||||
NearRandom() = default;
|
{
|
||||||
|
WanderRandom() = default;
|
||||||
};
|
};
|
||||||
// NewRpgStatus::QUESTING
|
// RPG_DO_QUEST
|
||||||
struct DoQuest {
|
struct DoQuest
|
||||||
|
{
|
||||||
const Quest* quest{nullptr};
|
const Quest* quest{nullptr};
|
||||||
uint32 questId{0};
|
uint32 questId{0};
|
||||||
int32 objectiveIdx{0};
|
int32 objectiveIdx{0};
|
||||||
WorldPosition pos{};
|
WorldPosition pos{};
|
||||||
uint32 lastReachPOI{0};
|
uint32 lastReachPOI{0};
|
||||||
};
|
};
|
||||||
|
// RPG_TRAVEL_FLIGHT
|
||||||
|
struct TravelFlight
|
||||||
|
{
|
||||||
|
ObjectGuid fromFlightMaster{};
|
||||||
|
uint32 fromNode{0};
|
||||||
|
uint32 toNode{0};
|
||||||
|
bool inFlight{false};
|
||||||
|
};
|
||||||
// RPG_REST
|
// RPG_REST
|
||||||
struct Rest {
|
struct Rest
|
||||||
|
{
|
||||||
Rest() = default;
|
Rest() = default;
|
||||||
};
|
};
|
||||||
struct Idle {
|
struct Idle
|
||||||
|
{
|
||||||
};
|
};
|
||||||
NewRpgStatus status{RPG_IDLE};
|
NewRpgStatus status{RPG_IDLE};
|
||||||
|
|
||||||
uint32 startT{0}; // start timestamp of the current status
|
uint32 startT{0}; // start timestamp of the current status
|
||||||
|
|
||||||
// MOVE_FAR
|
// MOVE_FAR
|
||||||
float nearestMoveFarDis{FLT_MAX};
|
float nearestMoveFarDis{FLT_MAX};
|
||||||
@@ -78,22 +72,25 @@ struct NewRpgInfo
|
|||||||
WorldPosition moveFarPos;
|
WorldPosition moveFarPos;
|
||||||
// END MOVE_FAR
|
// END MOVE_FAR
|
||||||
|
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
GoGrind go_grind;
|
GoGrind go_grind;
|
||||||
GoInnkeeper go_innkeeper;
|
GoCamp go_camp;
|
||||||
NearNpc near_npc;
|
WanderNpc wander_npc;
|
||||||
NearRandom near_random;
|
WanderRandom WANDER_RANDOM;
|
||||||
DoQuest do_quest;
|
DoQuest do_quest;
|
||||||
Rest rest;
|
Rest rest;
|
||||||
DoQuest quest;
|
DoQuest quest;
|
||||||
|
TravelFlight flight;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HasStatusPersisted(uint32 maxDuration) { return GetMSTimeDiffToNow(startT) > maxDuration; }
|
bool HasStatusPersisted(uint32 maxDuration) { return GetMSTimeDiffToNow(startT) > maxDuration; }
|
||||||
void ChangeToGoGrind(WorldPosition pos);
|
void ChangeToGoGrind(WorldPosition pos);
|
||||||
void ChangeToGoInnkeeper(WorldPosition pos);
|
void ChangeToGoCamp(WorldPosition pos);
|
||||||
void ChangeToNearNpc();
|
void ChangeToWanderNpc();
|
||||||
void ChangeToNearRandom();
|
void ChangeToWanderRandom();
|
||||||
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
void ChangeToDoQuest(uint32 questId, const Quest* quest);
|
||||||
|
void ChangeToTravelFlight(ObjectGuid fromFlightMaster, uint32 fromNode, uint32 toNode);
|
||||||
void ChangeToRest();
|
void ChangeToRest();
|
||||||
void ChangeToIdle();
|
void ChangeToIdle();
|
||||||
bool CanChangeTo(NewRpgStatus status);
|
bool CanChangeTo(NewRpgStatus status);
|
||||||
|
|||||||
@@ -23,16 +23,19 @@ void NewRpgStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
new TriggerNode("go grind status", NextAction::array(0, new NextAction("new rpg go grind", 3.0f), nullptr)));
|
new TriggerNode("go grind status", NextAction::array(0, new NextAction("new rpg go grind", 3.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("go innkeeper status", NextAction::array(0, new NextAction("new rpg go innkeeper", 3.0f), nullptr)));
|
new TriggerNode("go camp status", NextAction::array(0, new NextAction("new rpg go camp", 3.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("near random status", NextAction::array(0, new NextAction("new rpg move random", 3.0f), nullptr)));
|
new TriggerNode("wander random status", NextAction::array(0, new NextAction("new rpg wander random", 3.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("near npc status", NextAction::array(0, new NextAction("new rpg move npc", 3.0f), nullptr)));
|
new TriggerNode("wander npc status", NextAction::array(0, new NextAction("new rpg wander npc", 3.0f), nullptr)));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("do quest status", NextAction::array(0, new NextAction("new rpg do quest", 3.0f), nullptr)));
|
new TriggerNode("do quest status", NextAction::array(0, new NextAction("new rpg do quest", 3.0f), nullptr)));
|
||||||
|
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("travel flight status", NextAction::array(0, new NextAction("new rpg travel flight", 3.0f), nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
void NewRpgStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||||
|
|||||||
@@ -221,10 +221,11 @@ public:
|
|||||||
creators["rpg trade useful"] = &TriggerContext::rpg_trade_useful;
|
creators["rpg trade useful"] = &TriggerContext::rpg_trade_useful;
|
||||||
creators["rpg duel"] = &TriggerContext::rpg_duel;
|
creators["rpg duel"] = &TriggerContext::rpg_duel;
|
||||||
creators["go grind status"] = &TriggerContext::go_grind_status;
|
creators["go grind status"] = &TriggerContext::go_grind_status;
|
||||||
creators["go innkeeper status"] = &TriggerContext::go_innkeeper_status;
|
creators["go camp status"] = &TriggerContext::go_camp_status;
|
||||||
creators["near random status"] = &TriggerContext::near_random_status;
|
creators["wander random status"] = &TriggerContext::wander_random_status;
|
||||||
creators["near npc status"] = &TriggerContext::near_npc_status;
|
creators["wander npc status"] = &TriggerContext::wander_npc_status;
|
||||||
creators["do quest status"] = &TriggerContext::do_quest_status;
|
creators["do quest status"] = &TriggerContext::do_quest_status;
|
||||||
|
creators["travel flight status"] = &TriggerContext::travel_flight_status;
|
||||||
creators["can self resurrect"] = &TriggerContext::can_self_resurrect;
|
creators["can self resurrect"] = &TriggerContext::can_self_resurrect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,10 +419,11 @@ private:
|
|||||||
static Trigger* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulTrigger(botAI); }
|
static Trigger* rpg_trade_useful(PlayerbotAI* botAI) { return new RpgTradeUsefulTrigger(botAI); }
|
||||||
static Trigger* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelTrigger(botAI); }
|
static Trigger* rpg_duel(PlayerbotAI* botAI) { return new RpgDuelTrigger(botAI); }
|
||||||
static Trigger* go_grind_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_GO_GRIND); }
|
static Trigger* go_grind_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_GO_GRIND); }
|
||||||
static Trigger* go_innkeeper_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_GO_INNKEEPER); }
|
static Trigger* go_camp_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_GO_CAMP); }
|
||||||
static Trigger* near_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_RANDOM); }
|
static Trigger* wander_random_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_WANDER_RANDOM); }
|
||||||
static Trigger* near_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_NEAR_NPC); }
|
static Trigger* wander_npc_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_WANDER_NPC); }
|
||||||
static Trigger* do_quest_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_DO_QUEST); }
|
static Trigger* do_quest_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_DO_QUEST); }
|
||||||
|
static Trigger* travel_flight_status(PlayerbotAI* botAI) { return new NewRpgStatusTrigger(botAI, RPG_TRAVEL_FLIGHT); }
|
||||||
static Trigger* can_self_resurrect(PlayerbotAI* ai) { return new SelfResurrectTrigger(ai); }
|
static Trigger* can_self_resurrect(PlayerbotAI* ai) { return new SelfResurrectTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
#include "NewRpgInfo.h"
|
#include "NewRpgInfo.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "ReputationMgr.h"
|
#include "ReputationMgr.h"
|
||||||
#include "SharedDefines.h"
|
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
Unit* GrindTargetValue::Calculate()
|
Unit* GrindTargetValue::Calculate()
|
||||||
{
|
{
|
||||||
@@ -34,7 +34,8 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
|||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
Player* master = GetMaster();
|
Player* master = GetMaster();
|
||||||
|
|
||||||
if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() || !GET_PLAYERBOT_AI(master)))
|
if (master && (master == bot || master->GetMapId() != bot->GetMapId() || master->IsBeingTeleported() ||
|
||||||
|
!GET_PLAYERBOT_AI(master)))
|
||||||
master = nullptr;
|
master = nullptr;
|
||||||
|
|
||||||
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
||||||
@@ -89,16 +90,16 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
|||||||
// !sRandomPlayerbotMgr->IsRandomBot(bot)) continue;
|
// !sRandomPlayerbotMgr->IsRandomBot(bot)) continue;
|
||||||
|
|
||||||
// Bots in bot-groups no have a more limited range to look for grind target
|
// Bots in bot-groups no have a more limited range to look for grind target
|
||||||
if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT)
|
if (!bot->InBattleground() && master && botAI->HasStrategy("follow", BotState::BOT_STATE_NON_COMBAT) &&
|
||||||
&& sServerFacade->GetDistance2d(master, unit) > sPlayerbotAIConfig->lootDistance)
|
sServerFacade->GetDistance2d(master, unit) > sPlayerbotAIConfig->lootDistance)
|
||||||
{
|
{
|
||||||
if (botAI->HasStrategy("debug grind", BotState::BOT_STATE_NON_COMBAT))
|
if (botAI->HasStrategy("debug grind", BotState::BOT_STATE_NON_COMBAT))
|
||||||
botAI->TellMaster(chat->FormatWorldobject(unit) + " ignored (far from master).");
|
botAI->TellMaster(chat->FormatWorldobject(unit) + " ignored (far from master).");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
|
if (!bot->InBattleground() && (int)unit->GetLevel() - (int)bot->GetLevel() > 4 && !unit->GetGUID().IsPlayer())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Creature* creature = unit->ToCreature())
|
if (Creature* creature = unit->ToCreature())
|
||||||
if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())
|
if (CreatureTemplate const* CreatureTemplate = creature->GetCreatureTemplate())
|
||||||
@@ -110,11 +111,7 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inactiveGrindStatus = botAI->rpgInfo.status == RPG_GO_GRIND ||
|
bool inactiveGrindStatus = botAI->rpgInfo.status != RPG_WANDER_RANDOM && botAI->rpgInfo.status != RPG_IDLE;
|
||||||
botAI->rpgInfo.status == RPG_NEAR_NPC ||
|
|
||||||
botAI->rpgInfo.status == RPG_REST ||
|
|
||||||
botAI->rpgInfo.status == RPG_GO_INNKEEPER ||
|
|
||||||
botAI->rpgInfo.status == RPG_DO_QUEST;
|
|
||||||
|
|
||||||
float aggroRange = 30.0f;
|
float aggroRange = 30.0f;
|
||||||
if (unit->ToCreature())
|
if (unit->ToCreature())
|
||||||
|
|||||||
Reference in New Issue
Block a user