Skip to content

Commit

Permalink
Playerbots update
Browse files Browse the repository at this point in the history
  • Loading branch information
conan513 committed Oct 23, 2024
1 parent a6c027b commit c61211c
Show file tree
Hide file tree
Showing 95 changed files with 2,358 additions and 302 deletions.
2 changes: 2 additions & 0 deletions modules/mod-playerbots/conf/playerbots.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -1460,9 +1460,11 @@ AiPlayerbot.BotActiveAlone = 100
# Specify smart scaling is enabled or not.
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
AiPlayerbot.botActiveAloneSmartScale = 1

# Only when botLevel is between WhenMinLevel and WhenMaxLevel.
AiPlayerbot.botActiveAloneSmartScaleWhenMinLevel = 1
AiPlayerbot.botActiveAloneSmartScaleWhenMaxLevel = 80

# The server will tune bot activity to reach the desired server tick speed (in ms)
# bots will only join battleground when there is no lag based on latency diffs below
AiPlayerbot.botActiveAloneSmartScaleDiffWithPlayer = 100
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `tex
-- %my_level
('suggest_something', 'Wanna party in %zone_name.', 0, 0, '', 'Je veux faire la fête dans %zone_name.', '', '', '', '¡Vamos a perrear a %zone_name!', '', 'Ищу группу в %zone_name.'),
('suggest_something', 'Anyone is looking for %my_role?', 0, 0, '', 'Quelqu\'un cherche un %my_role ?', '', '', '', '¿Alguien está buscando %my_role?', '', 'Кто-нибудь ищет %my_role?'),
('suggest_something', '%my_role is looking for quild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'),
('suggest_something', '%my_role is looking for guild.', 0, 0, '', '%my_role recherche une guilde.', '', '', '', '%my_role está buscando hermandad.', '', '%my_role ищу гильдию.'),
('suggest_something', 'Looking for gold.', 0, 0, '', 'A la recherche de l\'or.', '', '', '', 'Buscando oro.', '', 'Дайте голды'),
('suggest_something', '%my_role wants to join a good guild.', 0, 0, '', '%my_role veut rejoindre une bonne guilde.', '', '', '', '%my_role quiere unirse a una buen hermandad.', '', '%my_role хочу в хорошую гильдию.'),
('suggest_something', 'Need a friend.', 0, 0, '', 'Besoin d\'un ami.', '', '', '', 'Necesito un amigo...', '', 'Ищу друга.'),
Expand Down Expand Up @@ -1457,19 +1457,3 @@ INSERT INTO `ai_playerbot_texts` (`name`, `text`, `say_type`, `reply_type`, `tex


('dummy_end', 'dummy', 0, 0, '', '', '', '', '', '', '', '');

DROP TABLE IF EXISTS `ai_playerbot_texts_chance`;

CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`probability` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8;

/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */;
INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES
(1, 'taunt', 30),
(2, 'aoe', 75),
(3, 'loot', 20);
/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DROP TABLE IF EXISTS `ai_playerbot_texts_chance`;
CREATE TABLE IF NOT EXISTS `ai_playerbot_texts_chance` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`probability` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8;

/*!40000 ALTER TABLE `ai_playerbot_texts_chance` DISABLE KEYS */;
INSERT INTO `ai_playerbot_texts_chance` (`id`, `name`, `probability`) VALUES
(1, 'taunt', 30),
(2, 'aoe', 75),
(3, 'loot', 20);
/*!40000 ALTER TABLE `ai_playerbot_texts_chance` ENABLE KEYS */;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
DROP TABLE IF EXISTS `playerbots_preferred_mounts`;
CREATE TABLE `playerbots_preferred_mounts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`guid` INT(11) NOT NULL,
`type` TINYINT(3) NOT NULL COMMENT '0: Ground, 1: Flying',
`spellid` INT(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `guid` (`guid`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
8 changes: 6 additions & 2 deletions modules/mod-playerbots/src/ChatHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,9 +304,13 @@ ItemIds ChatHelper::parseItems(std::string const text)

std::string const ChatHelper::FormatQuest(Quest const* quest)
{
if (!quest)
{
return "Invalid quest";
}

std::ostringstream out;
out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle()
<< "]|h|r";
out << "|cFFFFFF00|Hquest:" << quest->GetQuestId() << ':' << quest->GetQuestLevel() << "|h[" << quest->GetTitle() << "]|h|r";
return out.str();
}

Expand Down
21 changes: 17 additions & 4 deletions modules/mod-playerbots/src/LootObjectStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,23 @@ bool LootObject::IsLootPossible(Player* bot)
if (reqSkillValue > skillValue)
return false;

if (skillId == SKILL_MINING && !bot->HasItemCount(2901, 1))
return false;

if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1))
if (skillId == SKILL_MINING && !bot->HasItemCount(756, 1) &&
!bot->HasItemCount(778, 1) &&
!bot->HasItemCount(1819, 1) &&
!bot->HasItemCount(1893, 1) &&
!bot->HasItemCount(1959, 1) &&
!bot->HasItemCount(2901, 1) &&
!bot->HasItemCount(9465, 1) &&
!bot->HasItemCount(20723, 1) &&
!bot->HasItemCount(40772, 1) &&
!bot->HasItemCount(40892, 1) &&
!bot->HasItemCount(40893, 1) )

if (skillId == SKILL_SKINNING && !bot->HasItemCount(7005, 1) &&
!bot->HasItemCount(40772, 1) &&
!bot->HasItemCount(40893, 1) &&
!bot->HasItemCount(12709, 1) &&
!bot->HasItemCount(19901, 1) )
return false;

return true;
Expand Down
14 changes: 7 additions & 7 deletions modules/mod-playerbots/src/PlayerbotAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4224,19 +4224,18 @@ std::pair<uint32, uint32> PlayerbotAI::GetPriorityBracket(ActivePiorityType type
case ActivePiorityType::PLAYER_GUILD:
return {0, 50};
case ActivePiorityType::IN_ACTIVE_AREA:
return {30, 100};
case ActivePiorityType::IN_ACTIVE_MAP:
case ActivePiorityType::IN_EMPTY_SERVER:
return {50, 100};
case ActivePiorityType::IN_INACTIVE_MAP:
case ActivePiorityType::IN_ACTIVE_MAP:
return {70, 100};
case ActivePiorityType::IN_EMPTY_SERVER:
case ActivePiorityType::IN_INACTIVE_MAP:
return {80, 100};
default:
return {90, 100};
}

return {90, 100};
}
}

bool PlayerbotAI::AllowActive(ActivityType activityType)
{
Expand Down Expand Up @@ -4300,7 +4299,8 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
}

// GetPriorityBracket acitivity
float activePerc = 100;
float normalizedBotActiveAlone = sPlayerbotAIConfig->botActiveAlone > 100 ? 100 : sPlayerbotAIConfig->botActiveAlone;
float activePerc = normalizedBotActiveAlone;
if (sPlayerbotAIConfig->botActiveAloneSmartScale &&
bot->GetLevel() >= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMinLevel &&
bot->GetLevel() <= sPlayerbotAIConfig->botActiveAloneSmartScaleWhenMaxLevel)
Expand All @@ -4311,7 +4311,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
if (priorityBracket.first >= activityPercentage) return false;
if (priorityBracket.second <= activityPercentage && priorityBracket.second < 100) return true;
activePerc = (activityPercentage - priorityBracket.first) / (priorityBracket.second - priorityBracket.first);
activePerc *= (priorityBracket.second == 100) ? sPlayerbotAIConfig->botActiveAlone : 100;
activePerc *= (priorityBracket.second == 100) ? normalizedBotActiveAlone : 100;
}

// The last number if the amount it cycles per min. Currently set to 1% of the active bots.
Expand Down
33 changes: 25 additions & 8 deletions modules/mod-playerbots/src/PlayerbotMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
Player* bot = botSession->GetPlayer();
if (!bot)
{
// Debug log
LOG_DEBUG("mod-playerbots", "Bot player could not be loaded for account ID: {}", botAccountId);
botSession->LogoutPlayer(true);
delete botSession;
botLoading.erase(holder.GetGuid());
Expand All @@ -108,14 +110,22 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con

uint32 masterAccount = holder.GetMasterAccountId();
WorldSession* masterSession = masterAccount ? sWorld->FindSession(masterAccount) : nullptr;

// Check if masterSession->GetPlayer() is valid
Player* masterPlayer = masterSession ? masterSession->GetPlayer() : nullptr;
if (masterSession && !masterPlayer)
{
LOG_DEBUG("mod-playerbots", "Master session found but no player is associated for master account ID: {}", masterAccount);
}

std::ostringstream out;
bool allowed = false;
if (botAccountId == masterAccount)
{
allowed = true;
}
else if (masterSession && sPlayerbotAIConfig->allowGuildBots && bot->GetGuildId() != 0 &&
bot->GetGuildId() == masterSession->GetPlayer()->GetGuildId())
bot->GetGuildId() == masterPlayer->GetGuildId())
{
allowed = true;
}
Expand All @@ -129,10 +139,14 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
out << "Failure: You are not allowed to control bot " << bot->GetName().c_str();
}

if (allowed && masterSession)
if (allowed && masterSession && masterPlayer)
{
Player* player = masterSession->GetPlayer();
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(player);
PlayerbotMgr* mgr = GET_PLAYERBOT_MGR(masterPlayer);
if (!mgr)
{
LOG_DEBUG("mod-playerbots", "PlayerbotMgr not found for master player with GUID: {}", masterPlayer->GetGUID().GetRawValue());
}

uint32 count = mgr->GetPlayerbotsCount();
uint32 cls_count = mgr->GetPlayerbotsCountByClass(bot->getClass());
if (count >= sPlayerbotAIConfig->maxAddedBots)
Expand Down Expand Up @@ -428,14 +442,17 @@ void PlayerbotHolder::OnBotLogin(Player* const bot)
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
if (!botAI)
{
// Log a warning here to indicate that the botAI is null
LOG_DEBUG("mod-playerbots", "PlayerbotAI is null for bot with GUID: {}", bot->GetGUID().GetRawValue());
return;
}

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();
Expand Down
4 changes: 1 addition & 3 deletions modules/mod-playerbots/src/RandomPlayerbotMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1262,9 +1262,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>&
if (botAI)
{
// ignore when in when taxi with boat/zeppelin and has players nearby
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) &&
bot->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) &&
botAI->HasPlayerNearby())
if (botAI->IsTaxiFlying() && botAI->HasPlayerNearby())
return;
}

Expand Down
10 changes: 10 additions & 0 deletions modules/mod-playerbots/src/strategy/AiObjectContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
actionContexts.Add(new WotlkDungeonOKActionContext());
actionContexts.Add(new WotlkDungeonDTKActionContext());
actionContexts.Add(new WotlkDungeonVHActionContext());
actionContexts.Add(new WotlkDungeonGDActionContext());
actionContexts.Add(new WotlkDungeonHoSActionContext());
actionContexts.Add(new WotlkDungeonHoLActionContext());
actionContexts.Add(new WotlkDungeonUPActionContext());
actionContexts.Add(new WotlkDungeonCoSActionContext());

triggerContexts.Add(new TriggerContext());
triggerContexts.Add(new ChatTriggerContext());
Expand All @@ -72,6 +77,11 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
triggerContexts.Add(new WotlkDungeonOKTriggerContext());
triggerContexts.Add(new WotlkDungeonDTKTriggerContext());
triggerContexts.Add(new WotlkDungeonVHTriggerContext());
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
triggerContexts.Add(new WotlkDungeonHoSTriggerContext());
triggerContexts.Add(new WotlkDungeonHoLTriggerContext());
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());

valueContexts.Add(new ValueContext());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,9 +239,16 @@ bool CheckMountStateAction::Mount()
// continue;

uint32 index = (spellInfo->Effects[1].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED ||
spellInfo->Effects[2].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)
? 1
: 0;
spellInfo->Effects[2].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED ||
// Winged Steed of the Ebon Blade
// This mount is meant to autoscale from a 150% flyer
// up to a 280% as you train your flying skill up.
// This incorrectly gets categorised as a ground mount, force this to flyer only.
// TODO: Add other scaling mounts here if they have the same issue, or adjust above
// checks so that they are all correctly detected.
spellInfo->Id == 54729)
? 1 // Flying Mount
: 0; // Ground Mount

if (index == 0 &&
std::max(spellInfo->Effects[EFFECT_1].BasePoints, spellInfo->Effects[EFFECT_2].BasePoints) > 59)
Expand All @@ -263,6 +270,42 @@ bool CheckMountStateAction::Mount()
: 0;
}

// Check for preferred mounts table in db
QueryResult checkTable = PlayerbotsDatabase.Query(
"SELECT EXISTS(SELECT * FROM information_schema.tables WHERE table_schema = 'acore_playerbots' AND table_name = 'playerbots_preferred_mounts')");

if (checkTable)
{
uint32 tableExists = checkTable->Fetch()[0].Get<uint32>();
if (tableExists == 1)
{
// Check for preferred mount entry
QueryResult result = PlayerbotsDatabase.Query(
"SELECT spellid FROM playerbots_preferred_mounts WHERE guid = {} AND type = {}",
bot->GetGUID().GetCounter(), masterMountType);

if (result)
{
std::vector<uint32> mounts;
do
{
Field* fields = result->Fetch();
uint32 spellId = fields[0].Get<uint32>();
mounts.push_back(spellId);
} while (result->NextRow());

uint32 index = urand(0, mounts.size() - 1);
// Validate spell ID
if (index < mounts.size() && sSpellMgr->GetSpellInfo(mounts[index]))
{
// TODO: May want to do checks for 'bot riding skill > skill required to ride the mount'
return botAI->CastSpell(mounts[index], bot);
}
}
}
}

// No preferred mount found (or invalid), continue with random mount selection
std::map<int32, std::vector<uint32>>& spells = allSpells[masterMountType];
if (hasSwiftMount)
{
Expand Down
Loading

0 comments on commit c61211c

Please sign in to comment.