diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 8af2e0dd..57b4068c 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -312,7 +312,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa break; case CLASS_WARRIOR: if (tab == 2) - engine->addStrategiesNoInit("tank", "tank assist", "aoe", "mark rti", nullptr); + engine->addStrategiesNoInit("tank", "tank assist", "aoe", nullptr); else if (player->GetLevel() < 36 || tab == 0) engine->addStrategiesNoInit("arms", "aoe", "dps assist", /*"behind",*/ nullptr); else diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 00c84c57..cb9facf2 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -4135,18 +4135,33 @@ inline bool ZoneHasRealPlayers(Player* bot) bool PlayerbotAI::AllowActive(ActivityType activityType) { + // when botActiveAlone is 100% and smartScale disabled + if (sPlayerbotAIConfig->botActiveAlone >= 100 && !sPlayerbotAIConfig->botActiveAloneSmartScale) + { + return true; + } + + // Is in combat. Always defend yourself. + if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) + { + if (bot->IsInCombat()) + { + return true; + } + } + // only keep updating till initializing time has completed, // which prevents unneeded expensive GameTime calls. - // if (_isBotInitializing) - // { - // _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.12; + if (_isBotInitializing) + { + _isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig->maxRandomBots * 0.12; - // // no activity allowed during bot initialization - // if (_isBotInitializing) - // { - // return false; - // } - // } + // no activity allowed during bot initialization + if (_isBotInitializing) + { + return false; + } + } // General exceptions if (activityType == PACKET_ACTIVITY) @@ -4159,16 +4174,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) { return true; } - - // Is in combat. Defend yourself. - if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY) - { - if (bot->IsInCombat()) - { - return true; - } - } - + // bot map has active players. if (sPlayerbotAIConfig->BotActiveAloneForceWhenInMap) { @@ -4307,11 +4313,7 @@ bool PlayerbotAI::AllowActive(ActivityType activityType) { return false; } - if (sPlayerbotAIConfig->botActiveAlone >= 100 && !sPlayerbotAIConfig->botActiveAloneSmartScale) - { - return true; - } - + // ####################################################################################### // All mandatory conditations are checked to be active or not, from here the remaining // situations are usable for scaling when enabled. diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 89de2570..04f2fc9a 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -207,7 +207,10 @@ void PlayerbotFactory::Randomize(bool incremental) Prepare(); LOG_DEBUG("playerbots", "Resetting player..."); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); - bot->resetTalents(true); + if (!sPlayerbotAIConfig->equipmentPersistence || level < sPlayerbotAIConfig->equipmentPersistenceLevel) + { + bot->resetTalents(true); + } // bot->SaveToDB(false, false); ClearSkills(); // bot->SaveToDB(false, false); @@ -267,7 +270,7 @@ void PlayerbotFactory::Randomize(bool incremental) pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents"); LOG_DEBUG("playerbots", "Initializing talents..."); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { InitTalentsTree(); } @@ -302,7 +305,7 @@ void PlayerbotFactory::Randomize(bool incremental) pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip"); LOG_DEBUG("playerbots", "Initializing equipmemt..."); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) + if (!incremental || !sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { InitEquipment(incremental, incremental ? false : sPlayerbotAIConfig->twoRoundsGearInit); } diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index dad46bd8..ff16df1a 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -119,6 +119,7 @@ public: creators["move random"] = &StrategyContext::move_random; creators["formation"] = &StrategyContext::combat_formation; creators["move from group"] = &StrategyContext::move_from_group; + creators["worldbuff"] = &StrategyContext::world_buff; } private: @@ -186,6 +187,7 @@ private: static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); } static Strategy* combat_formation(PlayerbotAI* ai) { return new CombatFormationStrategy(ai); } static Strategy* move_from_group(PlayerbotAI* botAI) { return new MoveFromGroupStrategy(botAI); } + static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); } }; class MovementStrategyContext : public NamedObjectContext diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 3600ce66..4be5da24 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -105,7 +105,8 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) return false; } - if (!bot->IsValidAttackTarget(target) && sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId())) + if (sPlayerbotAIConfig->IsInPvpProhibitedZone(bot->GetZoneId()) + && (target->IsPlayer() || target->IsPet() || !bot->IsValidAttackTarget(target))) { if (verbose) botAI->TellError("I cannot attack others in PvP prohibited zones"); diff --git a/src/strategy/actions/CheckMountStateAction.cpp b/src/strategy/actions/CheckMountStateAction.cpp index 7ae52f74..953f47c6 100644 --- a/src/strategy/actions/CheckMountStateAction.cpp +++ b/src/strategy/actions/CheckMountStateAction.cpp @@ -71,14 +71,17 @@ bool CheckMountStateAction::Execute(Event event) if (!bot->GetGroup() || bot->GetGroup()->GetLeaderGUID() != master->GetGUID()) return false; + auto masterInShapeshiftForm = master->GetShapeshiftForm(); + // bool farFromMaster = sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->sightDistance; - if (master->IsMounted() && !bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat() && - botAI->GetState() != BOT_STATE_COMBAT) + if ((master->IsMounted() || masterInShapeshiftForm == FORM_FLIGHT || masterInShapeshiftForm == FORM_FLIGHT_EPIC || masterInShapeshiftForm == FORM_TRAVEL) + && !bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat() && botAI->GetState() != BOT_STATE_COMBAT) { return Mount(); } - if (!master->IsMounted() && bot->IsMounted()) + if ((!master->IsMounted() && masterInShapeshiftForm != FORM_FLIGHT && masterInShapeshiftForm != FORM_FLIGHT_EPIC && masterInShapeshiftForm != FORM_TRAVEL) + && bot->IsMounted()) { WorldPacket emptyPacket; bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); @@ -188,12 +191,23 @@ bool CheckMountStateAction::Mount() botAI->RemoveShapeshift(); botAI->RemoveAura("tree of life"); int32 masterSpeed = 59; + int32 masterMountType = 0; SpellInfo const* masterSpell = nullptr; - if (master && !master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty() && !bot->InBattleground()) + if (master != nullptr && !bot->InBattleground()) { - masterSpell = master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetSpellInfo(); - masterSpeed = std::max(masterSpell->Effects[1].BasePoints, masterSpell->Effects[2].BasePoints); + auto masterInShapeshiftForm = master->GetShapeshiftForm(); + + if (!master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty()) + { + masterSpell = master->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetSpellInfo(); + masterSpeed = std::max(masterSpell->Effects[1].BasePoints, masterSpell->Effects[2].BasePoints); + } + else if (masterInShapeshiftForm == FORM_FLIGHT || masterInShapeshiftForm == FORM_FLIGHT_EPIC) + { + masterMountType = 1; + masterSpeed = (masterInShapeshiftForm == FORM_FLIGHT_EPIC) ? 279 : 149; + } } else { @@ -261,7 +275,6 @@ bool CheckMountStateAction::Mount() allSpells[index][effect].push_back(spellId); } - int32 masterMountType = 0; if (masterSpell) { masterMountType = (masterSpell->Effects[1].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED || diff --git a/src/strategy/actions/LfgActions.cpp b/src/strategy/actions/LfgActions.cpp index fb3d008f..48890077 100644 --- a/src/strategy/actions/LfgActions.cpp +++ b/src/strategy/actions/LfgActions.cpp @@ -8,10 +8,14 @@ #include "AiFactory.h" #include "ItemVisitors.h" #include "LFGMgr.h" +#include "LFGPackets.h" +#include "Opcodes.h" #include "Playerbots.h" +#include "World.h" using namespace lfg; + bool LfgJoinAction::Execute(Event event) { return JoinLFG(); } uint32 LfgJoinAction::GetRoles() @@ -146,7 +150,22 @@ bool LfgJoinAction::JoinLFG() // Set RbotAId Browser comment std::string const _gs = std::to_string(botAI->GetEquipGearScore(bot, false, false)); - sLFGMgr->JoinLfg(bot, roleMask, list, _gs); + + // JoinLfg is not threadsafe, so make packet and queue into session + // sLFGMgr->JoinLfg(bot, roleMask, list, _gs); + + WorldPacket* data = new WorldPacket(CMSG_LFG_JOIN); + *data << (uint32)roleMask; + *data << (bool)false; + *data << (bool)false; + // Slots + *data << (uint8)(list.size()); + for (uint32 dungeon : list) + *data << (uint32)dungeon; + // Needs + *data << (uint8)3 << (uint8)0 << (uint8)0 << (uint8)0; + *data << _gs; + bot->GetSession()->QueuePacket(data); return true; } diff --git a/src/strategy/generic/NonCombatStrategy.cpp b/src/strategy/generic/NonCombatStrategy.cpp index c35e6168..1fa49d61 100644 --- a/src/strategy/generic/NonCombatStrategy.cpp +++ b/src/strategy/generic/NonCombatStrategy.cpp @@ -16,7 +16,6 @@ void NonCombatStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("near dark portal", NextAction::array(0, new NextAction("move to dark portal", 1.0f), nullptr))); // triggers.push_back(new TriggerNode("at dark portal azeroth", NextAction::array(0, new NextAction("use dark portal azeroth", 1.0f), nullptr))); // triggers.push_back(new TriggerNode("at dark portal outland", NextAction::array(0, new NextAction("move from dark portal", 1.0f), nullptr))); - // triggers.push_back(new TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), nullptr))); // triggers.push_back(new TriggerNode("vehicle near", NextAction::array(0, new NextAction("enter vehicle", 10.0f), nullptr))); } @@ -33,3 +32,8 @@ void MountStrategy::InitTriggers(std::vector& triggers) nullptr)));*/ /*triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("mount", 4.0f), nullptr)));*/ } + +void WorldBuffStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("need world buff", NextAction::array(0, new NextAction("world buff", 1.0f), NULL))); +} diff --git a/src/strategy/generic/NonCombatStrategy.h b/src/strategy/generic/NonCombatStrategy.h index d032dcf4..c6f266d1 100644 --- a/src/strategy/generic/NonCombatStrategy.h +++ b/src/strategy/generic/NonCombatStrategy.h @@ -48,4 +48,14 @@ public: std::string const getName() override { return "attack tagged"; } }; +class WorldBuffStrategy : public Strategy +{ +public: + WorldBuffStrategy(PlayerbotAI* ai) : Strategy(ai) {} + + uint32 GetType() const override { return STRATEGY_TYPE_NONCOMBAT; } + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "worldbuff"; } +}; + #endif