mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Compare commits
1 Commits
revert-136
...
directory_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6003dbc1b5 |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
DROP TABLE IF EXISTS `playerbots_account_keys`;
|
||||
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
||||
|
||||
CREATE TABLE `playerbots_account_keys` (
|
||||
CREATE TABLE `playerbot_account_keys` (
|
||||
`account_id` INT PRIMARY KEY,
|
||||
`security_key` VARCHAR(255) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
@@ -1,6 +1,6 @@
|
||||
DROP TABLE IF EXISTS `playerbots_account_links`;
|
||||
DROP TABLE IF EXISTS `playerbot_account_links`;
|
||||
|
||||
CREATE TABLE `playerbots_account_links` (
|
||||
CREATE TABLE `playerbot_account_links` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`account_id` INT NOT NULL,
|
||||
`linked_account_id` INT NOT NULL,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
DROP TABLE IF EXISTS `playerbot_account_keys`;
|
||||
CREATE TABLE IF NOT EXISTS `playerbots_account_keys` (
|
||||
`account_id` INT PRIMARY KEY,
|
||||
`security_key` VARCHAR(255) NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||
|
||||
DROP TABLE IF EXISTS `playerbot_account_links`;
|
||||
CREATE TABLE IF NOT EXISTS `playerbots_account_links` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`account_id` INT NOT NULL,
|
||||
`linked_account_id` INT NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY `account_link` (`account_id`, `linked_account_id`)
|
||||
) ENGINE=INNODB DEFAULT CHARSET=latin1;
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "CreatureData.h"
|
||||
#include "EmoteAction.h"
|
||||
#include "Engine.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "ExternalEventHelper.h"
|
||||
#include "GameObjectData.h"
|
||||
#include "GameTime.h"
|
||||
@@ -157,7 +156,7 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_AREATRIGGER, "area trigger");
|
||||
// masterIncomingPacketHandlers.AddHandler(CMSG_GAMEOBJ_USE, "use game object");
|
||||
// masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll");
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_LOOT_ROLL, "loot roll");
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_GOSSIP_HELLO, "gossip hello");
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_QUESTGIVER_HELLO, "gossip hello");
|
||||
masterIncomingPacketHandlers.AddHandler(CMSG_ACTIVATETAXI, "activate taxi");
|
||||
@@ -797,7 +796,6 @@ bool PlayerbotAI::IsAllowedCommand(std::string const text)
|
||||
unsecuredCommands.insert("sendmail");
|
||||
unsecuredCommands.insert("invite");
|
||||
unsecuredCommands.insert("leave");
|
||||
unsecuredCommands.insert("lfg");
|
||||
unsecuredCommands.insert("rpg status");
|
||||
}
|
||||
|
||||
@@ -1425,21 +1423,12 @@ void PlayerbotAI::DoNextAction(bool min)
|
||||
master = newMaster;
|
||||
botAI->SetMaster(newMaster);
|
||||
botAI->ResetStrategies();
|
||||
|
||||
if (!bot->InBattleground())
|
||||
{
|
||||
botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("+follow", BOT_STATE_NON_COMBAT);
|
||||
|
||||
if (botAI->GetMaster() == botAI->GetGroupMaster())
|
||||
botAI->TellMaster("Hello, I follow you!");
|
||||
else
|
||||
botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!");
|
||||
}
|
||||
if (botAI->GetMaster() == botAI->GetGroupMaster())
|
||||
botAI->TellMaster("Hello, I follow you!");
|
||||
else
|
||||
{
|
||||
// we're in a battleground, stay with the pack and focus on objective
|
||||
botAI->ChangeStrategy("-follow", BOT_STATE_NON_COMBAT);
|
||||
}
|
||||
botAI->TellMaster(!urand(0, 2) ? "Hello!" : "Hi!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6281,23 +6270,3 @@ SpellFamilyNames PlayerbotAI::Class2SpellFamilyName(uint8 cls)
|
||||
}
|
||||
return SPELLFAMILY_GENERIC;
|
||||
}
|
||||
|
||||
void PlayerbotAI::AddTimedEvent(std::function<void()> callback, uint32 delayMs)
|
||||
{
|
||||
class LambdaEvent final : public BasicEvent
|
||||
{
|
||||
std::function<void()> _cb;
|
||||
public:
|
||||
explicit LambdaEvent(std::function<void()> cb) : _cb(std::move(cb)) {}
|
||||
bool Execute(uint64 /*execTime*/, uint32 /*diff*/) override
|
||||
{
|
||||
_cb();
|
||||
return true; // remove after execution
|
||||
}
|
||||
};
|
||||
|
||||
// Every Player already owns an EventMap called m_Events
|
||||
bot->m_Events.AddEvent(
|
||||
new LambdaEvent(std::move(callback)),
|
||||
bot->m_Events.CalculateTime(delayMs));
|
||||
}
|
||||
@@ -590,9 +590,6 @@ public:
|
||||
NewRpgStatistic rpgStatistic;
|
||||
std::unordered_set<uint32> lowPriorityQuest;
|
||||
|
||||
// Schedules a callback to run once after <delayMs> milliseconds.
|
||||
void AddTimedEvent(std::function<void()> callback, uint32 delayMs);
|
||||
|
||||
private:
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||
bool mixed = false);
|
||||
|
||||
@@ -82,8 +82,6 @@ bool PlayerbotAIConfig::Initialize()
|
||||
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
||||
returnDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReturnDelay", 7000);
|
||||
lootDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.LootDelay", 1000);
|
||||
disabledWithoutRealPlayerLoginDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLoginDelay", 30);
|
||||
disabledWithoutRealPlayerLogoutDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.DisabledWithoutRealPlayerLogoutDelay", 300);
|
||||
|
||||
farDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FarDistance", 20.0f);
|
||||
sightDistance = sConfigMgr->GetOption<float>("AiPlayerbot.SightDistance", 75.0f);
|
||||
@@ -131,7 +129,6 @@ bool PlayerbotAIConfig::Initialize()
|
||||
allowAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowAccountBots", true);
|
||||
allowGuildBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowGuildBots", true);
|
||||
allowTrustedAccountBots = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowTrustedAccountBots", true);
|
||||
disabledWithoutRealPlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.DisabledWithoutRealPlayer", false);
|
||||
randomBotGuildNearby = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotGuildNearby", false);
|
||||
randomBotInvitePlayer = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotInvitePlayer", false);
|
||||
inviteChat = sConfigMgr->GetOption<bool>("AiPlayerbot.InviteChat", false);
|
||||
@@ -156,9 +153,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
LoadList<std::vector<uint32>>(
|
||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
||||
randomBotQuestIds);
|
||||
|
||||
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects", "176213,17155"),
|
||||
disallowedGameObjects);
|
||||
|
||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||
minRandomBots = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBots", 50);
|
||||
@@ -312,48 +307,11 @@ bool PlayerbotAIConfig::Initialize()
|
||||
summonAtInnkeepersEnabled = sConfigMgr->GetOption<bool>("AiPlayerbot.SummonAtInnkeepersEnabled", true);
|
||||
randomBotMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMinLevel", 1);
|
||||
randomBotMaxLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotMaxLevel", 80);
|
||||
if (randomBotMaxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
randomBotMaxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
|
||||
randomBotLoginAtStartup = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotLoginAtStartup", true);
|
||||
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 1);
|
||||
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 3);
|
||||
randomBotTeleLowerLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleLowerLevel", 3);
|
||||
randomBotTeleHigherLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleHigherLevel", 1);
|
||||
openGoSpell = sConfigMgr->GetOption<int32>("AiPlayerbot.OpenGoSpell", 6477);
|
||||
|
||||
// Zones for NewRpgStrategy teleportation brackets
|
||||
std::vector<uint32> zoneIds = {
|
||||
// Classic WoW - Low-level zones
|
||||
1, 12, 14, 85, 141, 215, 3430, 3524,
|
||||
// Classic WoW - Mid-level zones
|
||||
17, 38, 40, 130, 148, 3433, 3525,
|
||||
// Classic WoW - High-level zones
|
||||
10, 11, 44, 267, 331, 400, 406,
|
||||
// Classic WoW - Higher-level zones
|
||||
3, 8, 15, 16, 33, 45, 47, 51, 357, 405, 440,
|
||||
// Classic WoW - Top-level zones
|
||||
4, 28, 46, 139, 361, 490, 618, 1377,
|
||||
// The Burning Crusade - Zones
|
||||
3483, 3518, 3519, 3520, 3521, 3522, 3523, 4080,
|
||||
// Wrath of the Lich King - Zones
|
||||
65, 66, 67, 210, 394, 495, 2817, 3537, 3711, 4197
|
||||
};
|
||||
|
||||
for (uint32 zoneId : zoneIds)
|
||||
{
|
||||
std::string setting = "AiPlayerbot.ZoneBracket." + std::to_string(zoneId);
|
||||
std::string value = sConfigMgr->GetOption<std::string>(setting, "");
|
||||
|
||||
if (!value.empty())
|
||||
{
|
||||
size_t commaPos = value.find(',');
|
||||
if (commaPos != std::string::npos)
|
||||
{
|
||||
uint32 minLevel = atoi(value.substr(0, commaPos).c_str());
|
||||
uint32 maxLevel = atoi(value.substr(commaPos + 1).c_str());
|
||||
zoneBrackets[zoneId] = std::make_pair(minLevel, maxLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
randomChangeMultiplier = sConfigMgr->GetOption<float>("AiPlayerbot.RandomChangeMultiplier", 1.0);
|
||||
|
||||
randomBotCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotCombatStrategies", "-threat");
|
||||
@@ -373,12 +331,6 @@ bool PlayerbotAIConfig::Initialize()
|
||||
useFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFlyMountAtMinLevel", 60);
|
||||
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
|
||||
|
||||
// stagger bot flightpath takeoff
|
||||
delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u);
|
||||
delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u);
|
||||
gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u);
|
||||
gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u);
|
||||
|
||||
LOG_INFO("server.loading", "Loading TalentSpecs...");
|
||||
|
||||
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
|
||||
@@ -514,7 +466,6 @@ bool PlayerbotAIConfig::Initialize()
|
||||
equipmentPersistence = sConfigMgr->GetOption<bool>("AiPlayerbot.EquipmentPersistence", false);
|
||||
equipmentPersistenceLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.EquipmentPersistenceLevel", 80);
|
||||
groupInvitationPermission = sConfigMgr->GetOption<int32>("AiPlayerbot.GroupInvitationPermission", 1);
|
||||
keepAltsInGroup = sConfigMgr->GetOption<bool>("AiPlayerbot.KeepAltsInGroup", false);
|
||||
allowSummonInCombat = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonInCombat", true);
|
||||
allowSummonWhenMasterIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenMasterIsDead", true);
|
||||
allowSummonWhenBotIsDead = sConfigMgr->GetOption<bool>("AiPlayerbot.AllowSummonWhenBotIsDead", true);
|
||||
@@ -532,7 +483,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
autoGearQualityLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearQualityLimit", 3);
|
||||
autoGearScoreLimit = sConfigMgr->GetOption<int32>("AiPlayerbot.AutoGearScoreLimit", 0);
|
||||
|
||||
randomBotXPRate = sConfigMgr->GetOption<float>("AiPlayerbot.RandomBotXPRate", 1.0);
|
||||
playerbotsXPrate = sConfigMgr->GetOption<float>("AiPlayerbot.PlayerbotsXPRate", 1.0);
|
||||
randomBotAllianceRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotAllianceRatio", 50);
|
||||
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
|
||||
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
||||
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
bool IsInPvpProhibitedArea(uint32 id);
|
||||
|
||||
bool enabled;
|
||||
bool disabledWithoutRealPlayer;
|
||||
bool allowAccountBots, allowGuildBots, allowTrustedAccountBots;
|
||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
||||
@@ -72,7 +71,6 @@ public:
|
||||
float maxAoeAvoidRadius;
|
||||
std::set<uint32> aoeAvoidSpellWhitelist;
|
||||
bool tellWhenAvoidAoe;
|
||||
std::set<uint32> disallowedGameObjects;
|
||||
|
||||
uint32 openGoSpell;
|
||||
bool randomBotAutologin;
|
||||
@@ -101,7 +99,6 @@ public:
|
||||
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
|
||||
uint32 randomBotsPerInterval;
|
||||
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
|
||||
uint32 disabledWithoutRealPlayerLoginDelay, disabledWithoutRealPlayerLogoutDelay;
|
||||
bool randomBotJoinLfg;
|
||||
|
||||
// chat
|
||||
@@ -198,7 +195,6 @@ public:
|
||||
|
||||
bool randomBotLoginAtStartup;
|
||||
uint32 randomBotTeleLowerLevel, randomBotTeleHigherLevel;
|
||||
std::map<uint32, std::pair<uint32, uint32>> zoneBrackets;
|
||||
bool logInGroupOnly, logValuesPerTick;
|
||||
bool fleeingEnabled;
|
||||
bool summonAtInnkeepersEnabled;
|
||||
@@ -279,7 +275,7 @@ public:
|
||||
bool randomBotShowCloak;
|
||||
bool randomBotFixedLevel;
|
||||
bool disableRandomLevels;
|
||||
float randomBotXPRate;
|
||||
float playerbotsXPrate;
|
||||
uint32 randomBotAllianceRatio;
|
||||
uint32 randomBotHordeRatio;
|
||||
bool disableDeathKnightLogin;
|
||||
@@ -334,8 +330,6 @@ public:
|
||||
bool equipmentPersistence;
|
||||
int32 equipmentPersistenceLevel;
|
||||
int32 groupInvitationPermission;
|
||||
bool keepAltsInGroup = false;
|
||||
bool KeepAltsInGroup() const { return keepAltsInGroup; }
|
||||
bool allowSummonInCombat;
|
||||
bool allowSummonWhenMasterIsDead;
|
||||
bool allowSummonWhenBotIsDead;
|
||||
@@ -354,12 +348,6 @@ public:
|
||||
uint32 useFlyMountAtMinLevel;
|
||||
uint32 useFastFlyMountAtMinLevel;
|
||||
|
||||
// stagger flightpath takeoff
|
||||
uint32 delayMin;
|
||||
uint32 delayMax;
|
||||
uint32 gapMs;
|
||||
uint32 gapJitterMs;
|
||||
|
||||
std::string const GetTimestampStr();
|
||||
bool hasLog(std::string const fileName)
|
||||
{
|
||||
|
||||
@@ -157,7 +157,7 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
||||
bool PlayerbotHolder::IsAccountLinked(uint32 accountId, uint32 linkedAccountId)
|
||||
{
|
||||
QueryResult result = PlayerbotsDatabase.Query(
|
||||
"SELECT 1 FROM playerbots_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
|
||||
"SELECT 1 FROM playerbot_account_links WHERE account_id = {} AND linked_account_id = {}", accountId, linkedAccountId);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
@@ -473,11 +473,11 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
}
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (master)
|
||||
if (!master)
|
||||
{
|
||||
ObjectGuid masterGuid = master->GetGUID();
|
||||
if (master->GetGroup() && !master->GetGroup()->IsLeader(masterGuid))
|
||||
master->GetGroup()->ChangeLeader(masterGuid);
|
||||
// Log a warning to indicate that the master is null
|
||||
LOG_DEBUG("mod-playerbots", "Master is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
@@ -496,10 +496,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't disband alt groups when master goes away
|
||||
// Controlled by config
|
||||
if (sPlayerbotAIConfig->KeepAltsInGroup())
|
||||
else
|
||||
{
|
||||
uint32 account = sCharacterCache->GetCharacterAccountIdByGuid(member);
|
||||
if (!sPlayerbotAIConfig->IsInRandomAccountList(account))
|
||||
@@ -1737,7 +1734,7 @@ void PlayerbotMgr::HandleSetSecurityKeyCommand(Player* player, const std::string
|
||||
|
||||
// Store the hashed key in the database
|
||||
PlayerbotsDatabase.Execute(
|
||||
"REPLACE INTO playerbots_account_keys (account_id, security_key) VALUES ({}, '{}')",
|
||||
"REPLACE INTO playerbot_account_keys (account_id, security_key) VALUES ({}, '{}')",
|
||||
accountId, hashedKey.str());
|
||||
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("Security key set successfully.");
|
||||
@@ -1755,7 +1752,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
||||
Field* fields = result->Fetch();
|
||||
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||
|
||||
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbots_account_keys WHERE account_id = {}", linkedAccountId);
|
||||
result = PlayerbotsDatabase.Query("SELECT security_key FROM playerbot_account_keys WHERE account_id = {}", linkedAccountId);
|
||||
if (!result)
|
||||
{
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("Invalid security key.");
|
||||
@@ -1781,10 +1778,10 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
||||
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
PlayerbotsDatabase.Execute(
|
||||
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||
accountId, linkedAccountId);
|
||||
PlayerbotsDatabase.Execute(
|
||||
"INSERT IGNORE INTO playerbots_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||
"INSERT IGNORE INTO playerbot_account_links (account_id, linked_account_id) VALUES ({}, {})",
|
||||
linkedAccountId, accountId);
|
||||
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("Account linked successfully.");
|
||||
@@ -1793,7 +1790,7 @@ void PlayerbotMgr::HandleLinkAccountCommand(Player* player, const std::string& a
|
||||
void PlayerbotMgr::HandleViewLinkedAccountsCommand(Player* player)
|
||||
{
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbots_account_links WHERE account_id = {}", accountId);
|
||||
QueryResult result = PlayerbotsDatabase.Query("SELECT linked_account_id FROM playerbot_account_links WHERE account_id = {}", accountId);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -1834,7 +1831,7 @@ void PlayerbotMgr::HandleUnlinkAccountCommand(Player* player, const std::string&
|
||||
uint32 linkedAccountId = fields[0].Get<uint32>();
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
|
||||
PlayerbotsDatabase.Execute("DELETE FROM playerbots_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
|
||||
PlayerbotsDatabase.Execute("DELETE FROM playerbot_account_links WHERE (account_id = {} AND linked_account_id = {}) OR (account_id = {} AND linked_account_id = {})",
|
||||
accountId, linkedAccountId, linkedAccountId, accountId);
|
||||
|
||||
ChatHandler(player->GetSession()).PSendSysMessage("Account unlinked successfully.");
|
||||
|
||||
@@ -219,12 +219,9 @@ public:
|
||||
if (!player->GetSession()->IsBot())
|
||||
return;
|
||||
|
||||
if (!sRandomPlayerbotMgr->IsRandomBot(player))
|
||||
return;
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotXPRate != 1.0)
|
||||
if (sPlayerbotAIConfig->playerbotsXPrate != 1.0)
|
||||
{
|
||||
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->randomBotXPRate));
|
||||
amount = static_cast<uint32>(std::round(static_cast<float>(amount) * sPlayerbotAIConfig->playerbotsXPrate));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#include "UpdateTime.h"
|
||||
#include "World.h"
|
||||
#include "RandomPlayerbotFactory.h"
|
||||
#include <WorldSessionMgr.h>
|
||||
|
||||
struct GuidClassRaceInfo {
|
||||
ObjectGuid::LowType guid;
|
||||
@@ -356,43 +355,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
PERF_MON_TOTAL,
|
||||
onlineBotCount < maxAllowedBotCount ? "RandomPlayerbotMgr::Login" : "RandomPlayerbotMgr::UpdateAIInternal");
|
||||
|
||||
bool realPlayerIsLogged = false;
|
||||
if (sPlayerbotAIConfig->disabledWithoutRealPlayer)
|
||||
{
|
||||
if (sWorldSessionMgr->GetActiveAndQueuedSessionCount() > 0)
|
||||
{
|
||||
RealPlayerLastTimeSeen = time(nullptr);
|
||||
realPlayerIsLogged = true;
|
||||
|
||||
if (DelayLoginBotsTimer == 0)
|
||||
{
|
||||
DelayLoginBotsTimer = time(nullptr) + sPlayerbotAIConfig->disabledWithoutRealPlayerLoginDelay;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DelayLoginBotsTimer)
|
||||
{
|
||||
DelayLoginBotsTimer = 0;
|
||||
}
|
||||
|
||||
if (RealPlayerLastTimeSeen != 0 && onlineBotCount > 0 &&
|
||||
time(nullptr) > RealPlayerLastTimeSeen + sPlayerbotAIConfig->disabledWithoutRealPlayerLogoutDelay)
|
||||
{
|
||||
LogoutAllBots();
|
||||
LOG_INFO("playerbots",
|
||||
"Logout all bots due no real player session.");
|
||||
}
|
||||
}
|
||||
|
||||
if (availableBotCount < maxAllowedBotCount &&
|
||||
(sPlayerbotAIConfig->disabledWithoutRealPlayer == false ||
|
||||
(realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer)))
|
||||
{
|
||||
AddRandomBots();
|
||||
}
|
||||
}
|
||||
else if (availableBotCount < maxAllowedBotCount)
|
||||
if (availableBotCount < maxAllowedBotCount)
|
||||
{
|
||||
AddRandomBots();
|
||||
}
|
||||
@@ -428,11 +391,7 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
}
|
||||
}
|
||||
uint32 updateBots = sPlayerbotAIConfig->randomBotsPerInterval * onlineBotFocus / 100;
|
||||
uint32 maxNewBots = onlineBotCount < maxAllowedBotCount &&
|
||||
(sPlayerbotAIConfig->disabledWithoutRealPlayer == false ||
|
||||
(realPlayerIsLogged && DelayLoginBotsTimer != 0 && time(nullptr) >= DelayLoginBotsTimer))
|
||||
? maxAllowedBotCount - onlineBotCount
|
||||
: 0;
|
||||
uint32 maxNewBots = onlineBotCount < maxAllowedBotCount ? maxAllowedBotCount - onlineBotCount : 0;
|
||||
uint32 loginBots = std::min(sPlayerbotAIConfig->randomBotsPerInterval - updateBots, maxNewBots);
|
||||
|
||||
if (!availableBots.empty())
|
||||
@@ -473,8 +432,6 @@ void RandomPlayerbotMgr::UpdateAIInternal(uint32 elapsed, bool /*minimal*/)
|
||||
if (!loginBots)
|
||||
break;
|
||||
}
|
||||
|
||||
DelayLoginBotsTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1606,12 +1563,7 @@ void RandomPlayerbotMgr::PrepareZone2LevelBracket()
|
||||
zone2LevelBracket[2817] = {77, 80}; // Crystalsong Forest
|
||||
zone2LevelBracket[3537] = {68, 75}; // Borean Tundra
|
||||
zone2LevelBracket[3711] = {75, 80}; // Sholazar Basin
|
||||
zone2LevelBracket[4197] = {79, 80}; // Wintergrasp
|
||||
|
||||
// Override with values from config
|
||||
for (auto const& [zoneId, bracketPair] : sPlayerbotAIConfig->zoneBrackets) {
|
||||
zone2LevelBracket[zoneId] = {bracketPair.first, bracketPair.second};
|
||||
}
|
||||
zone2LevelBracket[4197] = {79, 80}; // Wintergrasp
|
||||
}
|
||||
|
||||
void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
@@ -1675,8 +1627,8 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
||||
uint32 level = (min_level + max_level + 1) / 2;
|
||||
WorldLocation loc(mapId, x, y, z, 0);
|
||||
collected_locs++;
|
||||
for (int32 l = (int32)level - (int32)sPlayerbotAIConfig->randomBotTeleLowerLevel;
|
||||
l <= (int32)level + (int32)sPlayerbotAIConfig->randomBotTeleHigherLevel; l++)
|
||||
for (int32 l = (int32)level - (int32)sPlayerbotAIConfig->randomBotTeleHigherLevel;
|
||||
l <= (int32)level + (int32)sPlayerbotAIConfig->randomBotTeleLowerLevel; l++)
|
||||
{
|
||||
if (l < 1 || l > maxLevel)
|
||||
{
|
||||
|
||||
@@ -206,8 +206,6 @@ private:
|
||||
time_t BgCheckTimer;
|
||||
time_t LfgCheckTimer;
|
||||
time_t PlayersCheckTimer;
|
||||
time_t RealPlayerLastTimeSeen = 0;
|
||||
time_t DelayLoginBotsTimer;
|
||||
time_t printStatsTimer;
|
||||
uint32 AddRandomBots();
|
||||
bool ProcessBot(uint32 bot);
|
||||
|
||||
@@ -531,7 +531,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
||||
if (player->GetLevel() >= 20)
|
||||
{
|
||||
nonCombatEngine->addStrategy("bhealth", false);
|
||||
nonCombatEngine->addStrategy("bstats", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -813,10 +813,6 @@ void PlayerbotFactory::InitPetTalents()
|
||||
void PlayerbotFactory::InitPet()
|
||||
{
|
||||
Pet* pet = bot->GetPet();
|
||||
|
||||
if (!pet && bot->GetPetStable() && bot->GetPetStable()->CurrentPet)
|
||||
return;
|
||||
|
||||
if (!pet)
|
||||
{
|
||||
if (bot->getClass() != CLASS_HUNTER || bot->GetLevel() < 10)
|
||||
@@ -865,8 +861,7 @@ void PlayerbotFactory::InitPet()
|
||||
uint32 pet_number = sObjectMgr->GeneratePetNumber();
|
||||
if (bot->GetPetStable() && bot->GetPetStable()->CurrentPet)
|
||||
{
|
||||
auto petGuid = bot->GetPetStable()->CurrentPet.value(); // To correct the build warnin in VS
|
||||
// bot->GetPetStable()->CurrentPet.value();
|
||||
bot->GetPetStable()->CurrentPet.value();
|
||||
// bot->GetPetStable()->CurrentPet.reset();
|
||||
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT);
|
||||
bot->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
|
||||
@@ -1743,7 +1738,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
||||
|
||||
if (incremental && oldItem)
|
||||
{
|
||||
float old_score = calculator.CalculateItem(oldItem->GetEntry(), oldItem->GetItemRandomPropertyId());
|
||||
float old_score = calculator.CalculateItem(oldItem->GetEntry());
|
||||
if (bestScoreForSlot < 1.2f * old_score)
|
||||
continue;
|
||||
}
|
||||
@@ -2205,15 +2200,33 @@ void PlayerbotFactory::InitSkills()
|
||||
//uint32 maxValue = level * 5; //not used, line marked for removal.
|
||||
bot->UpdateSkillsForLevel();
|
||||
|
||||
bot->SetSkill(SKILL_RIDING, 0, 0, 0);
|
||||
auto SafeLearn = [this](uint32 spellId)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
bot->learnSpell(spellId, false, true); // Avoid duplicate attempts in DB
|
||||
};
|
||||
|
||||
// Define Riding skill according to level
|
||||
if (bot->GetLevel() >= 70)
|
||||
bot->SetSkill(SKILL_RIDING, 300, 300, 300);
|
||||
else if (bot->GetLevel() >= 60)
|
||||
bot->SetSkill(SKILL_RIDING, 225, 225, 225);
|
||||
else if (bot->GetLevel() >= 40)
|
||||
bot->SetSkill(SKILL_RIDING, 150, 150, 150);
|
||||
else if (bot->GetLevel() >= 20)
|
||||
bot->SetSkill(SKILL_RIDING, 75, 75, 75);
|
||||
else
|
||||
bot->SetSkill(SKILL_RIDING, 0, 0, 0);
|
||||
|
||||
// Safe learning of mount spells
|
||||
if (bot->GetLevel() >= sPlayerbotAIConfig->useGroundMountAtMinLevel)
|
||||
bot->learnSpell(33388);
|
||||
SafeLearn(33388); // Apprentice
|
||||
if (bot->GetLevel() >= sPlayerbotAIConfig->useFastGroundMountAtMinLevel)
|
||||
bot->learnSpell(33391);
|
||||
SafeLearn(33391); // Journeyman
|
||||
if (bot->GetLevel() >= sPlayerbotAIConfig->useFlyMountAtMinLevel)
|
||||
bot->learnSpell(34090);
|
||||
SafeLearn(34090); // Expert
|
||||
if (bot->GetLevel() >= sPlayerbotAIConfig->useFastFlyMountAtMinLevel)
|
||||
bot->learnSpell(34091);
|
||||
SafeLearn(34091); // Artisan
|
||||
|
||||
uint32 skillLevel = bot->GetLevel() < 40 ? 0 : 1;
|
||||
uint32 dualWieldLevel = bot->GetLevel() < 20 ? 0 : 1;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "DBCStores.h"
|
||||
#include "ItemEnchantmentMgr.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
@@ -206,7 +205,7 @@ void StatsCollector::CollectSpellStats(uint32 spellId, float multiplier, int32 s
|
||||
}
|
||||
}
|
||||
|
||||
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount)
|
||||
void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchant)
|
||||
{
|
||||
for (int s = 0; s < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++s)
|
||||
{
|
||||
@@ -232,10 +231,6 @@ void StatsCollector::CollectEnchantStats(SpellItemEnchantmentEntry const* enchan
|
||||
}
|
||||
case ITEM_ENCHANTMENT_TYPE_STAT:
|
||||
{
|
||||
// for item random suffix
|
||||
if (!enchant_amount)
|
||||
enchant_amount = default_enchant_amount;
|
||||
|
||||
if (!enchant_amount)
|
||||
{
|
||||
break;
|
||||
@@ -255,7 +250,7 @@ bool StatsCollector::SpecialSpellFilter(uint32 spellId)
|
||||
// trinket
|
||||
switch (spellId)
|
||||
{
|
||||
case 60764: // Totem of Splintering
|
||||
case 60764: // Totem of Splintering
|
||||
if (type_ & (CollectorType::SPELL))
|
||||
return true;
|
||||
break;
|
||||
@@ -749,7 +744,7 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu
|
||||
|
||||
int32 StatsCollector::AverageValue(const SpellEffectInfo& effectInfo)
|
||||
{
|
||||
// float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
||||
//float basePointsPerLevel = effectInfo.RealPointsPerLevel; //not used, line marked for removal.
|
||||
int32 basePoints = effectInfo.BasePoints;
|
||||
int32 randomPoints = int32(effectInfo.DieSides);
|
||||
|
||||
@@ -772,7 +767,7 @@ bool StatsCollector::CheckSpellValidation(uint32 spellFamilyName, flag96 spelFal
|
||||
{
|
||||
if (PlayerbotAI::Class2SpellFamilyName(cls_) != spellFamilyName)
|
||||
return false;
|
||||
|
||||
|
||||
bool isHealingSpell = PlayerbotAI::IsHealingSpell(spellFamilyName, spelFalimyFlags);
|
||||
// strict to healer
|
||||
if (strict && (type_ & CollectorType::SPELL_HEAL))
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
void Reset();
|
||||
void CollectItemStats(ItemTemplate const* proto);
|
||||
void CollectSpellStats(uint32 spellId, float multiplier = 1.0f, int32 spellCooldown = -1);
|
||||
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant, uint32 default_enchant_amount = 0);
|
||||
void CollectEnchantStats(SpellItemEnchantmentEntry const* enchant);
|
||||
bool CanBeTriggeredByType(SpellInfo const* spellInfo, uint32 procFlags, bool strict = true);
|
||||
bool CheckSpellValidation(uint32 spellFamilyName, flag96 spelFalimyFlags, bool strict = true);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "AiFactory.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ItemEnchantmentMgr.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
@@ -60,7 +59,7 @@ void StatsWeightCalculator::Reset()
|
||||
}
|
||||
}
|
||||
|
||||
float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyIds)
|
||||
float StatsWeightCalculator::CalculateItem(uint32 itemId)
|
||||
{
|
||||
ItemTemplate const* proto = &sObjectMgr->GetItemTemplateStore()->at(itemId);
|
||||
|
||||
@@ -70,9 +69,6 @@ float StatsWeightCalculator::CalculateItem(uint32 itemId, int32 randomPropertyId
|
||||
Reset();
|
||||
|
||||
collector_->CollectItemStats(proto);
|
||||
|
||||
if (randomPropertyIds != 0)
|
||||
CalculateRandomProperty(randomPropertyIds, itemId);
|
||||
|
||||
if (enable_overflow_penalty_)
|
||||
ApplyOverflowPenalty(player_);
|
||||
@@ -120,53 +116,6 @@ float StatsWeightCalculator::CalculateEnchant(uint32 enchantId)
|
||||
return weight_;
|
||||
}
|
||||
|
||||
void StatsWeightCalculator::CalculateRandomProperty(int32 randomPropertyId, uint32 itemId)
|
||||
{
|
||||
if (randomPropertyId > 0)
|
||||
{
|
||||
ItemRandomPropertiesEntry const* item_rand = sItemRandomPropertiesStore.LookupEntry(randomPropertyId);
|
||||
if (!item_rand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
||||
{
|
||||
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
||||
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
||||
if (enchant)
|
||||
collector_->CollectEnchantStats(enchant);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemRandomSuffixEntry const* item_rand = sItemRandomSuffixStore.LookupEntry(-randomPropertyId);
|
||||
if (!item_rand)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32 i = PROP_ENCHANTMENT_SLOT_0; i < MAX_ENCHANTMENT_SLOT; ++i)
|
||||
{
|
||||
uint32 enchantId = item_rand->Enchantment[i - PROP_ENCHANTMENT_SLOT_0];
|
||||
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
|
||||
uint32 enchant_amount = 0;
|
||||
|
||||
for (int k = 0; k < MAX_ITEM_ENCHANTMENT_EFFECTS; ++k)
|
||||
{
|
||||
if (item_rand->Enchantment[k] == enchantId)
|
||||
{
|
||||
enchant_amount = uint32((item_rand->AllocationPct[k] * GenerateEnchSuffixFactor(itemId)) / 10000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (enchant)
|
||||
collector_->CollectEnchantStats(enchant, enchant_amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatsWeightCalculator::GenerateWeights(Player* player)
|
||||
{
|
||||
GenerateBasicWeights(player);
|
||||
@@ -344,8 +293,8 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||
stats_weights_[STATS_TYPE_CRIT] += 0.8f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 1.0f;
|
||||
}
|
||||
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || // holy
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION)) // heal
|
||||
else if ((cls == CLASS_PALADIN && tab == PALADIN_TAB_HOLY) || // holy
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_RESTORATION)) // heal
|
||||
{
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.9f;
|
||||
stats_weights_[STATS_TYPE_SPIRIT] += 0.15f;
|
||||
@@ -354,7 +303,7 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||
stats_weights_[STATS_TYPE_CRIT] += 0.6f;
|
||||
stats_weights_[STATS_TYPE_HASTE] += 0.8f;
|
||||
}
|
||||
else if ((cls == CLASS_PRIEST && tab != PRIEST_TAB_SHADOW) || // discipline / holy
|
||||
else if ((cls == CLASS_PRIEST && tab != PRIEST_TAB_SHADOW) || // discipline / holy
|
||||
(cls == CLASS_DRUID && tab == DRUID_TAB_RESTORATION))
|
||||
{
|
||||
stats_weights_[STATS_TYPE_INTELLECT] += 0.8f;
|
||||
@@ -515,9 +464,9 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
||||
// {
|
||||
// weight_ *= 1.0;
|
||||
// }
|
||||
// double hand
|
||||
if (proto->Class == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
// double hand
|
||||
bool isDoubleHand = proto->Class == ITEM_CLASS_WEAPON &&
|
||||
!(ITEM_SUBCLASS_MASK_SINGLE_HAND & (1 << proto->SubClass)) &&
|
||||
!(ITEM_SUBCLASS_MASK_WEAPON_RANGED & (1 << proto->SubClass));
|
||||
@@ -525,41 +474,29 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
||||
if (isDoubleHand)
|
||||
{
|
||||
weight_ *= 0.5;
|
||||
// spec without double hand
|
||||
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
||||
if (((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
||||
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
|
||||
}
|
||||
// spec without double hand
|
||||
// enhancement, rogue, ice dk, unholy dk, shield tank, fury warrior without titan's grip but with duel wield
|
||||
if (isDoubleHand &&
|
||||
((cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && player_->CanDualWield()) ||
|
||||
(cls == CLASS_ROGUE) || (cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_FROST) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanTitanGrip() && player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_PROTECTION) ||
|
||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_PROTECTION)))
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
// spec with double hand
|
||||
// fury without duel wield, arms, bear, retribution, blood dk
|
||||
if (!isDoubleHand)
|
||||
if (!isDoubleHand &&
|
||||
((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
||||
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield())))
|
||||
{
|
||||
if ((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
||||
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ENHANCEMENT && !player_->CanDualWield()))
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
// caster's main hand (cannot duel weapon but can equip two-hands stuff)
|
||||
if (cls == CLASS_MAGE ||
|
||||
cls == CLASS_PRIEST ||
|
||||
cls == CLASS_WARLOCK ||
|
||||
cls == CLASS_DRUID ||
|
||||
(cls == CLASS_SHAMAN && !player_->CanDualWield()))
|
||||
{
|
||||
weight_ *= 0.65;
|
||||
}
|
||||
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
// fury with titan's grip
|
||||
if ((!isDoubleHand || proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM ||
|
||||
@@ -568,18 +505,15 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
|
||||
if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN)
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
|
||||
if (cls == CLASS_ROGUE && (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) &&
|
||||
proto->SubClass != ITEM_SUBCLASS_WEAPON_DAGGER)
|
||||
{
|
||||
weight_ *= 0.5;
|
||||
}
|
||||
|
||||
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||
{
|
||||
@@ -625,13 +559,12 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
||||
if (hitOverflowType_ & CollectorType::SPELL)
|
||||
{
|
||||
hit_current = player->GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_HIT_CHANCE);
|
||||
hit_current +=
|
||||
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
||||
hit_current += player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
||||
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
||||
|
||||
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
||||
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
||||
hit_current += 3;
|
||||
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
|
||||
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
|
||||
hit_current += 3;
|
||||
|
||||
hit_overflow = SPELL_HIT_OVERFLOW;
|
||||
@@ -724,7 +657,7 @@ void StatsWeightCalculator::ApplyWeightFinetune(Player* player)
|
||||
{
|
||||
if (type_ & (CollectorType::MELEE | CollectorType::RANGED))
|
||||
{
|
||||
float armor_penetration_current /*, armor_penetration_overflow*/; // not used, line marked for removal.
|
||||
float armor_penetration_current/*, armor_penetration_overflow*/; //not used, line marked for removal.
|
||||
armor_penetration_current = player->GetRatingBonusValue(CR_ARMOR_PENETRATION);
|
||||
if (armor_penetration_current > 50)
|
||||
stats_weights_[STATS_TYPE_ARMOR_PENETRATION] *= 1.2f;
|
||||
|
||||
@@ -28,19 +28,18 @@ class StatsWeightCalculator
|
||||
public:
|
||||
StatsWeightCalculator(Player* player);
|
||||
void Reset();
|
||||
float CalculateItem(uint32 itemId, int32 randomPropertyId = 0);
|
||||
float CalculateItem(uint32 itemId);
|
||||
float CalculateEnchant(uint32 enchantId);
|
||||
|
||||
|
||||
void SetOverflowPenalty(bool apply) { enable_overflow_penalty_ = apply; }
|
||||
void SetItemSetBonus(bool apply) { enable_item_set_bonus_ = apply; }
|
||||
void SetQualityBlend(bool apply) { enable_quality_blend_ = apply; }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
void GenerateWeights(Player* player);
|
||||
void GenerateBasicWeights(Player* player);
|
||||
void GenerateAdditionalWeights(Player* player);
|
||||
|
||||
void CalculateRandomProperty(int32 randomPropertyId, uint32 itemId);
|
||||
|
||||
void CalculateItemSetMod(Player* player, ItemTemplate const* proto);
|
||||
void CalculateSocketBonus(Player* player, ItemTemplate const* proto);
|
||||
|
||||
|
||||
@@ -305,49 +305,6 @@ ItemIds ChatHelper::parseItems(std::string const text)
|
||||
return itemIds;
|
||||
}
|
||||
|
||||
ItemWithRandomProperty ChatHelper::parseItemWithRandomProperty(std::string const text)
|
||||
{
|
||||
ItemWithRandomProperty res;
|
||||
|
||||
size_t itemStart = text.find("Hitem:");
|
||||
if (itemStart == std::string::npos)
|
||||
return res;
|
||||
|
||||
itemStart += 6;
|
||||
if (itemStart >= text.length())
|
||||
return res;
|
||||
|
||||
size_t colonPos = text.find(':', itemStart);
|
||||
if (colonPos == std::string::npos)
|
||||
return res;
|
||||
|
||||
std::string itemIdStr = text.substr(itemStart, colonPos - itemStart);
|
||||
res.itemId = atoi(itemIdStr.c_str());
|
||||
|
||||
std::vector<std::string> params;
|
||||
size_t currentPos = colonPos + 1;
|
||||
|
||||
while (currentPos < text.length()) {
|
||||
size_t nextColon = text.find(':', currentPos);
|
||||
if (nextColon == std::string::npos) {
|
||||
size_t hTag = text.find("|h", currentPos);
|
||||
if (hTag != std::string::npos) {
|
||||
params.push_back(text.substr(currentPos, hTag - currentPos));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
params.push_back(text.substr(currentPos, nextColon - currentPos));
|
||||
currentPos = nextColon + 1;
|
||||
}
|
||||
|
||||
if (params.size() >= 6) {
|
||||
res.randomPropertyId = atoi(params[5].c_str());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string const ChatHelper::FormatQuest(Quest const* quest)
|
||||
{
|
||||
if (!quest)
|
||||
@@ -425,7 +382,7 @@ std::string const ChatHelper::FormatSpell(SpellInfo const* spellInfo)
|
||||
std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count, uint32 total)
|
||||
{
|
||||
char color[32];
|
||||
snprintf(color, sizeof(color), "%x", ItemQualityColors[proto->Quality]);
|
||||
sprintf(color, "%x", ItemQualityColors[proto->Quality]);
|
||||
|
||||
std::string itemName;
|
||||
const ItemLocale* locale = sObjectMgr->GetItemLocale(proto->ItemId);
|
||||
@@ -452,7 +409,7 @@ std::string const ChatHelper::FormatItem(ItemTemplate const* proto, uint32 count
|
||||
std::string const ChatHelper::FormatQItem(uint32 itemId)
|
||||
{
|
||||
char color[32];
|
||||
snprintf(color, sizeof(color), "%x", ItemQualityColors[0]);
|
||||
sprintf(color, "%x", ItemQualityColors[0]);
|
||||
|
||||
std::ostringstream out;
|
||||
out << "|c" << color << "|Hitem:" << itemId << ":0:0:0:0:0:0:0"
|
||||
@@ -25,11 +25,6 @@ struct ItemTemplate;
|
||||
typedef std::set<uint32> ItemIds;
|
||||
typedef std::set<uint32> SpellIds;
|
||||
|
||||
struct ItemWithRandomProperty {
|
||||
uint32 itemId{0};
|
||||
int32 randomPropertyId{0};
|
||||
};
|
||||
|
||||
class ChatHelper : public PlayerbotAIAware
|
||||
{
|
||||
public:
|
||||
@@ -38,7 +33,6 @@ public:
|
||||
static std::string const formatMoney(uint32 copper);
|
||||
static uint32 parseMoney(std::string const text);
|
||||
static ItemIds parseItems(std::string const text);
|
||||
static ItemWithRandomProperty parseItemWithRandomProperty(std::string const text);
|
||||
uint32 parseSpell(std::string const text);
|
||||
static std::string parseValue(const std::string& type, const std::string& text);
|
||||
|
||||
@@ -232,20 +232,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CollectItemsVisitor : public IterateItemsVisitor
|
||||
{
|
||||
public:
|
||||
CollectItemsVisitor() : IterateItemsVisitor() {}
|
||||
|
||||
std::vector<Item*> items;
|
||||
|
||||
bool Visit(Item* item) override
|
||||
{
|
||||
items.push_back(item);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ItemCountByQuality : public IterateItemsVisitor
|
||||
{
|
||||
public:
|
||||
@@ -85,7 +85,7 @@ void LootObject::Refresh(Player* bot, ObjectGuid lootGUID)
|
||||
bool hasAnyQuestItems = false;
|
||||
|
||||
GameObjectQuestItemList const* items = sObjectMgr->GetGameObjectQuestItemList(go->GetEntry());
|
||||
for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; i++)
|
||||
for (int i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; i++)
|
||||
{
|
||||
if (!items || i >= items->size())
|
||||
break;
|
||||
@@ -297,11 +297,6 @@ bool LootObject::IsLootPossible(Player* bot)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent bot from running to chests that are unlootable (e.g. Gunship Armory before completing the event)
|
||||
GameObject* go = botAI->GetGameObject(guid);
|
||||
if (go && go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE))
|
||||
return false;
|
||||
|
||||
if (skillId == SKILL_NONE)
|
||||
return true;
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
LootObject() : skillId(0), reqSkillValue(0), reqItem(0) {}
|
||||
LootObject(Player* bot, ObjectGuid guid);
|
||||
LootObject(LootObject const& other);
|
||||
LootObject& operator=(LootObject const& other) = default;
|
||||
|
||||
bool IsEmpty() { return !guid; }
|
||||
bool IsLootPossible(Player* bot);
|
||||
@@ -17,28 +17,28 @@
|
||||
#include "ValueContext.h"
|
||||
#include "WorldPacketActionContext.h"
|
||||
#include "WorldPacketTriggerContext.h"
|
||||
#include "raids/RaidStrategyContext.h"
|
||||
#include "raids/blackwinglair/RaidBwlActionContext.h"
|
||||
#include "raids/blackwinglair/RaidBwlTriggerContext.h"
|
||||
#include "raids/naxxramas/RaidNaxxActionContext.h"
|
||||
#include "raids/naxxramas/RaidNaxxTriggerContext.h"
|
||||
#include "raids/icecrown/RaidIccActionContext.h"
|
||||
#include "raids/icecrown/RaidIccTriggerContext.h"
|
||||
#include "raids/obsidiansanctum/RaidOsActionContext.h"
|
||||
#include "raids/obsidiansanctum/RaidOsTriggerContext.h"
|
||||
#include "raids/eyeofeternity/RaidEoEActionContext.h"
|
||||
#include "raids/vaultofarchavon/RaidVoATriggerContext.h"
|
||||
#include "raids/onyxia/RaidOnyxiaActionContext.h"
|
||||
#include "raids/onyxia/RaidOnyxiaTriggerContext.h"
|
||||
#include "raids/vaultofarchavon/RaidVoAActionContext.h"
|
||||
#include "raids/eyeofeternity/RaidEoETriggerContext.h"
|
||||
#include "raids/moltencore/RaidMcActionContext.h"
|
||||
#include "raids/moltencore/RaidMcTriggerContext.h"
|
||||
#include "raids/aq20/RaidAq20ActionContext.h"
|
||||
#include "raids/aq20/RaidAq20TriggerContext.h"
|
||||
#include "dungeons/DungeonStrategyContext.h"
|
||||
#include "dungeons/wotlk/WotlkDungeonActionContext.h"
|
||||
#include "dungeons/wotlk/WotlkDungeonTriggerContext.h"
|
||||
#include "RaidStrategyContext.h"
|
||||
#include "RaidBwlActionContext.h"
|
||||
#include "RaidBwlTriggerContext.h"
|
||||
#include "RaidNaxxActionContext.h"
|
||||
#include "RaidNaxxTriggerContext.h"
|
||||
#include "RaidIccActionContext.h"
|
||||
#include "RaidIccTriggerContext.h"
|
||||
#include "RaidOsActionContext.h"
|
||||
#include "RaidOsTriggerContext.h"
|
||||
#include "RaidEoEActionContext.h"
|
||||
#include "RaidVoATriggerContext.h"
|
||||
#include "RaidOnyxiaActionContext.h"
|
||||
#include "RaidOnyxiaTriggerContext.h"
|
||||
#include "RaidVoAActionContext.h"
|
||||
#include "RaidEoETriggerContext.h"
|
||||
#include "RaidMcActionContext.h"
|
||||
#include "RaidMcTriggerContext.h"
|
||||
#include "RaidAq20ActionContext.h"
|
||||
#include "RaidAq20TriggerContext.h"
|
||||
#include "DungeonStrategyContext.h"
|
||||
#include "WotlkDungeonActionContext.h"
|
||||
#include "WotlkDungeonTriggerContext.h"
|
||||
|
||||
AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
{
|
||||
@@ -75,7 +75,6 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
actionContexts.Add(new WotlkDungeonUPActionContext());
|
||||
actionContexts.Add(new WotlkDungeonCoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonFoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonPoSActionContext());
|
||||
actionContexts.Add(new WotlkDungeonToCActionContext());
|
||||
|
||||
triggerContexts.Add(new TriggerContext());
|
||||
@@ -103,8 +102,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
triggerContexts.Add(new WotlkDungeonOccTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonFoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonPoSTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonFosTriggerContext());
|
||||
triggerContexts.Add(new WotlkDungeonToCTriggerContext());
|
||||
|
||||
valueContexts.Add(new ValueContext());
|
||||
|
||||
@@ -1,450 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "InviteToGroupAction.h"
|
||||
|
||||
#include "BroadcastHelper.h"
|
||||
#include "Event.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool InviteToGroupAction::Invite(Player* inviter, Player* player)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (inviter == player)
|
||||
return false;
|
||||
|
||||
if (!GET_PLAYERBOT_AI(player) && !botAI->GetSecurity()->CheckLevelFor(PLAYERBOT_SECURITY_INVITE, true, player))
|
||||
return false;
|
||||
|
||||
if (Group* group = inviter->GetGroup())
|
||||
{
|
||||
if (GET_PLAYERBOT_AI(player) && !GET_PLAYERBOT_AI(player)->IsRealPlayer())
|
||||
if (!group->isRaidGroup() && group->GetMembersCount() > 4)
|
||||
group->ConvertToRaid();
|
||||
}
|
||||
|
||||
WorldPacket p;
|
||||
uint32 roles_mask = 0;
|
||||
p << player->GetName();
|
||||
p << roles_mask;
|
||||
inviter->GetSession()->HandleGroupInviteOpcode(p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InviteNearbyToGroupAction::Execute(Event event)
|
||||
{
|
||||
GuidVector nearGuids = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest friendly players")->Get();
|
||||
for (auto& i : nearGuids)
|
||||
{
|
||||
Player* player = ObjectAccessor::FindPlayer(i);
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
if (player == bot)
|
||||
continue;
|
||||
|
||||
if (player->GetMapId() != bot->GetMapId())
|
||||
continue;
|
||||
|
||||
if (player->GetGroup())
|
||||
continue;
|
||||
|
||||
if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
|
||||
continue;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
|
||||
if (player->isDND())
|
||||
continue;
|
||||
|
||||
if (player->IsBeingTeleported())
|
||||
continue;
|
||||
|
||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||
|
||||
if (botAI)
|
||||
{
|
||||
if (botAI->GetGrouperType() == GrouperType::SOLO &&
|
||||
!botAI->HasRealPlayerMaster()) // Do not invite solo players.
|
||||
continue;
|
||||
|
||||
if (botAI->HasActivePlayerMaster()) // Do not invite alts of active players.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (abs(int32(player->GetLevel() - bot->GetLevel())) > 2)
|
||||
continue;
|
||||
|
||||
if (sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
|
||||
continue;
|
||||
|
||||
// When inviting the 5th member of the group convert to raid for future invites.
|
||||
if (group && botAI->GetGrouperType() > GrouperType::LEADER_5 && !group->isRaidGroup() &&
|
||||
bot->GetGroup()->GetMembersCount() > 3)
|
||||
group->ConvertToRaid();
|
||||
|
||||
if (sPlayerbotAIConfig->inviteChat && sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%player"] = player->GetName();
|
||||
|
||||
if (group && group->isRaidGroup())
|
||||
bot->Say(BOT_TEXT2("join_raid", placeholders),
|
||||
(bot->GetTeamId() == ALLIANCE ? LANG_COMMON : LANG_ORCISH));
|
||||
else
|
||||
bot->Say(BOT_TEXT2("join_group", placeholders),
|
||||
(bot->GetTeamId() == ALLIANCE ? LANG_COMMON : LANG_ORCISH));
|
||||
}
|
||||
|
||||
return Invite(bot, player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InviteNearbyToGroupAction::isUseful()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->randomBotGroupNearby)
|
||||
return false;
|
||||
|
||||
if (bot->InBattleground())
|
||||
return false;
|
||||
|
||||
if (bot->InBattlegroundQueue())
|
||||
return false;
|
||||
|
||||
GrouperType grouperType = botAI->GetGrouperType();
|
||||
|
||||
if (grouperType == GrouperType::SOLO || grouperType == GrouperType::MEMBER)
|
||||
return false;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
|
||||
if (group)
|
||||
{
|
||||
if (group->isRaidGroup() && group->IsFull())
|
||||
return false;
|
||||
|
||||
if (botAI->GetGroupMaster() != bot)
|
||||
return false;
|
||||
|
||||
uint32 memberCount = group->GetMembersCount();
|
||||
|
||||
if (memberCount >= uint8(grouperType))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (botAI->HasActivePlayerMaster()) // Alts do not invite randomly
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
|
||||
FindGuildMembers worker;
|
||||
guild->BroadcastWorker(worker);
|
||||
|
||||
return worker.GetResult();
|
||||
}
|
||||
|
||||
bool InviteGuildToGroupAction::Execute(Event event)
|
||||
{
|
||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
||||
|
||||
for (auto& member : getGuildMembers())
|
||||
{
|
||||
Player* player = member;
|
||||
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
if (player == bot)
|
||||
continue;
|
||||
|
||||
if (player->GetGroup())
|
||||
continue;
|
||||
|
||||
if (player->isDND())
|
||||
continue;
|
||||
|
||||
if (!sPlayerbotAIConfig->randomBotInvitePlayer && GET_PLAYERBOT_AI(player)->IsRealPlayer())
|
||||
continue;
|
||||
|
||||
if (player->IsBeingTeleported())
|
||||
continue;
|
||||
|
||||
if (player->GetMapId() != bot->GetMapId() && player->GetLevel() < 30)
|
||||
continue;
|
||||
|
||||
if (WorldPosition(player).distance(bot) > 1000 && player->GetLevel() < 15)
|
||||
continue;
|
||||
|
||||
PlayerbotAI* playerAi = GET_PLAYERBOT_AI(player);
|
||||
|
||||
if (playerAi)
|
||||
{
|
||||
if (playerAi->GetGrouperType() == GrouperType::SOLO &&
|
||||
!playerAi->HasRealPlayerMaster()) // Do not invite solo players.
|
||||
continue;
|
||||
|
||||
if (playerAi->HasActivePlayerMaster()) // Do not invite alts of active players.
|
||||
continue;
|
||||
|
||||
if (player->GetLevel() >
|
||||
bot->GetLevel() + 5) // Invite higher levels that need money so they can grind money and help out.
|
||||
{
|
||||
if (!PAI_VALUE(bool, "should get money"))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bot->GetLevel() >
|
||||
player->GetLevel() + 5) // Do not invite members that too low level or risk dragging them to deadly places.
|
||||
continue;
|
||||
|
||||
if (!playerAi && sServerFacade->GetDistance2d(bot, player) > sPlayerbotAIConfig->sightDistance)
|
||||
continue;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
// When inviting the 5th member of the group convert to raid for future invites.
|
||||
if (group && botAI->GetGrouperType() > GrouperType::LEADER_5 && !group->isRaidGroup() &&
|
||||
bot->GetGroup()->GetMembersCount() > 3)
|
||||
{
|
||||
group->ConvertToRaid();
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->inviteChat &&
|
||||
(sRandomPlayerbotMgr->IsRandomBot(bot) || !botAI->HasActivePlayerMaster()))
|
||||
{
|
||||
BroadcastHelper::BroadcastGuildGroupOrRaidInvite(botAI, bot, player, group);
|
||||
}
|
||||
|
||||
return Invite(bot, player);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JoinGroupAction::Execute(Event event)
|
||||
{
|
||||
if (bot->InBattleground())
|
||||
return false;
|
||||
|
||||
if (bot->InBattlegroundQueue())
|
||||
return false;
|
||||
|
||||
Player* master = event.getOwner();
|
||||
|
||||
Group* group = master->GetGroup();
|
||||
|
||||
if (group)
|
||||
{
|
||||
if (group->IsFull())
|
||||
return false;
|
||||
|
||||
if (bot->GetGroup() == group)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetGroup())
|
||||
{
|
||||
if (botAI->HasRealPlayerMaster())
|
||||
return false;
|
||||
|
||||
if (!botAI->DoSpecificAction("leave", event, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
return Invite(master, bot);
|
||||
}
|
||||
|
||||
bool LfgAction::Execute(Event event)
|
||||
{
|
||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
||||
|
||||
if (bot->InBattleground())
|
||||
return false;
|
||||
|
||||
if (bot->InBattlegroundQueue())
|
||||
return false;
|
||||
|
||||
if (!botAI->IsSafe(requester))
|
||||
return false;
|
||||
|
||||
if (requester->GetLevel() == DEFAULT_MAX_LEVEL && bot->GetLevel() != DEFAULT_MAX_LEVEL)
|
||||
return false;
|
||||
|
||||
if (requester->GetLevel() > bot->GetLevel() + 4 || bot->GetLevel() > requester->GetLevel() + 4)
|
||||
return false;
|
||||
|
||||
std::string param = event.getParam();
|
||||
|
||||
if (!param.empty() && param != "40" && param != "25" && param != "20" && param != "10" && param != "5")
|
||||
return false;
|
||||
|
||||
Group* group = requester->GetGroup();
|
||||
|
||||
std::unordered_map<Classes, std::unordered_map<BotRoles, uint32>> allowedClassNr;
|
||||
std::unordered_map<BotRoles, uint32> allowedRoles;
|
||||
|
||||
allowedRoles[BOT_ROLE_TANK] = 1;
|
||||
allowedRoles[BOT_ROLE_HEALER] = 1;
|
||||
allowedRoles[BOT_ROLE_DPS] = 3;
|
||||
|
||||
BotRoles role = botAI->IsTank(requester, false)
|
||||
? BOT_ROLE_TANK
|
||||
: (botAI->IsHeal(requester, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
|
||||
Classes cls = (Classes)requester->getClass();
|
||||
|
||||
if (group)
|
||||
{
|
||||
if (param.empty() && group->isRaidGroup())
|
||||
// Default to WotLK Raiding. Max size 25
|
||||
param = "25";
|
||||
// Select optimal group layout.
|
||||
if (param == "40")
|
||||
{
|
||||
allowedRoles[BOT_ROLE_TANK] = 4;
|
||||
allowedRoles[BOT_ROLE_HEALER] = 16;
|
||||
allowedRoles[BOT_ROLE_DPS] = 20;
|
||||
/*
|
||||
allowedClassNr[CLASS_PALADIN][BOT_ROLE_TANK] = 0;
|
||||
allowedClassNr[CLASS_DRUID][BOT_ROLE_TANK] = 1;
|
||||
|
||||
allowedClassNr[CLASS_DRUID][BOT_ROLE_HEALER] = 3;
|
||||
allowedClassNr[CLASS_PALADIN][BOT_ROLE_HEALER] = 4;
|
||||
allowedClassNr[CLASS_SHAMAN][BOT_ROLE_HEALER] = 4;
|
||||
allowedClassNr[CLASS_PRIEST][BOT_ROLE_HEALER] = 11;
|
||||
|
||||
allowedClassNr[CLASS_WARRIOR][BOT_ROLE_DPS] = 8;
|
||||
allowedClassNr[CLASS_PALADIN][BOT_ROLE_DPS] = 4;
|
||||
allowedClassNr[CLASS_HUNTER][BOT_ROLE_DPS] = 4;
|
||||
allowedClassNr[CLASS_ROGUE][BOT_ROLE_DPS] = 6;
|
||||
allowedClassNr[CLASS_PRIEST][BOT_ROLE_DPS] = 1;
|
||||
allowedClassNr[CLASS_SHAMAN][BOT_ROLE_DPS] = 4;
|
||||
allowedClassNr[CLASS_MAGE][BOT_ROLE_DPS] = 15;
|
||||
allowedClassNr[CLASS_WARLOCK][BOT_ROLE_DPS] = 4;
|
||||
allowedClassNr[CLASS_DRUID][BOT_ROLE_DPS] = 1;
|
||||
*/
|
||||
}
|
||||
else if (param == "25")
|
||||
{
|
||||
allowedRoles[BOT_ROLE_TANK] = 3;
|
||||
allowedRoles[BOT_ROLE_HEALER] = 7;
|
||||
allowedRoles[BOT_ROLE_DPS] = 15;
|
||||
}
|
||||
else if (param == "20")
|
||||
{
|
||||
allowedRoles[BOT_ROLE_TANK] = 2;
|
||||
allowedRoles[BOT_ROLE_HEALER] = 5;
|
||||
allowedRoles[BOT_ROLE_DPS] = 13;
|
||||
}
|
||||
else if (param == "10")
|
||||
{
|
||||
allowedRoles[BOT_ROLE_TANK] = 2;
|
||||
allowedRoles[BOT_ROLE_HEALER] = 3;
|
||||
allowedRoles[BOT_ROLE_DPS] = 5;
|
||||
}
|
||||
|
||||
if (group->IsFull())
|
||||
{
|
||||
if (param.empty() || param == "5" || group->isRaidGroup())
|
||||
return false; // Group or raid is full so stop trying.
|
||||
else
|
||||
group->ConvertToRaid(); // We want a raid but are in a group so convert and continue.
|
||||
}
|
||||
|
||||
Group::MemberSlotList const& groupSlot = group->GetMemberSlots();
|
||||
for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++)
|
||||
{
|
||||
// Only add group member targets that are alive and near the player
|
||||
Player* player = ObjectAccessor::FindPlayer(itr->guid);
|
||||
|
||||
if (!botAI->IsSafe(player))
|
||||
return false;
|
||||
|
||||
role = botAI->IsTank(player, false) ? BOT_ROLE_TANK
|
||||
: (botAI->IsHeal(player, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
|
||||
cls = (Classes)player->getClass();
|
||||
|
||||
if (allowedRoles[role] > 0)
|
||||
allowedRoles[role]--;
|
||||
|
||||
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] > 0)
|
||||
allowedClassNr[cls][role]--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (allowedRoles[role] > 0)
|
||||
allowedRoles[role]--;
|
||||
|
||||
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] > 0)
|
||||
allowedClassNr[cls][role]--;
|
||||
}
|
||||
|
||||
role = botAI->IsTank(bot, false) ? BOT_ROLE_TANK : (botAI->IsHeal(bot, false) ? BOT_ROLE_HEALER : BOT_ROLE_DPS);
|
||||
cls = (Classes)bot->getClass();
|
||||
|
||||
if (allowedRoles[role] == 0)
|
||||
return false;
|
||||
|
||||
if (allowedClassNr[cls].find(role) != allowedClassNr[cls].end() && allowedClassNr[cls][role] == 0)
|
||||
return false;
|
||||
|
||||
if (bot->GetGroup())
|
||||
{
|
||||
if (botAI->HasRealPlayerMaster())
|
||||
return false;
|
||||
|
||||
if (!botAI->DoSpecificAction("leave", event, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool invite = Invite(requester, bot);
|
||||
|
||||
if (invite)
|
||||
{
|
||||
Event acceptEvent("accept invitation", requester ? requester->GetGUID() : ObjectGuid::Empty);
|
||||
if (!botAI->DoSpecificAction("accept invitation", acceptEvent, true))
|
||||
return false;
|
||||
|
||||
std::map<std::string, std::string> placeholders;
|
||||
placeholders["%role"] = (role & BOT_ROLE_TANK ? "tank" : (role & BOT_ROLE_HEALER ? "healer" : "dps"));
|
||||
placeholders["%spotsleft"] = std::to_string(allowedRoles[role] - 1);
|
||||
|
||||
std::ostringstream out;
|
||||
if (allowedRoles[role] > 1)
|
||||
{
|
||||
out << "Joining as " << placeholders["%role"] << ", " << placeholders["%spotsleft"] << " "
|
||||
<< placeholders["%role"] << " spots left.";
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
//botAI->DoSpecificAction("autogear");
|
||||
//botAI->DoSpecificAction("maintenance");
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Joining as " << placeholders["%role"] << ".";
|
||||
botAI->TellMasterNoFacing(out.str());
|
||||
|
||||
//botAI->DoSpecificAction("autogear");
|
||||
//botAI->DoSpecificAction("maintenance");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user