Merge branch 'master' of github.com:liyunfan1223/mod-playerbots

This commit is contained in:
Yunfan Li
2023-12-25 18:49:05 +08:00
17 changed files with 126 additions and 18 deletions

View File

@@ -124,6 +124,7 @@ bool PlayerbotAIConfig::Initialize()
maxRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotReviveTime", 5 * MINUTE);
minRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotTeleportInterval", 1 * HOUR);
maxRandomBotTeleportInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotTeleportInterval", 5 * HOUR);
randomBotInWorldWithRotaionDisabled = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotInWorldWithRotaionDisabled", 1 * YEAR);
randomBotTeleportDistance = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotTeleportDistance", 100);
randomBotsPerInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotsPerInterval", MINUTE);
minRandomBotsPriceChangeInterval = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotsPriceChangeInterval", 2 * HOUR);
@@ -328,6 +329,8 @@ bool PlayerbotAIConfig::Initialize()
randombotsWalkingRPGInDoors = sConfigMgr->GetOption<bool>("AiPlayerbot.RandombotsWalkingRPG.InDoors", false);
minEnchantingBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.MinEnchantingBotLevel", 60);
randombotStartingLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.RandombotStartingLevel", 5);
enableRotation = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableRotation", false);
rotationPoolSize = sConfigMgr->GetOption<int32>("AiPlayerbot.RotationPoolSize", 500);
gearscorecheck = sConfigMgr->GetOption<bool>("AiPlayerbot.GearScoreCheck", false);
randomBotPreQuests = sConfigMgr->GetOption<bool>("AiPlayerbot.PreQuests", true);

View File

@@ -70,6 +70,7 @@ class PlayerbotAIConfig
uint32 minRandomBotChangeStrategyTime, maxRandomBotChangeStrategyTime;
uint32 minRandomBotReviveTime, maxRandomBotReviveTime;
uint32 minRandomBotTeleportInterval, maxRandomBotTeleportInterval;
uint32 randomBotInWorldWithRotaionDisabled;
uint32 minRandomBotPvpTime, maxRandomBotPvpTime;
uint32 randomBotsPerInterval;
uint32 minRandomBotsPriceChangeInterval, maxRandomBotsPriceChangeInterval;
@@ -108,6 +109,8 @@ class PlayerbotAIConfig
bool randombotsWalkingRPGInDoors;
uint32 minEnchantingBotLevel;
uint32 randombotStartingLevel;
bool enableRotation;
uint32 rotationPoolSize;
bool gearscorecheck;
bool randomBotPreQuests;

View File

@@ -541,6 +541,7 @@ void PlayerbotFactory::InitPetTalents()
// LOG_INFO("playerbots", "{} init pet talents failed with petTalentType < 0({})", bot->GetName().c_str(), pet_family->petTalentType);
return;
}
pet->resetTalents();
std::map<uint32, std::vector<TalentEntry const*> > spells;
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
{
@@ -798,7 +799,9 @@ void PlayerbotFactory::InitTalentsTree(bool increment/*false*/, bool use_templat
{
uint32 specNo;
uint8 cls = bot->getClass();
if (increment && bot->GetFreeTalentPoints() <= 2) {
std::map<uint8, uint32> tabs = AiFactory::GetPlayerSpecTabs(bot);
uint32 total_tabs = tabs[0] + tabs[1] + tabs[2];
if (increment && bot->GetFreeTalentPoints() <= 2 && total_tabs != 0) {
specNo = AiFactory::GetPlayerSpecTab(bot);
} else {
uint32 point = urand(0, 100);

View File

@@ -287,10 +287,10 @@ void RandomPlayerbotFactory::CreateRandomBots()
}
PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS));
CharacterDatabase.Execute("UPDATE playerbots_names SET in_use=0 WHERE in_use=1");
CharacterDatabase.DirectExecute("UPDATE playerbots_names SET in_use = 0 WHERE in_use = 1");
/* TODO(yunfan): we need to sleep here to wait for async account deleted, or the newly account won't be created correctly
the better way is turning the async db operation to sync db operation */
std::this_thread::sleep_for(100ms * sPlayerbotAIConfig->randomBotAccountCount);
std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount);
LOG_INFO("playerbots", "Random bot characters deleted.");
LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server...");
World::StopNow(SHUTDOWN_EXIT_CODE);
@@ -335,7 +335,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
if (account_creation) {
/* wait for async accounts create to make character create correctly, same as account delete */
std::this_thread::sleep_for(100ms * sPlayerbotAIConfig->randomBotAccountCount);
std::this_thread::sleep_for(10ms * sPlayerbotAIConfig->randomBotAccountCount);
}
LOG_INFO("playerbots", "Creating random bot characters...");
@@ -403,7 +403,7 @@ void RandomPlayerbotFactory::CreateRandomBots()
if (bot_creation) {
LOG_INFO("playerbots", "Waiting for {} characters loading into database...", totalCharCount);
/* wait for characters load into database, or characters will fail to loggin */
std::this_thread::sleep_for(15ms * totalCharCount);
std::this_thread::sleep_for(10s);
}
for (WorldSession* session : sessionBots)

View File

@@ -337,6 +337,11 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
for (std::vector<uint32>::iterator i = sPlayerbotAIConfig->randomBotAccounts.begin(); i != sPlayerbotAIConfig->randomBotAccounts.end(); i++)
{
uint32 accountId = *i;
if (sPlayerbotAIConfig->enableRotation) {
uint32 limit = std::min((uint32)sPlayerbotAIConfig->randomBotAccounts.size(), sPlayerbotAIConfig->rotationPoolSize / 10 + 1);
uint32 index = urand(0, limit);
accountId = sPlayerbotAIConfig->randomBotAccounts[index];
}
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
stmt->SetData(0, accountId);
PreparedQueryResult result = CharacterDatabase.Query(stmt);
@@ -359,8 +364,12 @@ uint32 RandomPlayerbotMgr::AddRandomBots()
if (std::find(currentBots.begin(), currentBots.end(), guid) != currentBots.end())
continue;
SetEventValue(guid, "add", 1, urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime));
uint32 add_time = sPlayerbotAIConfig->enableRotation ?
urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime) :
sPlayerbotAIConfig->randomBotInWorldWithRotaionDisabled;
SetEventValue(guid, "add", 1, add_time);
SetEventValue(guid, "logout", 0, 0);
currentBots.push_back(guid);
@@ -969,8 +978,8 @@ void RandomPlayerbotMgr::Revive(Player* player)
SetEventValue(bot, "revive", 0, 0);
RandomTeleportGrindForLevel(player);
Refresh(player);
RandomTeleportGrindForLevel(player);
}
void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector<WorldLocation>& locs, bool hearth)

View File

@@ -337,7 +337,7 @@ bool AutoSetTalentsAction::Execute(Event event)
PlayerbotFactory factory(bot, bot->GetLevel());
factory.InitTalentsTree(true, true, true);
factory.InitPetTalents();
botAI->TellMaster(out);
return true;

View File

@@ -179,7 +179,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
p.rpos(0);
bot->GetSession()->HandleQuestgiverAcceptQuestOpcode(p);
if (bot->GetQuestStatus(questId) == QUEST_STATUS_NONE && !sPlayerbotAIConfig->syncQuestWithPlayer)
if (bot->GetQuestStatus(questId ) == QUEST_STATUS_NONE && sPlayerbotAIConfig->syncQuestWithPlayer)
{
Object* pObject = ObjectAccessor::GetObjectByTypeMask(*bot, questGiver, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);
bot->AddQuest(quest, pObject);
@@ -191,6 +191,7 @@ bool QuestAction::AcceptQuest(Quest const* quest, ObjectGuid questGiver)
botAI->TellMaster(out);
return true;
}
out << "Cannot accept";
}
out << " " << chat->FormatQuest(quest);

View File

@@ -13,6 +13,9 @@ bool QuestConfirmAcceptAction::Execute(Event event)
if (!quest || !bot->CanAddQuest(quest, true)) {
return false;
}
std::ostringstream out;
out << "Quest: " << chat->FormatQuest(quest) << " confirm accept";
botAI->TellMaster(out);
bot->GetSession()->HandleQuestConfirmAccept(sendPacket);
return true;
}

View File

@@ -16,10 +16,10 @@ class Player;
class PlayerbotAI;
class WorldObject;
class QuestConfirmAcceptAction : public QuestAction
class QuestConfirmAcceptAction : public Action
{
public:
QuestConfirmAcceptAction(PlayerbotAI* botAI) : QuestAction(botAI, "quest confirm accept") {}
QuestConfirmAcceptAction(PlayerbotAI* botAI) : Action(botAI, "quest confirm accept") {}
bool Execute(Event event) override;
};

View File

@@ -8,6 +8,7 @@
#include "ItemUsageValue.h"
#include "Object.h"
#include "Playerbots.h"
#include "QuestDef.h"
#include "WorldPacket.h"
void TalkToQuestGiverAction::ProcessQuest(Quest const* quest, Object* questGiver)
@@ -238,6 +239,7 @@ bool TurnInQueryQuestAction::Execute(Event event)
}
}
std::ostringstream out;
out << "Quest ";
switch (status)
{
case QUEST_STATUS_COMPLETE:
@@ -252,6 +254,9 @@ bool TurnInQueryQuestAction::Execute(Event event)
case QUEST_STATUS_FAILED:
out << "|cffff0000Failed|r";
break;
case QUEST_STATUS_REWARDED:
out << "|cffff0000Rewarded|r";
break;
}
out << ": " << chat->FormatQuest(quest);

View File

@@ -24,6 +24,7 @@
#include "QuestAction.h"
#include "PassLeadershipToMasterAction.h"
#include "PetitionSignAction.h"
#include "QuestConfirmAcceptAction.h"
#include "ReadyCheckAction.h"
#include "RememberTaxiAction.h"
#include "ReviveFromCorpseAction.h"
@@ -36,6 +37,7 @@
#include "TradeStatusAction.h"
#include "UseMeetingStoneAction.h"
#include "NamedObjectContext.h"
#include "QuestConfirmAcceptAction.h"
class PlayerbotAI;
@@ -92,6 +94,7 @@ class WorldPacketActionContext : public NamedObjectContext<Action>
creators["see spell"] = &WorldPacketActionContext::see_spell;
creators["arena team accept"] = &WorldPacketActionContext::arena_team_accept;
creators["turn in query quest"] = &WorldPacketActionContext::turn_in_query_quest;
creators["quest confirm accept"] = &WorldPacketActionContext::quest_confirm_accept;
}
private:
@@ -143,6 +146,7 @@ class WorldPacketActionContext : public NamedObjectContext<Action>
static Action* see_spell(PlayerbotAI* botAI) { return new SeeSpellAction(botAI); }
static Action* arena_team_accept(PlayerbotAI* botAI) { return new ArenaTeamAcceptAction(botAI); }
static Action* turn_in_query_quest(PlayerbotAI* botAI) { return new TurnInQueryQuestAction(botAI); }
static Action* quest_confirm_accept(PlayerbotAI* botAI) { return new QuestConfirmAcceptAction(botAI); }
};
#endif

View File

@@ -79,7 +79,6 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
CombatStrategy::InitTriggers(triggers);
// triggers.push_back(new TriggerNode("enemy too close for auto shot", NextAction::array(0, new NextAction("switch to melee", ACTION_HIGH), nullptr)));
triggers.push_back(new TriggerNode("enemy is close",
NextAction::array(0,
new NextAction("wing clip", ACTION_HIGH + 1),

View File

@@ -4,6 +4,7 @@
#include "RangeTriggers.h"
#include "MoveSplineInit.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "ServerFacade.h"
@@ -16,8 +17,8 @@ bool EnemyTooCloseForSpellTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
target->GetObjectSize() <= 10.0f &&
AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig->tooCloseDistance;
target->GetObjectSize() <= 10.0f &&
target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
// Unit* target = AI_VALUE(Unit*, "current target");
// if (!target) {
// return false;
@@ -79,7 +80,9 @@ bool EnemyTooCloseForAutoShotTrigger::IsActive()
bool EnemyTooCloseForShootTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) && AI_VALUE2(float, "distance", "current target") <= sPlayerbotAIConfig->shootDistance;
// target->IsWithinCombatRange()
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) && target->IsWithinCombatRange(bot, MIN_MELEE_REACH);
// Unit* target = AI_VALUE(Unit*, "current target");
// if (!target)