diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 45b98147..bce2e51f 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -87,8 +87,7 @@ AiPlayerbot.RandomBotShowCloak = 1 AiPlayerbot.DisableRandomLevels = 0 # Set randombots starting level here if "AiPlayerbot.DisableRandomLevels" enabled -# Recommended: 5+ -AiPlayerbot.RandombotStartingLevel = 5 +AiPlayerbot.RandombotStartingLevel = 1 # Set kill XP rate for bots (default: 1) # Server XP Rate * AiPlayerbot.KillXPRate @@ -456,7 +455,7 @@ AiPlayerbot.GlobalCooldown = 500 AiPlayerbot.MaxWaitForMove = 5000 # Action expiration time -AiPlayerbot.ExpireActionTime = 500 +AiPlayerbot.ExpireActionTime = 5000 # Max dispel auras duration AiPlayerbot.DispelAuraDuration = 700 diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index ac1c7139..733da71d 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -552,7 +552,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (sPlayerbotAIConfig->autoDoQuests) { - nonCombatEngine->addStrategy("travel"); + // nonCombatEngine->addStrategy("travel"); nonCombatEngine->addStrategy("rpg"); } else { nonCombatEngine->addStrategy("move random"); @@ -583,7 +583,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const if (sPlayerbotAIConfig->autoDoQuests) { - nonCombatEngine->addStrategy("travel"); + // nonCombatEngine->addStrategy("travel"); nonCombatEngine->addStrategy("rpg"); } else { nonCombatEngine->addStrategy("move random"); diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 840f34d7..dc5f819f 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -9,6 +9,7 @@ #include "GuildMgr.h" #include "MapMgr.h" #include "PetDefines.h" +#include "PlayerbotAIConfig.h" #include "Playerbots.h" #include "PerformanceMonitor.h" #include "PlayerbotDbStore.h" @@ -81,11 +82,7 @@ void PlayerbotFactory::Prepare() { if (!itemQuality) { - // if (level < 80) { itemQuality = ITEM_QUALITY_RARE; - // } else { - // itemQuality = ITEM_QUALITY_EPIC; - // } } if (bot->isDead()) @@ -93,16 +90,8 @@ void PlayerbotFactory::Prepare() bot->CombatStop(true); - if (!sPlayerbotAIConfig->disableRandomLevels) - { - bot->GiveLevel(level); - // bot->SetLevel(level); - } - else if (bot->getLevel() < sPlayerbotAIConfig->randombotStartingLevel) - { - bot->SetLevel(sPlayerbotAIConfig->randombotStartingLevel); - } - + bot->GiveLevel(level); + bot->SetUInt32Value(PLAYER_XP, 0); if (!sPlayerbotAIConfig->randomBotShowHelmet || !urand(0, 4)) { bot->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); @@ -123,8 +112,6 @@ void PlayerbotFactory::Randomize(bool incremental) LOG_INFO("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full")); Prepare(); - // bot->SaveToDB(false, false); - // bot->SaveToDB(false, false); LOG_INFO("playerbots", "Resetting player..."); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); bot->resetTalents(true); @@ -163,14 +150,9 @@ void PlayerbotFactory::Randomize(bool incremental) InitQuests(specialQuestIds); // quest rewards boost bot level, so reduce back - if (!sPlayerbotAIConfig->disableRandomLevels) - { - bot->SetLevel(level); - } - else if (bot->getLevel() < sPlayerbotAIConfig->randombotStartingLevel) - { - bot->SetLevel(sPlayerbotAIConfig->randombotStartingLevel); - } + + bot->GiveLevel(level); + ClearInventory(); bot->SetUInt32Value(PLAYER_XP, 0); @@ -346,8 +328,9 @@ void PlayerbotFactory::Randomize(bool incremental) void PlayerbotFactory::Refresh() { - Prepare(); + // Prepare(); // InitEquipment(true); + ClearInventory(); InitAmmo(); InitFood(); InitReagents(); @@ -656,6 +639,8 @@ void PlayerbotFactory::ClearSkills() void PlayerbotFactory::ClearEverything() { bot->SaveToDB(false, false); + bot->GiveLevel(bot->getClass() == CLASS_DEATH_KNIGHT ? sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) : sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)); + bot->SetUInt32Value(PLAYER_XP, 0); LOG_INFO("playerbots", "Resetting player..."); bot->resetTalents(true); bot->SaveToDB(false, false); diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index f5239185..e1842de8 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -942,8 +942,8 @@ bool RandomPlayerbotMgr::ProcessBot(Player* player) if (!teleport) { LOG_INFO("players", "Bot #{} <{}>: teleport for level and refresh", bot, player->GetName()); - RandomTeleportForLevel(player); Refresh(player); + RandomTeleportForLevel(player); uint32 time = urand(sPlayerbotAIConfig->minRandomBotTeleportInterval, sPlayerbotAIConfig->maxRandomBotTeleportInterval); ScheduleTeleport(bot, time); return true; @@ -1112,8 +1112,7 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "WITH GroupedData AS ( " "SELECT " "MIN( c.guid ) guid, " - "( " - "AVG( t.maxlevel ) + AVG( t.minlevel )) / 2 lvl " + "(AVG( t.maxlevel ) + AVG( t.minlevel )) / 2 lvl " "FROM " "creature c " "INNER JOIN creature_template t ON c.id1 = t.entry " @@ -1122,12 +1121,12 @@ void RandomPlayerbotMgr::PrepareTeleportCache() "AND t.lootid != 0 " "AND t.unit_flags != 768 " "AND map IN ({}) " - "AND t.maxlevel != 1 " + "AND c.id1 != 32820 " "GROUP BY " "map, " - "ROUND( position_x / 250 ) * 250, " - "ROUND( position_y / 250 ) * 250, " - "ROUND( position_z / 5 ) * 5 " + "ROUND( position_x / 500 ), " + "ROUND( position_y / 500 ), " + "ROUND( position_z / 50 ) " "HAVING " "count(*) > 10 " "AND MAX( t.maxlevel ) - MIN( t.minlevel ) < 5 " @@ -1254,12 +1253,12 @@ void RandomPlayerbotMgr::Randomize(Player* bot) if (bot->InBattleground()) return; - if (bot->getLevel() < 3) + if (bot->getLevel() < 2 || (bot->getLevel() < 56 && bot->getClass() == CLASS_DEATH_KNIGHT)) { RandomizeFirst(bot); - else if (bot->getLevel() < 57 && bot->getClass() == CLASS_DEATH_KNIGHT) - RandomizeFirst(bot); - else if (bot->getLevel() < sPlayerbotAIConfig->randomBotMaxLevel || !sPlayerbotAIConfig->downgradeMaxLevelBot) + } + else if (bot->getLevel() < sPlayerbotAIConfig->randomBotMaxLevel || !sPlayerbotAIConfig->downgradeMaxLevelBot) { IncreaseLevel(bot); + } else { RandomizeFirst(bot); } @@ -1314,6 +1313,12 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) level = urand(std::max(sPlayerbotAIConfig->randomBotMinLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)), std::max(sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL), maxLevel)); } + if (sPlayerbotAIConfig->disableRandomLevels) { + level = bot->getClass() == CLASS_DEATH_KNIGHT ? + std::max(sPlayerbotAIConfig->randombotStartingLevel, sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)) : + sPlayerbotAIConfig->randombotStartingLevel; + } + SetValue(bot, "level", level); PlayerbotFactory factory(bot, level); @@ -1345,6 +1350,41 @@ void RandomPlayerbotMgr::RandomizeFirst(Player* bot) pmo->finish(); } +void RandomPlayerbotMgr::RandomizeMin(Player* bot) +{ + PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "RandomizeMin"); + + uint32 level = sPlayerbotAIConfig->randomBotMinLevel; + + SetValue(bot, "level", level); + + PlayerbotFactory factory(bot, level); + factory.Randomize(false); + + uint32 randomTime = urand(sPlayerbotAIConfig->minRandomBotRandomizeTime, sPlayerbotAIConfig->maxRandomBotRandomizeTime); + uint32 inworldTime = urand(sPlayerbotAIConfig->minRandomBotInWorldTime, sPlayerbotAIConfig->maxRandomBotInWorldTime); + + PlayerbotsDatabasePreparedStatement* stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_UPD_RANDOM_BOTS); + stmt->SetData(0, randomTime); + stmt->SetData(1, "bot_delete"); + stmt->SetData(2, bot->GetGUID().GetCounter()); + PlayerbotsDatabase.Execute(stmt); + + stmt = PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_UPD_RANDOM_BOTS); + stmt->SetData(0, inworldTime); + stmt->SetData(1, "logout"); + stmt->SetData(2, bot->GetGUID().GetCounter()); + PlayerbotsDatabase.Execute(stmt); + + // teleport to a random inn for bot level + GET_PLAYERBOT_AI(bot)->Reset(true); + if (bot->GetGroup()) + bot->RemoveFromGroup(); + + if (pmo) + pmo->finish(); +} + void RandomPlayerbotMgr::Clear(Player* bot) { PlayerbotFactory factory(bot, bot->GetLevel()); @@ -1660,6 +1700,7 @@ bool RandomPlayerbotMgr::HandlePlayerbotConsoleCommand(ChatHandler* handler, cha } std::map handlers; + // handlers["initmin"] = &RandomPlayerbotMgr::RandomizeMin; handlers["init"] = &RandomPlayerbotMgr::RandomizeFirst; handlers["clear"] = &RandomPlayerbotMgr::Clear; handlers["levelup"] = handlers["level"] = &RandomPlayerbotMgr::IncreaseLevel; diff --git a/src/RandomPlayerbotMgr.h b/src/RandomPlayerbotMgr.h index 5af312bc..87640d72 100644 --- a/src/RandomPlayerbotMgr.h +++ b/src/RandomPlayerbotMgr.h @@ -49,6 +49,7 @@ class RandomPlayerbotMgr : public PlayerbotHolder void Randomize(Player* bot); void Clear(Player* bot); void RandomizeFirst(Player* bot); + void RandomizeMin(Player* bot); void IncreaseLevel(Player* bot); void ScheduleTeleport(uint32 bot, uint32 time = 0); void ScheduleChangeStrategy(uint32 bot, uint32 time = 0); diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 00f3b789..fb8a5786 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -158,11 +158,10 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, } bool generatePath = !bot->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && - !bot->IsFlying() && !bot->IsUnderWater(); + !bot->IsFlying() && !bot->isSwimming(); MotionMaster &mm = *bot->GetMotionMaster(); mm.Clear(); mm.MovePoint(mapId, x, y, z, generatePath); - AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); return true; } diff --git a/src/strategy/druid/DruidTriggers.h b/src/strategy/druid/DruidTriggers.h index b94f78d4..280be700 100644 --- a/src/strategy/druid/DruidTriggers.h +++ b/src/strategy/druid/DruidTriggers.h @@ -68,10 +68,10 @@ class MoonfireTrigger : public DebuffTrigger bool IsActive() override; }; -class FaerieFireTrigger : public DebuffTrigger +class FaerieFireTrigger : public DebuffOnBossTrigger { public: - FaerieFireTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "faerie fire") { } + FaerieFireTrigger(PlayerbotAI* botAI) : DebuffOnBossTrigger(botAI, "faerie fire") { } }; class FaerieFireFeralTrigger : public DebuffTrigger diff --git a/src/strategy/hunter/HunterActions.cpp b/src/strategy/hunter/HunterActions.cpp index 9ce55fea..31ac20b3 100644 --- a/src/strategy/hunter/HunterActions.cpp +++ b/src/strategy/hunter/HunterActions.cpp @@ -4,8 +4,14 @@ #include "HunterActions.h" #include "Event.h" +#include "GenericSpellActions.h" #include "Playerbots.h" +bool CastHuntersMarkAction::isUseful() +{ + return CastDebuffSpellAction::isUseful(); +} + bool CastViperStingAction::isUseful() { return AI_VALUE2(uint8, "mana", "self target") < 50 && AI_VALUE2(uint8, "mana", "current target") >= 30; diff --git a/src/strategy/hunter/HunterActions.h b/src/strategy/hunter/HunterActions.h index af04188d..01c8051b 100644 --- a/src/strategy/hunter/HunterActions.h +++ b/src/strategy/hunter/HunterActions.h @@ -11,9 +11,15 @@ class PlayerbotAI; class Unit; -BEGIN_RANGED_SPELL_ACTION(CastHuntersMarkAction, "hunter's mark") -END_SPELL_ACTION() +// BEGIN_RANGED_SPELL_ACTION(CastHuntersMarkAction, "hunter's mark") +// END_SPELL_ACTION() +class CastHuntersMarkAction : public CastDebuffSpellAction +{ + public: + CastHuntersMarkAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "hunter's mark") { } + bool isUseful() override; +}; class CastAutoShotAction : public CastSpellAction { public: diff --git a/src/strategy/hunter/HunterTriggers.h b/src/strategy/hunter/HunterTriggers.h index 46aab8d9..2d43b311 100644 --- a/src/strategy/hunter/HunterTriggers.h +++ b/src/strategy/hunter/HunterTriggers.h @@ -67,10 +67,10 @@ class BlackArrowTrigger : public DebuffTrigger BlackArrowTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "black arrow", 1, true) { } }; -class HuntersMarkTrigger : public DebuffTrigger +class HuntersMarkTrigger : public DebuffOnBossTrigger { public: - HuntersMarkTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "hunter's mark") { } + HuntersMarkTrigger(PlayerbotAI* botAI) : DebuffOnBossTrigger(botAI, "hunter's mark") { } }; class FreezingTrapTrigger : public HasCcTargetTrigger diff --git a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp index 27c48ea4..7440817f 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp @@ -596,8 +596,10 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt() } if (playerWithIcebolt) { Unit* boss = AI_VALUE2(Unit*, "find target", "sapphiron"); - float angle = boss->GetAngle(playerWithIcebolt); - return MoveTo(NAXX_MAP_ID, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f, playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT); + if (boss) { + float angle = boss->GetAngle(playerWithIcebolt); + return MoveTo(NAXX_MAP_ID, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f, playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT); + } } return false; } diff --git a/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h b/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h index 86b6a82e..a43dd638 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h +++ b/src/strategy/raids/naxxramas/RaidNaxxBossHelper.h @@ -22,7 +22,7 @@ class GenericBossHelper : public AiObject { public: GenericBossHelper(PlayerbotAI* botAI, std::string name): AiObject(botAI), name_(name) {} virtual bool UpdateBossAI() { - if(unit_ && !unit_->IsInWorld()) { + if(unit_ && (!unit_->IsInWorld() || !unit_->IsAlive())) { unit_ = nullptr; } if (!unit_) { diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 81c4389b..7877ed8b 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -205,6 +205,15 @@ bool DebuffTrigger::IsActive() return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", GetTargetName()) > life_bound; } +bool DebuffOnBossTrigger::IsActive() +{ + if (!DebuffTrigger::IsActive()) { + return false; + } + Creature *c = GetTarget()->ToCreature(); + return c && ((c->IsDungeonBoss()) || (c->isWorldBoss())); +} + bool SpellTrigger::IsActive() { return GetTarget(); diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index 282146de..b25965de 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -314,6 +314,13 @@ class DebuffTrigger : public BuffTrigger float life_bound; }; +class DebuffOnBossTrigger : public DebuffTrigger +{ + public: + DebuffOnBossTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false) : DebuffTrigger(botAI, spell, checkInterval, checkIsOwner) {} + bool IsActive() override; +}; + class DebuffOnAttackerTrigger : public DebuffTrigger { public: diff --git a/src/strategy/values/IsFacingValue.cpp b/src/strategy/values/IsFacingValue.cpp index 495bc920..8aa32c9b 100644 --- a/src/strategy/values/IsFacingValue.cpp +++ b/src/strategy/values/IsFacingValue.cpp @@ -11,5 +11,5 @@ bool IsFacingValue::Calculate() if (!target) return false; - return bot->HasInArc(CAST_ANGLE_IN_FRONT, target, sPlayerbotAIConfig->sightDistance); + return bot->HasInArc(CAST_ANGLE_IN_FRONT, target); }